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 static Tiger.Business.Biz; using Tiger.Model.Entitys.MES.Position; namespace Tiger.Business.MES.Transaction { /// /// MES岗位事务 /// public class Position : MESTransactionBase, IPosition { public IPosition Init(string id, string apiHost, string userCode, string postCode) { TransID = id; UserCode = userCode; ApiHost = apiHost; PostCode = postCode; CurPosition = Biz.Db.Queryable().Where(q => q.POST_CODE == postCode).First(); //if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.PositionNotExistsException", new Exception($"{postCode}|")); if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]不存在,请提交正确的岗位代码", new Exception($"{postCode}|")); CurLine = Biz.Db.Queryable().Where(q => q.LINE_CODE == CurPosition.LINE_CODE).First(); //if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.LineNotExistsException", new Exception($"{postCode}|{CurPosition.LINE_CODE}")); if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的产线[{CurPosition.LINE_CODE}]不存在,请先设置所属产线", new Exception($"{postCode}|{CurPosition.LINE_CODE}")); CurWorkshop = Biz.Db.Queryable().Where(q => q.WS_CODE == CurLine.WS_CODE).First(); //if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.WorkshopNotExistsException", new Exception($"{postCode}|{CurLine.WS_CODE}")); if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的车间[{CurLine.WS_CODE}]不存在,请先设置所属车间", new Exception($"{postCode}|{CurLine.WS_CODE}")); CurFactory = Biz.Db.Queryable().Where(q => q.FTY_CODE == CurWorkshop.FTY_CODE).First(); //if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.FactoryNotExistsException", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}")); if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的工厂[{CurWorkshop.FTY_CODE}]不存在,请先设置所属工厂", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}")); //加载当前产线的班制 CurShiftSys = Biz.Db.Queryable().Where(q => q.SFTS_CODE == CurLine.SFTS_CODE).IncludesAllFirstLayer().IncludesAllSecondLayer(q => q.Shifts).First(); return this; } #region Propertys & Variables public string UserCode { get; set; } public string PostCode { get; set; } public MES_FACTORY CurFactory { get; set; } public MES_WORKSHOP CurWorkshop { get; set; } public MES_LINE CurLine { get; set; } public MES_POSITION CurPosition { get; set; } public MES_SHIFT_SYS CurShiftSys { get; set; } public WorkBatch CurBatch { get; set; } public IWorkBatch WorkBatch => CurBatch; public List CurWipSNs { get; set; } = new(); public string CurSN => (CurWipSNs.Any() ? (CurWipSNs.First().TRAY_SN.IsNullOrEmpty() ? CurWipSNs.First().SN : CurWipSNs.First().TRAY_SN) : ""); public List CurWipSNHiss { get; set; } = new(); public List CurDefects { get; set; } = new(); public Dictionary Context { get; set; } = new(); public List Steps { get; set; } = new(); public WorkStep CurStep { get; set; } public List NextSteps { get; set; } = new(); public bool IsFinishNodeSteps => !Steps.Any(q => q.NodeType == IWorkStep.NodeTypes.Node && !q.IsFinished); public bool IsFinishAllSteps => !Steps.Any() || !Steps.Any(q => !q.IsFinished); //public int CurStep => Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).FirstOrDefault()?.Sequence ?? 0; private DbClient CommitDB; /// /// 是否需要临时存储数据库提交操作,待需要的时候再提交 /// public bool NeedTemporaryStoreDBCommitAction { get; set; } = false; protected Dictionary> DBCommitList { get; set; } = new(); protected List NodeCommitList { get; set; } = new(); private Dictionary OperInfoDic = new(); #endregion Propertys & Variables #region Functions /// /// 获取提交数据的DbClient对象 /// /// public DbClient GetCommitDB() { return CommitDB ??= Biz.Db; } /// /// 选择工单 /// /// /// public async Task SelectOrder(WoInput input) { var action = new ApiAction(); try { if (!WoContext.ExistsBatch(input.OrderNo, CurLine.LINE_CODE)) { var wo = await Biz.Db.Queryable().ByAuth(input.AuthOption).Where(q => q.ORDER_NO == input.OrderNo).FirstAsync(); //验证明细是否正确 if (wo.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{input.OrderNo}]不存在", input.OrderNo); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.EmptyException", input.OrderNo); return action; } if (wo.STATUS != BIZ_MES_WO.STATUSs.Release.GetValue() && wo.STATUS != BIZ_MES_WO.STATUSs.Working.GetValue()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{input.OrderNo}]状态[{wo.STATUS.GetEnum().GetName()}]不能生产"); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.StatusException", input.OrderNo, wo.STATUS.GetEnum().GetName()); return action; } var batch = await Biz.Db.Queryable().ByAuth(input.AuthOption).Where(q => q.ORDER_NO == input.OrderNo && q.ACT_LINE == CurLine.LINE_CODE).FirstAsync(); if (batch.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{input.OrderNo}]没有下发到产线状态[{CurLine.LINE_CODE}]"); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.LineException", input.OrderNo, CurLine.LINE_CODE); return action; } if (batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() && batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Working.GetValue()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{input.OrderNo}]状态[{wo.STATUS.GetEnum().GetName()}]不能生产"); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.StatusException", input.OrderNo, batch.STATUS.GetEnum().GetName()); return action; } var wb = new WorkBatch(input.OrderNo).Init(CurLine.LINE_CODE); WoContext.WoBatchDic.Add(wb.Batch.BATCH_NO, wb); } CurBatch = WoContext.GetBatch(input.OrderNo, CurLine.LINE_CODE); if (!OperInfoDic.ContainsKey(CurBatch.Batch.BATCH_NO)) { OperInfoDic.Add(CurBatch.Batch.BATCH_NO, new()); } action.Data = new { WorkOrder = CurBatch.WO, Bacth = CurBatch.Batch }; } catch (Exception ex) { action.CatchExceptionWithLog(ex, $"采集工序:选择工单异常"); } return action; } /// /// 获取当前时间所属的班制班次时段 /// public ShiftPeriod GetShiftPeriodForNow() { var time = DateTime.Now.ToString("HHmm").ToInt32(); foreach (var shift in CurShiftSys.Shifts) { var period = shift.Periods.Where(q => q.PRD_BEGIN <= time && time <= q.PRD_END).FirstOrDefault(); if (!period.IsNullOrEmpty()) { var result = new ShiftPeriod(); result.ShiftSys = CurShiftSys; result.Shift = shift; result.Period = period; return result; } } return null; } /// /// 重置工序操作 /// /// public ApiAction Reset() { var action = new ApiAction(); ResetNode(); action.IsSuccessed = true; action.LocaleMsg = new($"工序操作已重置,请重新扫描进站产品条码"); action.LocaleMsg = new("MES.Transaction.Position.ResetNode"); return action; } /// /// 重置当前工序,有需要则重写此方法 /// public virtual void ResetNode() { Steps.Clear(); CurWipSNs.Clear(); CurWipSNHiss.Clear(); CurStep = null; CurDefects.Clear(); } //获取当前的工序信息 protected OperInfo CurOperInfo(string locale) { OperInfo info = new(); if (CurBatch?.Batch?.BATCH_NO != null) { info = OperInfoDic[CurBatch.Batch.BATCH_NO ]; info.StepsInfo = Steps.Select(q => q.GetInfo(locale)).ToList(); } return info; } /// /// 设置当前条码的工序信息 /// public OperInfo SetOperNodeInfo(OperInfo info) { if (CurWipSNs.Any()) { info.CurNode = CurWipSNs.First().NODE_NAME; info.NextNode = string.Join(",", CurBatch.GetNextNodes(CurWipSNs.First()).Select(q => q.NODE_NAME)); } else { info.CurNode = " — "; info.NextNode = " — "; } return info; } /// /// 生成传入工步后续的行为到工步列表 /// /// public void GenerateSteps(WorkStep parent) { //递归添加所有工步 AddNextActToSteps(parent); //调整工步的序号 //while (CurBatch.Edges.Any(q => Steps.First(s => s.NodeID == q.SRC_NODE).Sequence <= Steps.First(s => s.NodeID == q.TGT_NODE).Sequence)) //{ // var edges = CurBatch.Edges.Where(q => Steps.First(s => s.NodeID == q.SRC_NODE).Sequence >= Steps.First(s => s.NodeID == q.TGT_NODE).Sequence).ToList(); // foreach (var edge in edges) // { // var source = Steps.First(s => s.NodeID == edge.SRC_NODE); // var target = Steps.First(s => s.NodeID == edge.TGT_NODE); // target.Sequence = source.Sequence + 1; // } //} } /// /// 添加节点的下一个行为到工步列表 /// /// private void AddNextActToSteps(WorkStep parent) { var edges = CurBatch.Edges.Where(q => q.SRC_NODE == parent.NodeID && CurBatch.NodeActs.Any(a => a.NODE_ID == parent.Node.ID && a.ID == q.TGT_NODE)).ToList(); foreach (var edge in edges) { var act = CurBatch.NodeActs.First(q => q.ID == edge.TGT_NODE); if (Steps.Any(q => q.NodeID == act.ID)) { var next = Steps.First(q => q.NodeID == act.ID); next.Sequence = next.Sequence > parent.Sequence ? next.Sequence : (parent.Sequence + 1); next.PrepNodeIDs.Add(parent.NodeID); next.PrepNodeIDs.AddRange(parent.PrepNodeIDs); next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList(); AddNextActToSteps(next); } else { var next = new WorkStep(IWorkStep.NodeTypes.Action, this) { Name = act.ACT_NAME, Sequence = parent.Sequence + 1, Node = parent.Node, OperSetting = CurBatch.NodeSets.FirstOrDefault(q => q.NODE_ID == parent.Node.ID), NodeAct = act, ActSetting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID), }; next.Init(); next.PrepNodeIDs.Add(parent.NodeID); next.PrepNodeIDs.AddRange(parent.PrepNodeIDs); next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList(); Steps.Add(next); AddNextActToSteps(next); } } } /// /// 根据传入的工步,返回下一步可执行的工步列表 /// /// public List GetNextSteps(WorkStep curStep) { var result = new List(); var nextSteps = Steps.Where(q => !q.IsFinished && CurBatch.Edges.Any(e => e.SRC_NODE == curStep.NodeID && e.TGT_NODE == q.NodeID) ).ToList(); //尝试将当前工步的后续工步添加到可以执行的工步列表 foreach (var step in nextSteps) { //查找有没有前置工步未完成,若有则不允许继续执行 if (!Steps.Any(q => step.PrepNodeIDs.Any(id => id == q.NodeID && !q.IsFinished))) { result.Add(step); } } //如果当前工步没有可执行的后续工步,则在前置工步查找还有没有后续工步没完成的工步,有则执行 if (!result.Any() && Steps.Any()) { //查找有没有前置工步未完成,若有则先完成未完成的前置工步 var prepIDs = curStep.PrepNodeIDs.Where(id => CurBatch.Edges.Any(e => e.SRC_NODE == id && Steps.Any(q => !q.IsFinished && e.TGT_NODE == q.NodeID))).ToList(); var prepSteps = Steps.Where(q => prepIDs.Contains(q.NodeID)).OrderByDescending(q => q.Sequence).ToList(); while (prepSteps.Any() && !result.Any()) { var prep = prepSteps.First(); var prepNext = GetNextSteps(prep); if (prepNext.Any()) { result = prepNext; } else { prepSteps.Remove(prep); } } } return result.OrderBy(q => q.NodeAct.ACT_NAME).ToList(); } /// /// 开始执行下一行为工步 /// /// public ApiAction BeginNextActionStep(SubmitInput input) { var result = new ApiAction(new SubmitOutput()); //设置后续可执行的工步列表 NextSteps = GetNextSteps(CurStep); //尝试有没有可以直接开始的后续工步 foreach (var step in NextSteps) { //尝试执行后续工步 var canBegin = step.TryBegin(input); //如果后续工步可以直接开始则直接执行 if (canBegin.IsSuccessed) { //更新当前执行工步为已开始工步 CurStep = step; //更新后续可执行的工步列表 NextSteps = GetNextSteps(CurStep); //返回结果到客户端 result = canBegin; result.Data.SetValue(CurBatch, CurStep, CurStep?.ID, IsFinishAllSteps); return result; } } //没有可以直接开始的后续工步,根据后续工步返回ApiAction result.Data.SetValue(CurBatch, CurStep, "", IsFinishAllSteps); //没有可以直接开始的后续工步,根据后续可执行工步列表返回相应的操作提示 if (NextSteps.Count == 1) { result.LocaleMsg = NextSteps.First().GetBeginMsg(); } else { result.LocaleMsg = new(T(L("MES.Transaction.Position.PleaseSelectNextStep"), input.Locale) + "\r\n" + string.Join("\r\n", NextSteps.Select(q => " >> " + T(q.GetBeginMsg(), input.Locale)))); } return result; } /// /// 保存工步的数据库提交操作到数据库 /// protected void SaveStepsCommitActionToDB() { //保存工步的数据库提交操作到提交操作列表 var commitList = new List(); foreach (var step in Steps.OrderBy(q => q.Sequence)) { commitList.Add(step.DBSubmitAction); } DBCommitList.Add(CurSN, commitList); //如果不需要临时存储数据库提交操作,则把提交操作列表提交到数据库 if (!NeedTemporaryStoreDBCommitAction) { //恢复临时存储标记为false NeedTemporaryStoreDBCommitAction = false; var dbTran = GetCommitDB().UseTran(() => { //在同一个事务中保存所有工步的数据 foreach (var wipSn in DBCommitList.Keys) { foreach (var action in DBCommitList[wipSn]) { action.Invoke(); } } }); if (dbTran.IsSuccess) { //保存成功则清空提交操作列表 DBCommitList.Clear(); } else { //抛出异常 throw dbTran.ErrorException; } } } protected void DoSaveToDB() { var dbTran = GetCommitDB().UseTran(() => { //在同一个事务中保存所有工步的数据 foreach (var step in Steps.OrderBy(q => q.Sequence)) { step.DBSubmitAction.Invoke(); } }); if (!dbTran.IsSuccess) { //抛出异常 throw dbTran.ErrorException; } } #region 打印专用方法 /// /// 获取打印标签模板过程变量值 /// /// 过程变量列表 /// 标签模板 /// public BAS_LABEL_TEMP SetLabelVariables(List labelPVs, BAS_LABEL_TEMP label, IWorkAction action) { foreach (var item in label.Variables) { switch (item.VAR_TYPE.GetEnum()) { case BAS_LABEL_VAR.VAR_TYPEs.Constant: item.Value = item.VAR_VALUE; break; case BAS_LABEL_VAR.VAR_TYPEs.ProcessVariable: item.Value = GetPrintProcessValue(labelPVs, item, action); break; case BAS_LABEL_VAR.VAR_TYPEs.DateVariable: item.Value = DateTime.Now.ToString(item.VAR_VALUE); break; case BAS_LABEL_VAR.VAR_TYPEs.BarcodeGenerate: item.Value = GetGeneratePValue(labelPVs, item); break; case BAS_LABEL_VAR.VAR_TYPEs.CustomVariable: default: item.Value = ""; break; } } return label; } /// /// 获取打印标签模板过程变量值 /// /// 过程变量列表 /// 标签模板变量 /// public string GetPrintProcessValue(List labelPVs, BAS_LABEL_VAR lv, IWorkAction action) { var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE); if (!pv.IsNullOrEmpty()) { switch (pv.VAR_TYPE.GetEnum()) { case BAS_LABEL_PV.VAR_TYPEs.ServerMethod: { switch (pv.VAR_METHOD) { case "GetSN": return CurSN; case "GetBAS_ITEM": return WorkBatch.Product.ToJson(); case "GetCustomer": return WorkBatch.Batch.ToJson(); case "GetVarByWo": return GetLabelVarWo(lv); default: return ""; } } case BAS_LABEL_PV.VAR_TYPEs.WebApi: break; case BAS_LABEL_PV.VAR_TYPEs.StoredProcedure: break; default: break; } } return ""; } /// /// 获取根据条码规则生成标签模板的过程变量值 /// /// /// /// public string GetGeneratePValue(List labelPVs, BAS_LABEL_VAR lv) { var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE); if (!pv.IsNullOrEmpty()) { switch (pv.VAR_TYPE.GetEnum()) { case BAS_LABEL_PV.VAR_TYPEs.BarcodeGenerate: { switch (pv.VAR_METHOD) { case "GetCartonGenerate": return Biz.CodeRule[lv.BARCODE_RULE ?? ""]?.Generate($"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? ""; case "GetHW21SNGenerate": return Biz.CodeRule[lv.BARCODE_RULE ?? ""]?.Generate("SN:","05").Data.ToString() ?? ""; default: return ""; } } default: break; } } return ""; } /// /// 获取工单维护的模板变量 /// /// /// private string GetLabelVarWo(BAS_LABEL_VAR lv) { string result = ""; var labelVarwos = Biz.Db.Queryable().Where(x => x.LABEL_ID == lv.LABEL_ID && x.VAR_NAME == lv.VAR_NAME).ToList(); if (labelVarwos.Any(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO)) { result = labelVarwos.First(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO).VAR_VALUE; } else { result = labelVarwos.Count > 0 ? labelVarwos[0].DEFAULT_VALUE : ""; } return result; } #endregion #endregion Functions public override bool Close(bool needSaveHistoryLog = false) { //needSaveHistoryLog = true; //保存操作日志 this.IsFinished = true; return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished; } }//endClass }