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 });
}
}
}