using NX_CommonClassLibrary; using NX_JsonClassLibrary; using NX_ModelClassLibrary.BaseModel; using NX_ModelClassLibrary.Common; using NX_ModelClassLibrary.CrnModel; using NX_ModelClassLibrary.CustomEnum; using NX_ModelClassLibrary.OpcModel; using NX_ModelClassLibrary.TranModel; using NX_ModelClassLibrary.WcsDispatch; using NX_ModelClassLibrary.WmsTask; using NX_WcsBiz.CommonBusiness; using NX_WcsDal.WcsDispatch; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace NX_WcsBiz.WcsDispatch { /// /// 任务反馈调度类 /// public class TaskResponse_Disp { #region 单例模式 /// /// 单例模式对象 /// private static TaskResponse_Disp _instance = null; private static readonly object lockObj = new object(); /// /// 单例模式方法 /// public static TaskResponse_Disp Instance { get { if (_instance == null) { lock (lockObj) { if (_instance == null) { _instance = new TaskResponse_Disp(); } } } return _instance; } } #endregion /// /// 任务反馈调度入口函数 /// /// 任务反馈传入参数对象 /// public DispUntilityReturnMd TaskResponseHandleFunc(TaskResponseMd taskResponseMd) { try { if (taskResponseMd == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈调度函数传入参数为空!!" }; } DispUntilityReturnMd retMd; switch (taskResponseMd.TaskResponseType) { case DispatchResponseHandleTypeEnum.输送线指令反馈完成: retMd = TranTaskResponseHandle(taskResponseMd); break; case DispatchResponseHandleTypeEnum.堆垛机指令反馈完成: retMd = CrnTaskResponseHandle(taskResponseMd); break; default: retMd = new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"未定义任务反馈处理枚举,任务反馈调度无法识别此类型!!" }; break; } return retMd; } catch (Exception ex) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈调度函数发生异常:【{ex.Message}】。" }; } } private DispUntilityReturnMd TranTaskResponseHandle(TaskResponseMd taskResponseMd) { BasWcsLocMd taskResponseLoc = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == taskResponseMd.CurrentLocNo); if (taskResponseLoc == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,传入站台不是系统配置好的站台号!{GetRetMsg(taskResponseMd)}" }; } WcsTranCmdMd wcsTranCmdMd = TaskResponse_Dal.Instance.GetFinishedWcsTranCmdOfPalletCode(taskResponseMd.TrayCode, taskResponseMd.PalletCode, taskResponseMd.CurrentLocNo); if (wcsTranCmdMd == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,传入参数无法获取完成的输送线信息!{GetRetMsg(taskResponseMd)}" }; } WmsTskTaskMd wmsTskTaskMd = TaskResponse_Dal.Instance.GetUnfinishWmsTaskOfTaskNo(taskResponseMd.TaskNo.ToString()); if (wmsTskTaskMd == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,无法获取到未完成的WMS大任务数据!{GetRetMsg(taskResponseMd)}" }; } if (taskResponseLoc.LocTypeCode == "InLoc") { string trayCode = string.Empty; if (!TaskRequest_Dal.Instance.VerifyTrayMsgAndBalanceMsg(taskResponseMd.PalletCode, out trayCode)) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,校验传入托盘号库存和组盘信息错误,无法进行下一步动作!{GetRetMsg(taskResponseMd)}" }; } // ToDo:20201215 孙亚龙 BasWcsLocMd regionLocNo = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == wmsTskTaskMd.ElocCode); BasBinMd CurrInBinMd = TaskResponse_Dal.Instance.GetBinMdOfCode(taskResponseLoc.LocBinExtMsg); List DistributableShelfLst = BasCommon_Biz.Instance.GetCrnRelationShelfLst(CurrInBinMd); // 获取空闲库位 BasBinMd emptyBin = BasCommon_Biz.Instance.GetDoubleExtensionEmptyBinMd(regionLocNo.LocBinExtMsg, DistributableShelfLst, trayCode); if (emptyBin == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"获取库区:【{regionLocNo.LocExtMsg}】的空闲库位失败,输送线任务反馈无法进行下一步动作!{GetRetMsg(taskResponseMd)}" }; } //生成堆垛机指令。更新WMS大任务当前站台为入库口站点。 BasBinMd inBinMd = TaskResponse_Dal.Instance.GetBinMdOfCodeAndType(taskResponseLoc.LocBinExtMsg, BasBinTypeEnum.入库口); BasNextLocRouteMd locRouteMd = TaskResponse_Dal.Instance.GetRouteMsg(taskResponseLoc, regionLocNo); if (locRouteMd == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈的请求参数验证错误,获取起点:【{taskResponseLoc.LocCode}】到终点:【{regionLocNo.LocCode}】的路线信息发生错误!{GetRetMsg(taskResponseMd)}" }; } int row = TaskResponse_Dal.Instance.InsertCrnCmdAndUpdateWmsTask(wmsTskTaskMd, emptyBin, inBinMd, locRouteMd); if (row > 0) { OperateResultInfo resultInfo = JsonHelper.ToObject(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus { TaskNo = wmsTskTaskMd.TaskNo, TrayCode = wmsTskTaskMd.TrayCode, OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户 PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘入库执行中, }))); if (resultInfo.Status == OperateStatus.Success) { return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"输送线任务完成反馈处理成功!--{resultInfo.Message}" }; } else { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" }; } } else { return new DispUntilityReturnMd { IsSuccess = true, RetMsg = "输送线任务完成反馈处理失败!生成下一步堆垛机指令错误!修改WMS大任务数据错误!!" }; } } else if (taskResponseLoc.LocTypeCode == "GeneralLoc" || taskResponseLoc.LocTypeCode == "OnLineLoc") { // ToDo:20201215 孙亚龙 //大任务到达出库分拣口。 int row = TaskResponse_Dal.Instance.UpdateWmsTaskToTargetLoc(wmsTskTaskMd); if (row > 0) { OperateResultInfo resultInfo = JsonHelper.ToObject(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus { TaskNo = wmsTskTaskMd.TaskNo, TrayCode = wmsTskTaskMd.TrayCode, OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户 PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘出库到目标, }))); if (resultInfo.Status == OperateStatus.Success) { return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"输送线任务完成反馈处理成功!--{resultInfo.Message}" }; } else { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" }; } } else { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = "输送线任务完成反馈处理失败!修改WMS大任务状态为托盘到目标错误!!" }; } } else { // ToDo:20201215 孙亚龙 // 由于目前的项目没有那么多站台类型,因此其它站台类型的代码暂时不添加。 // 后续项目使用到的话,再根据业务类型添加代码。 return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈暂时未收录该类型站台的反馈业务,请联系管理员或程序设计者!{GetRetMsg(taskResponseMd)}" }; } } private BasWcsLocMd GetOutLocMd() { List locMdLst = BasCommon_Biz.Instance.allWcsLocList.FindAll(x => x.LocTypeCode == "OnLineAndGeneralLoc" || x.LocTypeCode == "GeneralLoc"); Dictionary tranLocHaveGoodsDic = new Dictionary(); for (int i = 0; i < locMdLst.Count; i++) { BasWcsDevMd basWcsTranDevMd = BasCommon_Biz.Instance.basWcsDevMdList.FirstOrDefault(x => x.DevCode == locMdLst[i].LocExtMsg); if (GetTranHaveGoodsStatus(basWcsTranDevMd)) { tranLocHaveGoodsDic.Add(locMdLst[i], true); } else { tranLocHaveGoodsDic.Add(locMdLst[i], false); } } List tmpLocFalseLst = tranLocHaveGoodsDic.Where(x => x.Value == false).Select(x => x.Key).ToList(); if (tmpLocFalseLst.Count == 1) { return tmpLocFalseLst[0]; } else if (tmpLocFalseLst.Count < 1) { Random tmpRd = new Random(); int retIndex = tmpRd.Next(0, locMdLst.Count); return locMdLst[retIndex]; } else { Random tmpRd = new Random(); int retIndex = tmpRd.Next(0, tmpLocFalseLst.Count); return tmpLocFalseLst[retIndex]; } } private bool GetTranHaveGoodsStatus(BasWcsDevMd basWcsTranDevMd) { WcsOpcItemMd tmpFrontHaveGoodsFlagOpcItem = BasCommon_Biz.Instance.allOpcItemList.FirstOrDefault(x => x.DevCode == basWcsTranDevMd.DevCode && x.PlcCode == basWcsTranDevMd.DevPlcNo && x.OpcItemCode == "FrontHaveGoodsFlag"); WcsOpcItemMd tmpBackEndHaveGoodsFlagOpcItem = BasCommon_Biz.Instance.allOpcItemList.FirstOrDefault(x => x.DevCode == basWcsTranDevMd.DevCode && x.PlcCode == basWcsTranDevMd.DevPlcNo && x.OpcItemCode == "BackEndHaveGoodsFlag"); return Convert.ToBoolean(tmpFrontHaveGoodsFlagOpcItem.OpcItemValue) || Convert.ToBoolean(tmpBackEndHaveGoodsFlagOpcItem.OpcItemValue); } private DispUntilityReturnMd CrnTaskResponseHandle(TaskResponseMd taskResponseMd) { BasWcsLocMd taskResponseLoc = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == taskResponseMd.CurrentLocNo); if (taskResponseLoc == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,传入站台不是系统配置好的站台号!{GetRetMsg(taskResponseMd)}" }; } WcsCrnCmdMd wcsCrnCmdMd = TaskResponse_Dal.Instance.GetFinishedWcsCrnCmdOfPalletCode(taskResponseMd.PalletCode,taskResponseMd.TrayCode); if (wcsCrnCmdMd == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,传入参数无法获取完成的堆垛机指令信息!{GetRetMsg(taskResponseMd)}" }; } WmsTskTaskMd wmsTskTaskMd = TaskResponse_Dal.Instance.GetUnfinishWmsTaskOfTaskNo(taskResponseMd.TaskNo.ToString()); if (wmsTskTaskMd == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,无法获取到未完成的WMS大任务数据!{GetRetMsg(taskResponseMd)}" }; } //string trayCode = string.Empty; //if (!TaskRequest_Dal.Instance.VerifyTrayMsgAndBalanceMsg(taskResponseMd.PalletCode, out trayCode)) //{ // return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,校验传入托盘号库存和组盘信息错误,无法进行下一步动作!{GetRetMsg(taskResponseMd)}" }; //} BasBinMd eBinMd = TaskResponse_Dal.Instance.GetBinMdOfCode(wmsTskTaskMd.EbinCode); if (eBinMd.BinType == BasBinTypeEnum.存储库位 && taskResponseLoc.LocTypeCode == "RegionLoc" && wcsCrnCmdMd.CmdType == CrnCmdTypeEnum.IN)// 入库 { // ToDo:20201215 孙亚龙 int row = TaskResponse_Dal.Instance.UpdateWmsTaskToTargetLoc(wmsTskTaskMd); if (row > 0) { // ToDo:后续调用WMS接口,完成入库任务。 OperateResultInfo resultInfo = JsonHelper.ToObject(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus { TaskNo = wmsTskTaskMd.TaskNo, TrayCode = wmsTskTaskMd.TrayCode, OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户 PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘入库完成, }))); if (resultInfo.Status == OperateStatus.Success) { return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"堆垛机任务完成反馈处理成功!--{resultInfo.Message}" }; } else { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" }; } } else { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = "堆垛机任务完成反馈处理失败!修改WMS大任务状态为托盘到目标错误!!" }; } } else if (eBinMd.BinType == BasBinTypeEnum.出库口 && taskResponseLoc.LocTypeCode == "OutLoc" && wcsCrnCmdMd.CmdType == CrnCmdTypeEnum.OUT)// 出库 { //ToDo: 后续在这里增加判断1001和1008站台空闲的逻辑。增加动态均衡分配到两个作业口。 BasWcsLocMd eLocNo = GetOutLocMd(); //BasWcsLocMd eLocNo = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == wmsTskTaskMd.ElocCode); if (eLocNo.LocCode != wmsTskTaskMd.ElocCode) { //更新WMS大任务终点位置。 wmsTskTaskMd.ElocCode = eLocNo.LocCode; TaskResponse_Dal.Instance.UpdateWmsTaskElocNo(wmsTskTaskMd); } BasNextLocRouteMd locRouteMd = TaskResponse_Dal.Instance.GetRouteMsg(taskResponseLoc, eLocNo); if (locRouteMd == null) { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈的请求参数验证错误,获取起点:【{taskResponseLoc.LocCode}】到终点:【{eLocNo.LocCode}】的路线信息发生错误!{GetRetMsg(taskResponseMd)}" }; } int row = TaskResponse_Dal.Instance.InsertTranCmdAndUpdateWmsTask(wmsTskTaskMd, taskResponseLoc, eLocNo, locRouteMd); if (row > 0) { OperateResultInfo resultInfo = JsonHelper.ToObject(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus { TaskNo = wmsTskTaskMd.TaskNo, TrayCode = wmsTskTaskMd.TrayCode, OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户 PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘出库执行中, }))); if (resultInfo.Status == OperateStatus.Success) { return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"堆垛机任务完成反馈处理成功!--{resultInfo.Message}" }; } else { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" }; } } else { return new DispUntilityReturnMd { IsSuccess = true, RetMsg = "堆垛机任务完成反馈处理失败!生成下一步输送线指令错误!修改WMS大任务数据错误!!" }; } } else if (eBinMd.BinType == BasBinTypeEnum.存储库位 && taskResponseLoc.LocTypeCode == "RegionLoc" && wcsCrnCmdMd.CmdType == CrnCmdTypeEnum.MOVE) { TaskResponse_Dal.Instance.UpdateMoveWmsTaskAndBalance(wmsTskTaskMd); return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"堆垛机移库指令完成,任务反馈处理成功!" }; } else { return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈终点库位类型为入库口,不符合实际情况,请联系管理员或程序设计者,检查堆垛机指令是否生成有误!{GetRetMsg(taskResponseMd)}" }; } } private string GetRetMsg(TaskResponseMd taskResponseMd) { return $"反馈传入参数 --- 托盘号:【{taskResponseMd.PalletCode}】,请求站台号:【{taskResponseMd.CurrentLocNo}】,反馈处理类型:【{taskResponseMd.TaskResponseType}】"; } } }