From 006c12987d7dc7c2081fbf6715ebea98b93fdca0 Mon Sep 17 00:00:00 2001
From: Rodney Chen <rodney.chen@hotmail.com>
Date: 星期日, 08 十二月 2024 17:04:32 +0800
Subject: [PATCH] 增加工单批次缓存,不良代码缓存,岗位缓存

---
 Tiger.Business.MES/Common/WorkBatch.cs |  288 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 250 insertions(+), 38 deletions(-)

diff --git a/Tiger.Business.MES/Common/WorkBatch.cs b/Tiger.Business.MES/Common/WorkBatch.cs
index 72c507a..7d5fdaa 100644
--- a/Tiger.Business.MES/Common/WorkBatch.cs
+++ b/Tiger.Business.MES/Common/WorkBatch.cs
@@ -10,6 +10,9 @@
 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;
 
 namespace Tiger.Business
 {
@@ -47,31 +50,53 @@
 
         #region Functions
         /// <summary>
-        /// 鍒濆鍖栧伐鍗曡祫鏂�
+        /// 鍒濆鍖栧伐鍗曟壒娆¤祫鏂�
         /// </summary>
         /// <returns></returns>
         public WorkBatch Init(string lineCode)
         {
             LineCode = lineCode;
+            WO = Biz.Db.Queryable<BIZ_MES_WO>().Where(q => q.ORDER_NO == OrderNo).IncludesAllFirstLayer().First();
+            Batch = Biz.Db.Queryable<BIZ_MES_WO_BATCH>().Where(q => q.ORDER_NO == OrderNo && q.ACT_LINE == LineCode &&
+                                (q.STATUS == BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() || q.STATUS == BIZ_MES_WO_BATCH.STATUSs.Working.GetValue())).First();
             GetBatchInfo();
             return this;
         }
 
-        public void Update()
+        /// <summary>
+        /// 鏇存柊宸ュ崟鎵规璧勬枡
+        /// </summary>
+        /// <param name="updateAll"></param>
+        public void Update(bool updateAll = false)
         {
-            if (!WoContext.WoBatchDic.ContainsKey(Batch.BATCH_NO))
+            var strat = DateTime.Now;
+            var wo = Biz.Db.Queryable<BIZ_MES_WO>().Where(q => q.ORDER_NO == OrderNo).IncludesAllFirstLayer().First();
+            var batch = Biz.Db.Queryable<BIZ_MES_WO_BATCH>().Where(q => q.BATCH_NO == Batch.BATCH_NO).First();
+            if (WoContext.WoBatchDic.ContainsKey(batch.BATCH_NO))
+            {
+                if (wo.STATUS < BIZ_MES_WO.STATUSs.Release.GetValue() || batch.STATUS > BIZ_MES_WO_BATCH.STATUSs.Working.GetValue())
+                {
+                    WoContext.WoBatchDic.Remove(Batch.BATCH_NO);
+                }
+                else if(updateAll || wo.CHANGE_TIME > WO.CHANGE_TIME || batch.CHANGE_TIME > Batch.CHANGE_TIME)
+                {
+                    GetBatchInfo();
+                }
+            }
+            else
             {
                 GetBatchInfo();
-                WoContext.WoBatchDic.Add(Batch.BATCH_NO, this);
+                WoContext.WoBatchDic.Add(batch.BATCH_NO, this);
             }
+            WO = wo;
+            Batch = batch;
+            ConsoleExt.WriteLine($"{DateTime.Now:HH:mm:ss} ##### : {(DateTime.Now - strat).TotalSeconds}s", ConsoleColor.Yellow);
         }
 
         private void GetBatchInfo()
         {
-            WO = Biz.Db.Queryable<BIZ_MES_WO>().Where(q => q.ORDER_NO == OrderNo).IncludesAllFirstLayer().First();
+            ConsoleExt.WriteLine($"{DateTime.Now:HH:mm:ss} !!!!! ", ConsoleColor.Cyan);
             Product = Biz.Db.Queryable<BAS_ITEM>().Where(q => q.ITEM_CODE == WO.ITEM_CODE && q.AUTH_ORG == WO.AUTH_ORG).IncludesAllFirstLayer().First();
-            Batch = Biz.Db.Queryable<BIZ_MES_WO_BATCH>().Where(q => q.ORDER_NO == OrderNo && q.ACT_LINE == LineCode &&
-                                (q.STATUS == BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() || q.STATUS == BIZ_MES_WO_BATCH.STATUSs.Working.GetValue())).First();
             Customer = Biz.Db.Queryable<BAS_CUSTOMER>().Where(q => q.CUST_CODE == WO.CUST_CODE).First();
             WoSNs = Biz.Db.Queryable<BIZ_MES_WO_SN>().Where(q => q.WORK_ORDER == OrderNo).ToList();
             Edges = Biz.Db.Queryable<MES_WO_EDGE>().Where(q => q.WORK_ORDER == OrderNo).ToList();
@@ -90,7 +115,7 @@
         }
 
         /// <summary>
-        /// 娣诲姞鑺傜偣鐨勪笅涓�涓涓哄埌宸ユ鍒楄〃
+        /// 閫掑綊閬嶅巻宸ュ簭鑺傜偣锛岀粰涓嬬骇宸ュ簭鑺傜偣鎺掑簭鍜屾暣鐞嗗墠缃伐搴�
         /// </summary>
         /// <param name="parent"></param>
         private void NodeSorting(MES_WO_NODE parent)
@@ -126,15 +151,15 @@
         {
             var action = new ApiAction<SubmitOutput>(new SubmitOutput(), true);
 
-            WO = Biz.Db.Queryable<BIZ_MES_WO>().Where(q => q.ORDER_NO == OrderNo).IncludesAllFirstLayer().First();
-            Batch = Biz.Db.Queryable<BIZ_MES_WO_BATCH>().Where(q => q.ORDER_NO == OrderNo && q.ACT_LINE == LineCode).First();
+            Update();
+
             //宸ュ崟鎵规鐘舵�佷笉鏄凡涓嬪彂鎴栬�呯敓浜т腑锛屽垯涓嶅厑璁哥敓浜�
             if (Batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() && Batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Working.GetValue())
             {
                 action.IsSuccessed = false;
                 action.Data.SetValue(this, null);
                 //action.LocaleMsg = new($"宸ュ崟鎵规[{Batch.BATCH_NO}]鐘舵�乕{Batch.STATUS.GetEnum<BIZ_MES_WO_BATCH.STATUSs>().GetName()}]涓嶆槸鍏佽鐢熶骇鐨勭姸鎬侊紝璇锋壂鎻忓厑璁哥敓浜х殑浜у搧鏉$爜");
-                action.LocaleMsg = new("MES.WorkBatch.WoBatchStatusCanNotWork", Batch.BATCH_NO, Batch.STATUS.GetEnum<BIZ_MES_WO_BATCH.STATUSs>().GetName());
+                action.LocaleMsg = new("MES.WorkBatch.WoBatchStatusCanNotWork", Batch.BATCH_NO, Batch.STATUS.GetEnumDesc<BIZ_MES_WO_BATCH.STATUSs>());
             }
             //宸ュ崟鐘舵�佷笉鏄凡涓嬪彂鎴栬�呯敓浜т腑锛屽垯涓嶅厑璁哥敓浜�
             if (WO.STATUS != BIZ_MES_WO.STATUSs.Release.GetValue() && WO.STATUS != BIZ_MES_WO.STATUSs.Working.GetValue())
@@ -142,24 +167,25 @@
                 action.IsSuccessed = false;
                 action.Data.SetValue(this, null);
                 //action.LocaleMsg = new($"宸ュ崟[{WO.ORDER_NO}]鐘舵�乕{Batch.STATUS.GetEnum<BIZ_MES_WO.STATUSs>().GetName()}]涓嶆槸鍏佽鐢熶骇鐨勭姸鎬侊紝璇锋壂鎻忓厑璁哥敓浜х殑浜у搧鏉$爜");
-                action.LocaleMsg = new("MES.WorkBatch.WoStatusCanNotWork", WO.ORDER_NO, Batch.STATUS.GetEnum<BIZ_MES_WO.STATUSs>().GetName());
+                action.LocaleMsg = new("MES.WorkBatch.WoStatusCanNotWork", WO.ORDER_NO, Batch.STATUS.GetEnumDesc<BIZ_MES_WO.STATUSs>());
             }
             //宸ュ崟鎵规鎶曞叆鏁伴噺鍑忓幓鎶ュ簾鏁伴噺濡傛灉澶т簬绛変簬璁″垝鏁伴噺锛屽垯涓嶅厑璁哥敓浜�
-            //if (curNode.IS_INPUT == "Y" && Batch.INPUT_QTY - Batch.SCRAP_QTY >= Batch.PLAN_QTY)
-            if (curNodeSetting.IS_INPUT == "Y" && WoSNs.Count(q => q.STATUS > BIZ_MES_WO_SN.STATUSs.NotInput.GetValue() && q.BATCH_NO == Batch.BATCH_NO) - Batch.SCRAP_QTY >= 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), Batch.SCRAP_QTY, 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 (curNodeSetting.IS_INPUT == "Y" && WoSNs.Count(q => q.STATUS > BIZ_MES_WO_SN.STATUSs.NotInput.GetValue() && q.WORK_ORDER == WO.ORDER_NO) - WO.SCRAP_QTY >= 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), WO.SCRAP_QTY, 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);
             }
 
             return action;
@@ -182,8 +208,8 @@
                 var db = Biz.Db;
                 var dbTran = db.UseTran(() =>
                 {
-                    db.Updateable(WO, user).UpdateColumns(q => new { q.UPDATE_TIME, q.UPDATE_USER, q.STATUS, q.ACT_START_TIME }).ExecuteCommand();
-                    db.Updateable(Batch, user).UpdateColumns(q => new { q.UPDATE_TIME, q.UPDATE_USER, q.STATUS, q.ACT_START_TIME }).ExecuteCommand();
+                    db.Updateable(WO, user).UpdateColumns(q => new { q.STATUS, q.ACT_START_TIME }).ExecuteCommand();
+                    db.Updateable(Batch, user).UpdateColumns(q => new { q.STATUS, q.ACT_START_TIME }).ExecuteCommand();
                 });
                 if (!dbTran.IsSuccess)
                 {
@@ -222,6 +248,61 @@
         }
 
         /// <summary>
+        /// 妫�鏌ュ伐鍗曟槸鍚﹀畬宸ワ紝宸插畬宸ュ垯淇敼鐩稿簲鐘舵�佸苟璁板綍鍒版暟鎹簱
+        /// </summary>
+        /// <param name="user"></param>
+        /// <returns></returns>
+        public async Task<bool> CheckIsComplete(string user)
+        {
+            var woSNs = Biz.Db.Queryable<BIZ_MES_WO_SN>().Where(q => q.WORK_ORDER == OrderNo).ToList();
+
+            //鍒ゆ柇褰撳墠宸ュ崟鎵规鏄惁宸插畬宸�
+            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)
+            {
+                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)
+            {
+                WO.STATUS = BIZ_MES_WO.STATUSs.Closed.GetValue();
+                WO.ACT_END_TIME = DateTime.Now;
+            }
+
+            //淇濆瓨鏁版嵁搴�
+            var db = Biz.Db;
+            var dbTran = db.UseTran(() =>
+            {
+                db.Updateable(WO, user).UpdateColumns(q => new { q.UPDATE_TIME, q.UPDATE_USER, q.STATUS, q.ACT_END_TIME }).ExecuteCommand();
+                db.Updateable(Batch, user).UpdateColumns(q => new { q.UPDATE_TIME, q.UPDATE_USER, q.STATUS, q.ACT_END_TIME }).ExecuteCommand();
+            });
+            if (!dbTran.IsSuccess)
+            {
+                //throw dbTran.ErrorException;
+                Logger.Default.Fatal(dbTran.ErrorException, $"妫�鏌ュ伐鍗曟壒娆{Batch.BATCH_NO}]鏄惁瀹屽伐寮傚父");
+                return false;
+            }
+            //鍒犻櫎缂撳瓨
+            if (Batch.STATUS == BIZ_MES_WO_BATCH.STATUSs.Closed.GetValue())
+            {
+                WoContext.WoBatchDic.Remove(Batch.BATCH_NO);
+            }
+            if (WO.STATUS == BIZ_MES_WO.STATUSs.Closed.GetValue())
+            {
+                var list = WoContext.WoBatchDic.Where(q => q.Value.WO.ORDER_NO == OrderNo).Select(q => q.Key);
+                foreach (var item in list)
+                {
+                    WoContext.WoBatchDic.Remove(item);
+                }
+            }
+
+            return true;
+        }
+
+        /// <summary>
         /// 鏍规嵁宀椾綅缂栫爜鍒ゆ柇鏄笉鏄绔�
         /// </summary>
         /// <param name="postCode"></param>
@@ -248,7 +329,7 @@
         /// <returns></returns>
         public MES_WO_OPER GetNodeSetting(MES_WO_NODE node)
         {
-            return NodeSets.FirstOrDefault(q => q.NODE_ID == node.ID);
+            return NodeSets.FirstOrDefault(q => q.NODE_ID == node?.ID);
         }
 
         /// <summary>
@@ -275,6 +356,7 @@
                     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;
                 }
@@ -311,22 +393,25 @@
                         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;
-                }
                 //姝e父宸ュ簭杩囩珯
                 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);
                     //濡傛灉涓嬩竴涓彲鎵ц宸ュ簭鍖呭惈鐩爣宸ュ簭鍒欏厑璁歌繘绔�
@@ -337,11 +422,12 @@
                     }
 
                     //濡傛灉褰撳墠宸ュ簭鏈夊繀椤绘墽琛岀殑鍚庣画宸ュ簭锛屽垯鎶ラ敊
-                    if (nextNodes.Any(q => NodeSets.Any(s => s.NODE_ID == q.ID && s.IS_ACTIVE == "Y" && s.CAN_SKIP != "Y")))
+                    if (nextNodes.Any(q => q.OPER_CODE != "EndNode" && NodeSets.Any(s => s.NODE_ID == q.ID && s.IS_ACTIVE == "Y" && s.CAN_SKIP != "Y")))
                     {
                         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;
                     }
@@ -350,7 +436,7 @@
                     {
                         //鍦ㄥ墠缃伐搴忔煡鎵捐繕鏈夋病鏈夊悗缁伐搴忔病瀹屾垚鐨勫墠缃伐搴�
                         var prepIDs = curNode.PrepNodeIDs.Where(id =>
-                                                             Edges.Any(e => e.SRC_NODE == id && !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.NODE_ID == e.TGT_NODE && h.IsFinished))
+                                                             Edges.Any(e => e.SRC_NODE == id && !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.UNBIND_FLAG != "Y" && h.NODE_ID == e.TGT_NODE && h.IsFinished))
                                                              ).ToList();
                         foreach (var prepID in prepIDs)
                         {
@@ -371,6 +457,7 @@
                             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;
                         }
@@ -382,22 +469,22 @@
         }
 
         /// <summary>
-        /// 娣诲姞鑺傜偣鐨勪笅涓�涓彲鎵ц鑺傜偣
+        /// 鑾峰彇鑺傜偣鐨勪笅涓�涓彲鎵ц鑺傜偣锛堟帓闄ゆ湁鍓嶇疆宸ュ簭鏈畬鎴愮殑鑺傜偣锛�
         /// </summary>
         /// <param name="parent"></param>
         /// <param name="wipSN">褰撳墠鐨勬潯鐮佽繃绔欒褰曪紝闇�瑕佸鑸煡璇㈢敓浜ц繃绋嬭褰曚俊鎭�</param>
         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.NODE_ID == q.ID && h.IsFinished)
+                                                                && !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.UNBIND_FLAG != "Y" && h.NODE_ID == q.ID && h.IsFinished)
                                                              ).ToList();
             //灏濊瘯灏嗗綋鍓嶅伐搴忕殑鍚庣画宸ュ簭娣诲姞鍒板彲浠ユ墽琛岀殑宸ュ簭鍒楄〃
             foreach (var next in nextNodes)
             {
                 //鏌ユ壘鏈夋病鏈夊墠缃伐搴忔壘涓嶅埌宸茶壇鍝佽繃绔欑殑鍘嗗彶璁板綍锛岃嫢鏈夊垯涓嶅厑璁哥户缁墽琛�
-                if (!next.PrepNodeIDs.Any(id => !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.NODE_ID == id && h.IsFinished)) || parent.IS_FIRST_NODE == "Y")
+                if (!next.PrepNodeIDs.Any(id => !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.UNBIND_FLAG != "Y" && h.NODE_ID == id && h.IsFinished)) || parent.IS_FIRST_NODE == "Y")
                 {
                     var setting = NodeSets.FirstOrDefault(q => q.NODE_ID == next.ID);
                     //鍚庣画宸ュ簭鏄惎鐢ㄧ殑锛屽垯娣诲姞
@@ -417,7 +504,7 @@
         }
 
         /// <summary>
-        /// 鏍规嵁浼犲叆鐨勬潯鐮佽繑鍥炰笅涓�绔欏彲杩涘叆杩涘叆鐨勭洰鏍囧伐搴�
+        /// 鏍规嵁浼犲叆鐨勬潯鐮佽繑鍥炰笅涓�绔欏彲杩涘叆鐨勭洰鏍囧伐搴�
         /// </summary>
         /// <param name="wipSN">褰撳墠鐨勬潯鐮佽繃绔欒褰曪紝闇�瑕佸鑸煡璇㈢敓浜ц繃绋嬭褰曞拰鐢熶骇涓嶈壇璁板綍淇℃伅</param>
         /// <returns></returns>
@@ -451,7 +538,7 @@
                     {
                         //鍦ㄥ墠缃伐搴忔煡鎵捐繕鏈夋病鏈夊悗缁伐搴忔病瀹屾垚鐨勫墠缃伐搴�
                         var prepIDs = curNode.PrepNodeIDs.Where(id =>
-                                                             Edges.Any(e => e.SRC_NODE == id && !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.NODE_ID == e.TGT_NODE && h.IsFinished))
+                                                             Edges.Any(e => e.SRC_NODE == id && !wipSN.History.Any(h => h.WORK_ORDER == WO.ORDER_NO && h.UNBIND_FLAG != "Y" && h.NODE_ID == e.TGT_NODE && h.IsFinished))
                                                              ).ToList();
                         foreach (var prepID in prepIDs)
                         {
@@ -499,6 +586,131 @@
             return result;
         }
 
+        /// <summary>
+        /// 浠庡伐鍗曚腑绉婚櫎姝e湪鐢熶骇鐨勬潯鐮�
+        /// </summary>
+        /// <param name="wipList"></param>
+        /// <returns></returns>
+        public ApiAction RemoveWipSn(List<MES_WIP_DATA> wipList, string user)
+        {
+            var action = UnbindWipSnFromWO(WO, wipList, user);
+            //绉婚櫎鎴愬姛鍒欏鐞嗗伐鍗曠紦瀛樹腑鐨勬暟鎹�
+            if (action.IsSuccessed)
+            {
+                Update(true);
+            }
+
+            return action;
+        }
+
+        /// <summary>
+        /// 浠庡伐鍗曚腑瑙g粦姝e湪鐢熶骇鐨勬潯鐮�
+        /// </summary>
+        /// <param name="wo"></param>
+        /// <param name="wipList"></param>
+        /// <returns></returns>
+        public static ApiAction UnbindWipSnFromWO(BIZ_MES_WO wo, List<MES_WIP_DATA> wipList, string user)
+        {
+            var action = new ApiAction();
+
+            var wipIDs = wipList.Select(q => q.ID);
+            var batchs = wipList.Where(q => !q.BATCH_NO.IsNullOrEmpty()).GroupBy(q => new { q.BATCH_NO }).Select(g => new { 
+                g.Key.BATCH_NO, 
+                Qty = g.Count(),
+                OutQty = g.Count(q => MES_WIP_DATA.STATUSs.Output.GetValue() <= q.STATUS && q.STATUS < MES_WIP_DATA.STATUSs.InStorage.GetValue()),
+            });
+            var db = Biz.Db;
+            var dbTran = db.UseTran(() =>
+            {
+                //BIZ_MES_WO
+                wo.INPUT_QTY -= wipList.Count;
+                wo.OUTPUT_QTY -= wipList.Count(q => MES_WIP_DATA.STATUSs.Output.GetValue() <= q.STATUS && q.STATUS < MES_WIP_DATA.STATUSs.InStorage.GetValue());
+                wo.SCRAP_QTY += wipList.Count;
+                wo.STATUS = wo.STATUS.GetEnum<BIZ_MES_WO.STATUSs>() == BIZ_MES_WO.STATUSs.Closed ? BIZ_MES_WO.STATUSs.Working.GetValue() : wo.STATUS;
+                db.Updateable(wo, user).UpdateColumns(q => new { q.INPUT_QTY, q.OUTPUT_QTY, q.SCRAP_QTY, q.UPDATE_USER, q.UPDATE_TIME, q.STATUS }).ExecuteCommand();
+                //BIZ_MES_WO_BATCH
+                var wobatchs = Biz.Db.Queryable<BIZ_MES_WO_BATCH>().Where(q => batchs.Select(x => x.BATCH_NO).Contains(q.BATCH_NO)).ToList();
+                foreach (var batch in wobatchs)
+                {
+                    batch.INPUT_QTY -= batchs.Where(q=>q.BATCH_NO == batch.BATCH_NO).First().Qty;
+                    batch.OUTPUT_QTY -= batchs.Where(q => q.BATCH_NO == batch.BATCH_NO).First().OutQty;
+                    batch.SCRAP_QTY += batchs.Where(q => q.BATCH_NO == batch.BATCH_NO).First().Qty;
+                    batch.STATUS = batch.STATUS.GetEnum<BIZ_MES_WO_BATCH.STATUSs>() == BIZ_MES_WO_BATCH.STATUSs.Closed ? BIZ_MES_WO_BATCH.STATUSs.Working.GetValue() : batch.STATUS;
+                }
+                db.Updateable(wobatchs, user).UpdateColumns(q => new { q.INPUT_QTY, q.OUTPUT_QTY, q.SCRAP_QTY, q.UPDATE_USER, q.UPDATE_TIME, q.STATUS }).ExecuteCommand();
+                //BIZ_MES_WO_SN
+                db.Updateable<BIZ_MES_WO_SN>(user)
+                            .SetColumns(q => q.STATUS == BIZ_MES_WO_SN.STATUSs.Offline.GetValue())
+                            .SetColumns(q => q.TRAY_SN == null).SetColumns(q => q.OUTER_SN == null)
+                            .Where(q => q.WORK_ORDER == wo.ORDER_NO && wipIDs.Contains(q.WIP_ID))
+                            .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())
+                {
+                    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.FINISHED_FLAG = wipSN.HOLD_FLAG = "N";
+                    wipSN.UNBIND_FLAG = "Y";
+                    wipSN.NODE_ID = "";
+                    wipSN.NODE_NAME = "涓嬬嚎閫�搴�";
+                    wipSN.OPERATION_TIME = DateTime.Now;
+                    var his = new MES_WIP_HIS(wipSN, $"宸ュ崟[{wipSN.WORK_ORDER}]鏉$爜[{wipSN.SN}]涓嬬嚎");
+                    wipHiss.Add(his);
+                }
+                db.Storageable(wipList, user).ExecuteCommand();
+                db.Storageable(wipHiss, user).ExecuteCommand();
+                db.Updateable<MES_WIP_HIS>(user)
+                           .SetColumns(q => q.UNBIND_FLAG == "Y")
+                           .Where(q => q.WORK_ORDER == wo.ORDER_NO && wipIDs.Contains(q.WIP_ID))
+                           .ExecuteCommand();
+                //MES_WIP_PKG
+                var curpkg = db.Queryable<MES_WIP_PKG>().Where(q => wipIDs.Contains(q.WIP_ID)).ToList();
+                db.Deleteable(curpkg).ExecuteCommand();
+                var pkgs = new List<MES_WIP_PKG>();
+                do
+                {
+                    var parentSns = curpkg.Where(q => !q.PARENT_SN.IsNullOrEmpty()).Select(q => q.PARENT_SN).Distinct();
+                    curpkg = db.Queryable<MES_WIP_PKG>().Where(q => parentSns.Contains(q.SN)).ToList();
+                    foreach (var pkg in curpkg)
+                    {
+                        pkg.QTY = db.Queryable<MES_WIP_PKG>().Where(q => q.PARENT_SN == pkg.SN).Sum(q => q.QTY);
+                        pkgs.Add(pkg);
+                    }
+                }
+                while (curpkg.Any());
+                db.Updateable(pkgs, user).ExecuteCommand();
+                //MES_WIP_DFT锛屽湪涓婁粨搴撹閰嶅拰缁翠慨涔嬪墠锛屽厛鎶婁笉鑹褰曟爣璁颁负宸插鐞�
+                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)
+            {
+                //鎶涘嚭寮傚父
+                throw dbTran.ErrorException;
+            }
+            //鏇存柊宸ュ崟姹犱腑鐨勫伐鍗曟潯鐮佽〃鏁版嵁鐨勭姸鎬�
+            foreach (var item in WoContext.WoBatchDic)
+            {
+                if (item.Value.WO.ORDER_NO == wo.ORDER_NO)
+                {
+                    foreach (var woSn in item.Value.WoSNs.Where(q => wipIDs.Contains(q.WIP_ID)))
+                    {
+                        woSn.STATUS = BIZ_MES_WO_SN.STATUSs.Offline.GetValue();
+                    }
+                    item.Value.Update();
+                }
+            }
+            return action;
+        }
         #endregion
 
         /// <summary>

--
Gitblit v1.9.3