TaskResponse_Disp.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. using NX_CommonClassLibrary;
  2. using NX_JsonClassLibrary;
  3. using NX_ModelClassLibrary.BaseModel;
  4. using NX_ModelClassLibrary.Common;
  5. using NX_ModelClassLibrary.CrnModel;
  6. using NX_ModelClassLibrary.CustomEnum;
  7. using NX_ModelClassLibrary.OpcModel;
  8. using NX_ModelClassLibrary.TranModel;
  9. using NX_ModelClassLibrary.WcsDispatch;
  10. using NX_ModelClassLibrary.WmsTask;
  11. using NX_WcsBiz.CommonBusiness;
  12. using NX_WcsDal.WcsDispatch;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Text;
  17. using System.Threading.Tasks;
  18. namespace NX_WcsBiz.WcsDispatch
  19. {
  20. /// <summary>
  21. /// 任务反馈调度类
  22. /// </summary>
  23. public class TaskResponse_Disp
  24. {
  25. #region 单例模式
  26. /// <summary>
  27. /// 单例模式对象
  28. /// </summary>
  29. private static TaskResponse_Disp _instance = null;
  30. private static readonly object lockObj = new object();
  31. /// <summary>
  32. /// 单例模式方法
  33. /// </summary>
  34. public static TaskResponse_Disp Instance
  35. {
  36. get
  37. {
  38. if (_instance == null)
  39. {
  40. lock (lockObj)
  41. {
  42. if (_instance == null)
  43. {
  44. _instance = new TaskResponse_Disp();
  45. }
  46. }
  47. }
  48. return _instance;
  49. }
  50. }
  51. #endregion
  52. /// <summary>
  53. /// 任务反馈调度入口函数
  54. /// </summary>
  55. /// <param name="taskResponseMd">任务反馈传入参数对象</param>
  56. /// <returns></returns>
  57. public DispUntilityReturnMd TaskResponseHandleFunc(TaskResponseMd taskResponseMd)
  58. {
  59. try
  60. {
  61. if (taskResponseMd == null)
  62. {
  63. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈调度函数传入参数为空!!" };
  64. }
  65. DispUntilityReturnMd retMd;
  66. switch (taskResponseMd.TaskResponseType)
  67. {
  68. case DispatchResponseHandleTypeEnum.输送线指令反馈完成:
  69. retMd = TranTaskResponseHandle(taskResponseMd);
  70. break;
  71. case DispatchResponseHandleTypeEnum.堆垛机指令反馈完成:
  72. retMd = CrnTaskResponseHandle(taskResponseMd);
  73. break;
  74. default:
  75. retMd = new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"未定义任务反馈处理枚举,任务反馈调度无法识别此类型!!" };
  76. break;
  77. }
  78. return retMd;
  79. }
  80. catch (Exception ex)
  81. {
  82. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈调度函数发生异常:【{ex.Message}】。" };
  83. }
  84. }
  85. private DispUntilityReturnMd TranTaskResponseHandle(TaskResponseMd taskResponseMd)
  86. {
  87. BasWcsLocMd taskResponseLoc = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == taskResponseMd.CurrentLocNo);
  88. if (taskResponseLoc == null)
  89. {
  90. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,传入站台不是系统配置好的站台号!{GetRetMsg(taskResponseMd)}" };
  91. }
  92. WcsTranCmdMd wcsTranCmdMd = TaskResponse_Dal.Instance.GetFinishedWcsTranCmdOfPalletCode(taskResponseMd.TrayCode, taskResponseMd.PalletCode, taskResponseMd.CurrentLocNo);
  93. if (wcsTranCmdMd == null)
  94. {
  95. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,传入参数无法获取完成的输送线信息!{GetRetMsg(taskResponseMd)}" };
  96. }
  97. WmsTskTaskMd wmsTskTaskMd = TaskResponse_Dal.Instance.GetUnfinishWmsTaskOfTaskNo(taskResponseMd.TaskNo.ToString());
  98. if (wmsTskTaskMd == null)
  99. {
  100. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,无法获取到未完成的WMS大任务数据!{GetRetMsg(taskResponseMd)}" };
  101. }
  102. if (taskResponseLoc.LocTypeCode == "InLoc")
  103. {
  104. string trayCode = string.Empty;
  105. if (!TaskRequest_Dal.Instance.VerifyTrayMsgAndBalanceMsg(taskResponseMd.PalletCode, out trayCode))
  106. {
  107. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈完成请求参数验证错误,校验传入托盘号库存和组盘信息错误,无法进行下一步动作!{GetRetMsg(taskResponseMd)}" };
  108. }
  109. // ToDo:20201215 孙亚龙
  110. BasWcsLocMd regionLocNo = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == wmsTskTaskMd.ElocCode);
  111. BasBinMd CurrInBinMd = TaskResponse_Dal.Instance.GetBinMdOfCode(taskResponseLoc.LocBinExtMsg);
  112. List<BasShelfMd> DistributableShelfLst = BasCommon_Biz.Instance.GetCrnRelationShelfLst(CurrInBinMd);
  113. // 获取空闲库位
  114. BasBinMd emptyBin = BasCommon_Biz.Instance.GetDoubleExtensionEmptyBinMd(regionLocNo.LocBinExtMsg, DistributableShelfLst, trayCode);
  115. if (emptyBin == null)
  116. {
  117. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"获取库区:【{regionLocNo.LocExtMsg}】的空闲库位失败,输送线任务反馈无法进行下一步动作!{GetRetMsg(taskResponseMd)}" };
  118. }
  119. //生成堆垛机指令。更新WMS大任务当前站台为入库口站点。
  120. BasBinMd inBinMd = TaskResponse_Dal.Instance.GetBinMdOfCodeAndType(taskResponseLoc.LocBinExtMsg, BasBinTypeEnum.入库口);
  121. BasNextLocRouteMd locRouteMd = TaskResponse_Dal.Instance.GetRouteMsg(taskResponseLoc, regionLocNo);
  122. if (locRouteMd == null)
  123. {
  124. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈的请求参数验证错误,获取起点:【{taskResponseLoc.LocCode}】到终点:【{regionLocNo.LocCode}】的路线信息发生错误!{GetRetMsg(taskResponseMd)}" };
  125. }
  126. int row = TaskResponse_Dal.Instance.InsertCrnCmdAndUpdateWmsTask(wmsTskTaskMd, emptyBin, inBinMd, locRouteMd);
  127. if (row > 0)
  128. {
  129. OperateResultInfo resultInfo = JsonHelper.ToObject<OperateResultInfo>(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus
  130. {
  131. TaskNo = wmsTskTaskMd.TaskNo,
  132. TrayCode = wmsTskTaskMd.TrayCode,
  133. OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户
  134. PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘入库执行中,
  135. })));
  136. if (resultInfo.Status == OperateStatus.Success)
  137. {
  138. return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"输送线任务完成反馈处理成功!--{resultInfo.Message}" };
  139. }
  140. else
  141. {
  142. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" };
  143. }
  144. }
  145. else
  146. {
  147. return new DispUntilityReturnMd { IsSuccess = true, RetMsg = "输送线任务完成反馈处理失败!生成下一步堆垛机指令错误!修改WMS大任务数据错误!!" };
  148. }
  149. }
  150. else if (taskResponseLoc.LocTypeCode == "GeneralLoc" || taskResponseLoc.LocTypeCode == "OnLineLoc")
  151. {
  152. // ToDo:20201215 孙亚龙
  153. //大任务到达出库分拣口。
  154. int row = TaskResponse_Dal.Instance.UpdateWmsTaskToTargetLoc(wmsTskTaskMd);
  155. if (row > 0)
  156. {
  157. OperateResultInfo resultInfo = JsonHelper.ToObject<OperateResultInfo>(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus
  158. {
  159. TaskNo = wmsTskTaskMd.TaskNo,
  160. TrayCode = wmsTskTaskMd.TrayCode,
  161. OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户
  162. PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘出库到目标,
  163. })));
  164. if (resultInfo.Status == OperateStatus.Success)
  165. {
  166. return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"输送线任务完成反馈处理成功!--{resultInfo.Message}" };
  167. }
  168. else
  169. {
  170. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" };
  171. }
  172. }
  173. else
  174. {
  175. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = "输送线任务完成反馈处理失败!修改WMS大任务状态为托盘到目标错误!!" };
  176. }
  177. }
  178. else
  179. {
  180. // ToDo:20201215 孙亚龙
  181. // 由于目前的项目没有那么多站台类型,因此其它站台类型的代码暂时不添加。
  182. // 后续项目使用到的话,再根据业务类型添加代码。
  183. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"输送线任务反馈暂时未收录该类型站台的反馈业务,请联系管理员或程序设计者!{GetRetMsg(taskResponseMd)}" };
  184. }
  185. }
  186. private BasWcsLocMd GetOutLocMd()
  187. {
  188. List<BasWcsLocMd> locMdLst = BasCommon_Biz.Instance.allWcsLocList.FindAll(x => x.LocTypeCode == "OnLineAndGeneralLoc" || x.LocTypeCode == "GeneralLoc");
  189. Dictionary<BasWcsLocMd, bool> tranLocHaveGoodsDic = new Dictionary<BasWcsLocMd, bool>();
  190. for (int i = 0; i < locMdLst.Count; i++)
  191. {
  192. BasWcsDevMd basWcsTranDevMd = BasCommon_Biz.Instance.basWcsDevMdList.FirstOrDefault(x => x.DevCode == locMdLst[i].LocExtMsg);
  193. if (GetTranHaveGoodsStatus(basWcsTranDevMd))
  194. {
  195. tranLocHaveGoodsDic.Add(locMdLst[i], true);
  196. }
  197. else
  198. {
  199. tranLocHaveGoodsDic.Add(locMdLst[i], false);
  200. }
  201. }
  202. List<BasWcsLocMd> tmpLocFalseLst = tranLocHaveGoodsDic.Where(x => x.Value == false).Select(x => x.Key).ToList();
  203. if (tmpLocFalseLst.Count == 1)
  204. {
  205. return tmpLocFalseLst[0];
  206. }
  207. else if (tmpLocFalseLst.Count < 1)
  208. {
  209. Random tmpRd = new Random();
  210. int retIndex = tmpRd.Next(0, locMdLst.Count);
  211. return locMdLst[retIndex];
  212. }
  213. else
  214. {
  215. Random tmpRd = new Random();
  216. int retIndex = tmpRd.Next(0, tmpLocFalseLst.Count);
  217. return tmpLocFalseLst[retIndex];
  218. }
  219. }
  220. private bool GetTranHaveGoodsStatus(BasWcsDevMd basWcsTranDevMd)
  221. {
  222. WcsOpcItemMd tmpFrontHaveGoodsFlagOpcItem = BasCommon_Biz.Instance.allOpcItemList.FirstOrDefault(x => x.DevCode == basWcsTranDevMd.DevCode && x.PlcCode == basWcsTranDevMd.DevPlcNo && x.OpcItemCode == "FrontHaveGoodsFlag");
  223. WcsOpcItemMd tmpBackEndHaveGoodsFlagOpcItem = BasCommon_Biz.Instance.allOpcItemList.FirstOrDefault(x => x.DevCode == basWcsTranDevMd.DevCode && x.PlcCode == basWcsTranDevMd.DevPlcNo && x.OpcItemCode == "BackEndHaveGoodsFlag");
  224. return Convert.ToBoolean(tmpFrontHaveGoodsFlagOpcItem.OpcItemValue) || Convert.ToBoolean(tmpBackEndHaveGoodsFlagOpcItem.OpcItemValue);
  225. }
  226. private DispUntilityReturnMd CrnTaskResponseHandle(TaskResponseMd taskResponseMd)
  227. {
  228. BasWcsLocMd taskResponseLoc = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == taskResponseMd.CurrentLocNo);
  229. if (taskResponseLoc == null)
  230. {
  231. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,传入站台不是系统配置好的站台号!{GetRetMsg(taskResponseMd)}" };
  232. }
  233. WcsCrnCmdMd wcsCrnCmdMd = TaskResponse_Dal.Instance.GetFinishedWcsCrnCmdOfPalletCode(taskResponseMd.PalletCode,taskResponseMd.TrayCode);
  234. if (wcsCrnCmdMd == null)
  235. {
  236. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,传入参数无法获取完成的堆垛机指令信息!{GetRetMsg(taskResponseMd)}" };
  237. }
  238. WmsTskTaskMd wmsTskTaskMd = TaskResponse_Dal.Instance.GetUnfinishWmsTaskOfTaskNo(taskResponseMd.TaskNo.ToString());
  239. if (wmsTskTaskMd == null)
  240. {
  241. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,无法获取到未完成的WMS大任务数据!{GetRetMsg(taskResponseMd)}" };
  242. }
  243. //string trayCode = string.Empty;
  244. //if (!TaskRequest_Dal.Instance.VerifyTrayMsgAndBalanceMsg(taskResponseMd.PalletCode, out trayCode))
  245. //{
  246. // return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈完成请求参数验证错误,校验传入托盘号库存和组盘信息错误,无法进行下一步动作!{GetRetMsg(taskResponseMd)}" };
  247. //}
  248. BasBinMd eBinMd = TaskResponse_Dal.Instance.GetBinMdOfCode(wmsTskTaskMd.EbinCode);
  249. if (eBinMd.BinType == BasBinTypeEnum.存储库位 && taskResponseLoc.LocTypeCode == "RegionLoc" && wcsCrnCmdMd.CmdType == CrnCmdTypeEnum.IN)// 入库
  250. {
  251. // ToDo:20201215 孙亚龙
  252. int row = TaskResponse_Dal.Instance.UpdateWmsTaskToTargetLoc(wmsTskTaskMd);
  253. if (row > 0)
  254. {
  255. // ToDo:后续调用WMS接口,完成入库任务。
  256. OperateResultInfo resultInfo = JsonHelper.ToObject<OperateResultInfo>(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus
  257. {
  258. TaskNo = wmsTskTaskMd.TaskNo,
  259. TrayCode = wmsTskTaskMd.TrayCode,
  260. OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户
  261. PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘入库完成,
  262. })));
  263. if (resultInfo.Status == OperateStatus.Success)
  264. {
  265. return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"堆垛机任务完成反馈处理成功!--{resultInfo.Message}" };
  266. }
  267. else
  268. {
  269. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" };
  270. }
  271. }
  272. else
  273. {
  274. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = "堆垛机任务完成反馈处理失败!修改WMS大任务状态为托盘到目标错误!!" };
  275. }
  276. }
  277. else if (eBinMd.BinType == BasBinTypeEnum.出库口 && taskResponseLoc.LocTypeCode == "OutLoc" && wcsCrnCmdMd.CmdType == CrnCmdTypeEnum.OUT)// 出库
  278. {
  279. //ToDo: 后续在这里增加判断1001和1008站台空闲的逻辑。增加动态均衡分配到两个作业口。
  280. BasWcsLocMd eLocNo = GetOutLocMd();
  281. //BasWcsLocMd eLocNo = BasCommon_Biz.Instance.allWcsLocList.FirstOrDefault(x => x.LocCode == wmsTskTaskMd.ElocCode);
  282. if (eLocNo.LocCode != wmsTskTaskMd.ElocCode)
  283. {
  284. //更新WMS大任务终点位置。
  285. wmsTskTaskMd.ElocCode = eLocNo.LocCode;
  286. TaskResponse_Dal.Instance.UpdateWmsTaskElocNo(wmsTskTaskMd);
  287. }
  288. BasNextLocRouteMd locRouteMd = TaskResponse_Dal.Instance.GetRouteMsg(taskResponseLoc, eLocNo);
  289. if (locRouteMd == null)
  290. {
  291. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"任务反馈的请求参数验证错误,获取起点:【{taskResponseLoc.LocCode}】到终点:【{eLocNo.LocCode}】的路线信息发生错误!{GetRetMsg(taskResponseMd)}" };
  292. }
  293. int row = TaskResponse_Dal.Instance.InsertTranCmdAndUpdateWmsTask(wmsTskTaskMd, taskResponseLoc, eLocNo, locRouteMd);
  294. if (row > 0)
  295. {
  296. OperateResultInfo resultInfo = JsonHelper.ToObject<OperateResultInfo>(HttpRequestHelper.POST(AppConfigHelper.Get("WebApiUrl"), JsonHelper.ToJsonExt(new NoticeWmsPalletStatus
  297. {
  298. TaskNo = wmsTskTaskMd.TaskNo,
  299. TrayCode = wmsTskTaskMd.TrayCode,
  300. OperateUserId = 3,// 暂时写死,后续增加WCS管理员账户
  301. PalletCurrRunStatus = PalletTaskRunStatusEnum.托盘出库执行中,
  302. })));
  303. if (resultInfo.Status == OperateStatus.Success)
  304. {
  305. return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"堆垛机任务完成反馈处理成功!--{resultInfo.Message}" };
  306. }
  307. else
  308. {
  309. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务完成反馈处理失败!调用WMS接口发生错误。 --{resultInfo.Message}" };
  310. }
  311. }
  312. else
  313. {
  314. return new DispUntilityReturnMd { IsSuccess = true, RetMsg = "堆垛机任务完成反馈处理失败!生成下一步输送线指令错误!修改WMS大任务数据错误!!" };
  315. }
  316. }
  317. else if (eBinMd.BinType == BasBinTypeEnum.存储库位 && taskResponseLoc.LocTypeCode == "RegionLoc" && wcsCrnCmdMd.CmdType == CrnCmdTypeEnum.MOVE)
  318. {
  319. TaskResponse_Dal.Instance.UpdateMoveWmsTaskAndBalance(wmsTskTaskMd);
  320. return new DispUntilityReturnMd { IsSuccess = true, RetMsg = $"堆垛机移库指令完成,任务反馈处理成功!" };
  321. }
  322. else
  323. {
  324. return new DispUntilityReturnMd { IsSuccess = false, RetMsg = $"堆垛机任务反馈终点库位类型为入库口,不符合实际情况,请联系管理员或程序设计者,检查堆垛机指令是否生成有误!{GetRetMsg(taskResponseMd)}" };
  325. }
  326. }
  327. private string GetRetMsg(TaskResponseMd taskResponseMd)
  328. {
  329. return $"反馈传入参数 --- 托盘号:【{taskResponseMd.PalletCode}】,请求站台号:【{taskResponseMd.CurrentLocNo}】,反馈处理类型:【{taskResponseMd.TaskResponseType}】";
  330. }
  331. }
  332. }