using Rhea.Common; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading; using System.Threading.Tasks; using Tiger.Model; using Tiger.IBusiness; using Tiger.Business.WMS.Common; using Org.BouncyCastle.Ocsp; using Tiger.Model.Sharetronic.Shelf; using MailKit.Search; using Tiger.Business.WMS.Extensions; namespace Tiger.Business.WMS.Transaction { /// /// 备料任务下架事务 /// public class Out_BIZ_WMS_PREP : WmsTask, IOut_BIZ_WMS_PREP { public IOut_BIZ_WMS_PREP Init(string id, string userCode, string apiHost, string orgCode) { base.Init(id, userCode, apiHost, orgCode); CurPREP = new(MainDB, userCode, orgCode); Logger.Console.Info($"Start {this.GetType().Name} Transaction[ID: {TransID}]"); return this; } #region Propertys & Variables public Preparation CurPREP { get; set; } private List CurSn = new(); private BIZ_WMS_PREP_DTL CurPrepDtl = new(); public List Suggests { get; set; } = new(); public List CurPoolList => Suggests.Where(q => !q.poolItem.IsNullOrEmpty()).Select(q => q.poolItem).ToList(); public List LocationHis { get; set; } = new(); private bool isExceed = false; private bool isNeedCut = false; #endregion #region Functions /// /// 扫描入口 /// public async Task> Scan(BaseInput input) { var action = new ApiAction(new ScanOutput()); try { if (input.Command == "ScanOrder") { action = await ScanOrder(input); } else if (input.Command == "SelectItem") { action = await SelectItem(input); } else if (input.Command == "ConfirmExceed") { action = await ConfirmExceed(input); } else { if (CurPREP.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("备料前请先选择需要备料的单据"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.ScanItem.NotScanOrder"); action.Data.Command = "ScanOrder"; return SetOutPutMqttMsg(action, input.Locale); } if (CurPrepDtl.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("备料前请先选择需要备料的物料行"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.ScanItem.NotSelectItem"); action.Data.Command = "SelectItem"; return SetOutPutMqttMsg(action, input.Locale); } if (input.SN.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("条码不能为空"); action.LocaleMsg = Biz.L("WMS.Default.ScanItem.SnEmptyFailure"); return SetOutPutMqttMsg(action, input.Locale); } //扫描物料并复核 { action = await ScanItem(input); } } } catch (Exception ex) { //取消当前操作 ResetTrans(); //action.CatchExceptionWithLog(ex, $"扫描[{input.SN}]异常"); action.CatchExceptionWithLog(ex, Biz.L("WMS.Default.Scan.ScanException", input.SN)); } return SetOutPutMqttMsg(action, input.Locale); } /// /// 扫描下架单据号码 /// public async Task> ScanOrder(BaseInput input) { var action = new ApiAction(new ScanOutput()); try { var inputOrder = input?.Data?.JsonToObject(); if ((inputOrder?.BIZ_TYPE).IsNullOrEmpty() || (inputOrder?.SOURCE_ORDER ?? "").IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L($"请选择正确的备料任务类型和单号"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.ScanOrder.InputOrderIsNull"); return action; } if (!CurPREP.Order.IsNullOrEmpty() && inputOrder.BIZ_TYPE != CurPREP.Order.BIZ_TYPE) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L($"当前备料任务[{0}]的业务类型为{1},如需切换备料业务,请退出后重新选择"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.ScanOrder.BizTypeError", CurPREP.Order.ORDER_NO, CurPREP.Order.BIZ_TYPE.GetEnumDesc()); return action; } if (CurPREP.Order.IsNullOrEmpty() || !CurPREP.Order.SourceOrders.Any(q => q.SOURCE_ORDER == inputOrder.SOURCE_ORDER)) { action = CurPREP.AddOrder(inputOrder.BIZ_TYPE.GetEnum(), inputOrder.SOURCE_CODE); } else { //action.LocaleMsg = Biz.L($"当前备料任务[{0}]已包含单据[{1}],无需重复操作"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.ScanOrder.Repeat", CurPREP.Order.ORDER_NO, inputOrder.SOURCE_ORDER); } action.Data.Command = "SelectItem"; action.Data.Data = CurPREP.Order; } catch (Exception ex) { //取消当前操作 ResetTrans(); //action.CatchExceptionWithLog(ex, $"备料任务扫描单据异常(Data: {0})"); action.CatchExceptionWithLog(ex, Biz.L("WMS.Out_BIZ_WMS_PREP.ScanOrderException", input?.Data)); } return action; } /// /// 获取当前备料的备料任务信息 /// /// public async Task> GetPrepInfo() { var action = new ApiAction(); CurPREP.Order = MainDB.Queryable().Where(q => q.ID == CurPREP.Order.ID).IncludesAllFirstLayer().First(); action.Data = CurPREP.Order; return action; } /// /// 选择备料任务中要下架物料行 /// public async Task> SelectItem(BaseInput input) { var action = new ApiAction(new ScanOutput()); try { var inputDtl = input?.Data?.JsonToObject(); var prepDtl = MainDB.Queryable().Where(q => q.ID == inputDtl.ID).First(); if (prepDtl.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("备料前请先选择需要备料的物料行"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.ScanItem.NotSelectItem"); return action; } if (prepDtl.QTY_PREP > CurPREP.BizType.GetActReqQty(prepDtl)) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("当前选择物料行[{0}]已备料数量[{1}],以满足实际需求数量[{2}],无需继续备料"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.SelectItem.PrepFinish", prepDtl.ITEM_CODE, prepDtl.QTY_PREP, CurPREP.BizType.GetActReqQty(prepDtl)); return action; } //删除物料池中上一次分配的物料 MainDB.Deleteable().Where(q => q.TRANS_NO == prepDtl.ORDER_NO && q.TRANS_LINE == prepDtl.ORDER_LINE).ExecuteCommand(); if (!CurPrepDtl.IsNullOrEmpty()) { MainDB.Deleteable().Where(q => q.TRANS_NO == CurPrepDtl.ORDER_NO && q.TRANS_LINE == CurPrepDtl.ORDER_LINE).ExecuteCommand(); } CurPrepDtl = prepDtl; //如果上一次推荐有数据,则先灭掉亮的灯 if (Suggests.Any()) { //await CloseLight(LocationHis); } //如果是首套发料,则只推荐当前物料行的一盘物料 if (CurPREP.Order.CurBatch.DLVY_MODE == BIZ_WMS_PREP_BTH.DLVY_MODEs.First.GetValue()) { //推荐物料 Result> result = Suggest(CurPrepDtl.ORDER_NO, CurPrepDtl.ITEM_CODE, null, inputDtl.WH_ID, inputDtl.REGION_ID, inputDtl.SHELF_ID, input.AuthOption, 1); action.LocaleMsg = result.LocaleMsg; if (result.IsException) { action.IsSuccessed = false; return action; } Suggests.Clear(); Suggests = result.Data; if (Suggests.Count > 0) { var inv = Suggests.First(); var actQty = CurPrepDtl.QTY_PREP > CurPREP.BizType.GetActReqQty(CurPrepDtl) ? 0 : (CurPREP.BizType.GetActReqQty(CurPrepDtl) - CurPrepDtl.QTY_PREP); if (inv != null && actQty > 0) { inv.poolItem = inv.Item.GetPoolItem(OrgCode, nameof(CurPREP.Order), CurPrepDtl.ORDER_NO, CurPrepDtl.ORDER_LINE, actQty, true); } else { inv.poolItem = null; } } Suggests.RemoveAll(q => q.poolItem.IsNullOrEmpty()); } //如果是正常发料,则按实际需求数量推荐当前物料行的所有物料 if (CurPREP.Order.CurBatch.DLVY_MODE == BIZ_WMS_PREP_BTH.DLVY_MODEs.Supply.GetValue()) { //推荐物料 var actQty = CurPrepDtl.QTY_PREP > CurPREP.BizType.GetActReqQty(CurPrepDtl) ? 0 : (CurPREP.BizType.GetActReqQty(CurPrepDtl) - CurPrepDtl.QTY_PREP); Result> result = Suggest(CurPrepDtl.ORDER_NO, CurPrepDtl.ITEM_CODE, null, inputDtl.WH_ID, inputDtl.REGION_ID, inputDtl.SHELF_ID, input.AuthOption, actQty); action.LocaleMsg = result.LocaleMsg; if (result.IsException) { action.IsSuccessed = false; return action; } Suggests.Clear(); var remain = actQty; Suggests.ForEach((inv) => { if (remain > 0) { inv.poolItem = inv.Item.GetPoolItem(input.AuthOption.OrgCode, nameof(CurPREP.Order), CurPrepDtl.ORDER_NO, CurPrepDtl.ORDER_LINE, remain, false); remain -= inv.poolItem.ALLOC_QTY; } else { inv.poolItem = null; } }); Suggests.RemoveAll(q => q.poolItem.IsNullOrEmpty()); } //保存物料池到数据库 MainDB.Insertable(CurPoolList).ExecuteCommand(); CurPrepDtl.Suggests = Suggests; //action = await LightAll(new() { AuthOption = input.AuthOption, Color = LedColor.Blue }); action.Data.Command = "Normal"; action.Data.Data = CurPrepDtl; //action.LocaleMsg = Biz.L($"已选择要备料物料行[{0},可以开始备料下架"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.SelectItem.Success", CurPrepDtl.ITEM_CODE); } catch (Exception ex) { //取消当前操作 ResetTrans(); //action.CatchExceptionWithLog(ex, $"备料任务选择要物料行异常(Data: {0})"); action.CatchExceptionWithLog(ex, Biz.L("WMS.Out_BIZ_WMS_PREP.SelectItemException", input?.Data)); } return action; } /// /// 获取当前备料的物料行信息 /// /// public async Task> GetCurPrepItem() { var action = new ApiAction(); var prepDtl = MainDB.Queryable().Where(q => q.ID == CurPrepDtl.ID).First(); prepDtl.ERP_WH = CurPrepDtl.ERP_WH; prepDtl.WH_ID = CurPrepDtl.WH_ID; prepDtl.REGION_ID = CurPrepDtl.REGION_ID; prepDtl.SHELF_ID = CurPrepDtl.SHELF_ID; prepDtl.Suggests = Suggests; CurPrepDtl = prepDtl; CurPREP.Order.Details.RemoveAll(q => q.ID == CurPrepDtl.ID); CurPREP.Order.Details.Add(CurPrepDtl); action.Data = CurPrepDtl; return action; } /// /// 领料单推荐所有物料亮灯 /// /// /// public async Task> LightAll(LightEntityInput light) { var action = new ApiAction(); try { var list = Suggests.WhereIF(!light.ItemCode.IsNullOrEmpty(), q => q.Item.ITEM_CODE == light.ItemCode); if (list.Any()) { list = list.Where(q => q.Shelf.SHELF_TYPE == WMS_SHELF.SHELF_TYPEs.Smart.GetValue() || q.Shelf.SHELF_TYPE == WMS_SHELF.SHELF_TYPEs.QRCode.GetValue()); if (list.Any()) { list = list.Where(q => q.poolItem.STATUS < WMS_ITEM_POOL.STATUSs.WaitSend.GetValue()); if (list.Any()) { var locs = list.Select(x => x.Location.AddShelf(x.Shelf)).ToList(); LocationHis.AddRange(locs); //亮灯前先灭一遍 foreach (var shelf in list.Select(q => q.Shelf)) { await Share.Shelf.DownAll(shelf); } await Share.Shelf.LightMulti(TransID, light.Color, locs); action.LocaleMsg = Biz.L("亮灯成功,亮灯颜色[{0}]", light.Color.GetDesc()); } else { action.LocaleMsg = Biz.L($"无需亮灯,推荐的物料已全部下架"); } } else { action.LocaleMsg = Biz.L($"无需亮灯,推荐的物料不在智能货架上"); } } else { action.IsSuccessed = false; action.LocaleMsg = Biz.L($"亮灯失败,未找到推荐下架的物料"); } } catch (Exception ex) { action.CatchExceptionWithLog(ex, $"亮灯异常"); } return action; } /// /// 灭灯 /// /// public async Task CloseLight(List locations = null) { var action = new ApiAction(); try { if (locations != null) { foreach (var shelf in locations.Select(q => q.Shelf)) { await Share.Shelf.DownAll(shelf); } } //灭灯 await Share.Shelf.DownMulti(TransID, locations.IsNullOrEmpty(Suggests.Where(q => q.Shelf.SHELF_TYPE == WMS_SHELF.SHELF_TYPEs.Smart.GetValue() || q.Shelf.SHELF_TYPE == WMS_SHELF.SHELF_TYPEs.QRCode.GetValue()) .Select(x => x.Location).ToList())); } catch (Exception ex) { action.CatchExceptionWithLog(ex, $"灭灯异常"); } return action; } /// /// 扫描物料并复核,如果物料已经完成移库则货架上亮灯提醒储位 /// public async Task> ScanItem(BaseInput input) { var action = new ApiAction(new ScanOutput() { Command = Command }); try { //解析条码 Result result = GetInventory(input.SN, input.AuthOption, true); if (!result.IsSuccessed) { action.IsSuccessed = false; action.LocaleMsg = result.LocaleMsg; return SetOutPutMqttMsg(action, input.Locale); } var inv = result.Data as Inventory; //验证条码是否正确 if (!inv.isNormalStatus || inv.Status != WMS_ITEM.STATUSs.InStore) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("状态[{0}]异常,请重新扫描"); action.LocaleMsg = Biz.L("WMS.Default.ScanItem.StatusException", string.Join(',', inv.StatusList.Select(q => q.GetDesc()))); return SetOutPutMqttMsg(action, input.Locale); } //验证条码是否被锁定 if (inv.Items.Any(q => q.IS_LOCKED == "Y")) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("条码[{0}]已被锁定,请重新扫描"); action.LocaleMsg = Biz.L("WMS.Default.ScanItem.ItemIsLock", inv.CurPkg.SN); return SetOutPutMqttMsg(action, input.Locale); } //储位验证 if (inv.Location.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L($"条码[{0}]库存信息异常: 没有储位信息,请先上架后再扫描(储位Id: {1})"); action.LocaleMsg = Biz.L("WMS.Default.ScanItem.LocationIsNull", inv.CurPkg.SN, inv.CurPkg.LOCATION_ID); return SetOutPutMqttMsg(action, input.Locale); } //物料验证 if (inv.ItemInfo.IsNullOrEmpty() || inv.ItemInfo.IS_ACTIVE == "N") { action.IsSuccessed = false; //action.LocaleMsg = Biz.L($"物料编码[{0}]不存在或者该物料未启用"); action.LocaleMsg = Biz.L("WMS.Default.ScanItem.ItemCodeNotExistsOrNotActive", inv.ItemInfo.ITEM_CODE.IsNullOrEmpty(inv.Barcode.ItemCode)); return SetOutPutMqttMsg(action, input.Locale); } //判断是否在备料中的物料 if (!CurPREP.Order.Details.Any(q => q.ITEM_CODE == inv.ItemInfo.ITEM_CODE)) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L($"当前备料任务[{0}]不包含条码[{1}]的物料编码[{2}],请放回原储位"); action.LocaleMsg = Biz.L("WMS.Out_BIZ_WMS_PREP.ScanItem.NoNeedItemCode", inv.ItemInfo.ITEM_CODE.IsNullOrEmpty(inv.Barcode.ItemCode)); return action; } //ProcessingOrderDetail = input.SN; //if (WMSContext.TransactionDic.Where(q => !string.IsNullOrWhiteSpace(q.Value.ProcessingSn)).Any(q => q.Value.ProcessingSn == ProcessingSn && q.Value.TransID != this.TransID)) //{ // action.IsSuccessed = false; // action.LocaleMsg = Biz.L("当前条码正在执行中,无法扫描"); // return action; //} CurInvItem = inv; CurSn = CurInvItem.Items.Select(q => new BIZ_WMS_PREP_SN() { ORDER_NO = CurPREP.Order.ORDER_NO, ORDER_LINE = CurPrepDtl.ORDER_LINE, ORDER_BATCH = CurPREP.Order.CurBatch.BATCH.ToString(), SN = q.SN, ITEM_CODE = q.ITEM_CODE, UNIT = q.UNIT, QTY = q.QTY, QTY_DLVY = q.QTY, STATUS = q.STATUS, LOTNO = q.LOTNO, WH_CODE = CurInvItem.Warehouse.WH_CODE, REGION_CODE = CurInvItem.Region.REGION_CODE, SHELF_CODE = CurInvItem.Shelf.SHELF_CODE, LOCATION_CODE = CurInvItem.Location.LOCATION_CODE, FTY_CODE = CurPREP.Order.CurBatch.FTY_CODE, WS_CODE = CurPREP.Order.CurBatch.WS_CODE, LINE_CODE = CurPREP.Order.CurBatch.LINE_CODE, POST_CODE = CurPREP.Order.CurBatch.POST_CODE, OPER_CODE = CurPREP.Order.CurBatch.OPER_CODE, SEGMENT = CurPREP.Order.CurBatch.SEGMENT, SMT_NO = CurPrepDtl.SMT_NO, STATION_NO = CurPrepDtl.STATION_NO, FEEDER_NO = CurPrepDtl.FEEDER_NO, FEEDER_TYPE = CurPrepDtl.FEEDER_TYPE, IS_FIRST = CurPREP.Order.CurBatch.DLVY_MODE == BIZ_WMS_PREP_BTH.DLVY_MODEs.First.GetValue() ? "Y" : "N", NEED_CUTTING = "N", }).ToList(); //判断是否超发 isExceed = false; //计算剩余需求数量和条码中的发出数量 var actQty = CurPrepDtl.QTY_PREP > CurPREP.BizType.GetActReqQty(CurPrepDtl) ? 0 : (CurPREP.BizType.GetActReqQty(CurPrepDtl) - CurPrepDtl.QTY_PREP); if (actQty < CurInvItem.CurPkg.QTY) { isExceed = true; var remain = actQty; foreach (var sn in CurSn.OrderByDescending(q => q.QTY)) { sn.QTY_DLVY = remain >= sn.QTY ? sn.QTY : remain; sn.NEED_CUTTING = remain >= sn.QTY ? "N" : "Y"; remain -= sn.QTY_DLVY; } } //判断物料是否允许超发,如果不允许则必须截料,否则由用户在PDA选择是否截料 isNeedCut = CurInvItem.ItemInfo.DLVY_TYPE == BAS_ITEM.DLVY_TYPEs.ByDemand.GetValue(); //如果超发则返回前端处理,否则直接发出 if (isExceed) { //action.LocaleMsg = Biz.L($"条码[{0}]扫描成功,备料物料[{1}]需求[{2}]还需备料[{3}],条码需要截料,发出数量[{4}]"); //action.LocaleMsg = Biz.L($"条码[{0}]扫描成功,备料物料[{1}]需求[{2}]还需备料[{3}],请选择要超发还是截料?"); action.LocaleMsg = Biz.L($"WMS.Out_BIZ_WMS_PREP.ScanItem.Success{(isNeedCut ? "" : "Confirm")}", CurInvItem.SN, CurInvItem.ItemInfo.ITEM_CODE, CurPREP.BizType.GetActReqQty(CurPrepDtl), actQty); action.Data.Command = "ConfirmExceed"; action.Data.Data = new { isExceed, isNeedCut, CurSn, }; } else { input.Data = CurSn.ToJson(); action = await ConfirmExceed(input); } } catch (Exception ex) { action.CatchExceptionWithLog(ex, $"扫描物料[{input.SN}]复核异常"); } return SetOutPutMqttMsg(action, input.Locale); } /// /// 前端确认超发或者返回截料后的信息 /// /// /// public async Task> ConfirmExceed(BaseInput input) { var action = new ApiAction(new ScanOutput() { Command = "Normal" }); try { var sns = (input.Data ?? "").JsonToObject>() ?? new List(); if (!sns.Any()) { var actQty = CurPrepDtl.QTY_PREP > CurPREP.BizType.GetActReqQty(CurPrepDtl) ? 0 : (CurPREP.BizType.GetActReqQty(CurPrepDtl) - CurPrepDtl.QTY_PREP); action.IsSuccessed = false; //action.LocaleMsg = Biz.L($"条码[{0}]扫描成功,备料物料[{1}]需求[{2}]还需备料[{3}],条码需要截料,发出数量[{4}]"); //action.LocaleMsg = Biz.L($"条码[{0}]扫描成功,备料物料[{1}]需求[{2}]还需备料[{3}],请选择要超发还是截料?"); action.LocaleMsg = Biz.L($"WMS.Out_BIZ_WMS_PREP.ScanItem.Success{(isNeedCut ? "" : "Confirm")}", CurInvItem.SN, CurInvItem.ItemInfo.ITEM_CODE, CurPREP.BizType.GetActReqQty(CurPrepDtl), actQty); action.Data.Command = "ConfirmExceed"; action.Data.Data = new { isExceed, isNeedCut, CurSn, }; return SetOutPutMqttMsg(action, input.Locale); } else { foreach (var item in sns) { var sn = CurSn.First(q => q.ID == item.ID); sn.NEED_CUTTING = item.NEED_CUTTING;//前端返回Y认为是截料发料,N认为是整盘发料 sn.DeliverySN = item.DeliverySN; sn.ReserveSN = item.ReserveSN; } Command = "Normal"; } //出库下架 foreach (var item in CurInvItem.Items) { item.SOURCE_CODE = item.TRANS_CODE; item.SOURCE_ORDER = item.TRANS_NO; item.SOURCE_LINE = item.TRANS_LINE; item.TRANS_CODE = nameof(BIZ_WMS_PREP); item.TRANS_NO = CurPREP.Order.ORDER_NO; item.TRANS_LINE = CurPrepDtl.ORDER_LINE; } foreach (var item in CurInvItem.Packages) { item.SOURCE_CODE = item.TRANS_CODE; item.SOURCE_ORDER = item.TRANS_NO; item.SOURCE_LINE = item.TRANS_LINE; item.TRANS_CODE = nameof(BIZ_WMS_PREP); item.TRANS_NO = CurPREP.Order.ORDER_NO; item.TRANS_LINE = CurPrepDtl.ORDER_LINE; } Result downResult = TakeDown(CurSn, input.AuthOption, WMS_ITEM.STATUSs.OffShelf); if (!downResult.IsSuccessed) { action.IsSuccessed = false; action.LocaleMsg = downResult.LocaleMsg; ResetScan(); return SetOutPutMqttMsg(action, input.Locale); } else//处理备料任务数据 { foreach (var sn in CurSn) { sn.STATUS = WMS_ITEM.STATUSs.OffShelf.GetValue(); sn.DOWN_TIME = DateTime.Now; if (sn.NEED_CUTTING == "Y") { sn.NEED_CUTTING = "N"; sn.SN = sn.DeliverySN; sn.QTY = sn.QTY_DLVY; } } CurPrepDtl.QTY_PREP += CurSn.Sum(q => q.QTY_DLVY); CurPREP.Order.STATUS = BIZ_WMS_PREP.STATUSs.Picking.GetValue(); CurPREP.Order.CurBatch.STATUS = BIZ_WMS_PREP_BTH.STATUSs.Picking.GetValue(); CurPREP.Order.CurBatch.PICK_TIME = CurPREP.Order.CurBatch.PICK_TIME < new DateTime(2000, 1, 1) ? DateTime.Now : CurPREP.Order.CurBatch.PICK_TIME; //创建变量克隆对象用于传入DBSubmitAction中保存当前需要暂存的数据值 var _CurSn = CurSn.Clone(); var _CurPrepDtl = CurPrepDtl.Clone(); var _CurPREPOrder = CurPREP.Order.Clone(); var _CurPREPCurBatch = CurPREP.Order.CurBatch.Clone(); AddCommitAction("UpdatePrep", () => { //使用统一的事务DB对象 var db = GetCommitDB(); //数据保存逻辑 db.Insertable(_CurSn, UserCode).ExecuteCommand(); _CurPrepDtl.QTY_PREP = db.Queryable().Where(q => q.ORDER_NO == _CurPrepDtl.ORDER_NO && q.ORDER_LINE == _CurPrepDtl.ORDER_LINE).Sum(q => q.QTY_DLVY); db.Updateable(_CurPrepDtl, UserCode).UpdateColumns(q => new { q.QTY_PREP, q.UPDATE_TIME, q.UPDATE_USER }).ExecuteCommand(); db.Updateable(_CurPREPOrder, UserCode).UpdateColumns(q => new { q.STATUS, q.UPDATE_TIME, q.UPDATE_USER }).ExecuteCommand(); db.Updateable(_CurPREPCurBatch, UserCode).UpdateColumns(q => new { q.STATUS, q.PICK_TIME, q.UPDATE_TIME, q.UPDATE_USER }).ExecuteCommand(); }); //灭灯 if (CurInvItem.Shelf.IsLightShelf) { await Share.Shelf.DownSingle(TransID, CurInvItem.Location); } } //完成所有处理后使用事务保存数据 action = DoIfFinish(action, input.Locale); } catch (Exception ex) { //取消当前操作 ResetTrans(); //action.CatchExceptionWithLog(ex, $"扫描条码[{input.SN}]复核异常"); action.CatchExceptionWithLog(ex, Biz.L("WMS.Default.ScanItem.ScanException", input.SN)); } return SetOutPutMqttMsg(action, input.Locale); } /// /// 扫描货架或者储位 /// public async Task> ScanShelf(string Code, V_WH_UNIT whUnit) { var action = new ApiAction(new ScanOutput() { Command = Command }); try { if (Code.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("请输入或扫描有效的货架/储位码"); action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.ShelfCanNotEmpty"); return action; } CurScanShelf = new ScanShelfInfo(); // 查询货架信息 whUnit = whUnit.IsNullOrEmpty(await MainDB.Queryable().Where(t => (t.SHELF_CODE.ToUpper() == Code || t.LOCATION_CODE.ToUpper() == Code) && t.AUTH_ORG == OrgCode).IncludesAllFirstLayer().FirstAsync()); // 扫描货架代码,且为智能货架 if (!whUnit.IsNullOrEmpty() && whUnit.SHELF_CODE == Code) { CurScanShelf.Shelf = whUnit.Shelf; CurScanShelf.WarehouseCode = whUnit.WH_CODE; CurScanShelf.RegionCode = whUnit.REGION_CODE; CurScanShelf.ShelfCode = whUnit.SHELF_CODE; CurScanShelf.ShelfType = whUnit.SHELF_TYPE; CurScanShelf.IsSmartRack = true; } // 扫描库位代码 else if (!whUnit.IsNullOrEmpty() && whUnit.LOCATION_CODE == Code) { //var nLocation = await MainDB.Queryable().Where(t => t.LOCATION_CODE.ToUpper() == Code.ToUpper() && t.AUTH_ORG == OrgCode).IncludesAllFirstLayer().FirstAsync(); //if (nLocation == null) //{ // action.IsSuccessed = false; // //action.LocaleMsg = Biz.L("储位[{0}]不存在"); // action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.LocationNotExist", Code); // return action; //} if (whUnit.IS_ACTIVE == "N") { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("扫描的储位[{0}]未启用"); action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.ShelfOrLocationDisabled", Code); return action; } if (whUnit.Shelf.IsLightShelf || whUnit.Location.IS_SINGLE == "Y") { var locationData = MainDB.Queryable().Where(q => q.LOCATION_ID == whUnit.LOCATION_ID && q.AUTH_ORG == OrgCode).First(); if (!locationData.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("储位[{0}]已存有物料[{1}],请检查系统库存信息"); action.LocaleMsg = Biz.L($"WMS.Default.ScanShelf.ItemAlreadyExistsInLocation", Code, locationData.SN); return action; } } CurScanShelf.Shelf = whUnit.Shelf; CurScanShelf.Location = whUnit.Location; CurScanShelf.WarehouseCode = whUnit.WH_CODE; CurScanShelf.RegionCode = whUnit.REGION_CODE; CurScanShelf.ShelfCode = whUnit .SHELF_CODE; CurScanShelf.LocationCode = whUnit.LOCATION_CODE; CurScanShelf.IsSmartRack = false; } else { action.IsSuccessed = false; //action.LocaleMsg = Biz.L("请输入或扫描有效的货架/储位码"); action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.ShelfCanNotEmpty"); return action; } CurScanShelf.IsScanShelf = true; //action.LocaleMsg = Biz.L("扫描货架/储位[{0}]成功"); action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.ScanSucceeded", Code); action.Data.Data = CurScanShelf; } catch (Exception ex) { //取消当前操作 ResetTrans(); //action.CatchExceptionWithLog(ex, $"扫描货架/储位[{0}]异常"); action.CatchExceptionWithLog(ex, Biz.L("WMS.Default.ScanShelf.ScanException", Code)); } return action; } /// /// 完成所有处理后使用事务保存数据 /// /// /// /// /// public ApiAction DoIfFinish(ApiAction action, string locale, Action doAfterSave = null) { //保存数据库 SaveCommitListToDB(); //保存数据成功后执行 doAfterSave?.Invoke(); // 返回数据 action.Data.Data = new DefaultScanItemOutput() { SN = CurInvItem.SN, ItemCode = CurInvItem.ItemInfo.ITEM_CODE, MaterialName = CurInvItem.ItemInfo.ITEM_NAME, Qty = CurInvItem.CurPkg.QTY, Unit = CurInvItem.CurPkg.UNIT, regionCode = CurInvItem.Region.REGION_CODE, locationCode = CurInvItem.Location?.LOCATION_CODE, DateCode = CurInvItem.Items[0].PROD_DATE, ScanAfCut = CurInvItem.Warehouse.SCAN_AF_CUT }; //action.LocaleMsg = Biz.L($"扫描条码[{0}]从储位[{1}]下架成功"); action.LocaleMsg = Biz.L("WMS.Default.ScanItem.TakeDownSucceeded", CurInvItem.SN, CurInvItem.Location?.LOCATION_CODE); //重置工序 ResetScan(); return SetOutPutMqttMsg(action, locale); } /// /// 调用发料单据的ERP接口 /// /// /// public async Task CommitToERP(BaseInput input) { var action = await CurPREP.Order.BIZ_TYPE.GetEnum() .CommitToERP(this, input); return action; } #endregion /// /// 重置事务数据,有需要则重写此方法 /// public override void ResetTrans() { ResetScan(); CurPREP = new(MainDB, UserCode, OrgCode); CurPrepDtl = new(); CurScanShelf = null; base.ResetTrans(); } /// /// 重置本次扫码信息 /// public override void ResetScan() { Command = "Normal"; CurInvItem = null; CurSn = new(); base.ResetScan(); } public override bool Close(bool needSaveHistoryLog = false) { //CloseLight(LocationHis).Wait(); if (!(CurPREP?.Order?.ORDER_NO ?? "").IsNullOrEmpty()) { MainDB.Deleteable().Where(x => x.TRANS_NO == CurPREP.Order.ORDER_NO).ExecuteCommand(); } this.IsFinished = true; return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished; } }//endClass }