using Microsoft.CodeAnalysis.Differencing; using Rhea.Common; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Tiger.IBusiness; using Tiger.IBusiness.MES.WorkAction; using Tiger.Model; using Tiger.Model.Entitys.MES.Position; namespace Tiger.Business.MES.WorkAction { public class PackingAction : IPackingAction { #region Propertys & Variables #region 固定写法,工序中的必要信息 public bool IsFinished { get; set; } = false; public IWorkStep CurStep { get; set; } public IPosition CurPosition { get; set; } public MES_WO_NODE_ACT NodeAct { get; set; } public MES_WO_ACTION Setting { get; set; } #endregion public BAS_PKG_RULE PkgRule { get; set; } public BAS_PKG_PROD PkgProd { get; set; } public WipPkg CurPkg { get; set; } public WipPkgItem CurPkgItem { get; set; } public PackingActionOutput CurCmd { get; set; } public int PrintTimes = 0; public Dictionary LabelDic { get; set; } = new(); public List LabelPV { get; set; } = new(); public int FinishLevel = 0; private bool IsManually => CurStep.IsNullOrEmpty(); #endregion Propertys & Variables #region Functions /// /// 初始化工序行为(正常条码过站) /// /// public void Init(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting) { #region 固定写法,给默认变量赋值 CurStep = curStep; CurPosition = position; NodeAct = nodeAct; Setting = setting; #endregion //正常条码过站执行包装行为 PkgRule = Biz.Db.Queryable().Where(q => q.RULE_CODE == setting.PKG_CODE).IncludesAllFirstLayer().IncludesAllSecondLayer(q => q.Details).First(); //根据行为设置获取多层包装的标签打印模板字典 var codes = (Setting.OPTION_1 ?? "").JsonToObject>() ?? new List(); foreach (var code in codes) { var label = code.LABEL_CODE.IsNullOrEmpty() ? null : Biz.Db.Queryable().Where(q => q.LABEL_CODE == code.LABEL_CODE).IncludesAllFirstLayer().First(); LabelDic.Add(code.PKG_LEVEL, label); } LabelPV = Biz.Db.Queryable().ToList(); //如果工序上下文中没有包装记录则新建一个,有且未包装完成则获取当前的包装记录 if (CurPosition.Context.ContainsKey("CurPackage") && !CurPosition.Context["CurPackage"].IsNullOrEmpty() && !(CurPosition.Context["CurPackage"] as WipPkg).IsFinished) { CurPkg = (CurPosition.Context["CurPackage"] as WipPkg).Clone(); } else { var max = PkgRule.Details.OrderByDescending(q => q.PKG_LEVEL).First(); CurPkg = new WipPkg() { WorkBatch = CurPosition.WorkBatch.Batch.BATCH_NO, RULE_CODE = PkgRule.RULE_CODE, RULE_NAME = PkgRule.RULE_NAME, PROD_CODE = CurPosition.WorkBatch.WO.ITEM_CODE, ITEM_CODE = Biz.Db.Queryable().Where(q => q.FLOW_SN == CurPosition.CurWipSNs.First().FLOW_SN).First()?.ITEM_CODE, Item = new WipPkgItem() { PKG_CODE = max.PKG_CODE, PKG_NAME = max.PkgType.PKG_NAME, IS_MIN_PKG = max.PkgType.IS_MIN_PKG, PKG_LEVEL = max.PKG_LEVEL, PKG_QTY = max.PKG_QTY, LABEL_CODE = LabelDic.Count > max.PKG_LEVEL ? LabelDic[max.PKG_LEVEL]?.LABEL_CODE : null, } }; WipPkgItem child = null; foreach (var dtl in PkgRule.Details.OrderBy(q => q.PKG_LEVEL)) { if (1 < dtl.PKG_LEVEL && dtl.PKG_LEVEL < max.PKG_LEVEL) { var item = new WipPkgItem() { PKG_CODE = dtl.PKG_CODE, PKG_NAME = dtl.PkgType.PKG_NAME, IS_MIN_PKG = dtl.PkgType.IS_MIN_PKG, PKG_LEVEL = dtl.PKG_LEVEL, PKG_QTY = dtl.PKG_QTY, LABEL_CODE = LabelDic.Count > dtl.PKG_LEVEL ? LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE : null, }; if (!child.IsNullOrEmpty()) { item.Items.Add(child); } child = item; } } if (!child.IsNullOrEmpty()) { CurPkg.Item.Items.Add(child); } //删除工序上下文中的包装记录 if (CurPosition.Context.ContainsKey("CurPackage")) { CurPosition.Context.Remove("CurPackage"); CurPosition.Context.Remove("CurLabelDic"); } } //获取是否包装完后需要称重 CurPkg.NeedWeighing = Setting.OPTION_2 == "Y"; //获取包装规则的称重范围 PkgProd = Biz.Db.Queryable().Where(q => q.PKG_RULE_ID == PkgRule.ID && q.ITEM_CODE == CurPosition.WorkBatch.WO.ITEM_CODE).First(); CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("记录包装数据")); } /// /// 初始化工序行为(手动结束包装专用) /// /// public void Init(IPosition position) { #region 固定写法,给默认变量赋值 CurStep = null; CurPosition = position; NodeAct = null; Setting = null; #endregion //获取当前的包装记录 if (CurPosition.Context.ContainsKey("CurPackage") && !CurPosition.Context["CurPackage"].IsNullOrEmpty()) { CurPkg = (CurPosition.Context["CurPackage"] as WipPkg).Clone(); } else { throw new Exception("找不到包装数据,请重新扫描需要包装的产品"); } //手动结束包装专用,临时执行行为 PkgRule = Biz.Db.Queryable().Where(q => q.RULE_CODE == CurPkg.RULE_CODE).IncludesAllFirstLayer().IncludesAllSecondLayer(q => q.Details).First(); //根据行为设置获取多层包装的标签打印模板字典 LabelDic = CurPosition.Context["CurLabelDic"] as Dictionary; LabelPV = Biz.Db.Queryable().ToList(); //获取包装规则的称重范围 PkgProd = Biz.Db.Queryable().Where(q => q.PKG_RULE_ID == PkgRule.ID && q.ITEM_CODE == CurPkg.PROD_CODE).First(); //把 CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("记录包装数据")); } /// /// 获取行为开始的提示信息 /// /// public Locale GetBeginMsg() { var min = PkgRule.Details.OrderBy(q => q.PKG_LEVEL).First(); //行为设定的OPTION_1是第一层包装的标签模板代码,如果为空则不需要打印 if (LabelDic[min.PKG_LEVEL].IsNullOrEmpty()) { var msg = new Locale("MES.WorkAction.PackingAction.BeginMsg", min.PKG_LEVEL, min.PkgType.PKG_NAME, CurPosition.CurSN); //var msg = new Locale($"已扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码[{CurPosition.CurWipSN.SN}]"); return msg; } else { var msg = new Locale("MES.WorkAction.PackingAction.BeginPrint", min.PKG_LEVEL, min.PkgType.PKG_NAME, LabelDic[min.PKG_LEVEL]?.LABEL_CODE, LabelDic[min.PKG_LEVEL].LABEL_NAME); //var msg = new Locale($"开始打印第{min.PKG_LEVEL}层包装[{min.PkgType.PKG_NAME}]的标签[{LabelDic[min.PKG_LEVEL]?.LABEL_CODE}: {LabelDic[min.PKG_LEVEL].LABEL_NAME}]"); return msg; } } /// /// 尝试开始执行工序行为 /// /// public ApiAction TryBegin(SubmitInput input) { var action = new ApiAction(new SubmitOutput()); action.LocaleMsg = GetBeginMsg(); var min = PkgRule.Details.OrderBy(q => q.PKG_LEVEL).First(); if (min.PKG_LEVEL == CurPkg.Item.PKG_LEVEL && CurPkg.NeedWeighing) { var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Weighing"; data.PkgLevel = min.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("上称称重")); action.Data.Data = data; action.Data.ShortMsg = new("上称称重", ShortMessage.Types.Success); //action.LocaleMsg = new($"请把外包装上称称重"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseWeighing"); } //根据包装不同层级的标签模板代码,如果为空则不需要打印 else if (LabelDic[min.PKG_LEVEL].IsNullOrEmpty()) { input.Data = new PackingActionInput() { ExecCode = "Scan", IsFinish = true, PkgLevel = min.PKG_LEVEL, PkgSN = CurPosition.CurSN, }.ToJson(); action = Submit(input); } else { //设置打印变量值 LabelDic[min.PKG_LEVEL] = CurPosition.SetLabelVariables(LabelPV, LabelDic[min.PKG_LEVEL], this); var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Print"; data.PkgLevel = min.PKG_LEVEL; data.PrintLable = LabelDic[min.PKG_LEVEL]; CurCmd = data; PrintTimes++; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("打印标签")); action.IsSuccessed = true; action.Data.Data = data; action.Data.ShortMsg = new("打印标签", ShortMessage.Types.Normal); //action.LocaleMsg = new Locale($"开始第{PrintTimes}次打印第{min.PKG_LEVEL}层包装[{min.PkgType.PKG_NAME}]的标签[{LabelDic[min.PKG_LEVEL]?.LABEL_CODE}: {LabelDic[min.PKG_LEVEL].LABEL_NAME}]"); action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, min.PKG_LEVEL, min.PkgType.PKG_NAME, LabelDic[min.PKG_LEVEL]?.LABEL_CODE, LabelDic[min.PKG_LEVEL].LABEL_NAME); } //如果返回成功则认为当前行为可以开始执行,否则返回失败 //action.IsSuccessed = true; return action; } /// /// 工序行为提交数据 /// /// public ApiAction Submit(SubmitInput input) { var action = new ApiAction(new SubmitOutput()); var pInput = input?.Data?.JsonToObject(); switch (pInput?.ExecCode) { //Scan:扫码,扫描当前包装层级的条码 case "Scan": if (CurCmd.IsNullOrEmpty() || CurCmd.ExecCode == "Scan" || (CurCmd.ExecCode == "Print" && CurCmd.PkgLevel == pInput.PkgLevel)) { //客户端扫描失败 if (!pInput.IsFinish || pInput.PkgSN.IsNullOrEmpty()) { var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel); CurStep?.SetStatusMessage(StepStatus.Error, Biz.L("扫描错误")); action.Data.ShortMsg = new("扫描错误", ShortMessage.Types.Error); action.IsSuccessed = false; //action.LocaleMsg = new($"条码扫描失败,请重新扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.ScanFail", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME); CurPosition.ResetNode(); return action; } //验证当前包装条码是否已经被扫描过 if (CurPosition.GetPackageList(CurPkg.Item).Any(q => q.SN == pInput.PkgSN)) { var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel); CurStep?.SetStatusMessage(StepStatus.Error, Biz.L("扫描错误")); action.Data.ShortMsg = new("扫描错误", ShortMessage.Types.Error); action.IsSuccessed = false; //action.LocaleMsg = new($"条码[{pInput.PkgSN}]无需重复扫描,请扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.ScanRepeat", pInput.PkgSN, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME); CurPosition.ResetNode(); return action; } //客户端扫描成功 CurCmd = null; PrintTimes = 0; action = SavePkgData(input, action); //if (action.IsSuccessed) //{ // CurStep?.SetStatusMessage(StepStatus.Success, Biz.L("扫描成功")); // action.Data.ShortMsg = new("扫描成功", ShortMessage.Types.Success); //} } break; //Print:打印,打印当前包装层级的标签 case "Print": if (CurCmd.ExecCode == "Print") { var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel); //客户端完成打印 if (pInput.IsFinish) { CurCmd = null; PrintTimes = 0; var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Scan"; data.PkgLevel = dtl.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("扫描标签")); action.Data.Data = data; action.Data.ShortMsg = new("扫描标签", ShortMessage.Types.Normal); //action.LocaleMsg = new($"请扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseScanLabel", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME); } //客户端打印失败 else { //如果打印失败则尝试三次重新打印,如果都失败则重置工序 if (PrintTimes < 3 && !CurCmd.IsNullOrEmpty()) { PrintTimes++; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("重新打印")); action.Data.Data = CurCmd; action.Data.ShortMsg = new("重新打印", ShortMessage.Types.Normal); //action.LocaleMsg = new Locale($"开始{PrintTimes}次打印第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签[{LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE}: {LabelDic[dtl.PKG_LEVEL].LABEL_NAME}]"); action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME); } else { CurCmd = null; PrintTimes = 0; CurStep?.SetStatusMessage(StepStatus.Error, Biz.L("打印失败")); action.Data.ShortMsg = new("打印失败", ShortMessage.Types.Failed); action.IsSuccessed = false; //action.LocaleMsg = new($"尝试第{PrintTimes}次打印第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签[{LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE}: {LabelDic[dtl.PKG_LEVEL].LABEL_NAME}]失败,工序已重置,请重新扫描进站产品条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PrintFail3Times", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME); CurPosition.ResetNode(); } } } break; // Weighing:称重,完成包装后对整个包装成称重 case "Weighing": if (CurCmd.ExecCode == "Weighing") { if (!pInput.WeightInfo.IsNullOrEmpty() && pInput.WeightInfo.Weight > 0) { //验证重量数据是否符合设置好的重量范围 if (!PkgProd.IsNullOrEmpty() && ((pInput.WeightInfo.Weight < PkgProd.MIN_WEIGHT && !IsManually) || PkgProd.MAX_WEIGHT < pInput.WeightInfo.Weight)) { action.IsSuccessed = false; CurStep?.SetStatusMessage(StepStatus.Error, Biz.L("重量超限")); action.Data.Data = CurCmd; action.Data.ShortMsg = new("重量超限", ShortMessage.Types.Failed); //action.LocaleMsg = new($"外包装重量[{0}]超出产品[{1}]在包装规则[{2}]中的预设范围[{3} - {4}],请处理后重新上称称重"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PackageOverWeight", pInput.WeightInfo.Weight + pInput.WeightInfo.Unit.IsNullOrEmpty("", " " + pInput.WeightInfo.Unit), CurPosition.WorkBatch.WO.ITEM_CODE, PkgRule.RULE_NAME, PkgProd.MIN_WEIGHT + PkgProd.MIN_UNIT.IsNullOrEmpty("", " " + PkgProd.MIN_UNIT), PkgProd.MAX_WEIGHT + PkgProd.MAX_UNIT.IsNullOrEmpty("", " " + PkgProd.MAX_UNIT)); return action; } CurCmd = null; PrintTimes = 0; CurPkg.WeightInfo.Weight = pInput.WeightInfo.Weight; CurPkg.WeightInfo.Unit = pInput.WeightInfo.Unit; CurPkg.NeedWeighing = false; //称重成功,继续行为 var dtl = PkgRule.Details.FirstOrDefault(q => q.PKG_LEVEL == FinishLevel + 1); //最外层包装已处理完成则直接结束行为 if (CurPkg.Item.PKG_LEVEL == FinishLevel) { action = End(input); } //最外层包装未打印扫描则继续 else { //如果为空则不需要打印 if (LabelDic[dtl.PKG_LEVEL].IsNullOrEmpty()) { var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Scan"; data.PkgLevel = dtl.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("扫描标签")); action.Data.Data = data; action.Data.ShortMsg = new("扫描标签", ShortMessage.Types.Normal); //action.LocaleMsg = new($"请扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseScanLabel", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME); } else { //设置打印变量值 LabelDic[dtl.PKG_LEVEL] = CurPosition.SetLabelVariables(LabelPV, LabelDic[dtl.PKG_LEVEL], this); var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Print"; data.PkgLevel = dtl.PKG_LEVEL; data.PrintLable = LabelDic[dtl.PKG_LEVEL]; CurCmd = data; PrintTimes++; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("打印标签")); action.Data.Data = data; action.Data.ShortMsg = new("打印标签", ShortMessage.Types.Normal); //action.LocaleMsg = new Locale($"开始第{PrintTimes}次打印第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签[{LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE}: {LabelDic[dtl.PKG_LEVEL].LABEL_NAME}]"); action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME); } } } else { action.IsSuccessed = false; CurStep?.SetStatusMessage(StepStatus.Error, Biz.L("称重失败")); action.Data.Data = CurCmd; action.Data.ShortMsg = new("称重失败", ShortMessage.Types.Failed); //action.LocaleMsg = new($"外包装称重数据异常,请重新上称称重"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseWeighingAgain"); return action; } } break; // Complete:完成,完成全部包装后结束行为 case "Complete": if (CurCmd.ExecCode == "Complete") { CurCmd = null; PrintTimes = 0; //打印后称重 if (CurPkg.NeedWeighing) { var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Weighing"; data.PkgLevel = CurPkgItem.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Success, Biz.L("包装成功")); action.Data.Data = data; action.Data.ShortMsg = new("包装成功", ShortMessage.Types.Success); //action.LocaleMsg = new($"请把包装[{CurPkgItem.Package.SN}]上称称重"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseWeighing", CurPkgItem.Package.SN); } else { action = End(input); } } break; // 手动结束包装,保存暂存的包装数据 case null: { CurCmd = null; PrintTimes = 0; FinishLevel = 1; WipPkgItem curItem = CurPkg.Item; while (curItem.PKG_LEVEL > 2) { var next = curItem.Items.FirstOrDefault(q => !q.IsFinished); curItem = next; } CurPkgItem = curItem; //手动结束包装默认从第二层包装开始验证 var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == 2); if (dtl.PKG_LEVEL == CurPkg.Item.PKG_LEVEL && CurPkg.NeedWeighing) { var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Weighing"; data.PkgLevel = dtl.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("上称称重")); action.Data.Data = data; action.Data.ShortMsg = new("上称称重", ShortMessage.Types.Success); //action.LocaleMsg = new($"请把外包装上称称重"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseWeighing"); } //根据包装不同层级的标签模板代码,如果为空则不需要打印 else if (LabelDic[dtl.PKG_LEVEL].IsNullOrEmpty()) { var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Scan"; data.PkgLevel = dtl.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("扫描标签")); action.Data.Data = data; action.Data.ShortMsg = new("扫描标签", ShortMessage.Types.Normal); //action.LocaleMsg = new($"请扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseScanLabel", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME); } else { //设置打印变量值 LabelDic[dtl.PKG_LEVEL] = CurPosition.SetLabelVariables(LabelPV, LabelDic[dtl.PKG_LEVEL], this); var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Print"; data.PkgLevel = dtl.PKG_LEVEL; data.PrintLable = LabelDic[dtl.PKG_LEVEL]; CurCmd = data; PrintTimes++; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("打印标签")); action.Data.Data = data; action.Data.ShortMsg = new("打印标签", ShortMessage.Types.Normal); //action.LocaleMsg = new Locale($"开始第{PrintTimes}次打印第{min.PKG_LEVEL}层包装[{min.PkgType.PKG_NAME}]的标签[{LabelDic[min.PKG_LEVEL]?.LABEL_CODE}: {LabelDic[min.PKG_LEVEL].LABEL_NAME}]"); action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME); } } break; default: break; } //如果行为设置为出错需要重置工序操作 if (!action.IsSuccessed && NodeAct?.NEED_RESET == "Y") { CurPosition.ResetNode(); } return action; } //保存包装信息 public ApiAction SavePkgData(SubmitInput input, ApiAction action) { var pInput = input.Data?.JsonToObject(); try { //正在处理的包装层级明细 var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == FinishLevel + 1); //没有保存过任何包装层级的数据,则先处理最小包装数据 if (FinishLevel == 0) { CurPkgItem = new WipPkgItem() { PKG_CODE = dtl.PKG_CODE, PKG_NAME = dtl.PkgType.PKG_NAME, IS_MIN_PKG = dtl.PkgType.IS_MIN_PKG, PKG_LEVEL = dtl.PKG_LEVEL, PKG_QTY = dtl.PKG_QTY, LABEL_CODE = LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE, IsFinished = true, }; CurPkgItem.Package = Biz.Db.Queryable().Where(q => q.SN == pInput.PkgSN && q.AUTH_ORG == CurPosition.WorkBatch.WO.AUTH_ORG).First() ?? new() { AUTH_ORG = CurPosition.WorkBatch.WO.AUTH_ORG, AUTH_PROD = CurPosition.CurLine.LINE_CODE, SN = pInput.PkgSN, }; CurPkgItem.Package.WIP_ID = CurPosition.CurWipSNs.Count == 1 ? CurPosition.CurWipSNs.First().ID : null; CurPkgItem.Package.PKG_TYPE = dtl.PkgType.PKG_NAME; CurPkgItem.Package.ITEM_CODE = CurPosition.CurWipSNs.First().ITEM_CODE; CurPkgItem.Package.QTY = CurPosition.CurWipSNs.First().QTY; CurPkgItem.Package.UNIT = dtl.PkgType.PKG_NAME; CurPkgItem.Package.WORK_ORDER = CurPosition.CurWipSNs.First().WORK_ORDER; CurPkgItem.Package.BATCH_NO = CurPosition.CurWipSNs.First().BATCH_NO; CurPkgItem.Package.ROT_CODE = CurPosition.CurWipSNs.First().ROT_CODE; CurPkgItem.Package.NODE_ID = CurPosition.CurWipSNs.First().NODE_ID; CurPkgItem.Package.NODE_NAME = CurPosition.CurWipSNs.First().NODE_NAME; CurPkgItem.Package.FTY_CODE = CurPosition.CurWipSNs.First().FTY_CODE; CurPkgItem.Package.WS_CODE = CurPosition.CurWipSNs.First().WS_CODE; CurPkgItem.Package.LINE_CODE = CurPosition.CurWipSNs.First().LINE_CODE; CurPkgItem.Package.POST_CODE = CurPosition.CurWipSNs.First().POST_CODE; CurPkgItem.Package.OPER_CODE = CurPosition.CurWipSNs.First().OPER_CODE; CurPkgItem.Package.SEGMENT = CurPosition.CurWipSNs.First().SEGMENT; CurPkgItem.Package.ACT_ID = NodeAct.ID; FinishLevel++; //完成包装的层级小于最外层包装层级 if (FinishLevel < PkgRule.Details.Max(q => q.PKG_LEVEL)) { //当前处理的包装层级已经处理完,继续往上保存 action = SavePkgData(input, action); } //最外层包装已经完成包装,保存包装数据到数据库 else { CurPkg.Item = CurPkgItem; action = CompletePkg(); } } //处理其他包装层级数据 else { //客户端提交的包装层级等于当前处理的包装层级 if (pInput.PkgLevel == dtl.PKG_LEVEL) { CurPkgItem.IsFinished = true; CurPkgItem.Package = IsManually ? new() { AUTH_ORG = CurPosition.WorkBatch.WO.AUTH_ORG, AUTH_PROD = CurPosition.CurLine.LINE_CODE, SN = pInput.PkgSN, PKG_TYPE = dtl.PkgType.PKG_NAME, ITEM_CODE = CurPkgItem.Items.First().Package.ITEM_CODE, QTY = CurPkgItem.Items.Sum(q => q.Package.QTY), UNIT = dtl.PkgType.PKG_NAME, WORK_ORDER = CurPkgItem.Items.First().Package.WORK_ORDER, BATCH_NO = CurPkgItem.Items.First().Package.BATCH_NO, ROT_CODE = CurPkgItem.Items.First().Package.ROT_CODE, NODE_ID = CurPkgItem.Items.First().Package.NODE_ID, NODE_NAME = CurPkgItem.Items.First().Package.NODE_NAME, FTY_CODE = CurPkgItem.Items.First().Package.FTY_CODE, WS_CODE = CurPkgItem.Items.First().Package.WS_CODE, LINE_CODE = CurPkgItem.Items.First().Package.LINE_CODE, POST_CODE = CurPkgItem.Items.First().Package.POST_CODE, OPER_CODE = CurPkgItem.Items.First().Package.OPER_CODE, SEGMENT = CurPkgItem.Items.First().Package.SEGMENT, } : new() { AUTH_ORG = CurPosition.WorkBatch.WO.AUTH_ORG, AUTH_PROD = CurPosition.CurLine.LINE_CODE, SN = pInput.PkgSN, PKG_TYPE = dtl.PkgType.PKG_NAME, ITEM_CODE = CurPosition.CurWipSNs.First().ITEM_CODE, QTY = CurPkgItem.Items.Sum(q => q.Package.QTY), UNIT = dtl.PkgType.PKG_NAME, WORK_ORDER = CurPosition.CurWipSNs.First().WORK_ORDER, BATCH_NO = CurPosition.CurWipSNs.First().BATCH_NO, ROT_CODE = CurPosition.CurWipSNs.First().ROT_CODE, NODE_ID = CurPosition.CurWipSNs.First().NODE_ID, NODE_NAME = CurPosition.CurWipSNs.First().NODE_NAME, FTY_CODE = CurPosition.CurWipSNs.First().FTY_CODE, WS_CODE = CurPosition.CurWipSNs.First().WS_CODE, LINE_CODE = CurPosition.CurWipSNs.First().LINE_CODE, POST_CODE = CurPosition.CurWipSNs.First().POST_CODE, OPER_CODE = CurPosition.CurWipSNs.First().OPER_CODE, SEGMENT = CurPosition.CurWipSNs.First().SEGMENT, ACT_ID = NodeAct.ID, }; FinishLevel++; //完成包装的层级小于最外层包装层级 if (FinishLevel < PkgRule.Details.Max(q => q.PKG_LEVEL)) { //当前处理的包装层级已经处理完,继续往上保存 action = SavePkgData(input, action); } //最外层包装已经完成包装,保存包装数据到数据库 else { action = CompletePkg(); } } //当前处理的包装层级已经处理完,继续往上保存 else if (pInput.PkgLevel == FinishLevel) { //获取当前的包装明细的上一层包装对象 WipPkgItem curItem = CurPkg.Item; while (curItem.PKG_LEVEL > dtl.PKG_LEVEL) { var next = curItem.Items.FirstOrDefault(q => !q.IsFinished); if (next.IsNullOrEmpty()) { var nextDtl = PkgRule.Details.First(q => q.PKG_LEVEL == curItem.PKG_LEVEL - 1); next = new WipPkgItem() { PKG_CODE = nextDtl.PKG_CODE, PKG_NAME = nextDtl.PkgType.PKG_NAME, IS_MIN_PKG = nextDtl.PkgType.IS_MIN_PKG, PKG_LEVEL = nextDtl.PKG_LEVEL, PKG_QTY = nextDtl.PKG_QTY, LABEL_CODE = LabelDic[nextDtl.PKG_LEVEL]?.LABEL_CODE, }; curItem.Items.Add(next); } curItem = next; } //添加当前的包装明细到上一层包装的明细列表 if (!curItem.Items.Contains(CurPkgItem)) { curItem.Items.Add(CurPkgItem); } CurPkgItem = curItem; //添加明细后判断当前包装层级的明细数量是否等于包装数量,若相等则标记当前包装层级为完成并尝试打印标签 if (CurPkgItem.Items.Count(q => q.IsFinished) == CurPkgItem.PKG_QTY || IsManually) { //打印前称重:如果当前的包装明细的上一层包装对象是最外层包装且需要称重时,先称重,合格后在发印或者扫描最外层包装标签 if (CurPkgItem.PKG_LEVEL == CurPkg.Item.PKG_LEVEL && CurPkg.NeedWeighing) { var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Weighing"; data.PkgLevel = CurPkgItem.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("上称称重")); action.Data.Data = data; action.Data.ShortMsg = new("上称称重", ShortMessage.Types.Success); //action.LocaleMsg = new($"请把外包装上称称重"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseWeighing"); } else { //如果为空则不需要打印 if (LabelDic[dtl.PKG_LEVEL].IsNullOrEmpty()) { var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Scan"; data.PkgLevel = dtl.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("扫描标签")); action.Data.Data = data; action.Data.ShortMsg = new("扫描标签", ShortMessage.Types.Normal); //action.LocaleMsg = new($"请扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseScanLabel", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME); } else { //设置打印变量值 LabelDic[dtl.PKG_LEVEL] = CurPosition.SetLabelVariables(LabelPV, LabelDic[dtl.PKG_LEVEL], this); var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Print"; data.PkgLevel = dtl.PKG_LEVEL; data.PrintLable = LabelDic[dtl.PKG_LEVEL]; CurCmd = data; PrintTimes++; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("打印标签")); action.Data.Data = data; action.Data.ShortMsg = new("打印标签", ShortMessage.Types.Normal); //action.LocaleMsg = new Locale($"开始第{PrintTimes}次打印第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签[{LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE}: {LabelDic[dtl.PKG_LEVEL].LABEL_NAME}]"); action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL]?.LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME); } } } //当前包装层级的明细数量未达到包装数量,则完成本次扫描,等待下个产品进站 else { action = End(input); } } //数据异常 else { CurStep?.SetStatusMessage(StepStatus.Error, Biz.L("包装错误")); action.Data.ShortMsg = new("包装错误", ShortMessage.Types.Error); var pdtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel); action.IsSuccessed = false; //action.LocaleMsg = new($"客户端提交的包装层级[{pdtl.PKG_LEVEL}]({pdtl.PkgType.PKG_NAME})数据不是正在处理的包装层级[{dtl.PKG_LEVEL}]({dtl.PkgType.PKG_NAME}),工序已重置,请重新扫描进站产品条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.SaveLevelNotMatchException", pdtl.PKG_LEVEL, pdtl.PkgType.PKG_NAME, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME); CurPosition.ResetNode(); } } } catch (System.Exception ex) { CurStep?.SetStatusMessage(StepStatus.Error, Biz.L("包装异常")); action.Data.ShortMsg = new("包装异常", ShortMessage.Types.Exception); var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel); action.CatchExceptionWithLog(ex, $"包装行为:扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码[{input.SN}]后保存数据失败"); action.IsSuccessed = false; //action.LocaleMsg = new($"扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码[{input.SN}]后保存数据失败,工序已重置,请重新扫描进站产品条码"); action.LocaleMsg = new("MES.WorkAction.PackingAction.SavePkgDataException", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, input.SN); CurPosition.ResetNode(); } return action; } public List GetMinPackageList(WipPkgItem parent) { List list = new(); if (parent.Items.Any()) { foreach (var item in parent.Items) { item.Package.PARENT_SN = parent.Package?.SN; list.AddRange(GetMinPackageList(item)); } } else { if (!parent.Package.IsNullOrEmpty()) { list.Add(parent.Package); } } return list; } public ApiAction CompletePkg() { var action = new ApiAction(new SubmitOutput()); var data = new PackingActionOutput() { PkgInfo = CurPkg }; data.ExecCode = "Complete"; data.PkgLevel = CurPkg.Item.PKG_LEVEL; CurCmd = data; CurStep?.SetStatusMessage(StepStatus.Normal, Biz.L("保存包装数据")); action.Data.Data = data; action.Data.ShortMsg = new("保存包装数据", ShortMessage.Types.Normal); //action.LocaleMsg = new($"第{CurPkg.Item.PKG_LEVEL}层包装[{CurPkg.Item.PKG_NAME}]已经全部完成,保存包装数据"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PackageComplete", CurPkg.Item.PKG_LEVEL, CurPkg.Item.PKG_NAME); //手动结束包装则标记行为完成 //if (IsManually) //{ // IsFinished = true; //} return action; } /// /// 结束执行工序行为 /// /// public ApiAction End(SubmitInput input) { var action = new ApiAction(new SubmitOutput()); //记录外包装的称重数据 if (CurPkg.IsFinished) { CurPkg.Item.Package.WEIGHT = CurPkg.WeightInfo.Weight; CurPkg.Item.Package.WEIGHT_UNIT = CurPkg.WeightInfo.Unit; } //不是手动结束包装则保存行为操作记录 if (!IsManually) { //记录行为操作记录 var wipActs = new List(); foreach (var wipSn in CurPosition.CurWipSNs) { var wipAct = new MES_WIP_ACT() { AUTH_ORG = CurPosition.WorkBatch.WO.AUTH_ORG, AUTH_PROD = CurPosition.CurLine.LINE_CODE, WIP_ID = wipSn.ID, HIS_ID = CurPosition.CurWipSNHiss.First(q => q.SN == wipSn.SN).ID, SN = wipSn.SN, STATUS = wipSn.STATUS, ITEM_CODE = wipSn.ITEM_CODE, WORK_ORDER = wipSn.WORK_ORDER, BATCH_NO = wipSn.BATCH_NO, ROT_CODE = wipSn.ROT_CODE, NODE_ID = wipSn.NODE_ID, NODE_NAME = wipSn.NODE_NAME, ACT_ID = NodeAct.ID, ACT_NAME = NodeAct.ACT_NAME, FTY_CODE = wipSn.FTY_CODE, WS_CODE = wipSn.WS_CODE, LINE_CODE = wipSn.LINE_CODE, POST_CODE = wipSn.POST_CODE, OPER_CODE = wipSn.OPER_CODE, SEGMENT = wipSn.SEGMENT, FLOW_SN = wipSn.FLOW_SN, TRAY_SN = wipSn.TRAY_SN, INNER_SN = wipSn.INNER_SN, CARTON_SN = wipSn.CARTON_SN, PALLET_SN = wipSn.PALLET_SN, OPERATION_TIME = DateTime.Now, SFTS_CODE = wipSn.SFTS_CODE, SFT_CODE = wipSn.SFT_CODE, PRD_CODE = wipSn.PRD_CODE, ACT_TYPE = NodeAct.ACT_TYPE, ACT_SN = wipSn.SN, ACT_RESULT = "Y", ELAPSED_TIME = CurStep.GetElapsedTime().TotalMilliseconds.ToInt64(), TRACE_INFO = $"产品条码[{string.Join(",", CurPosition.CurSN)}]包装完成", }; wipActs.Add(wipAct); } //创建变量克隆对象用于传入DBSubmitAction中保存当前需要暂存的数据值 var _wipActs = wipActs.Clone(); var _pkgList = CurPkg.IsFinished ? CurPosition.GetPackageList(CurPkg.Item) : new(); //保存数据 CurStep.DBSubmitAction = () => { var db = CurPosition.GetCommitDB(); if (_wipActs.Any()) { db.Storageable(_wipActs, CurPosition.UserCode).ExecuteCommand(); } if (_pkgList.Any()) { db.Storageable(_pkgList, CurPosition.UserCode).ExecuteCommand(); var wipIDs = _pkgList.Where(q => !q.WIP_ID.IsNullOrEmpty()).Select(q => q.WIP_ID).ToList(); var nodeID = _pkgList.First().NODE_ID; var actID = _pkgList.First().ACT_ID; var wo = _pkgList.First().WORK_ORDER; //包装信息保存到在制品信息表 db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.INNER_SN == q.CARTON_SN) .SetColumns(q => q.CARTON_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && wipIDs.Contains(q.ID)) .ExecuteCommand(); //包装信息保存到生产过程记录 db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.INNER_SN == q.CARTON_SN) .SetColumns(q => q.CARTON_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && q.NODE_ID == nodeID && wipIDs.Contains(q.WIP_ID)) .ExecuteCommand(); //包装信息保存到生产行为记录 db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.INNER_SN == q.CARTON_SN) .SetColumns(q => q.CARTON_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && q.NODE_ID == nodeID && q.ACT_ID == actID && wipIDs.Contains(q.WIP_ID)) .ExecuteCommand(); //包装信息保存到工单条码明细表 db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.OUTER_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && wipIDs.Contains(q.WIP_ID)) .ExecuteCommand(); } }; } else { if (CurPkg.IsFinished) { var _pkgList = CurPosition.GetPackageList(CurPkg.Item); //最外层包装已经完成包装,则把工序中暂存标记设为false,统一提交包装内产品的过站记录 CurPosition.NeedTemporaryStoreDBCommitAction = false; //保存数据 CurPosition.SaveStepsCommitActionToDB(() => { var db = CurPosition.GetCommitDB(); if (_pkgList.Any()) { db.Storageable(_pkgList, CurPosition.UserCode).ExecuteCommand(); var wipIDs = _pkgList.Where(q => !q.WIP_ID.IsNullOrEmpty()).Select(q => q.WIP_ID).ToList(); var nodeID = _pkgList.First().NODE_ID; var actID = _pkgList.First().ACT_ID; var wo = _pkgList.First().WORK_ORDER; //包装信息保存到在制品信息表 db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.INNER_SN == q.CARTON_SN) .SetColumns(q => q.CARTON_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && wipIDs.Contains(q.ID)) .ExecuteCommand(); //包装信息保存到生产过程记录 var endOperCode = CurPkg.IsReachedEndNode ? "EndNode" : "NotReachedEndNode"; db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.INNER_SN == q.CARTON_SN) .SetColumns(q => q.CARTON_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && (q.NODE_ID == nodeID || q.OPER_CODE == endOperCode) && wipIDs.Contains(q.WIP_ID)) .ExecuteCommand(); //包装信息保存到生产行为记录 db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.INNER_SN == q.CARTON_SN) .SetColumns(q => q.CARTON_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && q.NODE_ID == nodeID && q.ACT_ID == actID && wipIDs.Contains(q.WIP_ID)) .ExecuteCommand(); //包装信息保存到工单条码明细表 db.Updateable() .SetColumns(q => q.TRAY_SN == CurPkg.Item.Package.SN) .SetColumns(q => q.OUTER_SN == CurPkg.Item.Package.SN) .Where(q => q.WORK_ORDER == wo && wipIDs.Contains(q.WIP_ID)) .ExecuteCommand(); } }); //如果当前条码已经完工,检查当前工单批次和工单是否完工 if (CurPkg.IsReachedEndNode) { CurPosition.WorkBatch.CheckIsComplete(CurPosition.UserCode); } } } //最外层包装已经完成包装,则把工序中暂存标记设为false,统一提交包装内产品的过站记录 //最外层包装未完成包装,则把工序中暂存标记设为true,待全部包装完成再统一提交包装内产品的过站记录 CurPosition.NeedTemporaryStoreDBCommitAction = !CurPkg.IsFinished; //如果工序上下文中没有包装记录则新建一个 if (CurPosition.Context.ContainsKey("CurPackage")) { CurPosition.Context["CurPackage"] = CurPkg; CurPosition.Context["CurLabelDic"] = LabelDic; } else { CurPosition.Context.Add("CurPackage", CurPkg); CurPosition.Context.Add("CurLabelDic", LabelDic); } //action.LocaleMsg = new($"条码[{CurPosition.CurSN}]包装完成"); action.LocaleMsg = new("MES.WorkAction.PackingAction.PackingSuccess", CurPosition.CurSN); IsFinished = true; CurStep?.SetStatusMessage(StepStatus.Finished, Biz.L("包装完成")); action.Data.ShortMsg = new("包装完成", ShortMessage.Types.Success); return action; } #endregion Functions } }