Files
tnb.server/WarehouseMgr/Tnb.WarehouseMgr/WmsOutStockService.cs
2024-04-23 10:16:16 +08:00

1037 lines
59 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Diagnostics;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
using JNPF.Common.Core.Manager;
using JNPF.Common.Dtos.VisualDev;
using JNPF.Common.Extension;
using JNPF.Common.Security;
using JNPF.EventBus;
using JNPF.FriendlyException;
using JNPF.Systems.Entitys.Permission;
using JNPF.Systems.Interfaces.System;
using JNPF.VisualDev;
using JNPF.VisualDev.Entitys;
using JNPF.VisualDev.Interfaces;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using SqlSugar;
using Tnb.BasicData.Entities;
using Tnb.Common.Utils;
using Tnb.WarehouseMgr.Entities;
using Tnb.WarehouseMgr.Entities.Attributes;
using Tnb.WarehouseMgr.Entities.Consts;
using Tnb.WarehouseMgr.Entities.Dto;
using Tnb.WarehouseMgr.Entities.Dto.Inputs;
using Tnb.WarehouseMgr.Entities.Enums;
using Tnb.WarehouseMgr.Interfaces;
using Tnb.WarehouseMgr.Print;
namespace Tnb.WarehouseMgr
{
/// <summary>
/// 出库申请业务类
/// </summary>
[OverideVisualDev(ModuleConsts.MODULE_WMSOUTSTOCK_ID)]
[ServiceModule(BizTypeId)]
public class WmsOutStockService : DevServBase<WmsOutStockService>, IWmsOutStockService
{
private const string BizTypeId = "26191522660645";
private readonly ISqlSugarClient _db;
private readonly IDictionaryDataService _dictionaryDataService;
private readonly IRunService _runService;
private readonly IVisualDevService _visualDevService;
private readonly IWareHouseService _wareHouseService;
private readonly IUserManager _userManager;
private readonly IBillRullService _billRullService;
private readonly IWmsCarryMoveInStockService _wmsCarryMoveInStockService;
private readonly IWmsCarryService _wareCarryService;
public WmsOutStockService(
ISqlSugarRepository<WmsOutstockD> repository,
IDictionaryDataService dictionaryDataService,
IRunService runService,
IVisualDevService visualDevService,
IWareHouseService wareHouseService,
IUserManager userManager,
IBillRullService billRullService,
IWmsCarryMoveInStockService wmsCarryMoveInStockService,
IWmsCarryService wareCarryService,
IEventPublisher eventPublisher) : base(repository.AsSugarClient())
{
_db = repository.AsSugarClient();
_dictionaryDataService = dictionaryDataService;
_runService = runService;
_visualDevService = visualDevService;
_wareHouseService = wareHouseService;
_userManager = userManager;
_billRullService = billRullService;
_wmsCarryMoveInStockService = wmsCarryMoveInStockService;
_wareCarryService = wareCarryService;
OverideFuncs.CreateAsync = OutStockApplyFor;
}
public async Task<dynamic> OutStockApplyFor(VisualDevModelDataCrInput input)
{
List<WmsOutstockD> outStockDList = new();
try
{
await _db.Ado.BeginTranAsync();
//判断目标库位是否自动签收
BasLocation? loc = null;
if (input.data.ContainsKey(nameof(WmsPointH.location_id)) && input.data[nameof(WmsPointH.location_id)].IsNotEmptyOrNull())
{
loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == input.data[nameof(WmsPointH.location_id)].ToString());
}
else if (input.data.ContainsKey(nameof(WmsOutstockH.station_id)) && input.data[nameof(WmsOutstockH.station_id)].IsNotEmptyOrNull())
{
//多个投料库位
/*
* 天益
* 2、不管库位是否为空 获取到所有库位 A B
* 2.1 根据这些库位去查任务执行 目的库位是这些库位的未完成任务数。 A 10 B 9
* 2.2 哪个最少给哪个
*/
OrganizeEntity? org = await _db.Queryable<OrganizeEntity>().FirstAsync(it => it.Id == input.data[nameof(WmsOutstockH.station_id)].ToString());
if (!org?.FeedingLocationId.IsNullOrWhiteSpace() ?? false)
{
List<string?> fLocIds = JArray.Parse(org.FeedingLocationId).Values<string>().ToList();
var minTaskNumLocs = await _db.Queryable<WmsPretaskH>().Where(it => it.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID && fLocIds.Contains(it.endlocation_id))
.GroupBy(it => it.endlocation_id)
.Select(it => new
{
it.endlocation_id,
count = SqlFunc.AggregateCount(it.endlocation_id)
})
.MergeTable()
.OrderBy(it => it.count)
.ToListAsync();
if (minTaskNumLocs?.Count > 0)
{
List<string?> freeLocIds = fLocIds.Except(minTaskNumLocs.Select(x => x.endlocation_id)).ToList();
if (freeLocIds?.Count > 0)
{
int rIdx = Random.Shared.Next(0, freeLocIds.Count);
loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == freeLocIds[rIdx]);
}
else
{
string firstLocId = minTaskNumLocs.FirstOrDefault().endlocation_id;
loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == firstLocId);
}
}
else if (minTaskNumLocs?.Count < 1)
{
int rIdx = Random.Shared.Next(0, fLocIds.Count);
loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == fLocIds[rIdx]);
}
input.data[nameof(WmsOutstockH.location_id)] = loc.id;
}
}
List<string> carryIds = new();
var mapKeys = new List<string> { "tablefield120", "details" };
//tablefield120 出库物料明细
if (input.data.Keys.Any(k => mapKeys.Contains(k))) //input.data.ContainsKey("tablefield120") && input.data["tablefield120"].IsNotEmptyOrNull()
{
if (input.data.ContainsKey("tablefield120") && input.data["tablefield120"].IsNotEmptyOrNull())
{
outStockDList = input.data["tablefield120"].ToObject<List<WmsOutstockD>>();
}
else
{
outStockDList = input.data["details"].ToObject<List<WmsOutstockD>>();
}
if (outStockDList?.Count > 0)
{
List<WmsCarryMat> carryMats = new();
List<WmsCarryCode> carryCodes = new();
List<WmsCarryCode> carryCodesPart = new();
foreach (WmsOutstockD os in outStockDList)
{
OutStockStrategyQuery OutStockStrategyInput = new()
{
carry_id = input.data[nameof(OutStockStrategyQuery.carry_id)]?.ToString() ?? string.Empty,
warehouse_id = input.data[nameof(WmsOutstockH.warehouse_id)]?.ToString() ?? string.Empty,
material_id = os.material_id,
code_batch = os.code_batch,
};
List<WmsCarryH> outStkCarrys = await _wareHouseService.OutStockStrategy(OutStockStrategyInput);
Expression<Func<WmsCarryH, WmsCarryCode, bool>> whereExp = input.data.ContainsKey(nameof(WmsOutstockH.carry_id)) && input.data[nameof(WmsOutstockH.carry_id)].IsNotEmptyOrNull()
? (a, b) => a.id == input.data[nameof(WmsOutstockH.carry_id)].ToString()
: (a, b) => outStkCarrys.Select(x => x.id).Contains(b.carry_id);
carryCodesPart = await _db.Queryable<WmsCarryH>().InnerJoin<WmsCarryCode>((a, b) => a.id == b.carry_id).InnerJoin<BasLocation>((a, b, c) => a.location_id == c.id)
.Where(whereExp)
.Select<WmsCarryCode>()
.MergeTable()
.OrderBy(it => it.create_time)
.ToListAsync();
if (carryCodesPart?.Count > 0)
{
decimal codeQty = carryCodesPart.Sum(x => x.codeqty);
if (codeQty < os.pr_qty)
{
throw new AppFriendlyException($"需要出库[{os.pr_qty}],实际库存{codeQty},数量不足", 500);
}
List<WmsCarryCode> curCarryCodes = new();
for (int i = 0; i < carryCodesPart.Count; i++)
{
if (os.pr_qty > carryCodesPart[i].codeqty)
{
os.pr_qty -= carryCodesPart[i].codeqty;
curCarryCodes.Add(carryCodesPart[i]);
}
else if (os.pr_qty <= carryCodesPart[i].codeqty)
{
WmsCarryCode curCarryCode = DeepCopyHelper<WmsCarryCode>.DeepCopy(carryCodesPart[i]);
curCarryCode.codeqty = os.pr_qty;
curCarryCodes.Add(curCarryCode);
break;
}
}
carryCodes.AddRange(curCarryCodes);
List<WmsCarryMat> partCarryMats = curCarryCodes.Adapt<List<WmsCarryMat>>();
for (int i = 0; i < partCarryMats.Count; i++)
{
partCarryMats[i].need_qty = curCarryCodes[i].codeqty;
}
carryMats.AddRange(partCarryMats);
}
}
if (carryMats.Count > 0)
{
carryMats.ForEach(x => x.id = SnowflakeIdHelper.NextId());
carryMats = carryMats.OrderBy(o => o.create_time).GroupBy(g => new { g.carry_id, g.material_id, g.code_batch, g.material_specification, g.container_no })
.Select(x =>
{
WmsCarryMat[] arr = x.ToArray();
WmsCarryMat carryMat = arr[^arr.Length];
carryMat.need_qty = x.Sum(d => d.need_qty);
return carryMat;
})
.ToList();
_ = await _db.Insertable(carryMats).ExecuteCommandAsync();
Dictionary<string, decimal> dic = carryMats.DistinctBy(x => x.carry_id).ToDictionary(x => x.carry_id, x => x.need_qty);
List<string> allOutIds = new();
List<string> sortingOutIds = new();
foreach (KeyValuePair<string, decimal> pair in dic)
{
List<WmsCarryCode> codes = carryCodesPart.FindAll(x => x.carry_id == pair.Key);
if (codes?.Count > 0)
{
if (pair.Value == codes.Sum(d => d.codeqty))
{
allOutIds.Add(pair.Key);
}
else
{
sortingOutIds.Add(pair.Key);
}
}
}
carryIds = allOutIds.Concat(sortingOutIds).ToList();
WmsCarryH carryH = new()
{
out_status = ((int)EnumOutStatus.).ToString(),
source_id = input.data.ContainsKey(nameof(WmsOutstockH.source_id)) ? input.data[nameof(WmsOutstockH.source_id)]?.ToString() ?? string.Empty : string.Empty,
source_code = input.data.ContainsKey(nameof(WmsOutstockH.source_code)) ? input.data[nameof(WmsOutstockH.source_code)]?.ToString() ?? string.Empty : string.Empty,
};
_ = await _db.Updateable(carryH)
.UpdateColumns(it => new { it.out_status, it.source_id, it.source_code })
.Where(it => allOutIds.Contains(it.id))
.ExecuteCommandAsync();
carryH.out_status = ((int)EnumOutStatus.).ToString();
_ = await _db.Updateable(carryH)
.UpdateColumns(it => new { it.out_status, it.source_id, it.source_code })
.Where(it => sortingOutIds.Contains(it.id))
.ExecuteCommandAsync();
}
List<WmsCarryH> carrys = await _db.Queryable<WmsCarryH>().Where(it => carryIds.Contains(it.id)).ToListAsync();
if (carrys?.Count > 0)
{
VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(ModuleConsts.MODULE_WMSOUTSTOCK_ID, true);
await _runService.Create(templateEntity, input);
List<WmsPretaskH> preTasks = new();
List<string> locIds = new();
//当出现多个载具同时出库,可能需要进入电梯时
int ele = 2;
foreach (WmsCarryH carry in carrys)
{
bool isMatch = await IsCarryAndLocationMatchByCarryStd(carry, loc);
if (!isMatch)
{
throw new AppFriendlyException("该载具无法放置到目标库位", 500);
}
WmsPointH sPoint = null!;
WmsPointH ePoint = null!;
if (input.data.ContainsKey(nameof(WmsPointH.location_id)))
{
sPoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_id == carry.location_id);
}
if (input.data.ContainsKey(nameof(WmsPointH.location_id)) && input.data[nameof(WmsPointH.location_id)].IsNotEmptyOrNull())
{
ePoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_id == loc.id);
}
if (sPoint != null && ePoint != null)
{
List<WmsPointH> points = await _wareHouseService.PathAlgorithmsEle(sPoint.id, ePoint.id, ele);
locIds.AddRange(points.Select(x => x.location_id).ToList()!);
//根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序)
if (points?.Count > 0)
{
if (points.Count <= 2)
{
throw new AppFriendlyException("该路径不存在", 500);
}
List<WmsPretaskH> curPreTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it =>
{
WmsPointH? sPoint = it.FirstOrDefault();
WmsPointH? ePoint = it.LastOrDefault();
WmsPretaskH preTask = new()
{
org_id = _userManager.User.OrganizeId,
startlocation_id = sPoint?.location_id ?? string.Empty,
startlocation_code = sPoint?.location_code ?? string.Empty,
endlocation_id = ePoint?.location_id ?? string.Empty,
endlocation_code = ePoint?.location_code!,
start_floor = sPoint?.floor.ToString(),
end_floor = ePoint?.floor.ToString(),
startpoint_id = sPoint?.id!,
startpoint_code = sPoint?.point_code!,
endpoint_id = ePoint?.id!,
endpoint_code = ePoint?.point_code!,
bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(),
status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID,
biz_type = WmsWareHouseConst.BIZTYPE_WMSOUTSTOCK_ID,
task_type = WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID,
carry_id = carry.id,
carry_code = carry.carry_code,
area_id = sPoint?.area_id ?? string.Empty,
area_code = it.Key,
require_id = input.data["ReturnIdentity"].ToString(),
require_code = input.data[nameof(preTask.bill_code)]?.ToString()!,
create_id = _userManager.UserId,
create_time = DateTime.Now
};
return preTask;
}).ToList();
if (loc.is_sign == 0)
{
curPreTasks[^1].is_sign = 0; // 修改最后一个元素的是否签收值
}
preTasks.AddRange(curPreTasks);
//判断当前任务中 是否有电梯任务。有的话ele+1
var eleP = curPreTasks.Find(x => x.area_code.Contains("ELE"));
if (eleP != null)
{
ele++;
}
}
}
}
List<WmsPretaskCode> pretaskCodes = new();
foreach (WmsPretaskH pt in preTasks)
{
List<WmsCarryCode> partCodes = carryCodes.FindAll(x => x.carry_id == pt.carry_id).Distinct().ToList();
List<WmsPretaskCode> curPreTaskCodes = partCodes.Adapt<List<WmsPretaskCode>>();
curPreTaskCodes.ForEach(x =>
{
x.id = SnowflakeIdHelper.NextId();
x.bill_id = pt.id;
x.create_time = DateTime.Now;
});
pretaskCodes.AddRange(curPreTaskCodes);
}
bool isOk = await _wareHouseService.GenPreTask(preTasks, pretaskCodes);
if (isOk)
{
outStockDList.ForEach(x => x.line_status = WmsWareHouseConst.BILLSTATUS_ON_ID);
_ = await _db.Updateable(outStockDList).UpdateColumns(it => it.line_status).ExecuteCommandAsync();
_ = await _db.Updateable<WmsOutstockH>().SetColumns(it => it.status == WmsWareHouseConst.BILLSTATUS_ON_ID).Where(it => it.id == input.data["ReturnIdentity"].ToString()).ExecuteCommandAsync();
GenPreTaskUpInput genPreTaskAfterUpInput = new()
{
CarryIds = preTasks.Select(x => x.carry_id).ToList(),
LocationIds = new HashSet<string>(locIds).ToList()
};
await _wareHouseService.GenInStockTaskHandleAfter(genPreTaskAfterUpInput, it => new WmsCarryH { is_lock = 1 }, it => new BasLocation { is_lock = 1 });
}
}
else
{
throw new AppFriendlyException("库存不足", 500);
}
}
else
{
throw new AppFriendlyException($"请输入物料明细", 500);
}
}
await _db.Ado.CommitTranAsync();
}
catch (Exception ex)
{
JNPF.Logging.Log.Error(ex.ToString());
await _db.Ado.RollbackTranAsync();
throw;
}
finally
{
await InvokeGenPretaskExcute();
}
return Task.FromResult((input.data["ReturnIdentity"].ToString(), outStockDList));
}
public dynamic? PrintTest(List<string> barCodes)
{
// open port.
int nLen, ret, sw;
byte[] pbuf = new byte[128];
string strmsg;
IntPtr ver;
System.Text.Encoding encAscII = System.Text.Encoding.ASCII;
_ = System.Text.Encoding.Unicode;
// dll version.
ver = PPLBUtility.B_Get_DLL_Version(0);
// search port.
nLen = PPLBUtility.B_GetUSBBufferLen() + 1;
strmsg = "DLL ";
strmsg += Marshal.PtrToStringAnsi(ver);
strmsg += "\r\n";
if (nLen > 1)
{
byte[] buf1, buf2;
int len1 = 128, len2 = 128;
buf1 = new byte[len1];
buf2 = new byte[len2];
_ = PPLBUtility.B_EnumUSB(pbuf);
_ = PPLBUtility.B_GetUSBDeviceInfo(1, buf1, out len1, buf2, out len2);
sw = 1;
if (1 == sw)
{
ret = PPLBUtility.B_CreatePrn(12, encAscII.GetString(buf2, 0, len2));// open usb.
}
else
{
ret = PPLBUtility.B_CreateUSBPort(1);// must call B_GetUSBBufferLen() function fisrt.
}
if (0 != ret)
{
}
else
{
strmsg += "Open USB:\r\nDevice name: ";
strmsg += encAscII.GetString(buf1, 0, len1);
strmsg += "\r\nDevice path: ";
_ = encAscII.GetString(buf2, 0, len2);
//sw = 2;
if (2 == sw)
{
//Immediate Error Report.
_ = PPLBUtility.B_WriteData(1, encAscII.GetBytes("^ee\r\n"), 5);//^ee
ret = PPLBUtility.B_ReadData(pbuf, 4, 1000);
}
}
}
else
{
_ = System.IO.Directory.CreateDirectory(PPLBUtility.szSavePath);
ret = PPLBUtility.B_CreatePrn(0, PPLBUtility.szSaveFile);// open file.
strmsg += "Open ";
strmsg += PPLBUtility.szSaveFile;
if (0 != ret)
{
}
else
{
}
}
if (0 != ret)
{
return null;
}
// sample setting.
//B_Set_DebugDialog(1);
//var sznop2 = "测试";
//var sznop1 = "测试2";
_ = PPLBUtility.B_Set_Originpoint(0, 0);
_ = PPLBUtility.B_Select_Option(2);
_ = PPLBUtility.B_Set_Darkness(8);
_ = PPLBUtility.B_Del_Pcx("*");// delete all picture.
//PPLBUtility.B_WriteData(0, encAscII.GetBytes(sznop2), sznop2.Length);
//PPLBUtility.B_WriteData(1, encAscII.GetBytes(sznop1), sznop1.Length);
//When using standard label, and the printer is Intelli Print mode or Smart Print mode,
//When calling this function and giving the correct label information,
//the immediate print function will be enabled according to the label length setting.
_ = PPLBUtility.B_Set_LabelForSmartPrint(254 * 3, 30);//label information: length= 3 * 25.4 mm, gap= 3 mm.
//draw box.
//PPLBUtility.B_Draw_Box(20, 20, 4, 760, 560);
//PPLBUtility.B_Draw_Line('O', 400, 20, 4, 540);
//print text, true type text.
_ = PPLBUtility.B_Prn_Text(250, 50, 0, 2, 2, 2, 'N', "PPLB Lib Example");
//PPLBUtility.B_Prn_Text_TrueType(30, 100, 30, "Arial", 1, 400, 0, 0, 0, "AA", "TrueType Font");//save in printer.
//PPLBUtility.B_Prn_Text_TrueType_W(30, 160, 20, 20, "Times New Roman", 1, 400, 0, 0, 0, "AB", "TT_W: 多字元測試");
//PPLBUtility.B_Prn_Text_TrueType_Uni(30, 220, 30, "Times New Roman", 1, 400, 0, 0, 0, "AC", Encoding.Unicode.GetBytes("TT_Uni: 多字元測試"), 1);//UTF-16
//encUnicode.GetBytes("\xFEFF", 0, 1, pbuf, 0);//UTF-16.//pbuf[0]=0xFF,pbuf[1]=0xFE;
//encUnicode.GetBytes("TT_UniB: 多字元測試", 0, 14, pbuf, 2);//copy mutil byte.
//encUnicode.GetBytes("\x0000", 0, 1, pbuf, 30);//null.//pbuf[30]=0x00,pbuf[31]=0x00;
//PPLBUtility.B_Prn_Text_TrueType_UniB(30, 280, 30, "Times New Roman", 1, 400, 0, 0, 0, "AD", pbuf, 0);//Byte Order Mark.
int labelWth = 800;
int barcodeWth = 508;
_ = (labelWth - barcodeWth) / 2;
//barcode.
_ = PPLBUtility.B_Prn_Barcode(150, 100, 0, "E80", 8, 500, 70, 'N', "1234<+10>");//have a counter
//PPLBUtility.B_Bar2d_QR(420, 200, 1, 3, 'M', 'A', 0, 0, 0, "QR CODE");
//picture.
//PPLBUtility.B_Get_Graphic_ColorBMP(420, 280, "bb.bmp");// Color bmp file.
//PPLBUtility.B_Get_Graphic_ColorBMPEx(420, 320, 200, 150, 2, "bb1", "bb.bmp");//180 angle.
//IntPtr himage = LoadImage(IntPtr.Zero, "bb.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//PPLBUtility.B_Get_Graphic_ColorBMP_HBitmap(630, 280, 250, 80, 1, "bb2", himage);//90 angle.
//if (IntPtr.Zero != himage)
// DeleteObject(himage);
// output.
_ = PPLBUtility.B_Print_Out(1);// copy 2.
// close port.
PPLBUtility.B_ClosePrn();
return "success";
}
/// <summary>
/// 根据出库申请单ID获取申请单明细信息
/// </summary>
/// <param name="billId"></param>
/// <returns></returns>
[HttpGet]
public async Task<dynamic> GetInStockDetailsListById([FromRoute] string billId)
{
Dictionary<string, object> dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID);
List<WmsOutstockD> items = await _db.Queryable<WmsOutstockD>().Where(it => it.bill_id == billId).ToListAsync();
_db.ThenMapper(items,
it => it.line_status = dic.ContainsKey(it.line_status) ? dic[it.line_status]?.ToString()! : "");
return items;
}
/// <summary>
/// 生产出库接口
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
//[NonUnify]
[AllowAnonymous]
public async Task<dynamic> MESCreateOutstock(MESCreateOutstockInput input)
{
bool isSuccessful = true;
try
{
await _db.Ado.BeginTranAsync();
//出库申请主表
WmsOutstockH outstock = input.outstock.Adapt<WmsOutstockH>();
//出库申请明细表
List<WmsOutstockD> outstockDs = input.outstockDs.Adapt<List<WmsOutstockD>>();
BasLocation location = await _db.Queryable<BasLocation>().SingleAsync(it => it.location_code == input.outstock.location_code && it.is_type != EnumLocationType..ToString());
//如果数据不全或有误,
if (location.IsNull() || outstockDs?.Count < 1)
{
//报错, 提示数据不全或有误。
throw new AppFriendlyException("数据不全或有误!", 500);
}
// 生成出库申请数据,添加其他数据 主表
outstock.id = SnowflakeIdHelper.NextId();
outstock.location_id = location.id;
outstock.biz_type = WmsWareHouseConst.BIZTYPE_WMSOUTSTOCK_ID;
outstock.bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_OUTSTOCK_ENCODE).GetAwaiter().GetResult();
outstock.generate_type = "0";// 自动
outstock.sync_status = WmsWareHouseConst.SYNC_STATUS_NONEEDSYNC;//未同步
outstock.status = WmsWareHouseConst.BILLSTATUS_ADD_ID;// 新增
outstock.create_id = _userManager.UserId;
outstock.create_time = DateTime.Now;
//明细表
foreach (WmsOutstockD outstockD in outstockDs!)
{
outstockD.id = SnowflakeIdHelper.NextId();
outstockD.bill_id = outstock.id;
outstockD.line_status = WmsWareHouseConst.BILLSTATUS_ADD_ID;
outstockD.qty = 0;
outstock.create_time = outstock.create_time;
outstock.create_id = outstock.create_id;
}
//var loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == outstock.location_id.ToString());
List<string>? carryIds = new();
//tablefield120 出库物料明细
List<WmsOutstockD> outStockDList = outstockDs.ToObject<List<WmsOutstockD>>();
if (outStockDList?.Count > 0)
{
List<WmsCarryMat> carryMats = new();
List<WmsCarryCode> carryCodes = new();
foreach (WmsOutstockD os in outStockDList)
{
Expressionable<WmsCarryH, WmsCarryCode, BasLocation> whereExp = Expressionable.Create<WmsCarryH, WmsCarryCode, BasLocation>()
.And((a, b, c) => a.is_lock == 0)
.And((a, b, c) => !string.IsNullOrEmpty(a.location_id))
.And((a, b, c) => a.status == (int)EnumCarryStatus.)
.And((a, b, c) => c.is_type == ((int)EnumLocationType.).ToString())
.And((a, b, c) => b.material_id == os.material_id)
.AndIF(!string.IsNullOrEmpty(os.material_specification), (a, b, c) => b.material_specification == os.material_specification)
.AndIF(!string.IsNullOrEmpty(os.container_no), (a, b, c) => b.container_no == os.container_no)
.AndIF(!string.IsNullOrEmpty(os.code_batch), (a, b, c) => b.code_batch == os.code_batch);
List<WmsCarryCode> carryCodesPart = await _db.Queryable<WmsCarryH>().InnerJoin<WmsCarryCode>((a, b) => a.id == b.carry_id).InnerJoin<BasLocation>((a, b, c) => a.location_id == c.id)
.Where(whereExp.ToExpression())
.Select<WmsCarryCode>()
.ToListAsync();
if (carryCodesPart?.Count > 0)
{
decimal codeQty = carryCodesPart.Sum(x => x.codeqty);
if (codeQty < os.pr_qty)
{
throw new AppFriendlyException($"需要出库[{os.pr_qty}],实际库存{codeQty},数量不足", 500);
}
List<WmsCarryCode> curCarryCodes = new();
for (int i = 0; i < carryCodesPart.Count; i++)
{
if (os.pr_qty > carryCodesPart[i].codeqty)
{
os.pr_qty -= carryCodesPart[i].codeqty;
curCarryCodes.Add(carryCodesPart[i]);
}
else if (os.pr_qty <= carryCodesPart[i].codeqty)
{
WmsCarryCode tmp = DeepCopyHelper<WmsCarryCode>.DeepCopy(carryCodesPart[i]);
tmp.codeqty = os.pr_qty;
curCarryCodes.Add(tmp);
break;
}
}
carryCodes.AddRange(curCarryCodes);
List<WmsCarryMat> partCarryMats = curCarryCodes.Adapt<List<WmsCarryMat>>();
for (int i = 0; i < partCarryMats.Count; i++)
{
partCarryMats[i].need_qty = curCarryCodes[i].codeqty;
}
carryMats.AddRange(partCarryMats);
}
}
if (carryMats.Count > 0)
{
carryMats.ForEach(x => x.id = SnowflakeIdHelper.NextId());
carryMats = carryMats.OrderBy(o => o.create_time).GroupBy(g => new { g.carry_id, g.material_id, g.code_batch })
.Select(x =>
{
WmsCarryMat[] arr = x.ToArray();
WmsCarryMat carryMat = arr[^arr.Length];
carryMat.need_qty = x.Sum(d => d.need_qty);
return carryMat;
})
.ToList();
_ = await _db.Insertable(carryMats).ExecuteCommandAsync();
Dictionary<string, decimal> dic = carryMats.DistinctBy(x => x.carry_id).ToDictionary(x => x.carry_id, x => x.need_qty);
List<string> allOutIds = new();
List<string> sortingOutIds = new();
foreach (KeyValuePair<string, decimal> pair in dic)
{
List<WmsCarryCode> codes = carryCodes.FindAll(x => x.carry_id == pair.Key);
if (codes?.Count > 0)
{
if (pair.Value == codes.Sum(d => d.codeqty))
{
allOutIds.Add(pair.Key);
}
else
{
sortingOutIds.Add(pair.Key);
}
}
}
carryIds = allOutIds.Concat(sortingOutIds).ToList();
if (carryIds?.Count > 0)
{
string carryId = carryIds[^carryIds.Count];
WmsCarryH curCurry = await _db.Queryable<WmsCarryH>().SingleAsync(it => it.id == carryId);
bool isMatch = await IsCarryAndLocationMatchByCarryStd(curCurry, location);
if (!isMatch)
{
throw new AppFriendlyException("该载具无法放置到目标库位", 500);
}
}
_ = await _db.Insertable(outstock).ExecuteCommandAsync();
_ = await _db.Insertable(outstockDs).ExecuteCommandAsync();
_ = await _db.Updateable<WmsCarryH>().SetColumns(it => new WmsCarryH { out_status = ((int)EnumOutStatus.).ToString(), source_id = outstock.source_id, source_code = outstock.source_code }).Where(it => allOutIds.Contains(it.id)).ExecuteCommandAsync();
_ = await _db.Updateable<WmsCarryH>().SetColumns(it => new WmsCarryH { out_status = ((int)EnumOutStatus.).ToString(), source_id = outstock.source_id, source_code = outstock.source_code }).Where(it => sortingOutIds.Contains(it.id)).ExecuteCommandAsync();
}
List<WmsCarryH> carrys = await _db.Queryable<WmsCarryH>().Where(it => carryIds.Contains(it.id)).ToListAsync();
if (carrys?.Count > 0)
{
List<WmsPretaskH> preTasks = new();
List<string> locIds = new();
foreach (WmsCarryH carry in carrys)
{
WmsPointH sPoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_id == carry.location_id);
WmsPointH ePoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_id == outstock.location_id.ToString());
if (sPoint != null && ePoint != null)
{
List<WmsPointH> points = new List<WmsPointH>();
if (sPoint.area_code != ePoint.area_code)
{
points = await _wareHouseService.PathAlgorithms(sPoint.id, ePoint.id);
if (points.Count <= 2)
{
throw new AppFriendlyException("该路径不存在", 500);
}
}
else
{
points.Add(sPoint);
points.Add(ePoint);
}
locIds.AddRange(points.Select(x => x.location_id).ToList()!);
//根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序)
if (points?.Count > 0)
{
List<WmsPretaskH> curPreTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it =>
{
WmsPointH? sPoint = it.FirstOrDefault();
WmsPointH? ePoint = it.LastOrDefault();
WmsPretaskH preTask = new()
{
org_id = _userManager.User.OrganizeId,
startlocation_id = sPoint?.location_id ?? string.Empty,
startlocation_code = sPoint?.location_code ?? string.Empty,
endlocation_id = ePoint?.location_id ?? string.Empty,
endlocation_code = ePoint?.location_code ?? string.Empty,
startpoint_id = sPoint.id,
startpoint_code = sPoint.point_code,
endpoint_id = ePoint.id,
endpoint_code = ePoint.point_code,
start_floor = sPoint?.floor.ToString(),
end_floor = ePoint?.floor.ToString(),
bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(),
status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID,
biz_type = WmsWareHouseConst.BIZTYPE_WMSOUTSTOCK_ID,
task_type = WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID,
carry_id = carry.id,
carry_code = carry.carry_code,
area_id = sPoint?.area_id ?? string.Empty,
area_code = it.Key,
require_id = outstock.id.ToString(),
require_code = outstock.bill_code?.ToString(),
create_id = _userManager.UserId,
create_time = DateTime.Now,
source_id = outstock.source_id,
source_code = outstock.source_code,
};
return preTask;
}).ToList();
if (location.is_sign == 0)
{
curPreTasks[^1].is_sign = 0; // 修改最后一个元素的是否签收值
}
preTasks.AddRange(curPreTasks);
}
}
}
List<WmsPretaskCode> pretaskCodes = new();
foreach (WmsPretaskH pt in preTasks)
{
List<WmsCarryCode> partCodes = carryCodes.FindAll(x => x.carry_id == pt.carry_id).Distinct().ToList();
List<WmsPretaskCode> curPreTaskCodes = partCodes.Adapt<List<WmsPretaskCode>>();
curPreTaskCodes.ForEach(x =>
{
x.id = SnowflakeIdHelper.NextId();
x.bill_id = pt.id;
x.create_time = DateTime.Now;
});
pretaskCodes.AddRange(curPreTaskCodes);
}
bool isOk = await _wareHouseService.GenPreTask(preTasks, pretaskCodes);
if (isOk)
{
outstockDs.ForEach(x => x.line_status = WmsWareHouseConst.BILLSTATUS_ON_ID);
_ = await _db.Updateable(outstockDs).UpdateColumns(it => it.line_status).ExecuteCommandAsync();
_ = await _db.Updateable<WmsOutstockH>().SetColumns(it => new WmsOutstockH { status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => it.id == outstock.id).ExecuteCommandAsync();
GenPreTaskUpInput genPreTaskAfterUpInput = new()
{
CarryIds = preTasks.Select(x => x.carry_id).ToList(),
LocationIds = new HashSet<string>(locIds).ToList()
};
await _wareHouseService.GenInStockTaskHandleAfter(genPreTaskAfterUpInput, it => new WmsCarryH { is_lock = 1 }, it => new BasLocation { is_lock = 1 });
}
}
else
{
throw new AppFriendlyException("库存不足", 500);
}
}
else
{
throw new AppFriendlyException($"请输入物料明细", 500);
}
await _db.Ado.CommitTranAsync();
}
catch (Exception ex)
{
isSuccessful = false;
JNPF.Logging.Log.Error(ex.Message);
await _db.Ado.RollbackTranAsync();
throw;
}
finally
{
await InvokeGenPretaskExcute();
}
return isSuccessful;
}
public override async Task ModifyAsync(WareHouseUpInput input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
try
{
Stopwatch sw = Stopwatch.StartNew();
await _db.Ado.BeginTranAsync();
string carryId = input.carryIds[^input.carryIds.Count];
WmsCarryH carry = await _db.Queryable<WmsCarryH>().SingleAsync(it => it.id == carryId);
if (carry != null)
{
List<WmsOutstockD>? otds = await _db.Queryable<WmsOutstockD>().Where(it => it.bill_id == input.requireId).ToListAsync();
EnumOutStatus outStatus = carry.out_status.ToEnum<EnumOutStatus>();
if (outStatus == EnumOutStatus.)
{
Stopwatch swAllOut = Stopwatch.StartNew();
//当前载具对应的所有条码插入
List<WmsCarryCode> carryCodes = await _db.Queryable<WmsCarryCode>().Where(it => it.carry_id == carryId).ToListAsync();
List<WmsOutstockCode> outStockCodes = carryCodes.Adapt<List<WmsOutstockCode>>();
outStockCodes.ForEach(x =>
{
string? billDId = otds?.Find(xx => xx.material_id == x.material_id && xx.code_batch == x.code_batch && xx.material_specification == x.material_specification && xx.container_no == x.container_no)?.id;
if (billDId.IsNullOrEmpty())
{
billDId = otds?.Find(xx => xx.material_id == x.material_id)?.id;
}
x.id = SnowflakeIdHelper.NextId();
x.bill_id = input.requireId;
x.bill_d_id = billDId!;
x.org_id = _userManager.User == null?"": _userManager.User.OrganizeId;
x.create_id = _userManager.UserId== null ? "":_userManager.UserId;
x.create_time = DateTime.Now;
});
_ = await _db.Insertable(outStockCodes).ExecuteCommandAsync();
List<string> detailIds = outStockCodes.Select(x => x.bill_d_id).ToList();
List<WmsOutstockD> curOutstockDetails = otds.FindAll(x => detailIds.Contains(x.id));
Dictionary<string, List<decimal>> dic = outStockCodes.GroupBy(g => g.bill_d_id).ToDictionary(x => x.Key, x => x.Select(x => x.codeqty).ToList());
foreach (WmsOutstockD osd in curOutstockDetails)
{
if (dic.ContainsKey(osd.id))
{
osd.qty += dic[osd.id].Sum(d => d);
osd.line_status = osd.qty >= osd.pr_qty ? WmsWareHouseConst.BILLSTATUS_COMPLETE_ID : WmsWareHouseConst.BILLSTATUS_ON_ID;
}
}
_ = await _db.Updateable(curOutstockDetails).ExecuteCommandAsync();
if (otds.All(x => x.line_status == WmsWareHouseConst.BILLSTATUS_COMPLETE_ID))
{
_ = await _db.Updateable<WmsOutstockH>().SetColumns(it => new WmsOutstockH { status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID }).Where(it => it.id == input.requireId).ExecuteCommandAsync();
//如果是自动单据,需要回更上层系统
}
else
{
//如果没有完成,修改为工作中
_ = await _db.Updateable<WmsOutstockH>().SetColumns(it => new WmsOutstockH { status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => it.id == input.requireId).ExecuteCommandAsync();
}
_ = _wareCarryService.UpdateNullCarry(carry).Unwrap();
swAllOut.Stop();
Logger.Information($"全部出耗时:{swAllOut.ElapsedMilliseconds}ms");
}
else if (outStatus == EnumOutStatus.)
{
Stopwatch swFJOut = Stopwatch.StartNew();
if (input.distaskCodes?.Count > 0)
{
List<WmsOutstockCode> osCodes = input.distaskCodes.Adapt<List<WmsOutstockCode>>();
osCodes.ForEach(x =>
{
string? billDId = otds?.Find(xx => xx.material_id == x.material_id && xx.code_batch == x.code_batch && xx.material_specification == x.material_specification && xx.container_no == x.container_no)?.id;
if (billDId.IsNullOrEmpty())
{
billDId = otds?.Find(xx => xx.material_id == x.material_id)?.id;
}
x.id = SnowflakeIdHelper.NextId();
x.bill_id = input.requireId;
x.bill_d_id = billDId!;
x.org_id = _userManager.User?.OrganizeId;
x.create_id = _userManager.UserId;
x.create_time = DateTime.Now;
});
_ = await _db.Insertable(osCodes).ExecuteCommandAsync();
// 更新主表
List<string> detailIds = osCodes.Select(x => x.bill_d_id).ToList();
List<WmsOutstockD> curOutstockDetails = otds.FindAll(x => detailIds.Contains(x.id));
Dictionary<string, List<decimal>> dic = osCodes.GroupBy(g => g.bill_d_id).ToDictionary(x => x.Key, x => x.Select(x => x.codeqty).ToList());
foreach (WmsOutstockD osd in curOutstockDetails)
{
if (dic.ContainsKey(osd.id))
{
osd.qty += dic[osd.id].Sum(d => d);
if (osd.qty >= osd.pr_qty)
{
osd.qty = osd.pr_qty;
osd.line_status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID;
}
else
{
osd.line_status = WmsWareHouseConst.BILLSTATUS_ON_ID;
}
}
}
_ = await _db.Updateable(curOutstockDetails).ExecuteCommandAsync();
if (otds.All(x => x.line_status == WmsWareHouseConst.BILLSTATUS_COMPLETE_ID))
{
//如果是自动单据,需要回更上层系统
_ = await _db.Updateable<WmsOutstockH>().SetColumns(it => new WmsOutstockH { status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID }).Where(it => it.id == input.requireId).ExecuteCommandAsync();
}
else
{
//如果没有完成,修改为工作中
_ = await _db.Updateable<WmsOutstockH>().SetColumns(it => new WmsOutstockH { status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => it.id == input.requireId).ExecuteCommandAsync();
}
List<WmsCarryCode> carryCodes = await _db.Queryable<WmsCarryCode>().Where(it => input.carryIds.Contains(it.carry_id!)).ToListAsync();
Dictionary<string, decimal> dicCodeQty = carryCodes.GroupBy(g => g.barcode).ToDictionary(x => x.Key, x => x.First().codeqty);
Dictionary<string, decimal> dicUpdate = new();
List<string> delBarcodes = new();
foreach (WmsDistaskCode dtc in input.distaskCodes)
{
if (dicCodeQty.ContainsKey(dtc.barcode))
{
if (dtc.codeqty < dicCodeQty[dtc.barcode])
{
dicUpdate[dtc.barcode] = dicCodeQty[dtc.barcode] - dtc.codeqty;
}
else
{
delBarcodes.Add(dtc.barcode);
}
}
}
if (dicUpdate.Count > 0)
{
foreach (KeyValuePair<string, decimal> pair in dicUpdate)
{
WmsCarryCode? carryCode = carryCodes.Find(x => x.barcode == pair.Key);
if (carryCode != null)
{
carryCode.codeqty = pair.Value;
_ = await _db.Updateable(carryCode).UpdateColumns(it => it.codeqty).ExecuteCommandAsync();
}
}
}
if (delBarcodes.Count > 0)
{
_ = await _db.Deleteable<WmsCarryCode>().Where(it => delBarcodes.Contains(it.barcode)).ExecuteCommandAsync();
}
int row = await _db.Updateable<WmsCarryH>().SetColumns(it => new WmsCarryH { out_status = ((int)EnumOutStatus.).ToString() }).Where(it => input.carryIds.Contains(it.id)).ExecuteCommandAsync();
_ = await _db.Deleteable<WmsCarryMat>().Where(it => input.carryIds.Contains(it.carry_id)).ExecuteCommandAsync();
swFJOut.Stop();
Logger.Information($"出库申请运行耗时{swFJOut.ElapsedMilliseconds}ms");
sw = Stopwatch.StartNew();
//载具移入
WmsOutstockH outStockH = await _db.Queryable<WmsOutstockH>().SingleAsync(it => it.id == input.requireId);
VisualDevModelDataCrInput visulDevInput = new()
{
data = new Dictionary<string, object>
{
[nameof(InStockStrategyQuery.warehouse_id)] = outStockH.warehouse_id,
[nameof(WmsPointH.location_id)] = outStockH.location_id,
[nameof(WmsCarryD.carry_id)] = input.carryIds.First(),
[nameof(WmsCarryH.carry_code)] = carry.carry_code,
[nameof(WmsHandleH.biz_type)] = WmsWareHouseConst.BIZTYPE_CARRYMOVEINSTOCK_ID,
[nameof(WmsHandleH.create_id)] = _userManager.UserId,
[nameof(WmsHandleH.create_time)] = DateTime.Now,
[nameof(WmsMoveInstock.status)] = WmsWareHouseConst.BILLSTATUS_ADD_ID,
[nameof(WmsHandleH.bill_code)] = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_CARRYMOINSTK_ENCODE).GetAwaiter().GetResult(),
}
};
_ = _wmsCarryMoveInStockService.CarryMoveIn(visulDevInput);
Logger.Information($"载具移入耗时{sw.ElapsedMilliseconds}ms");
await _db.Ado.CommitTranAsync();
}
}
}
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
}
}