| | |
| | | using Tiger.IBusiness; |
| | | using Tiger.Model.Entitys.MES.Position; |
| | | using Tiger.Business.MES; |
| | | using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser; |
| | | using Org.BouncyCastle.Ocsp; |
| | | using System.IO; |
| | | |
| | |
| | | |
| | | #region Functions |
| | | /// <summary> |
| | | /// 初始化工单资料 |
| | | /// 初始化工单批次资料 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public WorkBatch Init(string lineCode) |
| | |
| | | return this; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 更新工单批次资料 |
| | | /// </summary> |
| | | /// <param name="updateAll"></param> |
| | | public void Update(bool updateAll = false) |
| | | { |
| | | var strat = DateTime.Now; |
| | |
| | | |
| | | Update(); |
| | | |
| | | var woSNs = Biz.Db.Queryable<BIZ_MES_WO_SN>().Where(q => q.WORK_ORDER == OrderNo).ToList(); |
| | | //工单批次状态不是已下发或者生产中,则不允许生产 |
| | | if (Batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() && Batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Working.GetValue()) |
| | | { |
| | |
| | | action.LocaleMsg = new("MES.WorkBatch.WoStatusCanNotWork", WO.ORDER_NO, Batch.STATUS.GetEnumDesc<BIZ_MES_WO.STATUSs>()); |
| | | } |
| | | //工单批次投入数量减去报废数量如果大于等于计划数量,则不允许生产 |
| | | if (curNode.IS_FIRST_NODE == "Y" && WoSNs.Count(q => q.BATCH_NO == Batch.BATCH_NO && BIZ_MES_WO_SN.STATUSs.NotInput.GetValue() < q.STATUS && q.STATUS <= BIZ_MES_WO_SN.STATUSs.Finished.GetValue()) >= Batch.PLAN_QTY) |
| | | var batchInput = woSNs.Where(q => q.BATCH_NO == Batch.BATCH_NO && BIZ_MES_WO_SN.STATUSs.NotInput.GetValue() < q.STATUS && q.STATUS <= BIZ_MES_WO_SN.STATUSs.Finished.GetValue()).DistinctBy(q => q.WIP_ID).Sum(q => q.QTY); |
| | | if (curNode.IS_FIRST_NODE == "Y" && batchInput >= Batch.PLAN_QTY) |
| | | { |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | //action.LocaleMsg = new($"工单批次[{0}]已投入 {1},其中报废 {2},以满足计划数量[{3}],无需继续投入"); |
| | | action.LocaleMsg = new("MES.WorkBatch.BatchInputEnough", Batch.BATCH_NO, WoSNs.Count(q => q.BATCH_NO == Batch.BATCH_NO), WoSNs.Count(q => q.BATCH_NO == Batch.BATCH_NO && q.STATUS > BIZ_MES_WO_SN.STATUSs.Finished.GetValue()), Batch.PLAN_QTY); |
| | | action.LocaleMsg = new("MES.WorkBatch.BatchInputEnough", Batch.BATCH_NO, batchInput, woSNs.Where(q => q.BATCH_NO == Batch.BATCH_NO && q.STATUS > BIZ_MES_WO_SN.STATUSs.Finished.GetValue()).DistinctBy(q => q.WIP_ID).Sum(q => q.QTY), Batch.PLAN_QTY); |
| | | } |
| | | //工单投入数量减去报废数量如果大于等于计划数量,则不允许生产 |
| | | if (curNode.IS_FIRST_NODE == "Y" && WoSNs.Count(q =>q.WORK_ORDER == WO.ORDER_NO && BIZ_MES_WO_SN.STATUSs.NotInput.GetValue() < q.STATUS && q.STATUS <= BIZ_MES_WO_SN.STATUSs.Finished.GetValue()) >= WO.PLAN_QTY) |
| | | var woInput = woSNs.Where(q => q.WORK_ORDER == WO.ORDER_NO && BIZ_MES_WO_SN.STATUSs.NotInput.GetValue() < q.STATUS && q.STATUS <= BIZ_MES_WO_SN.STATUSs.Finished.GetValue()).DistinctBy(q => q.WIP_ID).Sum(q => q.QTY); |
| | | if (curNode.IS_FIRST_NODE == "Y" && woInput >= WO.PLAN_QTY) |
| | | { |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | //action.LocaleMsg = new($"工单[{0}]已投入 {1},其中报废 {2},以满足计划数量[{3}],无需继续投入"); |
| | | action.LocaleMsg = new("MES.WorkBatch.WoInputEnough", WO.ORDER_NO, WoSNs.Count(q => q.WORK_ORDER == WO.ORDER_NO), WoSNs.Count(q => q.WORK_ORDER == WO.ORDER_NO && q.STATUS > BIZ_MES_WO_SN.STATUSs.Finished.GetValue()), WO.PLAN_QTY); |
| | | action.LocaleMsg = new("MES.WorkBatch.WoInputEnough", WO.ORDER_NO, woInput, woSNs.Where(q => q.WORK_ORDER == WO.ORDER_NO && q.STATUS > BIZ_MES_WO_SN.STATUSs.Finished.GetValue()).DistinctBy(q => q.WIP_ID).Sum(q => q.QTY), WO.PLAN_QTY); |
| | | } |
| | | |
| | | WoSNs = woSNs; |
| | | return action; |
| | | } |
| | | |
| | |
| | | WO.STATUS = BIZ_MES_WO.STATUSs.Working.GetValue(); |
| | | WO.ACT_START_TIME = WO.ACT_START_TIME < new DateTime(2000, 1, 1) ? DateTime.Now : WO.ACT_START_TIME; |
| | | Batch.STATUS = BIZ_MES_WO_BATCH.STATUSs.Working.GetValue(); |
| | | Batch.ACT_START_TIME = WO.ACT_START_TIME < new DateTime(2000, 1, 1) ? DateTime.Now : WO.ACT_START_TIME; |
| | | Batch.ACT_START_TIME = Batch.ACT_START_TIME < new DateTime(2000, 1, 1) ? DateTime.Now : Batch.ACT_START_TIME; |
| | | //保存数据库 |
| | | var db = Biz.Db; |
| | | var dbTran = db.UseTran(() => |
| | |
| | | |
| | | //判断当前工单批次是否已完工 |
| | | if (!woSNs.Any(q => q.BATCH_NO == Batch.BATCH_NO && q.STATUS < BIZ_MES_WO_SN.STATUSs.Finished.GetValue()) && |
| | | woSNs.Count(q => q.BATCH_NO == Batch.BATCH_NO && q.STATUS == BIZ_MES_WO_SN.STATUSs.Finished.GetValue()) == Batch.PLAN_QTY) |
| | | woSNs.Where(q => q.BATCH_NO == Batch.BATCH_NO && q.STATUS == BIZ_MES_WO_SN.STATUSs.Finished.GetValue()).Sum(q=>q.QTY) == Batch.PLAN_QTY) |
| | | { |
| | | Batch.STATUS = BIZ_MES_WO_BATCH.STATUSs.Closed.GetValue(); |
| | | Batch.ACT_END_TIME = DateTime.Now; |
| | |
| | | |
| | | //判断当前工单是否已完工 |
| | | if (!woSNs.Any(q => q.STATUS < BIZ_MES_WO_SN.STATUSs.Finished.GetValue()) && |
| | | woSNs.Count(q => q.STATUS == BIZ_MES_WO_SN.STATUSs.Finished.GetValue()) == WO.PLAN_QTY) |
| | | woSNs.Where(q => q.STATUS == BIZ_MES_WO_SN.STATUSs.Finished.GetValue()).Sum(q => q.QTY) == WO.PLAN_QTY) |
| | | { |
| | | WO.STATUS = BIZ_MES_WO.STATUSs.Closed.GetValue(); |
| | | WO.ACT_END_TIME = DateTime.Now; |
| | |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | var nextList = Nodes.Where(q => q.IS_FIRST_NODE == "Y"); |
| | | //action.LocaleMsg = new($"条码[{0}]在工序[{1}]过站扫描错误,请先通过以下工序:{2}"); |
| | | action.LocaleMsg = new("MES.WorkBatch.GotoNextNodeException", input.SN, nextNode.NODE_NAME, string.Join(", ", nextList.Select(q => q.NODE_NAME + (GetNodeSetting(q)?.CAN_SKIP == "Y" ? $"({Biz.T(Biz.L("MES.WorkBatch.Optional"), input.Locale)})" : "")))); |
| | | return action; |
| | | } |
| | |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | var nextList = reflowNodes.Where(q => wipSN.REFLOW_NODE.IsNullOrEmpty() || wipSN.REFLOW_NODE == q.NODE_NAME); |
| | | //action.LocaleMsg = new($"工序[{0}]不是条码[{1}]在工序[{2}]维修后可回流的工序,请选择回流到以下工序:{3}"); |
| | | action.LocaleMsg = new("MES.WorkBatch.ReflowToNodeException", nextNode.NODE_NAME, input.SN, curNode.NODE_NAME, string.Join(", ", nextList.Select(q => q.NODE_NAME + (GetNodeSetting(q)?.CAN_SKIP == "Y" ? $"({Biz.T(Biz.L("MES.WorkBatch.Optional"), input.Locale)})" : "")))); |
| | | return action; |
| | | } |
| | | } |
| | | //不良品入站:如果产品有不良记录且目标工序不是维修工序且不允许不良品入站,则报错 |
| | | else if (wipSN.Defects.Any(q => q.WORK_ORDER == WO.ORDER_NO && q.STATUS < MES_WIP_DFT.STATUSs.Resolved.GetValue()) |
| | | && nextSetting.ALLOW_DFT_IN != "Y" && nextNode.Operation.OPER_TYPE != MES_OPERATION.OPER_TYPEs.Repair.GetValue()) |
| | | { |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | action.LocaleMsg = new("MES.WorkBatch.PleaseGotoRepair", curNode.NODE_NAME, input.SN); |
| | | return action; |
| | | } |
| | | //正常工序过站 |
| | | else |
| | | { |
| | | //不良品入站:如果产品有不良记录且目标工序不是维修工序且不允许不良品入站,则报错 |
| | | if (wipSN.Defects.Any(q => q.STATUS < MES_WIP_DFT.STATUSs.Resolved.GetValue()) |
| | | && nextSetting.ALLOW_DFT_IN != "Y" && nextNode.Operation.OPER_TYPE != MES_OPERATION.OPER_TYPEs.Repair.GetValue()) |
| | | { |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | //action.LocaleMsg = new($"工序[{0}]不允许不良品入站,条码[{1}]存在不良记录,请先按流程指引操作或者进入维修"); |
| | | action.LocaleMsg = new("MES.WorkBatch.PleaseGotoRepair", curNode.NODE_NAME, input.SN); |
| | | return action; |
| | | } |
| | | |
| | | //添加条码当前工序的下一个可执行工序 |
| | | var nextNodes = GetNextNodes(curNode, wipSN); |
| | | //如果下一个可执行工序包含目标工序则允许进站 |
| | |
| | | { |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | var nextList = nextNodes.Where(q => NodeSets.Any(s => s.NODE_ID == q.ID && s.IS_ACTIVE == "Y" && s.CAN_SKIP != "Y")); |
| | | var nextList = nextNodes.Where(q => NodeSets.Any(s => s.NODE_ID == q.ID && s.IS_ACTIVE == "Y")); |
| | | //action.LocaleMsg = new($"条码[{0}]在工序[{1}]过站扫描错误,请先通过以下工序:{2}"); |
| | | action.LocaleMsg = new("MES.WorkBatch.GotoNextNodeException", input.SN, nextNode.NODE_NAME, string.Join(", ", nextList.Select(q => q.NODE_NAME + (GetNodeSetting(q)?.CAN_SKIP == "Y" ? $"({Biz.T(Biz.L("MES.WorkBatch.Optional"), input.Locale)})" : "")))); |
| | | return action; |
| | | } |
| | |
| | | action.IsSuccessed = false; |
| | | action.Data.SetValue(this, null); |
| | | var nextList = nextNodes.Where(q => NodeSets.Any(s => s.NODE_ID == q.ID && s.IS_ACTIVE == "Y")); |
| | | //action.LocaleMsg = new($"条码[{0}]在工序[{1}]过站扫描错误,请先通过以下工序:{2}"); |
| | | action.LocaleMsg = new("MES.WorkBatch.GotoNextNodeException", input.SN, nextNode.NODE_NAME, string.Join(", ", nextList.Select(q => q.NODE_NAME + (GetNodeSetting(q)?.CAN_SKIP == "Y" ? $"({Biz.T(Biz.L("MES.WorkBatch.Optional"), input.Locale)})" : "")))); |
| | | return action; |
| | | } |
| | |
| | | private List<MES_WO_NODE> GetNextNodes(MES_WO_NODE parent, MES_WIP_DATA wipSN) |
| | | { |
| | | var result = new List<MES_WO_NODE>(); |
| | | var nextNodes = Nodes.Where(q => q.Operation.OPER_TYPE != MES_OPERATION.OPER_TYPEs.Repair.GetValue() |
| | | var nextNodes = Nodes.Where(q => q.Operation.OPER_TYPE != MES_OPERATION.OPER_TYPEs.Repair.GetValue() |
| | | && Edges.Any(e => e.SRC_NODE == parent.ID && e.TGT_NODE == q.ID) |
| | | && !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.UNBIND_FLAG != "Y" && h.NODE_ID == q.ID && h.IsFinished) |
| | | ).ToList(); |
| | |
| | | .ExecuteCommand(); |
| | | //MES_WIP_DATA & MES_WIP_HIS |
| | | var wipHiss = new List<MES_WIP_HIS>(); |
| | | foreach (var wipSN in wipList.Where(q => q.STATUS != MES_WIP_DATA.STATUSs.Offline.GetValue())) |
| | | foreach (var wipSN in wipList) //.Where(q => q.STATUS != MES_WIP_DATA.STATUSs.Offline.GetValue()) |
| | | { |
| | | wipSN.STATUS = MES_WIP_DATA.STATUSs.Offline.GetValue(); |
| | | wipSN.TRAY_SN = wipSN.INNER_SN = wipSN.CARTON_SN = wipSN.PALLET_SN = wipSN.SHIPPING_ORDER = null; |
| | |
| | | wipSN.NODE_ID = ""; |
| | | wipSN.NODE_NAME = "下线退库"; |
| | | wipSN.OPERATION_TIME = DateTime.Now; |
| | | wipSN.OPERATION_END = DateTime.Now; |
| | | var his = new MES_WIP_HIS(wipSN, $"工单[{wipSN.WORK_ORDER}]条码[{wipSN.SN}]下线"); |
| | | wipHiss.Add(his); |
| | | } |
| | |
| | | while (curpkg.Any()); |
| | | db.Updateable(pkgs, user).ExecuteCommand(); |
| | | //MES_WIP_DFT,在上仓库装配和维修之前,先把不良记录标记为已处理 |
| | | db.Updateable<MES_WIP_DFT>(user) |
| | | .SetColumns(q => q.STATUS == MES_WIP_DFT.STATUSs.Resolved.GetValue()) |
| | | .Where(q => q.WORK_ORDER == wo.ORDER_NO && wipIDs.Contains(q.WIP_ID)) |
| | | db.Updateable<MES_WIP_DATA>(user) |
| | | .SetColumns(q => q.DFT_FLAG == "N") |
| | | .SetColumns(q => q.DFT_COUNT == 0) |
| | | .SetColumns(q => q.DFT_CODE == null) |
| | | .Where(q => q.WORK_ORDER == wo.ORDER_NO && wipIDs.Contains(q.ID)) |
| | | .ExecuteCommand(); |
| | | db.Updateable<MES_WIP_DFT>(user) |
| | | .SetColumns(q => q.STATUS == MES_WIP_DFT.STATUSs.Resolved.GetValue()) |
| | | .Where(q => q.WORK_ORDER == wo.ORDER_NO && wipIDs.Contains(q.WIP_ID)) |
| | | .ExecuteCommand(); |
| | | }); |
| | | if (!dbTran.IsSuccess) |
| | | { |