Files
tnb.server/WarehouseMgr/Tnb.WarehouseMgr/WmsOutStockService.cs

962 lines
54 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;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Aop.Api.Domain;
using JNPF.Common.Const;
using JNPF.Common.Contracts;
using JNPF.Common.Core.Manager;
using JNPF.Common.Dtos.VisualDev;
using JNPF.Common.Extension;
using JNPF.Common.Security;
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.Mvc;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
using SqlSugar;
using SqlSugar.DbConvert;
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 System.Reflection;
using Tnb.WarehouseMgr.Print;
using System.Runtime.InteropServices;
namespace Tnb.WarehouseMgr
{
/// <summary>
/// 出库申请业务类
/// </summary>
[OverideVisualDev(ModuleConsts.MODULE_WMSOUTSTOCK_ID)]
[ServiceModule(BizTypeId)]
public class WmsOutStockService : BaseWareHouseService, 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,
ITaskMessageNotify taskMessageNotify) : base(taskMessageNotify.Writer)
{
_db = repository.AsSugarClient();
_dictionaryDataService = dictionaryDataService;
_runService = runService;
_visualDevService = visualDevService;
_wareHouseService = wareHouseService;
_userManager = userManager;
_billRullService = billRullService;
_wmsCarryMoveInStockService = wmsCarryMoveInStockService;
_wareCarryService = wareCarryService;
OverideFuncs.CreateAsync = OutStockApplyFor;
}
private async Task<dynamic> OutStockApplyFor(VisualDevModelDataCrInput input)
{
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 哪个最少给哪个
*/
var org = await _db.Queryable<OrganizeEntity>().FirstAsync(it => it.Id == input.data[nameof(WmsOutstockH.station_id)].ToString());
if (!org?.FeedingLocationId.IsNullOrWhiteSpace() ?? false)
{
var 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)
{
var freeLocIds = fLocIds.Except(minTaskNumLocs.Select(x => x.endlocation_id)).ToList();
if (freeLocIds?.Count > 0)
{
var rIdx = new Random().Next(0, freeLocIds.Count);
loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == freeLocIds[rIdx]);
}
else
{
var firstLocId = minTaskNumLocs.FirstOrDefault().endlocation_id;
loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == firstLocId);
}
}
else if (minTaskNumLocs?.Count < 1)
{
var rIdx = new Random().Next(0, fLocIds.Count);
loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == fLocIds[rIdx]);
}
input.data[nameof(WmsOutstockH.location_id)] = loc.id;
}
}
var carryIds = new List<string>();
//tablefield120 出库物料明细
if (input.data.ContainsKey("tablefield120") && input.data["tablefield120"].IsNotEmptyOrNull())
{
var outStockDList = input.data["tablefield120"].ToObject<List<WmsOutstockD>>();
if (outStockDList?.Count > 0)
{
List<WmsCarryMat> carryMats = new();
List<WmsCarryCode> carryCodes = new();
List<WmsCarryCode> carryCodesPart = new();
foreach (var os in outStockDList)
{
var OutStockStrategyInput = new OutStockStrategyQuery
{
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,
};
var 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)
{
var 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);
var 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 =>
{
var 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();
var dic = carryMats.DistinctBy(x => x.carry_id).ToDictionary(x => x.carry_id, x => x.need_qty);
var allOutIds = new List<string>();
var sortingOutIds = new List<string>();
foreach (var pair in dic)
{
var 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();
var carryH = new WmsCarryH
{
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();
}
var 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();
foreach (var carry in carrys)
{
var 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)
{
var points = await _wareHouseService.PathAlgorithms(sPoint.id, ePoint.id);
locIds.AddRange(points.Select(x => x.location_id).ToList()!);
//根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序)
if (points?.Count > 0)
{
if (points.Count <= 2) throw new AppFriendlyException("该路径不存在", 500);
var curPreTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it =>
{
var sPoint = it.FirstOrDefault();
var 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);
}
}
}
List<WmsPretaskCode> pretaskCodes = new();
foreach (var pt in preTasks)
{
var partCodes = carryCodes.FindAll(x => x.carry_id == pt.carry_id).Distinct().ToList();
var 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);
}
var 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();
genPreTaskAfterUpInput.CarryIds = preTasks.Select(x => x.carry_id).ToList();
genPreTaskAfterUpInput.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 Publish(nameof(IWareHouseService.GenTaskExecute));
}
return Task.FromResult(true);
}
public async Task<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 encUnicode = 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)
{
strmsg += "Open USB fail!";
}
else
{
strmsg += "Open USB:\r\nDevice name: ";
strmsg += encAscII.GetString(buf1, 0, len1);
strmsg += "\r\nDevice path: ";
strmsg += 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)
{
strmsg += " file fail!";
}
else
{
strmsg += " file succeed!";
}
}
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.
var labelWth = 800;
var barcodeWth = 508;
var x = (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)
{
var dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID);
var 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]
public async Task<dynamic> MESCreateOutstock(MESCreateOutstockInput input)
{
var isSuccessful = true;
try
{
await _db.Ado.BeginTranAsync();
//出库申请主表
WmsOutstockH outstock = input.outstock.Adapt<WmsOutstockH>();
//出库申请明细表
List<WmsOutstockD> outstockDs = input.outstockDs.Adapt<List<WmsOutstockD>>();
var 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 = "1";// 自动
outstock.sync_status = WmsWareHouseConst.SYNC_STATUS__NOTSYNC;//未同步
outstock.status = WmsWareHouseConst.BILLSTATUS_ADD_ID;// 新增
outstock.create_id = _userManager.UserId;
outstock.create_time = DateTime.Now;
//明细表
foreach (var 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());
var carryIds = new List<string>();
//tablefield120 出库物料明细
var outStockDList = outstockDs.ToObject<List<WmsOutstockD>>();
if (outStockDList?.Count > 0)
{
List<WmsCarryMat> carryMats = new();
List<WmsCarryCode> carryCodes = new();
foreach (var os in outStockDList)
{
var 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.code_batch), (a, b, c) => b.code_batch == os.code_batch);
var 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)
{
var codeQty = carryCodes.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)
{
var tmp = DeepCopyHelper<WmsCarryCode>.DeepCopy(carryCodesPart[i]);
tmp.codeqty = os.pr_qty;
curCarryCodes.Add(tmp);
break;
}
}
carryCodes.AddRange(curCarryCodes);
var 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 =>
{
var 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();
var dic = carryMats.DistinctBy(x => x.carry_id).ToDictionary(x => x.carry_id, x => x.need_qty);
var allOutIds = new List<string>();
var sortingOutIds = new List<string>();
foreach (var pair in dic)
{
var 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)
{
var carryId = carryIds[^carryIds.Count];
var curCurry = await _db.Queryable<WmsCarryH>().SingleAsync(it => it.id == carryId);
var 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();
}
var 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 (var 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)
{
var points = await _wareHouseService.PathAlgorithms(sPoint.id, ePoint.id);
locIds.AddRange(points.Select(x => x.location_id).ToList()!);
//根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序)
if (points?.Count > 0)
{
if (points.Count <= 2) throw new AppFriendlyException("该路径不存在", 500);
var curPreTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it =>
{
var sPoint = it.FirstOrDefault();
var 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,
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 (var pt in preTasks)
{
var partCodes = carryCodes.FindAll(x => x.carry_id == pt.carry_id).Distinct().ToList();
var 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);
}
var 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();
genPreTaskAfterUpInput.CarryIds = preTasks.Select(x => x.carry_id).ToList();
genPreTaskAfterUpInput.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 Publish(nameof(IWareHouseService.GenTaskExecute));
}
return isSuccessful;
}
public override async Task ModifyAsync(WareHouseUpInput input)
{
if (input == null) throw new ArgumentNullException(nameof(input));
try
{
await _db.Ado.BeginTranAsync();
var carryId = input.carryIds[^input.carryIds.Count];
var carry = await _db.Queryable<WmsCarryH>().SingleAsync(it => it.id == carryId);
if (carry != null)
{
var otds = await _db.Queryable<WmsOutstockD>().Where(it => it.bill_id == input.requireId).ToListAsync();
var outStatus = carry.out_status.ToEnum<EnumOutStatus>();
if (outStatus == EnumOutStatus.)
{
//当前载具对应的所有条码插入
var carryCodes = await _db.Queryable<WmsCarryCode>().Where(it => it.carry_id == carryId).ToListAsync();
var outStockCodes = carryCodes.Adapt<List<WmsOutstockCode>>();
outStockCodes.ForEach(x =>
{
var billDId = otds?.Find(xx => xx.material_id == x.material_id && xx.code_batch == x.code_batch)?.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(outStockCodes).ExecuteCommandAsync();
var detailIds = outStockCodes.Select(x => x.bill_d_id).ToList();
var curOutstockDetails = otds.FindAll(x => detailIds.Contains(x.id));
var dic = outStockCodes.GroupBy(g => g.bill_d_id).ToDictionary(x => x.Key, x => x.Select(x => x.codeqty).ToList());
foreach (var osd in curOutstockDetails)
{
if (dic.ContainsKey(osd.id))
{
osd.qty += dic[osd.id].Sum(d => d);
if (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();
}
await _wareCarryService.UpdateNullCarry(carry).Unwrap();
}
else if (outStatus == EnumOutStatus.)
{
if (input.distaskCodes?.Count > 0)
{
var osCodes = input.distaskCodes.Adapt<List<WmsOutstockCode>>();
osCodes.ForEach(x =>
{
var billDId = otds?.Find(xx => xx.material_id == x.material_id && xx.code_batch == x.code_batch)?.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();
// 更新主表
var detailIds = osCodes.Select(x => x.bill_d_id).ToList();
var curOutstockDetails = otds.FindAll(x => detailIds.Contains(x.id));
var dic = osCodes.GroupBy(g => g.bill_d_id).ToDictionary(x => x.Key, x => x.Select(x => x.codeqty).ToList());
foreach (var 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();
}
var carryCodes = await _db.Queryable<WmsCarryCode>().Where(it => input.carryIds.Contains(it.carry_id!)).ToListAsync();
var dicCodeQty = carryCodes.GroupBy(g => g.barcode).ToDictionary(x => x.Key, x => x.First().codeqty);
var dicUpdate = new Dictionary<string, decimal>();
var delBarcodes = new List<string>();
foreach (var 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 (var 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();
}
var 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();
//载具移入
var outStockH = await _db.Queryable<WmsOutstockH>().SingleAsync(it => it.id == input.requireId);
var visulDevInput = new VisualDevModelDataCrInput();
visulDevInput.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)] = input.bizTypeId,
[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(),
};
await _wmsCarryMoveInStockService.CarryMoveIn(visulDevInput);
}
}
await _db.Ado.CommitTranAsync();
}
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
}
}