using Rhea.Common; using Tiger.IBusiness; 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.Model.Entitys.MES.Position; namespace Tiger.Business.MES.Transaction { /// /// 测试工序事务 /// public class TestNode : Position, ITestNode { public new ITestNode Init(string id, string apiHost, string userCode, string postCode) { base.Init(id, apiHost, userCode, postCode); Logger.Console.Info($"User[{userCode}] start a {this.GetType().Name}[{postCode}] Transaction[ID: {TransID}]"); return this; } #region Propertys & Variables #endregion Propertys & Variables #region Functions /// /// 测试工序:提交操作数据 /// /// /// public async Task> Submit(SubmitInput input) { var action = new ApiAction(new SubmitOutput()); try { //工步列表为空或者工序节点工步有未完成时,优先完成工序节点工步 if (Steps.IsNullOrEmpty() || !IsFinishNodeSteps) { //先判断当前工单不为空且当前岗位在当前工单是不是首站,如果是则不允许变更当前工单,尝试把条码绑定到当前工单 if (!CurBatch.IsNullOrEmpty() && CurBatch.IsFirstNode(PostCode)) { action = NodeSubmit(action, input); return action; } //当前岗位在当前工单不是首站,则查找条码已绑定的工单当作当前工单 else { var wosns = Biz.Db.Queryable((q, s) => new JoinQueryInfos(JoinType.Inner, q.ORDER_NO == s.WORK_ORDER)) .ByAuth(input.AuthOption).Where((q, s) => s.SN == input.SN || s.TRAY_SN == input.SN).Select((q, s) => new { Batch = q, SN = s }).ToList(); //查找到条码已绑定的工单 if (!wosns.IsNullOrEmpty()) { if (wosns.First().Batch.ACT_LINE != CurLine.LINE_CODE) { action.IsSuccessed = false; //action.LocaleMsg = new($"条码[{0}]已在产线[{1}]投入生产,请在正确岗位扫描"); action.LocaleMsg = new("MES.Transaction.PackingNode.Submit.NotCorrectLine", input.SN, wosns.First().Batch.ACT_LINE); return action; } else { if (CurBatch?.Batch?.ORDER_NO != wosns.First().Batch.ORDER_NO) { //条码已绑定的工单不等于当前工单则重新选择工单 var result = await SelectOrder(new() { AuthOption = input.AuthOption, OrderNo = wosns.First().Batch.ORDER_NO }); if (!result.IsSuccessed) { action.IsSuccessed = result.IsSuccessed; action.LocaleMsg = result.LocaleMsg; return action; } } //条码过站 action = NodeSubmit(action, input); return action; } } //查找不到条码已绑定的工单 else { //没有当前工单,则先选择工单后再扫描条码 if (CurBatch.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = new($"未选择工单,请先选择要生产的工单"); action.LocaleMsg = new("MES.Transaction.TestNode.Submit.NotSelectOrderException"); return action; } //有当前工单且不是投入,则提示条码未投入生产,请先去首站扫描 else { action.IsSuccessed = false; //action.LocaleMsg = new($"条码[{input.SN}]尚未投入生产,请先去首站扫描", input.SN); action.LocaleMsg = new("MES.Transaction.TestNode.Submit.NotInputException", input.SN); return action; } } } } //完成第一步,后开始执行当前工序的行为列表 //完成工序节点工步后,后开始执行当前工序的行为工步 else if (IsFinishNodeSteps && !IsFinishAllSteps) { var submitStep = Steps.Where(q => q.ID == input.CurStepID && !q.IsFinished).FirstOrDefault(); if (submitStep.IsNullOrEmpty()) { action = BeginNextActionStep(input); return action; } else { var result = submitStep.Submit(input); //如果当前工步已完成,开始执行下一工步 if (result.IsSuccessed && submitStep.IsFinished) { result = BeginNextActionStep(input); } //如果当前工步未完成 else { //行为执行出错,工步被重置 if (Steps.IsNullOrEmpty()) { result.LocaleMsg = new(Biz.T(result.LocaleMsg, input.Locale) + Biz.T(Biz.L("MES.Transaction.Position.RescanSN"), input.Locale)); } else { result.Data.SetValue(CurBatch, CurStep, CurStep?.ID, IsFinishAllSteps); } } //如果所有工步都完成 if (IsFinishAllSteps) { return DoIfFinishAllSteps(result); } return result; } } //没有可执行的工步 ResetNode(); action.IsSuccessed = false; //action.LocaleMsg = new($"岗位[{CurPosition.POST_CODE}]工步执行异常,请重新扫描产品条码", CurPosition.POST_CODE); action.LocaleMsg = new("MES.Transaction.TestNode.Submit.WorkStepException", CurPosition.POST_CODE); } catch (Exception ex) { //action.CatchExceptionWithLog(ex, $"测试工序:提交操作数据异常"); action.CatchExceptionWithLog(ex, Biz.L("MES.Transaction.TestNode.SubmitException")); } return action; } /// /// 工序节点工步提交数据 /// /// /// /// public ApiAction NodeSubmit(ApiAction action, SubmitInput input) { var curNode = CurBatch.GetNode(PostCode); try { //判断工单实时状态判断是否可以生产 var woStatus = CurBatch.CheckCanProduce(curNode); if (!woStatus.IsSuccessed) { return woStatus; } //非法过站防呆:进入工序时要增加判断条码是否按流程过站 var wipSNs = Biz.Db.Queryable().IncludesAllFirstLayer().Where(q => (q.SN == input.SN || q.TRAY_SN == input.SN) && q.WORK_ORDER == CurBatch.WO.ORDER_NO).ToList(); if (wipSNs.IsNullOrEmpty()) { var wipSN = new MES_WIP_DATA() { SN = input.SN, STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(), ITEM_CODE = CurBatch.WO.ITEM_CODE, WORK_ORDER = CurBatch.Batch.ORDER_NO, BATCH_NO = CurBatch.Batch.BATCH_NO, HOLD_FLAG = "N", REWORK_FLAG = CurBatch.WO.ORDER_TYPE == BIZ_MES_WO.ORDER_TYPEs.Rework.GetValue() ? "Y" : "N", FINISHED_FLAG = "N", INV_FLAG = "N", DFT_FLAG = "N", DFT_COUNT = 0, }; wipSNs.Add(wipSN); } var canGotoNext = CurBatch.CanGotoNext(input, wipSNs.First(), curNode); if (!canGotoNext.IsSuccessed) { return canGotoNext; } //当工步列表为空,则执行当前工序的必要逻辑当作第一个工序节点,完成后按需求创建后续的工步列表 if (Steps.IsNullOrEmpty()) { //绑定条码到工单 foreach (var wipSN in wipSNs) { if (!CurBatch.WoSNs.Any(q => q.SN == wipSN.SN)) { CurBatch.WoSNs.Add(new() { WORK_ORDER = CurBatch.Batch.ORDER_NO, SN = wipSN.SN, TRAY_SN = wipSN.TRAY_SN, STATUS = BIZ_MES_WO_SN.STATUSs.NotInput.GetValue(), }); } } //更新工单条码明细信息 var woSNs = CurBatch.WoSNs.Where(q => wipSNs.Any(w => q.SN == w.SN)).ToList(); foreach (var woSN in woSNs) { woSN.AUTH_ORG = CurBatch.WO.AUTH_ORG; woSN.AUTH_PROD = CurLine.LINE_CODE; woSN.BATCH_NO = CurBatch.Batch.BATCH_NO; } //条码过站 foreach (var wipSN in wipSNs) { wipSN.AUTH_ORG = CurBatch.WO.AUTH_ORG; wipSN.AUTH_PROD = CurLine.LINE_CODE; wipSN.STATUS = MES_WIP_DATA.STATUSs.OK.GetValue();//wipSN.STATUS > 0 ? MES_WIP_DATA.STATUSs.OK.GetValue() : wipSN.STATUS; wipSN.ROT_CODE = CurBatch.WO.ROUTE_CODE; wipSN.NODE_ID = curNode.ID; wipSN.NODE_NAME = curNode.NODE_NAME; wipSN.FTY_CODE = CurFactory.FTY_CODE; wipSN.WS_CODE = CurWorkshop.WS_CODE; wipSN.LINE_CODE = CurLine.LINE_CODE; wipSN.POST_CODE = CurPosition.POST_CODE; wipSN.OPER_CODE = curNode.OPER_CODE; wipSN.SEGMENT = curNode.SEGMENT; wipSN.OPERATION_TIME = DateTime.Now; var curShiftPeriod = GetShiftPeriodForNow(); if (!curShiftPeriod.IsNullOrEmpty()) { wipSN.SFTS_CODE = curShiftPeriod.ShiftSys.SFTS_CODE; wipSN.SFT_CODE = curShiftPeriod.Shift.SFT_CODE; wipSN.PRD_CODE = curShiftPeriod.Period.PRD_CODE; } //如果是投入站 if (curNode.IS_INPUT == "Y") { var woSN = woSNs.First(q => q.SN == wipSN.SN); woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Inputed.GetValue(); wipSN.STATUS = MES_WIP_DATA.STATUSs.Input.GetValue(); wipSN.INLINE_DATE = DateTime.Now; } //如果是产出站 if (curNode.IS_OUTPUT == "Y") { var woSN = woSNs.First(q => q.SN == wipSN.SN); woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Finished.GetValue(); wipSN.STATUS = MES_WIP_DATA.STATUSs.Finished.GetValue(); wipSN.OUTLINE_DATE = DateTime.Now; } //如果有提交不良 if (!input.DFT_CODE.IsNullOrEmpty()) { wipSN.STATUS = MES_WIP_DATA.STATUSs.NG.GetValue(); wipSN.DFT_FLAG = "Y"; wipSN.DFT_COUNT++; wipSN.DFT_CODE = input.DFT_CODE; } } //工单开工 CurBatch.StartWorking(UserCode); //把当前条码增加到当前条码列表 CurWipSNs = wipSNs; CurWipSNHiss.Clear(); foreach (var wipSN in wipSNs) { CurWipSNHiss.Add(new MES_WIP_HIS(wipSN, $"工单[{wipSN.WORK_ORDER}]条码[{wipSN.SN}]在岗位[{wipSN.POST_CODE}]过站工序[{wipSN.NODE_NAME}]成功")); } //初始化工步列表 Steps.Clear(); var curStep = new Biz.WorkStep(IWorkStep.Types.Node, this) { Sequence = Steps.Count + 1, Node = curNode, DBSubmitAction = () => { var db = GetCommitDB(); db.Storageable(woSNs, UserCode).ExecuteCommand(); db.Storageable(wipSNs, UserCode).ExecuteCommand(); db.Storageable(CurWipSNHiss, UserCode).ExecuteCommand(); //如果是投入站 if (curNode.IS_INPUT == "Y") { db.Updateable().SetColumns(q => q.INPUT_QTY == q.INPUT_QTY + wipSNs.Count).Where(q => q.ORDER_NO == CurBatch.WO.ORDER_NO).ExecuteCommand(); db.Updateable().SetColumns(q => q.INPUT_QTY == q.INPUT_QTY + wipSNs.Count).Where(q => q.BATCH_NO == CurBatch.Batch.BATCH_NO).ExecuteCommand(); } //如果是产出站 if (curNode.IS_OUTPUT == "Y") { db.Updateable().SetColumns(q => q.OUTPUT_QTY == q.OUTPUT_QTY + wipSNs.Count).Where(q => q.ORDER_NO == CurBatch.WO.ORDER_NO).ExecuteCommand(); db.Updateable().SetColumns(q => q.OUTPUT_QTY == q.OUTPUT_QTY + wipSNs.Count).Where(q => q.BATCH_NO == CurBatch.Batch.BATCH_NO).ExecuteCommand(); } } }; Steps.Add(curStep); //有需要用户提交信息则添加工序节点的其他工步 //最后添加当前工序的行为工步 try { GenerateSteps(curStep); } catch (System.Exception ex) { ResetNode(); //action.CatchExceptionWithLog(ex, $"{curNode.NODE_NAME}:工序行为工步生成异常,请检查工序行为设置"); action.CatchExceptionWithLog(ex, Biz.L("MES.Transaction.TestNode.NodeSubmit.GenerateStepsException", curNode.NODE_NAME)); } //完成第一个工序节点工步 curStep.IsFinished = true; CurStep = curStep; } else if (!IsFinishNodeSteps) { var curStep = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First(); //完成当前工序节点工步 curStep.IsFinished = true; CurStep = curStep; } //未完成所有工步 if (!IsFinishAllSteps) { var result = new ApiAction(new SubmitOutput()); //未完成所有工序节点工步 if (!IsFinishNodeSteps) { var next = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First(); //设置后续可执行的工步列表 NextSteps.Clear(); NextSteps.Add(next); //根据后续工步返回ApiAction result.Data.SetValue(CurBatch, CurStep, next.ID, IsFinishAllSteps); //根据工序节点工步的序号返回相应的操作提示 switch (next.Sequence) { case 2: //action.LocaleMsg = new($"请执行第二步"); result.LocaleMsg = new("MES.Transaction.TestNode.第二步操作提示"); break; default: break; } } //已完成所有工序节点工步,开始执行行为工步 else { result = BeginNextActionStep(input); } return result; } //已完成所有工步 else { action.Data.SetValue(CurBatch, CurStep, "", IsFinishAllSteps); action = DoIfFinishAllSteps(action); } } catch (Exception ex) { ResetNode(); //action.CatchExceptionWithLog(ex, $"{curNode.NODE_NAME}:工序节点工步提交数据异常,请检查工序节点设置"); action.CatchExceptionWithLog(ex, Biz.L("MES.Transaction.TestNode.NodeSubmitException", curNode.NODE_NAME)); } return action; } /// /// 完成所有工步后执行 /// /// /// public ApiAction DoIfFinishAllSteps(ApiAction action) { //保存数据库 SaveStepsCommitActionToDB(); //保存成功,返回过站消息 //action.LocaleMsg = new($"工单[{CurWipSN.WORK_ORDER}]的条码[{CurWipSN.SN}]在岗位[{CurWipSN.POST_CODE}]工序[{CurWipSN.NODE_NAME}]过站成功,状态[{CurWipSN.STATUS.GetEnumDesc()}]"); action.LocaleMsg = new("MES.Transaction.CollectNode.ScanSn.PassSuccess", CurWipSNs.First().WORK_ORDER, CurSN, CurWipSNs.First().POST_CODE, CurWipSNs.First().NODE_NAME, CurWipSNs.First().STATUS.GetEnumDesc()); //重置工序 ResetNode(); return action; } /// /// 测试工序:获取工序不良代码 /// /// public ApiAction> GetDefects() { var action = new ApiAction>(); //没有当前工单,则先选择工单后再扫描条码 if (CurBatch.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = new($"请先扫描要过站的条码"); action.LocaleMsg = new("MES.Transaction.TestNode.GetDefects.NotScanException"); return action; } action.Data = CurBatch.GetNodeDefects(PostCode); return action; } #endregion Functions public override bool Close(bool needSaveHistoryLog = false) { //needSaveHistoryLog = true; //保存操作日志 this.IsFinished = true; return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished; } }//endClass }