using iWareSql; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using iWareSql.DBModel; using XiGang.Core.Model; using iWareSql.DataAccess; using iWareCommon.Common.Globle; using System.Threading; using iWareCommon.Utils; using iWareModel; using iWareCC.Common.Helper; namespace iWareCC { /// /// 出库计划任务分解线程 /// public class OutPlanTaskDecompose { /// /// 处理【下发中】的出库计划任务 /// public static void HandlerIssuingTask() { var errMsg = ""; bool result; while (true) { Thread.Sleep(2000);//休眠2秒 try { if (SystemValue.isAllowRuning_HandlerIssuingTask && SystemValue.isStartedModel) { //查询状态=下发中的出库计划 var queryState1 = (int)OutPlanStateEnum.下发中; var queryState2 = (int)OutPlanStateEnum.部分下发; List planList = null; var isAllowDecomposePlanTask = false; using (DbModel context = new DbModel()) { planList = context.Plan_OutTask.Where(x => x.PlanState == queryState1 || x.PlanState == queryState2).ToList(); if (planList != null && planList.Count > 0) { //屏蔽,这样每次只处理3个,会导致赵通他们板链线ecu刷数据 【EditBy shaocx,2022-08-12】 /* //首先验证下是否允许下发 isAllowDecomposePlanTask = IsAllowDecomposePlanTask(context, ref errMsg); if (isAllowDecomposePlanTask == false) { SystemWarningMsg._lbl_Alert_HandlerIssuingTask = errMsg; continue;//继续下一个循环 } //*/ } } if (planList != null && planList.Count > 0) { foreach (var item in planList) { errMsg = "";//重置 using (DbModel mycontext = new DbModel()) { //建议:一次只执行一个出库计划,只要有一个计划成功创建了任务,该循环就跳出,目的是解决出库计划时若下发5个任务中,若其中4号任务不齐套,在5号及以后出库时4号任务刚好齐套,则将4号任务作为最高优先级插队进行出库 【EditBy shaocx,2022-08-10】 result = SingleOutPlanTaskHandler(mycontext, item, ref errMsg); Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, "处理【下发中】的出库计划任务=>" + errMsg); SystemWarningMsg._lbl_Alert_HandlerIssuingTask = errMsg + "[处理任务" + item.PlanNo + "]"; if (result == true) { break;//跳出循环,直接执行循环的下一个过程 【EditBy shaocx,2022-08-10】 } } } } } } catch (Exception ex) { SystemWarningMsg._lbl_Alert_HandlerIssuingTask = "出现异常:" + ex.Message; Log4NetHelper.WriteErrorLog(LogType.CCWCFService, "HandlerIssuingTask出现异常:" + ex.Message, ex); } } } /// /// /// /// /// /// /// true:表示已经找到库存,并创建好了任务,false:表示没有找到库存 private static bool SingleOutPlanTaskHandler(DbModel context, Plan_OutTask outTask, ref string errMsg) { bool fun_Result = false; //注意:这里必须重新获取下对象,因为前面的方法中DbModel是不一样的,不是一个上下文,修改不了数据 【EditBy shaocx,2022-07-28】 Plan_OutTask new_outTask = context.Plan_OutTask.Where(x => x.Id == outTask.Id).First(); errMsg = ""; var queryState1 = (int)OutTaskDetailStateEnum.等待中; var queryState2 = (int)OutTaskDetailStateEnum.缺料; var detaiList = context.Plan_OutTaskDetail.Where(x => (x.OutTaskDetailState == queryState1 || x.OutTaskDetailState == queryState2) && x.M_PlanId == new_outTask.Id) .OrderBy(x => x.CreateTime)//按照创建时间升序 【EditBy shaocx,2022-08-10】 .ThenBy(x => x.PlanSequence)//其次按照顺序升序,主要是给 按照按订货号出库的出库顺序来的 【EditBy shaocx,2024-01-31】 .ToList(); if (detaiList != null && detaiList.Count > 0) { //建议:一次只执行一次出库任务 foreach (var item in detaiList) { var result = SingleOutPlanDetailTaskHandlerForVirtual(context, new_outTask, item, ref errMsg); //var result = false;//暂时先屏蔽读取虚拟库存的数据 if (result == false) {//表示没有找到虚拟库存,就再去查 真实库存 result = SingleOutPlanDetailTaskHandler(context, new_outTask, item, ref errMsg); if (result == false) {//表示没有找到实际库存 } else {//表示找到了实际库存,并成功创建了任务 fun_Result = true; break;//成功后就跳出循环 } } else {//表示找到了虚拟出库,并成功创建了任务 fun_Result = true; break;//成功后就跳出循环 } } } else { //不予处理 } return fun_Result; } /// /// 单个处理出库计划明细-真实库存中处理 /// /// /// /// /// /// true:表示已经找到库存,并创建好了任务,false:表示没有找到库存 private static bool SingleOutPlanDetailTaskHandler(DbModel context, Plan_OutTask outTask, Plan_OutTaskDetail outDetailTask, ref string errMsg) { errMsg = ""; var remark = "消费下发中的任务"; //1、搜索库存是否存在 var queliaoReason = ""; var findStore = StoreHandler.FindStoreForOutPlan(context, outDetailTask, ref errMsg, ref queliaoReason); if (findStore == null) {//表示查找库存失败 //更新Plan_OutTaskDetail表的OperationRemark值 var changeOutTaskDetailState = OutTaskDetailStateEnum.缺料; outDetailTask.OutTaskDetailState = (int)changeOutTaskDetailState; outDetailTask.OutTaskDetailStateName = changeOutTaskDetailState.ToString();//更新 状态为缺料 [EditBy shaocx,2022-08-24] outDetailTask.OperationRemark = SysGloble.QUELIAO_STR; //赋值缺料原因 【Editby shaocx,2022-10-24】 outDetailTask.Remark = MyExtendHelper.GetQueliaoReason(outDetailTask.Remark, queliaoReason); outDetailTask.ModifyTime = DateTime.Now; outDetailTask.ModifyBy = SysGloble.WCSSystem; //重要:!提前生成顺序号 [EditBy shaocx,2022-08-24] string taskSequenceGuid = ""; outDetailTask.MainTaskSequence = MainTaskHandler.GenerateTaskSequence(context, ref taskSequenceGuid); outDetailTask.TaskSequenceGuid = taskSequenceGuid; context.SaveChanges(); Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, errMsg); return false; } else {//查找到库存 #region 事务处理 string taskSequenceGuid = ""; int myTaskSequence = GetLastOutTaskDetailTaskSequenceForQueLiao(context, outDetailTask, ref taskSequenceGuid); using (var trans = context.Database.BeginTransaction()) { try { var sourcePlace = StationHandler.GetPlaceByPlaceId(findStore.StationId, context); //2、锁定库存 StationHandler.SetPlaceLockStatus(true, SysGloble.WCSSystem, ref sourcePlace, remark); StationHandler.SetPlaceTaskDoingStatus(true, SysGloble.WCSSystem, ref sourcePlace, remark); //3、创建出库任务 FunRetEntity addOutStoreTaskResult = MainTaskHandler.AddOutStoreTask(outDetailTask, findStore, context, MainTaskTypeEnum.自动出库, new SysUser() { ID = 0, Name = SysGloble.WCSSystem }, sourcePlace, myTaskSequence, taskSequenceGuid); if (addOutStoreTaskResult.result == false) { errMsg = addOutStoreTaskResult.resMsg; throw new Exception(errMsg); } //4、更新出库明细表 var mainTask = addOutStoreTaskResult.resData as Task_Main; if (mainTask == null) { errMsg = "新建的主任务对象为NULL"; throw new Exception(errMsg); } outDetailTask.TaskSequenceGuid = mainTask.TaskSequenceGuid;//重要!保存TaskSequenceGuid值 【EditBy shaocx,2022-08-25】 outDetailTask.OperationRemark = "设备任务已创建";//注意:这里的OperationRemark一定要更新,因为缺料的时候我更新了,缺料的查询也用到了 【EditBy shaocx,2022-04-29】 outDetailTask.MainTaskId = mainTask.Id; outDetailTask.MainTaskNo = mainTask.TaskNo; outDetailTask.SerialNumber = findStore.SerialNumber;//保存序列号 outDetailTask.OrderNo = findStore.OrderNo; outDetailTask.MaterialId = findStore.MaterialId;//保存物料信息 var changeOutTaskDetailState = OutTaskDetailStateEnum.设备任务待执行; PlanOutTaskHandler.UpdateStateForOutTaskDetail(outDetailTask, changeOutTaskDetailState, remark); //5、更新出库主表 SetPlanStateForPlan_OutTask(context, outTask, changeOutTaskDetailState, remark); //清理之前残留的缺料的信息 【Editby shaocx,2022-10-24】 outDetailTask.Remark = MyExtendHelper.CleareQueliaoReason(outDetailTask.Remark); ////更改任务主表为任务已分解 ////更新主表的任务状态 //var _changeTaskState = MainTaskStatusEnum.出库任务已分解; //mainTask.TaskState = (int)_changeTaskState; //mainTask.TaskStateName = _changeTaskState.ToString(); //保存数据库 context.SaveChanges(); trans.Commit(); return true;//找到了库存,并处理成功了 } catch (Exception ex) { trans.Rollback(); SystemWarningMsg._lbl_Alert_HandlerIssuingTask = "SingleOutPlanDetailTaskHandler出现异常:" + ex.Message; Log4NetHelper.WriteErrorLog(LogType.CCWCFService, "SingleOutPlanDetailTaskHandler 出现异常:" + ex.Message, ex); throw ex; } } #endregion } } /// /// 单个处理出库计划明细-虚拟库存中处理 [Editby shaocx,2022-07-28] /// /// /// /// /// /// true:表示找到虚拟库存,并处理成功了,false表示没有找到虚拟库存 private static bool SingleOutPlanDetailTaskHandlerForVirtual(DbModel context, Plan_OutTask outTask, Plan_OutTaskDetail outDetailTask, ref string errMsg) { errMsg = ""; var remark = "消费下发中的任务"; //1、搜索库存是否存在 var findVirtualStore = StoreHandler.FindStoreForOutPlanByVirtual(context, outDetailTask, ref errMsg); if (findVirtualStore == null) {//表示查找库存失败 return false;//表示在虚拟库存中没有找到库存 } else {//查找到库存 #region 事务处理 using (var trans = context.Database.BeginTransaction()) { try { //1、库存移除 context.Wms_VirtualStore.Remove(findVirtualStore); //findVirtualStore.IsDeleted = true; //findVirtualStore.ModifyBy = ""; //findVirtualStore.OperationRemark = remark + "[锁定库存]"; //findVirtualStore.ModifyTime = DateTime.Now; //2、创建虚拟出库任务,注意:任务状态必须是已完成,因为是虚拟出库 FunRetEntity addOutStoreTaskResult = MainTaskHandler.AddOutStoreTaskForVirtual(outDetailTask, findVirtualStore, context, MainTaskTypeEnum.自动出库, new SysUser() { ID = 0, Name = SysGloble.WCSSystem }); if (addOutStoreTaskResult.result == false) { errMsg = addOutStoreTaskResult.resMsg; throw new Exception(errMsg); } //4、更新出库明细表 var mainTask = addOutStoreTaskResult.resData as Task_Main; if (mainTask == null) { errMsg = "新建的主任务对象为NULL"; throw new Exception(errMsg); } outDetailTask.OperationRemark = "设备任务已创建,并完成";//注意:这里的OperationRemark一定要更新,因为缺料的时候我更新了,缺料的查询也用到了 【EditBy shaocx,2022-04-29】 outDetailTask.MainTaskId = mainTask.Id; outDetailTask.MainTaskNo = mainTask.TaskNo; outDetailTask.SerialNumber = findVirtualStore.SerialNumber;//保存序列号 outDetailTask.OrderNo = findVirtualStore.OrderNo; outDetailTask.MaterialId = findVirtualStore.MaterialId;//保存物料信息 var changeOutTaskDetailState = OutTaskDetailStateEnum.完成;//注意:要变成 已完成 PlanOutTaskHandler.UpdateStateForOutTaskDetail(outDetailTask, changeOutTaskDetailState, remark); //5、更新出库主表 SetPlanStateForPlan_OutTask(context, outTask, changeOutTaskDetailState, remark); //保存数据库 context.SaveChanges(); trans.Commit(); return true; } catch (Exception ex) { trans.Rollback(); SystemWarningMsg._lbl_Alert_HandlerIssuingTask = "SingleOutPlanDetailTaskHandler出现异常:" + ex.Message; Log4NetHelper.WriteErrorLog(LogType.CCWCFService, "SingleOutPlanDetailTaskHandler 出现异常:" + ex.Message, ex); throw ex; } } #endregion } } private static void SetPlanStateForPlan_OutTask(DbModel context, Plan_OutTask outTask, OutTaskDetailStateEnum currnetChange, string remark) { //计算数量 var queryState1 = (int)OutTaskDetailStateEnum.完成; var queryState2 = (int)OutTaskDetailStateEnum.执行中; var allPlanList = context.Plan_OutTaskDetail.Where(x => x.M_PlanId == outTask.Id).ToList(); outTask.Qty = allPlanList.Count;//重新赋值总数量 var issued_planList = allPlanList.Where(x => x.OutTaskDetailState == queryState1 || x.OutTaskDetailState == queryState2).ToList(); int issued_planListCount = issued_planList.Count(); if (currnetChange == OutTaskDetailStateEnum.完成 || currnetChange == OutTaskDetailStateEnum.执行中) { //计入本次要修改的条数 //是否这里不需要+1,待测试 【重要!!!!!】 //issued_planListCount += 1; } OutPlanStateEnum changeOutTaskDetailState; if (outTask.Qty <= issued_planListCount) {//更新主表状态为 全部下发 changeOutTaskDetailState = OutPlanStateEnum.全部下发; PlanOutTaskHandler.UpdateStateForOutTask(outTask, changeOutTaskDetailState, remark); //修改齐套性为已齐套 [EditBy shaocx,2022-05-16] outTask.IsPickFinished = true; //更新计划进度 outTask.PlanRate = 100; outTask.Qty_Finish = outTask.Qty; outTask.Qty_NoFinish = 0; } else if (issued_planListCount > 0) { changeOutTaskDetailState = OutPlanStateEnum.部分下发; PlanOutTaskHandler.UpdateStateForOutTask(outTask, changeOutTaskDetailState, remark); //更新计划进度 //outTask.PlanRate = (issued_planListCount / allPlanList.Count()) * 100; outTask.PlanRate = CSharpHelper.ExecPercentRetInt(issued_planListCount, outTask.Qty); outTask.Qty_Finish = issued_planListCount; outTask.Qty_NoFinish = outTask.Qty - issued_planListCount; } } /// /// 是否允许继续分解任务计划 [EditBy shaocx,2022-08-11] /// /// /// private static bool IsAllowDecomposePlanTask(DbModel context, ref string errMsg) { var queryState1 = (int)MainTaskStatusEnum.待出库; var queryState2 = (int)MainTaskStatusEnum.出库任务已分解; var queryState3 = (int)MainTaskStatusEnum.出库中; var queryMaterialType = (int)MaterialTypeEnum.一般物料; var queryInOutFlag = (int)MainInOutFlagEnum.出库; var mainList = context.Task_Main.Where(x => (x.TaskState == queryState1 || x.TaskState == queryState2 || x.TaskState == queryState3) && x.MaterialType == queryMaterialType && x.InOutFlag == queryInOutFlag).ToList(); if (mainList != null && mainList.Count >= 3) {//为什么是3,考虑到 1012+2个出库口都有发动机的情况 errMsg = "目前已有" + mainList.Count + "条出库任务未结束,不允许继续分解任务计划"; return false; } return true; } /// /// 缺料的数据,插队处理 /// /// /// /// private static int GetLastOutTaskDetailTaskSequenceForQueLiao(DbModel context, Plan_OutTaskDetail planDetail, ref string taskSequenceGuid) { if (planDetail.OutTaskDetailState == (int)OutTaskDetailStateEnum.缺料) {//如果是缺料的话,就需要 插队处理 【EditBy shaocx,2022-08-24】 //首先要判断当前同一个TaskSequenceGuid是否都做完了,如果都做完了,那么他就要排到第一位优先执行,如果还没做完,就按照原先的顺序来。 taskSequenceGuid = planDetail.TaskSequenceGuid; bool isNeedChaDui = PlanOutTaskHandler.IsNeedChaDuiCommonTaskSequenceGuid(context, taskSequenceGuid); if (isNeedChaDui) { return 1;//插队处理 } return Convert.ToInt32(planDetail.MainTaskSequence);//按照原先的节奏顺序走 } return 0;//正常排序 } } }