using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using JNPF.Common.Core.Manager; using JNPF.Common.Filter; using JNPF.EventBus; using JNPF.Systems.Interfaces.System; using JNPF.VisualDev; using JNPF.VisualDev.Entitys.Dto.VisualDevModelData; using JNPF.VisualDev.Interfaces; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using Newtonsoft.Json; using SqlSugar; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Attributes; using Tnb.WarehouseMgr.Entities.Entity; using Tnb.WarehouseMgr.Interfaces; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Extension; using JNPF.Common.Security; using JNPF.FriendlyException; using JNPF.VisualDev.Entitys; using Microsoft.AspNetCore.Authorization; using Tnb.BasicData.Entities; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Enums; using JNPF.Common.Enums; using Tnb.WarehouseMgr.Entities.Dto.Inputs; using Microsoft.Extensions.Logging; using JNPF.Systems.Entitys.System; using JNPF.Systems.Entitys.Permission; using Aop.Api.Domain; namespace Tnb.WarehouseMgr { /// /// 原材料转库单 /// [OverideVisualDev(ModuleConsts.MODULE_WMSMATERIALTRANSFER_ID)] [ServiceModule(BizTypeId)] public class WmsMaterialTransferService : BaseWareHouseService { private const string BizTypeId = "34354738929685"; private readonly ISqlSugarClient _db; private readonly IRunService _runService; private readonly IVisualDevService _visualDevService; private readonly IWareHouseService _wareHouseService; private readonly IBillRullService _billRullService; private readonly IUserManager _userManager; public static SemaphoreSlim s_taskDistributeToZCC = new(1); public WmsMaterialTransferService( ISqlSugarRepository repository, IRunService runService, IVisualDevService visualDevService, IWareHouseService wareHouseService, IUserManager userManager, IBillRullService billRullService, IEventPublisher eventPublisher) { _db = repository.AsSugarClient(); _runService = runService; _visualDevService = visualDevService; _wareHouseService = wareHouseService; _userManager = userManager; _billRullService = billRullService; OverideFuncs.GetListAsync = GetList; } [NonAction] private async Task GetList(VisualDevModelListQueryInput input) { try { SqlSugarPagedList result = await _db.Queryable() .InnerJoin((a, b) => a.status == b.Id) .InnerJoin((a, b, c) => c.Id == a.create_id) .InnerJoin((a, b, c, d) => d.id == a.warehouse_outstock) .InnerJoin((a, b, c, d, e) => e.id == a.warehouse_instock) // 只显示未完成的单据 .Where( a => a.status != "25065149810453") .Select((a, b, c, d, e) => new WmsMaterialTransfer { id = a.id, create_id = c.RealName, create_time = a.create_time, modify_id = a.modify_id, modify_time = a.modify_time, org_id = a.org_id, tenant_id = a.tenant_id, timestamp = a.timestamp, bill_code = a.bill_code, status = b.FullName, bill_date = a.bill_date, warehouse_outstock = d.whname, warehouse_instock = e.whname, type = a.type, biller_out = a.biller_out, depart_out = a.depart_out, biller_in = a.biller_in, depart_in = a.depart_in, deliver_date = a.deliver_date, arrival_date = a.arrival_date, order_code = a.order_code, }) .ToPagedListAsync(input.currentPage, input.pageSize); var _data = PageResult.SqlSugarPageResult(result); var json = JsonConvert.SerializeObject(_data); var data = JsonConvert.DeserializeObject(json); JArray mainTable = data.list; foreach (dynamic row in mainTable) { row.deliver_date = row.deliver_date.Value?.ToString("yyyy-MM-dd"); row.arrival_date = row.arrival_date.Value?.ToString("yyyy-MM-dd"); row.create_time = row.create_time.Value?.ToString("yyyy-MM-dd"); } List wmsTransferInstockDs = _db.Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.material_id == b.id) ) .Select((a, b) => new WmsMaterialTransferD { id = a.id, material_id = a.material_id, material_code = b.code, material_ex = b.name, material_specification = b.material_specification, unit_id = a.unit_id, unit_code = a.unit_code, code_batch = a.code_batch, station_code = a.station_code, qty = a.qty, yxfqty = a.yxfqty, yzqty = a.yzqty, bill_id = a.bill_id, lineno = a.lineno, f_flowtaskid = a.f_flowtaskid, f_flowid = a.f_flowid, }) .Where(a => mainTable.Select(r => r["id"].ToString()).ToList().Contains(a.bill_id)).ToList(); foreach (JObject wmsTransferInstockH in mainTable) { wmsTransferInstockH["tablefield121"] = JArray.Parse(JsonConvert.SerializeObject(wmsTransferInstockDs.Where(r => r.bill_id == wmsTransferInstockH["id"].ToString()))); } return data; } catch (Exception ex) { return Task.FromResult(ex); } } /// /// 获取物料库存 /// /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task MaterialInventory(MaterialTransferGetMaterialInventoryInput input) { try { if (input.palletCount <= 0) { throw new AppFriendlyException("托盘数必须大于0", 500); } if (string.IsNullOrEmpty(input.material_id)) { throw new AppFriendlyException("物料id不可为空", 500); } if (string.IsNullOrEmpty(input.code_batch)) { throw new AppFriendlyException("批号不可为空", 500); } //入库取终点 //出库起点 OutStockStrategyQuery inStockStrategyInput = new() { warehouse_id = WmsWareHouseConst.WAREHOUSE_YCL_ID, material_id = input.material_id, code_batch = input.code_batch, Size = input.palletCount }; List items = await _wareHouseService.OutStockStrategy(inStockStrategyInput); decimal qty = _db.Queryable().Where(r => items.Select(a => a.id).Contains(r.carry_id) && r.material_id == input.material_id).Sum(r => r.codeqty); JObject keyValuePairs = new JObject(); keyValuePairs["realPalletCount"] = items.Count; keyValuePairs["realInvQty"] = qty; return await ToApiResult(HttpStatusCode.OK, "成功", keyValuePairs); } catch (Exception ex) { await _db.Ado.RollbackTranAsync(); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } } /// /// 按托下发 /// /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task Distribute(MaterialTransferDistributeInput input) { try { if (string.IsNullOrEmpty(input.source_id)) { throw new AppFriendlyException("来源单据id不可为空", 500); } if (input.palletCount <= 0) { throw new AppFriendlyException("托盘数必须大于0", 500); } if (input.qty <= 0) { throw new AppFriendlyException("数量必须大于0", 500); } if (string.IsNullOrEmpty(input.code_batch)) { throw new AppFriendlyException("批号不可为空", 500); } WmsMaterialTransferD wmsMaterialTransferD = await _db.Queryable().FirstAsync(it => it.id == input.source_id); WmsMaterialTransfer wmsMaterialTransfer = await _db.Queryable().FirstAsync(it => it.id == wmsMaterialTransferD.bill_id); if (wmsMaterialTransferD.yxfqty == wmsMaterialTransferD.qty) { throw new AppFriendlyException("已下发数量已达到转库数量", 500); } await s_taskExecuteSemaphore.WaitAsync(); await _db.Ado.BeginTranAsync(); //入库取终点 //出库起点 OutStockStrategyQuery inStockStrategyInput = new() { warehouse_id = WmsWareHouseConst.WAREHOUSE_YCL_ID, material_id = wmsMaterialTransferD.material_id, code_batch = wmsMaterialTransferD.code_batch, Size = input.palletCount }; List items = await _wareHouseService.OutStockStrategy(inStockStrategyInput); if (items.Count == 0) { throw new AppFriendlyException($@"没有可以出库的载具", 500); } decimal qty = _db.Queryable().Where(r => items.Select(a => a.id).Contains(r.carry_id) && r.material_id == wmsMaterialTransferD.material_id).Sum(r => r.codeqty); // 暂定PDA上查询到的物料批次和库存数量与提交时获取的不一致时,需要前台重新获取库存接口 if (input.palletCount != items.Count || input.qty != qty) { throw new AppFriendlyException($@"当前实际托盘数量为{input.palletCount} 实际库存数量为{qty},与前台数据不一致,请重新获取库存", HttpStatusCode.InternalServerError); } foreach(var wmsCarryH in items) { WmsCarryCode wmsCarryCode = await _db.Queryable().Where(r => r.carry_id == wmsCarryH.id).FirstAsync(); BasLocation startLocation = await _db.Queryable().Where(r => r.location_code == wmsCarryH.location_code).FirstAsync(); BasLocation endLocation = null; // 集中供料区三工位 if (wmsMaterialTransfer.warehouse_instock == WmsWareHouseConst.WAREHOUSE_JZGL_ID) { // 根据三工位任务数平均分配任务 暂定 endLocation = await _db.Queryable().Where(r => _wareHouseService.GetFloor1GLSGWOutstockLocation().Contains(r.id)).OrderBy("is_lock, task_nums, location_code").FirstAsync(); } // 中储仓三工位 else if(wmsMaterialTransfer.warehouse_instock == WmsWareHouseConst.WAREHOUSE_ZC_ID) { // 根据三工位任务数平均分配任务 暂定 endLocation = await _db.Queryable().Where(r => _wareHouseService.GetFloor1WXSGWOutstockLocation().Contains(r.id)).OrderBy("is_lock, task_nums, location_code").FirstAsync(); } CommonCreatePretaskInput commonCreatePretaskInput = new CommonCreatePretaskInput(); commonCreatePretaskInput.startlocation_id = startLocation.id; commonCreatePretaskInput.endlocation_id = endLocation.id; commonCreatePretaskInput.task_type = WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID; commonCreatePretaskInput.biz_type = WmsWareHouseConst.BIZTYPE_WMSMATERIALTRANSFER_ID; commonCreatePretaskInput.require_id = input.source_id; commonCreatePretaskInput.carry_id = wmsCarryH.id; commonCreatePretaskInput.carry_code = wmsCarryH.carry_code; Entities.Dto.Outputs.Result res = await _wareHouseService.CommonCreatePretask(commonCreatePretaskInput); if (res.code != HttpStatusCode.OK) { Logger.LogInformation($@"生成预任务失败"); throw new AppFriendlyException($@"生成预任务失败", 500); } } // 更新子表已下发数量 await _db.Updateable().SetColumns(r => r.yxfqty == r.yxfqty + input.qty).Where(r => r.id == input.source_id).ExecuteCommandAsync(); await _db.Ado.CommitTranAsync(); } catch (Exception ex) { await _db.Ado.RollbackTranAsync(); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } finally { _ = s_taskExecuteSemaphore.Release(); InvokeGenPretaskExcute(); } return await ToApiResult(HttpStatusCode.OK, "成功"); } public override async Task ModifyAsync(WareHouseUpInput input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } WmsCarryCode wmsCarryCode = await _db.Queryable().Where(r => r.carry_id == input.carryIds[0]).SingleAsync(); if (wmsCarryCode == null) { Logger.LogWarning($"【ModifyAsync】载具{input.carryIds[0]}没有绑定物料条码"); return; } // 更新已转数量 bool isOk = await _db.Updateable().SetColumns(it => new WmsMaterialTransferD { yzqty = it.yzqty + wmsCarryCode.codeqty }) .Where(it => it.id == input.requireId).ExecuteCommandHasChangeAsync(); // 如果所有明细已完成 更新主表状态为完成 WmsMaterialTransferD wmsMaterialTransferd = await _db.Queryable().Where(r => r.id == input.requireId).SingleAsync(); List wmsMaterialTransferDs = _db.Queryable() .Where(a => a.bill_id == wmsMaterialTransferd.bill_id && a.yzqty < a.qty).ToList(); bool isOk2 = true; if (wmsMaterialTransferDs.Count == 0) { isOk2 = await _db.Updateable().SetColumns(it => new WmsMaterialTransfer { status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID }) .Where(it => it.id == wmsMaterialTransferd.bill_id).ExecuteCommandHasChangeAsync(); } if (!isOk || !isOk2) { throw Oops.Oh(ErrorCode.COM1001); } } /// /// 中储仓下发到二楼暂存仓 /// /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task DistributeToZCC(MaterialTransferDistributeToZCCInput input) { s_taskDistributeToZCC.Wait(); try { WmsMaterialTransfer wmsMaterialTransfer = _db.Queryable().Where(r => r.id == input.source_id).First(); if (wmsMaterialTransfer == null) { Logger.LogWarning($"不存在id为{input.source_id}的转库单!"); throw new AppFriendlyException($"不存在id为{input.source_id}的转库单!", 500); } if (wmsMaterialTransfer.status != WmsWareHouseConst.BILLSTATUS_ADD_ID) { Logger.LogWarning($@"当前转库单状态为{wmsMaterialTransfer.status},不能下发中储仓下发到二楼暂存仓任务!"); throw new AppFriendlyException($@"当前转库单状态为{wmsMaterialTransfer.status},不能下发中储仓下发到二楼暂存仓任务!", 500); } List wmsMaterialTransferds = _db.Queryable().Where(r => r.bill_id == input.source_id).ToList(); // 转库单载具子表 List wmsMaterialTransferCarrys = new List(); foreach (WmsMaterialTransferD wmsMaterialTransferD in wmsMaterialTransferds) { //出库取起点,获取所有符合输入的载具规格的载具 OutStockStrategyQuery OutStockStrategyInput = new() { warehouse_id = "2", material_id = wmsMaterialTransferD.material_id, code_batch = wmsMaterialTransferD.code_batch }; List? carrys = await _wareHouseService.OutStockStrategy(OutStockStrategyInput); // 需要转库数量 decimal? needOut = wmsMaterialTransferD.qty; foreach (WmsCarryH wmsCarryH in carrys) { if (needOut <= 0) { break; } WmsCarryCode wmsCarryCode = _db.Queryable().Where(r => r.carry_id == wmsCarryH.id).First(); needOut -= wmsCarryCode.codeqty; BasLocation endlocation_ssx = await _db.Queryable().Where(r => new string[2] { "32609229889045", "32609238573589" }.Contains(r.id)).OrderBy("is_lock, task_nums, location_code").FirstAsync(); await _db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => endlocation_ssx.id == it.id).ExecuteCommandAsync(); // 转库单载具子表 WmsMaterialTransferCarry wmsMaterialTransferCarry = new WmsMaterialTransferCarry(); wmsMaterialTransferCarry.bill_id = input.source_id; wmsMaterialTransferCarry.carry_id = wmsCarryH.id; wmsMaterialTransferCarry.carry_code = wmsCarryH.carry_code; wmsMaterialTransferCarry.create_id = input.create_id; wmsMaterialTransferCarry.create_time = DateTime.Now; wmsMaterialTransferCarry.endlocation_id = endlocation_ssx.id; wmsMaterialTransferCarry.endlocation_code = endlocation_ssx.location_code; wmsMaterialTransferCarry.startlocation_id = wmsCarryH.location_id; wmsMaterialTransferCarry.startlocation_code = wmsCarryH.location_code; wmsMaterialTransferCarry.mat_bill_id = wmsMaterialTransferD.id; wmsMaterialTransferCarry.qty = wmsCarryCode.codeqty; wmsMaterialTransferCarrys.Add(wmsMaterialTransferCarry); } if (needOut > 0) { throw new AppFriendlyException($"物料{wmsMaterialTransferD.material_code}没有足够的库存!,缺失数量为{needOut}", 500); } } await _db.Ado.BeginTranAsync(); await _db.Updateable().SetColumns(r => new WmsMaterialTransfer { status = WmsWareHouseConst.BILLSTATUS_ON_ID, carry_count = wmsMaterialTransferCarrys.Count, remainbindracknum = wmsMaterialTransferCarrys.Count }).Where(r => r.id == input.source_id).ExecuteCommandAsync(); Logger.LogInformation($"【DistributeToZCC】更新转库单{wmsMaterialTransfer.bill_code}主表的数据"); await _db.Insertable(wmsMaterialTransferCarrys).ExecuteCommandAsync(); Logger.LogInformation($"【DistributeToZCC插入转库单{wmsMaterialTransfer.bill_code}载具表的数据"); foreach (WmsMaterialTransferCarry wmsMaterialTransferCarry in wmsMaterialTransferCarrys) { CommonCreatePretaskInput commonCreatePretaskInput = new CommonCreatePretaskInput(); commonCreatePretaskInput.startlocation_id = wmsMaterialTransferCarry.startlocation_id; commonCreatePretaskInput.endlocation_id = wmsMaterialTransferCarry.endlocation_id; commonCreatePretaskInput.carry_id = wmsMaterialTransferCarry.carry_id; commonCreatePretaskInput.carry_code = wmsMaterialTransferCarry.carry_code; commonCreatePretaskInput.task_type = WmsWareHouseConst.BIZTYPE_WMSTRANSFER_ID; commonCreatePretaskInput.biz_type = WmsWareHouseConst.BIZTYPE_WMSMATERIALTRANSFER_ID; commonCreatePretaskInput.require_id = wmsMaterialTransferCarry.mat_bill_id; commonCreatePretaskInput.isExcuteMission = false; var res = await _wareHouseService.CommonCreatePretask(commonCreatePretaskInput); if (res.code != JNPF.Common.Enums.HttpStatusCode.OK) { Logger.LogInformation($"【DistributeToZCC生成预任务失败 载具 {wmsMaterialTransferCarry.carry_code}"); throw new AppFriendlyException($"生成预任务失败 载具 {wmsMaterialTransferCarry.carry_code}", 500); } await _db.Updateable().SetColumns(r => r.yxfqty == r.yxfqty + wmsMaterialTransferCarry.qty).Where(r => r.id == wmsMaterialTransferCarry.mat_bill_id).ExecuteCommandAsync(); } Logger.LogInformation($"转库单{wmsMaterialTransfer.bill_code}预任务{wmsMaterialTransferCarrys.Count}条全部生成成功"); await _db.Ado.CommitTranAsync(); } catch(Exception ex) { await _db.Ado.RollbackTranAsync(); Logger.LogError("【DistributeToZCC】" + ex.Message); Logger.LogError("【DistributeToZCC】" + ex.StackTrace); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } finally { s_taskDistributeToZCC.Release(); InvokeGenPretaskExcute(); } return await ToApiResult(HttpStatusCode.OK, "成功"); } /// /// 从暂存仓呼叫料架到产线 /// /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task CallRackToProductionLine(MaterialTransferCallRackToProductionLineInput input) { WmsCarryH wmsCarryH = _db.Queryable().Where(r => r.carry_code == input.carry_code).First(); if (wmsCarryH == null) { Logger.LogWarning($"不存在编码为{input.carry_code}的料架号!"); throw new AppFriendlyException($"不存在编码为{input.carry_code}的料架号!", 500); } if (string.IsNullOrEmpty(wmsCarryH.work_station)) { Logger.LogWarning($"此料架目标工位为空!{input.carry_code}"); throw new AppFriendlyException($"此料架目标工位为空!{input.carry_code}!", 500); } if (string.IsNullOrEmpty(wmsCarryH.location_id)) { Logger.LogWarning($"此料架的库位为空!{input.carry_code}"); throw new AppFriendlyException($"此料架的库位为空!{input.carry_code}", 500); } BasLocation endlocation = _db.Queryable().Where(r => r.location_code == wmsCarryH.work_station).First(); WmsDistaskH wmsDistaskH = _db.Queryable().Where(r => r.carry_code == wmsCarryH.carry_code && r.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID).First(); if (wmsDistaskH != null) { Logger.LogWarning($"此料架{input.carry_code}存在未完成的任务{wmsDistaskH.bill_code}!"); throw new AppFriendlyException($"此料架{input.carry_code}存在未完成的任务{wmsDistaskH.bill_code}!", 500); } try { CommonCreatePretaskInput commonCreatePretaskInput = new CommonCreatePretaskInput(); commonCreatePretaskInput.startlocation_id = wmsCarryH.location_id; commonCreatePretaskInput.endlocation_id = endlocation.id; commonCreatePretaskInput.carry_id = wmsCarryH.id; commonCreatePretaskInput.carry_code = wmsCarryH.carry_code; commonCreatePretaskInput.task_type = ""; commonCreatePretaskInput.biz_type = ""; var res = await _wareHouseService.CommonCreatePretask(commonCreatePretaskInput); if (res.code != JNPF.Common.Enums.HttpStatusCode.OK) { Logger.LogInformation($"【CallRackToProductionLine】生成预任务失败 载具 {wmsCarryH.carry_code}"); throw new AppFriendlyException($"生成预任务失败 载具 {wmsCarryH.carry_code}", 500); } } catch (Exception ex) { Logger.LogError("【CallRackToProductionLine】" + ex.Message); Logger.LogError("【CallRackToProductionLine】" + ex.StackTrace); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } return await ToApiResult(HttpStatusCode.OK, "成功"); } } }