using HH.Redis.ReisModel; using HH.WMS.BLL; using HH.WMS.BLL.Algorithm; using HH.WMS.BLL.External; using HH.WMS.BLL.InStock; using HH.WMS.BLL.MoveStock; using HH.WMS.BLL.SysMgr; using HH.WMS.Common; using HH.WMS.Common.Algorithm; using HH.WMS.Common.External; using HH.WMS.Common.Para; using HH.WMS.DAL; using HH.WMS.DAL.Basic; using HH.WMS.DAL.InStock; using HH.WMS.Entitys; using HH.WMS.Entitys.Basic; using HH.WMS.Entitys.Entitys; using HH.WMS.Entitys.External; using HH.WMS.Entitys.MoveStock; using HH.WMS.TaskService.Dto; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace HH.WMS.TaskService.Jobs { /// /// 移库 /// public class MoveStockJob { private readonly LockDto _lockDto = new LockDto { IsLock = false }; public void Run() { var logPara = LogType.LogPara("移库任务"); if (_lockDto.IsLock) { Log.Detail(logPara, "当前移库任务正在被锁定,还存在未执行结束的任务:" + _lockDto.TaskNo); return; } var moveStockJobDto = new MoveStockJobPara(); try { HandleMoveStock(ref moveStockJobDto, logPara); if (!moveStockJobDto.BasisResponse.Success) RollbackTask(ref moveStockJobDto, logPara); } catch (Exception ex) { Log.Detail(logPara, "异常:" + ex.Message); RollbackTask(ref moveStockJobDto, logPara); } _lockDto.Unlock(); } private void HandleMoveStock(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { GetMoveStockTask(ref moveStockJobDto, logPara); if (!moveStockJobDto.BasisResponse.Success) { moveStockJobDto.Normal(); return; } CalculateStartBit(ref moveStockJobDto, logPara); if (!moveStockJobDto.BasisResponse.Success) return; MoveOutLocation(ref moveStockJobDto, logPara); if (!moveStockJobDto.BasisResponse.Success) return; CalculateEndBit(ref moveStockJobDto, logPara); if (!moveStockJobDto.BasisResponse.Success) return; MoveLocation(ref moveStockJobDto, logPara); if (!moveStockJobDto.BasisResponse.Success) return; } //获取移库管理中未执行的数据,只取一条,且将状态变为执行中 private void GetMoveStockTask(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { moveStockJobDto.MoveStockMst = BLLCreator.Create().GetMst(); if (moveStockJobDto.MoveStockMst == null) { Log.Detail(logPara, "当前没有需要执行的移库任务!"); moveStockJobDto.Error("当前没有需要执行的移库任务!", logPara); return; } if (moveStockJobDto.MoveStockMst.CN_F_QUANTITY <= (moveStockJobDto.MoveStockMst.CN_F_MOVE_QUANTITY + moveStockJobDto.MoveStockMst.CN_F_ALLOC_QUANTITY)) { //BLLCreator.Create().UpdateMstState(moveStockJobDto.MoveStockMst.CN_GUID, "完成", null, logPara); moveStockJobDto.Error("移库任务已完成!",logPara); return; } //检查当前起始库区、结束库区没有未执行、执行中的任务 var taskList = BLLCreator.Create().GetTaskByAreaCode(moveStockJobDto.MoveStockMst.CN_S_START_AREA); if (taskList.Any()) { moveStockJobDto.Error("当前库区:" + moveStockJobDto.MoveStockMst.CN_S_START_AREA + " 存在未完成的任务:" + LogDescribe.Content(taskList), logPara); return; } BLLCreator.Create().UpdateMstState(moveStockJobDto.MoveStockMst.CN_GUID, "执行中", null, logPara); _lockDto.Lock(moveStockJobDto.MoveStockMst.CN_GUID); } //计算起点货位 private void CalculateStartBit(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { List lstArea = new List(); areaPriorClass areaClass = new areaPriorClass(); areaClass.areaCode = moveStockJobDto.MoveStockMst.CN_S_START_AREA; areaClass.Prior = 1; lstArea.Add(areaClass); //调用入库算法,获取货位 OutAssignEnitty oAe = new OutAssignEnitty() { projectCode = "ys001", lstAreaPrior = lstArea, stockCode = moveStockJobDto.MoveStockMst.CN_S_STOCK_CODE, itemCode = moveStockJobDto.MoveStockMst.CN_S_ITEM_CODE, traySpec = "", itemQty = moveStockJobDto.MoveStockMst.CN_F_QUANTITY, lockLocation = true,//是否需要锁定货位 lotNo = moveStockJobDto.MoveStockMst.CN_S_LOT_NO }; Log.Detail(logPara, "移库起点货位算法,参数为:" + JsonConvert.SerializeObject(oAe)); OutAssignResultEntity oaEresult = BLLCreator.Create().OutAssign(oAe); Log.Detail(logPara, "移库起点货位算法,结果为:" + JsonConvert.SerializeObject(oaEresult)); if (!oaEresult.Success) { if (oaEresult.Msg.Contains("库存不足") || oaEresult.Msg.Contains("货位不足")) moveStockJobDto.MoveStockMst.CN_S_STATE = "完成"; moveStockJobDto.Error("移库起点货位计算失败!" + oaEresult.Msg, logPara); return; } moveStockJobDto.StartLocation = oaEresult.locationCode; moveStockJobDto.TrayCode = oaEresult.trayCode; } //移动货位(移出同排同列外面的货位) private void MoveOutLocation(ref MoveStockJobPara moveStockJobPara, LogPara logPara) { var msg = ""; //获取当前货位所在列外面有几个满货位 var locationExt = BLLCreator.Create>().GetSingleEntity(new { CN_S_LOCATION_CODE = moveStockJobPara.StartLocation }); if (locationExt == null) { moveStockJobPara.Error("当前算法计算的起始货位码不正确,未在货位扩展表中找到数据!", logPara); return; } Log.Detail(logPara, "当前货位信息:" + LogDescribe.Content(locationExt)); var curFloor = Convert.ToInt32(locationExt.CN_S_FLOOR); var locations = BLLCreator.Create>().GetList(new { CN_S_COL = locationExt.CN_S_COL, CN_S_ROW = locationExt.CN_S_ROW }).Where(w => Convert.ToInt32(w.CN_S_FLOOR) > curFloor).OrderByDescending(e => e.CN_S_FLOOR); Log.Detail(logPara, "同排同列且在当前货位外层的货位集合," + LogDescribe.Content(locations.ToList())); var startLocations = new List(); var endLocations = new List(); var trayCodes = new List(); var isAllow = true; if (!locations.Any()) { Log.Detail(logPara, "当前货位的外层没有阻碍!"); moveStockJobPara.Normal(); return; } foreach (var location in locations) { if (isAllow) { if (Convert.ToInt32(location.CN_S_FLOOR) > curFloor) { if (location.CN_S_USE_STATE.Equals("满") && location.CN_S_LOCATION_STATE.Equals("正常")) { startLocations.Add(location.CN_S_LOCATION_CODE); var trayLocation = BLLCreator.Create>().GetSingleEntity(new { CN_S_LOCATION_CODE = location.CN_S_LOCATION_CODE }); Log.Detail(logPara, LogDescribe.Content(trayLocation)); if (trayLocation == null) { isAllow = false; } else { trayCodes.Add(trayLocation.CN_S_TRAY_CODE); } //调用入库算法,获取空货位 List lstTmpArea = new List(); lstTmpArea.Add(new areaPriorClass { areaCode = location.CN_S_AREA_CODE.Trim(), Prior = 1 }); InAssignEntity iAe = new InAssignEntity() { lstAreaPrior = lstTmpArea, logicAreaCode = "", objectCode = trayLocation.CN_S_TRAY_CODE, projectCode = "ys001", lockLocation = true //是否需要锁定货位 }; iAe.lstDevice = null; Log.Detail(logPara, "调用入库算法参数:" + JsonConvert.SerializeObject(iAe)); InAssignResultEntity irEresult = BLLCreator.Create().InAssign(iAe); Log.Detail(logPara, "调用入库算法结果:" + (irEresult.Success ? "成功" : ("失败," + irEresult.Msg)) + ",计算的货位:" + irEresult.locationCode); if (!irEresult.Success) { isAllow = false; msg = irEresult.Msg; } else { endLocations.Add(irEresult.locationCode); } } } } } //调用入库算法 if (isAllow) { if (startLocations.Count > 0) { List inWorkAreaEntitys = new List(); for (int i = 0; i < startLocations.Count; i++) { inWorkAreaEntitys.Add(new InWorkAreaEntity { isTransport = "Y", startBit = startLocations[i], endBit = endLocations[i], projectCode = "ys001", trayCode = trayCodes[i], data = null, creator = moveStockJobPara.MoveStockMst.CN_S_CREATOR, creatorBy = moveStockJobPara.MoveStockMst.CN_S_CREATOR_BY }); } Log.Detail(logPara, "调用入库方法,参数:" + JsonConvert.SerializeObject(inWorkAreaEntitys)); var result = BLLCreator.Create().InWorkArea(inWorkAreaEntitys, logPara); if (!result.success) { foreach (var taskPara in inWorkAreaEntitys) { BLLCreator.Create>().Update(new { CN_S_LOCATION_STATE = "正常", CN_S_USE_STATE = "满" }, new { CN_S_LOCATION_CODE = taskPara.startBit }); BLLCreator.Create>().Update(new { CN_S_LOCATION_STATE = "正常", CN_S_USE_STATE = "空" }, new { CN_S_LOCATION_CODE = taskPara.endBit }); } Log.Detail(logPara, "执行入库方法失败!回滚所有任务,原因:" + result.errMsg + ",参数:" + JsonConvert.SerializeObject(result.okList)); msg = result.errMsg; moveStockJobPara.Error("执行入库方法失败!原因:" + result.errMsg, logPara); return; } else { moveStockJobPara.OkTasks = result.okList; //moveStockJobDto.MoveOutLocationResultData = okList; //向AMS下达任务 //var sendParamList = new List(); //var parentGuid = moveStockJobPara.MoveStockMst.CN_GUID; //result.okList.ForEach(m => { // sendParamList.Add(new TN_WM_TRANSPORT_TASKEntity // { // CN_S_TASK_NO = m.taskNo, // CN_S_START_BIT = m.startBit, // CN_S_END_BIT = m.endBit, // CN_N_PRIORITY = m.priority, // CN_S_CIR_OBJ_CODE = m.trayCode, // CN_S_PROJECT_CODE = "", // CN_T_CREATE = "" // }); // BLLCreator.Create().AddDtl(parentGuid, m.taskNo, "入库", 0, null, logPara); //}); //调用AMS,下达出库指令 //var amsResult = BLLCreator.Create().SendTask(sendParamList, "入库"); //Log.Detail(logPara, "调用AMS,下达出库指令!参数:" + LogDescribe.Content(sendParamList) + ",结果:" + (amsResult.Success ? "成功!" : ("失败," + amsResult.Exception.Message))); } } } else { if (endLocations.Any()) { //起点 //foreach (var startLocation in startLocations) //{ // //解锁被锁定的货位 CreateDAL().UpdateState(endLocation, "正常", "空", "预出库锁定", null); // BLLCreator.Create>().Update(new { CN_S_LOCATION_STATE = "正常", CN_S_USE_STATE = "满" }, new { CN_S_LOCATION_CODE = startLocation }); //} foreach (var endLocation in endLocations) { //解锁被锁定的货位 CreateDAL().UpdateState(endLocation, "正常", "空", "预出库锁定", null); BLLCreator.Create>().Update(new { CN_S_LOCATION_STATE = "正常", CN_S_USE_STATE = "空" }, new { CN_S_LOCATION_CODE = endLocation }); Log.Detail(logPara, "解锁被锁定的货位: " + endLocation + "为正常,空!"); } } moveStockJobPara.Error("不能移动货位,原因:" + msg, logPara); return; } return; } //计算终点货位 private void CalculateEndBit(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { //调用入库算法,获取空货位 List lstTmpArea = new List(); lstTmpArea.Add(new areaPriorClass { areaCode = moveStockJobDto.MoveStockMst.CN_S_END_AREA.Trim(), Prior = 1 }); InAssignEntity iAe = new InAssignEntity() { lstAreaPrior = lstTmpArea, logicAreaCode = "", objectCode = moveStockJobDto.TrayCode, projectCode = "ys001", needCalLock = false, lockLocation = false //是否需要锁定货位 }; iAe.lstDevice = null; Log.Detail(logPara, "移库的终点货位算法参数为:" + JsonConvert.SerializeObject(iAe)); InAssignResultEntity irEresult = BLLCreator.Create().InAssign(iAe); Log.Detail(logPara, "移库的终点货位算法结果为:" + JsonConvert.SerializeObject(irEresult)); if (!irEresult.Success) { moveStockJobDto.Error("移库终点货位计算失败!" + irEresult.Msg, logPara); } moveStockJobDto.EndLocation = irEresult.locationCode; } //移动货位 private void MoveLocation(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { var entity = new TrayOnShelfEntity() { CN_S_LOCATION_CODE = moveStockJobDto.EndLocation, CN_S_TRAY_CODE = moveStockJobDto.TrayCode, CN_S_END_AREA_CODE = moveStockJobDto.MoveStockMst.CN_S_END_AREA, CN_S_DEVICE_NO = moveStockJobDto.StartLocation, CN_S_TASK_TYPE = "移库" }; Log.Detail(logPara, "移动,参数为:" + JsonConvert.SerializeObject(entity)); var inResult = BLLCreator.Create().SimZTShelfMoveStock(ref moveStockJobDto, entity, new RedisUserEntity { CN_S_LOGIN = moveStockJobDto.MoveStockMst.CN_S_CREATOR, CN_S_NAME = moveStockJobDto.MoveStockMst.CN_S_CREATOR_BY }, logPara); Log.Detail(logPara, "移动,结果为:" + JsonConvert.SerializeObject(inResult)); if (!inResult.Success) { moveStockJobDto.Error("移动货位失败!原因:" + inResult.Msg, logPara); } else { //向AMS下达指令 SendToAms(ref moveStockJobDto, logPara); if (!moveStockJobDto.BasisResponse.Success) RollbackTask(ref moveStockJobDto, logPara); //增加库存分配量 AddAllocQty(ref moveStockJobDto, logPara); //BLLCreator.Create().AddMoveQty(moveStockJobDto.MoveStockMst.CN_GUID, null, logPara); //AddAllocQty(oaEresult.trayCode, saveMoveStockDto.StockCode, saveMoveStockDto.StartAreaCode, logPara); } } //增加分配量 private void AddAllocQty(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { Log.Detail(logPara, "升起始库区分配量"); var trayItemMsts = DALCreator.Create>().GetList(new { CN_S_TRAY_CODE = moveStockJobDto.TrayCode }); if (trayItemMsts != null) { if (trayItemMsts.Count > 0) { foreach (var trayItemMst in trayItemMsts) { trayItemMst.CN_F_QUANTITY = 0; trayItemMst.TrayItemDtlList = DALCreator.Create>().GetList(new { CN_PARENT_GUID = trayItemMst.CN_GUID }); Log.Detail(logPara, "库区:" + moveStockJobDto.MoveStockMst.CN_S_START_AREA + "," + LogDescribe.Content(trayItemMst)); foreach (var trayItemDtl in trayItemMst.TrayItemDtlList) { trayItemMst.CN_F_QUANTITY += Convert.ToDecimal(trayItemDtl.CN_F_PACKING_QTY); var curReuslt = DALCreator.Create().AddAllocQty(new TN_WM_B_AREA_QTYEntity { CN_F_QUANTITY = Convert.ToDecimal(trayItemDtl.CN_F_PACKING_QTY), CN_S_ITEM_CODE = trayItemMst.CN_S_ITEM_CODE, CN_S_ITEM_STATE = trayItemMst.CN_S_ITEM_STATE, CN_S_STOCK_AREA = moveStockJobDto.MoveStockMst.CN_S_START_AREA, CN_S_LOT_NO = trayItemDtl.CN_S_LOT_NO, CN_S_PRODUCTION_BATCH = trayItemMst.CN_S_PRODUCTION_BATCH }, null, logPara); Log.Detail(logPara, LogDescribe.Content(trayItemMst) + " 库区量表执行结果:" + LogDescribe.Content(curReuslt)); } } } } } private void SendToAms(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { if (moveStockJobDto.OkTasks == null) return; if (moveStockJobDto.OkTasks.Count() == 0) return; //向AMS下达任务 var sendParamList = new List(); var parentGuid = moveStockJobDto.MoveStockMst.CN_GUID; var count = moveStockJobDto.OkTasks.Count(); for (var i = 0; i < count; i++) { var m = moveStockJobDto.OkTasks[i]; if (i == (count - 1)) { var qty = DALCreator.Create().GetItemQtyByTrayCode(m.trayCode, logPara); BLLCreator.Create().AddDtl(parentGuid, m.taskNo, "移库", qty, null, logPara); } else { BLLCreator.Create().AddDtl(parentGuid, m.taskNo, "转运", 0, null, logPara); } sendParamList.Add(new TN_WM_TRANSPORT_TASKEntity { CN_S_TASK_NO = m.taskNo, CN_S_START_BIT = m.startBit, CN_S_END_BIT = m.endBit, CN_N_PRIORITY = m.priority, CN_S_CIR_OBJ_CODE = m.trayCode, CN_S_PROJECT_CODE = "", CN_T_CREATE = "", CN_S_STOCK_CODE = m.startStock }); } //调用AMS,下达出库指令 var amsResult = BLLCreator.Create().SendTask(sendParamList, "转运"); Log.Detail(logPara, "调用AMS,下达出库指令!参数:" + LogDescribe.Content(sendParamList) + ",结果:" + (amsResult.Success ? "成功!" : ("失败," + amsResult.Exception.Message))); if (!amsResult.Success) moveStockJobDto.Error(amsResult.Exception.Message, logPara); } private void AddAreaAllocQty(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { Log.Detail(logPara, "升起始库区分配量"); var trayItemMsts = DALCreator.Create>().GetList(new { CN_S_TRAY_CODE = moveStockJobDto.TrayCode }); if (trayItemMsts != null) { if (trayItemMsts.Count > 0) { foreach (var trayItemMst in trayItemMsts) { trayItemMst.CN_F_QUANTITY = 0; trayItemMst.TrayItemDtlList = DALCreator.Create>().GetList(new { CN_PARENT_GUID = trayItemMst.CN_GUID }); foreach (var trayItemDtl in trayItemMst.TrayItemDtlList) { trayItemMst.CN_F_QUANTITY += Convert.ToDecimal(trayItemDtl.CN_S_SERIAL_NO); } Log.Detail(logPara, "库区:" + moveStockJobDto.MoveStockMst.CN_S_START_AREA + "," + LogDescribe.Content(trayItemMst)); var curReuslt = DALCreator.Create().AddAllocQty(new TN_WM_B_AREA_QTYEntity { CN_F_QUANTITY = trayItemMst.CN_F_QUANTITY, CN_S_ITEM_CODE = trayItemMst.CN_S_ITEM_CODE, CN_S_ITEM_STATE = trayItemMst.CN_S_ITEM_STATE, CN_S_STOCK_AREA = moveStockJobDto.MoveStockMst.CN_S_START_AREA, CN_S_LOT_NO = trayItemMst.CN_S_LOT_NO, CN_S_PRODUCTION_BATCH = trayItemMst.CN_S_PRODUCTION_BATCH }, null, logPara); Log.Detail(logPara, LogDescribe.Content(trayItemMst) + " 库区量表执行结果:" + LogDescribe.Content(curReuslt)); } } } } //回滚 private void RollbackTask(ref MoveStockJobPara moveStockJobDto, LogPara logPara) { if (!string.IsNullOrEmpty(moveStockJobDto.StartLocation)) BLLCreator.Create>().Update(new { CN_S_LOCATION_STATE = "正常" }, new { CN_S_LOCATION_CODE = moveStockJobDto.StartLocation }); if (moveStockJobDto.OkTasks.Any()) { Log.Detail(logPara, "待回滚的任务:" + JsonConvert.SerializeObject(moveStockJobDto.OkTasks)); moveStockJobDto.OkTasks.ForEach(t => { BLLCreator.Create().ExecuteState(t.taskNo, "取消", logPara); }); } var state = moveStockJobDto.MoveStockMst.CN_S_STATE == "完成" ? "完成" : "执行失败"; BLLCreator.Create>().Update(new { CN_S_STATE = state, CN_S_RESULT = moveStockJobDto.BasisResponse.Message }, new { moveStockJobDto.MoveStockMst.CN_GUID }); } } }