using HH.WMS.BLL.Algorithm; using HH.WMS.BLL.Basic; using HH.WMS.BLL.Common; using HH.WMS.BLL.CoreServer; using HH.WMS.BLL.Interface; using HH.WMS.BLL.SysMgr; using HH.WMS.Common; using HH.WMS.Common.Algorithm; using HH.WMS.Common.Algorithm.Out; using HH.WMS.DAL; using HH.WMS.DAL.Basic; using HH.WMS.DAL.InStock; using HH.WMS.DAL.OutStock; using HH.WMS.Entitys; using HH.WMS.Entitys.Basic; using HH.WMS.Entitys.Common; using HH.WMS.Entitys.Entitys; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HH.WMS.BLL.OutStock { public class TN_WM_SORTING_LISTBLL : DapperBaseBLL { #region 分拣单列表 /// /// 分拣单列表 /// /// /// public List GetSortings(string key) { return CreateDAL().GetSortings(key); } #endregion #region 确认分拣 /// /// 确认分拣 /// /// /// /// public OperateResult ConfirmSorting(bool sortingPicked, bool wavePicked, string waveNo, List sortingResult, string boxNo = "") { //分拣单捡完了,根据分拣单获取库区锁定明细 //List outLockDtl = new List(); List areaQtyList = new List(); //算法策略 List lstStrate = BLLCreator.Create().GetStrateListByAreaOrStock("", "", Constants.Out) .OrderByDescending(a => a.CN_N_PRIORITY).Select(o => o.CN_S_CODE).ToList(); Log.Info("确认分拣", "lstStrate"); Log.Info("确认分拣", JsonConvert.SerializeObject(lstStrate)); if (sortingPicked) { Log.Info("确认分拣sortingResult", JsonConvert.SerializeObject(sortingResult)); var currentSorting = CreateDAL>() .GetSingleEntity(new { CN_S_SORTING_NO = sortingResult[0].CN_S_SORTING_NO }); if (currentSorting != null) { var currentSortingDtl = CreateDAL>() .GetList(new { CN_S_SORTING_NO = currentSorting.CN_S_SORTING_NO }); currentSorting.SortingDtlList = currentSortingDtl; areaQtyList = CreateDAL>().GetList(new { CN_S_ITEM_CODE = currentSortingDtl.Select(x => x.CN_S_ITEM_CODE).ToList() }); //反批分库区分配量 Log.Info("确认分拣", "BatchesAreaQty"); var result = areaQtyList.BatchesAreaQty(new List() { currentSorting }, lstStrate, true); Log.Info("确认分拣", JsonConvert.SerializeObject(result)); if (!result.Success) return result; } } //分拣结果的托盘物料关联数据 var trayItemMstList = CreateDAL>().GetList(new { CN_S_TRAY_CODE = sortingResult.Select(x => x.CN_S_TRAY_CODE).ToList(), CN_S_ITEM_CODE = sortingResult.Select(x => x.CN_S_ITEM_CODE).ToList() }); foreach (var trayItemMst in trayItemMstList) { trayItemMst.TrayItemDtlList = new List(); trayItemMst.UnpackingDtl = new List(); //属于当前托盘,当前物料的分拣明细 var currentSortingResult = sortingResult.Where(x => x.CN_S_ITEM_CODE == trayItemMst.CN_S_ITEM_CODE && x.CN_S_TRAY_CODE == trayItemMst.CN_S_TRAY_CODE); decimal qty = currentSortingResult.Sum(y => y.CN_F_QUANTITY); if (trayItemMst.CN_F_QUANTITY >= qty && trayItemMst.CN_F_ALLOC_QTY >= qty) { trayItemMst.CN_F_QUANTITY -= qty; trayItemMst.CN_F_ALLOC_QTY -= qty; Log.Info("确认分拣", "0001"); trayItemMst.TrayItemDtlList = CreateDAL>().GetList(new { CN_PARENT_GUID = trayItemMst.CN_GUID }).OrderBy(x => x.CN_S_LOT_NO).ToList(); Log.Info("确认分拣", "0002"); //空的生产批次放后面 currentSortingResult = currentSortingResult.Select(x => new { index = string.IsNullOrEmpty(x.CN_S_PRODUCTION_BATCH) ? 0 : 1, x }).OrderByDescending(y => y.index).ThenBy(z => z.x.CN_S_PRODUCTION_BATCH).Select(m => m.x); Log.Info("确认分拣", "0003"); foreach (string stegy in lstStrate) { //逐个策略进行计算 switch (stegy) { case "FirstInFirstOut": trayItemMst.TrayItemDtlList = trayItemMst.TrayItemDtlList.OrderBy(o => o.CN_S_LOT_NO).ToList(); break; case "FirstWarrantFirstOut": trayItemMst.TrayItemDtlList = trayItemMst.TrayItemDtlList.Select(x => new { index = string.IsNullOrEmpty(x.CN_S_PRODUCTION_BATCH) ? 0 : 1, x }).OrderByDescending(y => y.index).ThenBy(z => z.x.CN_S_PRODUCTION_BATCH).Select(m => m.x).ToList(); break; } } Log.Info("确认分拣", "0004"); foreach (var cs in currentSortingResult) { var csQty = cs.CN_F_QUANTITY; if (csQty == 0) continue; //箱码(箱码只扣除箱码) if (!string.IsNullOrEmpty(cs.CN_S_PACKING_UNIT)) { var existsPackingUnit = trayItemMst.TrayItemDtlList.FindAll(f => f.CN_S_PACKING_UNIT == cs.CN_S_PACKING_UNIT && (string.IsNullOrEmpty(cs.CN_S_PRODUCTION_BATCH) || cs.CN_S_PRODUCTION_BATCH == f.CN_S_PRODUCTION_BATCH)); if (!existsPackingUnit.Any()) return OperateResult.Error("托盘:" + trayItemMst.CN_S_TRAY_CODE + "中未找到包装单位为:" + cs.CN_S_PACKING_UNIT + ",物料编码:" + cs.CN_S_ITEM_CODE + ",生产批次:" + cs.CN_S_PRODUCTION_BATCH + " 的物料"); foreach (var ep in existsPackingUnit) { if (csQty == 0) break; if (ep.CN_F_QUANTITY >= csQty) { ep.CN_F_QUANTITY -= csQty; csQty = 0; } else { csQty -= ep.CN_F_QUANTITY; ep.CN_F_QUANTITY = 0; } } } else { //当前分拣的是单独包装 //可能不存在单个包装(拆包),可能存在单独包装但不够(拆包),可能单独包装都够 //先找所有为单独包装的,把没有包装单位的放前面,然后把最小个包装的放前面 trayItemMst.TrayItemDtlList = trayItemMst.TrayItemDtlList.Select(x => new { emptyPackingUnitIndex = string.IsNullOrEmpty(x.CN_S_PACKING_UNIT) ? 0 : 1, x }).OrderBy(o => o.emptyPackingUnitIndex).ThenBy(o => o.x.CN_F_PACKING_QTY).Select(s => s.x).ToList(); foreach (var tdtl in trayItemMst.TrayItemDtlList) { //需要拆包的 if (!string.IsNullOrEmpty(tdtl.CN_S_PACKING_UNIT)) { //一包装内的个数 var packingQty = !tdtl.CN_F_PACKING_QTY.HasValue || tdtl.CN_F_PACKING_QTY == 0 ? 1 : tdtl.CN_F_PACKING_QTY.Value; //有几个包装呢 decimal multiple = tdtl.CN_F_QUANTITY / packingQty; if (tdtl.CN_F_QUANTITY > csQty) { tdtl.CN_F_QUANTITY -= csQty; csQty = 0; //不止一个包装时 if (multiple > 1)//取余拆单 { int restQty = (int)tdtl.CN_F_QUANTITY / (int)packingQty; if (restQty > 0) { var restAloneQty = tdtl.CN_F_QUANTITY % packingQty; if (restAloneQty > 0) { tdtl.CN_F_QUANTITY = restQty * packingQty; //多余出来的部分创建一条新记录 var aloneDtl = tdtl.Clone() as TN_WM_B_TRAY_ITEM_DTLEntity; aloneDtl.CN_GUID = Guid.NewGuid().ToString(); aloneDtl.CN_F_QUANTITY = restAloneQty; aloneDtl.CN_F_PACKING_QTY = 0; aloneDtl.CN_S_PACKING_UNIT = ""; trayItemMst.UnpackingDtl.Add(aloneDtl); } } else//拆的只剩单个 { tdtl.CN_F_PACKING_QTY = 0; tdtl.CN_S_PACKING_UNIT = ""; } } else//直接可以拆 { tdtl.CN_F_PACKING_QTY = 0; tdtl.CN_S_PACKING_UNIT = ""; } } else//数量大于等于包装数时全部扣完 { csQty -= tdtl.CN_F_QUANTITY; tdtl.CN_F_QUANTITY = 0; } } else//不需要拆包,直接扣 { if (tdtl.CN_F_QUANTITY >= csQty) { tdtl.CN_F_QUANTITY -= csQty; csQty = 0; } else { csQty -= tdtl.CN_F_QUANTITY; tdtl.CN_F_QUANTITY = 0; } } } } if (csQty > 0) return OperateResult.Error("物料:" + cs.CN_S_ITEM_CODE + ",包装单位:" + cs.CN_S_PACKING_UNIT + "在托盘:" + cs.CN_S_TRAY_CODE + "中不足"); //Log.Info("确认分拣cs", "000401"); //foreach (var trayItemDtl in trayItemMst.TrayItemDtlList) //{ // if (csQty == 0) break; // if (trayItemDtl.CN_F_QUANTITY == 0) continue; // if (((cs.CN_F_PACKING_QTY <= 1 && trayItemDtl.CN_F_PACKING_QTY <= 1) || cs.CN_S_PACKING_UNIT == trayItemDtl.CN_S_PACKING_UNIT) && // (string.IsNullOrEmpty(cs.CN_S_PRODUCTION_BATCH) || cs.CN_S_PRODUCTION_BATCH == trayItemDtl.CN_S_PRODUCTION_BATCH) // //&& // //(string.IsNullOrEmpty(cs.CN_S_LOT_NO) || cs.CN_S_LOT_NO // //.Equals(trayItemDtl.CN_S_LOT_NO)) // ) // { // if (trayItemDtl.CN_F_QUANTITY >= csQty) // { // trayItemDtl.CN_F_QUANTITY -= csQty; // //如果扣的当前是包,并且拣货不是按包来拣,拆包! // if (trayItemDtl.CN_F_PACKING_QTY > 1 && // cs.CN_F_PACKING_QTY > 1 && // (cs.CN_F_PACKING_QTY != trayItemDtl.CN_F_PACKING_QTY)) // { // trayItemDtl.CN_F_PACKING_QTY = 1; // trayItemDtl.CN_S_PACKING_UNIT = cs.CN_S_MEASURE_UNIT; // } // csQty = 0; // } // else // { // csQty -= trayItemDtl.CN_F_QUANTITY; // trayItemDtl.CN_F_QUANTITY = 0; // } // } //} } } } var currentTrayLocation = CreateDAL>().GetSingleEntity(new { CN_S_TRAY_CODE = sortingResult[0].CN_S_TRAY_CODE }); Log.Info("ConfirmSorting 分拣结果的托盘物料关联数据", JsonConvert.SerializeObject(trayItemMstList)); Log.Info("确认分拣", "UseTransaction start"); var operateResult = UseTransaction(trans => { Log.Info("ConfirmSorting ", "确认分拣开始-------------------------------------------------------"); //保存分拣结果 CreateDAL>().AddRange(sortingResult, trans); Log.Info("ConfirmSorting ", "保存分拣结果完成"); //下降托盘物料数据量 Log.Info("ConfirmSorting 下降托盘物料数据量数据:trayItemMstList", JsonConvert.SerializeObject(trayItemMstList)); Log.Info("ConfirmSorting 下降托盘物料数据量数据:currentTrayLocation", JsonConvert.SerializeObject(currentTrayLocation)); CreateDAL().DropTrayItemQty(trayItemMstList, currentTrayLocation, trans); //是否有拆包新增的数据 foreach (var m in trayItemMstList) { if (m.UnpackingDtl.Any()) CreateDapperDAL().AddRange(m.UnpackingDtl, trans); } Log.Info("ConfirmSorting ", "下降托盘物料数据量"); //分拣单全部捡完置为已分拣 if (sortingPicked) { CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_SORTING_NO = sortingResult[0].CN_S_SORTING_NO }, trans); Log.Info("ConfirmSorting ", "分拣单全部捡完置为已分拣"); if (areaQtyList.Any()) { Log.Info("ConfirmSorting ", "降库存"); Log.Info("ConfirmSorting 降库存数据", JsonConvert.SerializeObject(areaQtyList)); CreateDAL().UpdateAreaQtyAndAlloc(areaQtyList, trans); Log.Info("ConfirmSorting ", "降库存完成"); } //降库存 //if (outLockDtl.Any()) //{ // //CreateDAL().UpdateAllocQtyByLock(Constants.Rule_SortingNo, outLockDtl, trans); // Log.Info("ConfirmSorting ", "降库存"); // CreateDAL().DeleteOutLock(outLockDtl, trans); // Log.Info("ConfirmSorting ", "删除锁定明细"); //} } //波次捡完置为已分拣 if (wavePicked) { CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_WAVE_NO = waveNo }, trans); Log.Info("ConfirmSorting ", "波次捡完置为已分拣"); //出库单状态,已分拣 CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_WAVE_CODE = waveNo }, trans); } if (!string.IsNullOrEmpty(boxNo)) { //容器绑定 CreateDAL>().Update(new { CN_S_SORTING_CODE = sortingResult[0].CN_S_SORTING_NO, CN_S_STATE = Constants.TrayState_InUse }, new { CN_S_TRAY_CODE = boxNo }, trans); Log.Info("ConfirmSorting ", "容器绑定"); } Log.Info("ConfirmSorting ", "确认分拣完成-------------------------------------------------------"); }); if (operateResult.Success && currentTrayLocation != null) { var currentTrayItemMst = CreateDAL>().GetList(new { CN_S_TRAY_CODE = currentTrayLocation.CN_S_TRAY_CODE }); if (!currentTrayItemMst.Any()) { operateResult = UseTransaction(trans => { CreateDAL().ClearLocationByTrayCode(currentTrayLocation, trans); }); } } return operateResult; } #endregion public void SavePickData(SavePickEntity entity, IDbTransaction trans) { //保存分拣结果 CreateDAL>().AddRange(entity.SortingResult, trans); Log.Info("SavePickData ", "保存分拣结果完成"); //更新分拣明细已拣数量 if (entity.SortingLocation != null) { entity.SortingLocation.ForEach(e => { CreateDapperDAL().Update(new { CN_F_PICKED_QTY = e.CN_F_QUANTITY }, new { CN_GUID = e.CN_GUID }, trans); }); } //下降托盘物料数据量 Log.Info("SavePickData 下降托盘物料数据量数据:trayItemMstList", JsonConvert.SerializeObject(entity.TrayItemList)); Log.Info("SavePickData 下降托盘物料数据量数据:currentTrayLocation", JsonConvert.SerializeObject(entity.TrayLocation)); CreateDAL().DropTrayItemQty(entity.TrayItemList, entity.TrayLocation, trans); Log.Info("SavePickData ", "下降托盘物料数据量"); //分拣单全部捡完置为已分拣 if (entity.SortingPicked) { CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_SORTING_NO = entity.SortingNo }, trans); Log.Info("SavePickData ", "分拣单全部捡完置为已分拣"); //分拣单全部拣完,降库区库存 if (entity.AreaQtyList.Any()) { Log.Info("SavePickData ", "降库存"); Log.Info("SavePickData 降库存数据", JsonConvert.SerializeObject(entity.AreaQtyList)); CreateDAL().UpdateAreaQtyAndAlloc(entity.AreaQtyList, trans); Log.Info("SavePickData ", "降库存完成"); } } //波次捡完置为已分拣 if (entity.WavePicked) { CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_WAVE_NO = entity.WaveNo }, trans); Log.Info("SavePickData ", "波次捡完置为已分拣"); //出库单状态,已分拣 CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_WAVE_CODE = entity.WaveNo }, trans); } if (!string.IsNullOrEmpty(entity.BoxNo)) { //容器绑定 CreateDAL>().Update(new { CN_S_SORTING_CODE = entity.SortingNo, CN_S_STATE = Constants.TrayState_InUse }, new { CN_S_TRAY_CODE = entity.BoxNo }, trans); Log.Info("SavePickData ", "容器绑定"); } } #region (PDA汇聚)保存边拣边播 /// /// (PDA汇聚)保存边拣边播 /// /// public OperateResult SaveBJBB(SavePickEntity entity) { Log.Info("保存边拣边播", "UseTransaction start"); var operateResult = UseTransaction(trans => { Log.Info("保存边拣边播", "保存边拣边播开始--------------------------------------------------------"); //保存订单拣货明细 CreateDAL>().AddRange(entity.OrderSortingRel, trans); Log.Info("SaveBJBB ", "保存订单拣货完成"); //保存拣货信息 SavePickData(entity, trans); Log.Info("保存边拣边播", "保存边拣边播结束--------------------------------------------------------"); }); #region 非自动库才会全部捡完才会解绑托盘和货位关系 var currentArea = CreateDAL().GetStockAreaEntity(entity.CurrentSorting.CN_S_STOCK_AREA); //非自动库才会全部捡完才会解绑托盘和货位关系 if (currentArea != null && currentArea.CN_C_IS_AUTO != Constants.Y && operateResult.Success && entity.TrayLocation != null) { var currentTrayItemMst = CreateDAL>().GetList(new { CN_S_TRAY_CODE = entity.TrayLocation.CN_S_TRAY_CODE }); if (!currentTrayItemMst.Any()) { operateResult = UseTransaction(trans => { CreateDAL().ClearLocationByTrayCode(entity.TrayLocation, trans); }); } } #endregion return operateResult; } #endregion public OperateResult SaveXJHB(SavePickEntity entity) { Log.Info("保存先拣后播", "UseTransaction start"); var operateResult = UseTransaction(trans => { Log.Info("保存先拣后播", "保存先拣后播开始--------------------------------------------------------"); //保存拣货信息 SavePickData(entity, trans); Log.Info("保存边拣边播", "保存先拣后播结束--------------------------------------------------------"); }); #region 非自动库才会全部捡完才会解绑托盘和货位关系 var currentArea = CreateDAL().GetStockAreaEntity(entity.CurrentSorting.CN_S_STOCK_AREA); //非自动库才会全部捡完才会解绑托盘和货位关系 if (currentArea != null && currentArea.CN_C_IS_AUTO != Constants.Y && operateResult.Success && entity.TrayLocation != null) { var currentTrayItemMst = CreateDAL>().GetList(new { CN_S_TRAY_CODE = entity.TrayLocation.CN_S_TRAY_CODE }); if (!currentTrayItemMst.Any()) { operateResult = UseTransaction(trans => { CreateDAL().ClearLocationByTrayCode(entity.TrayLocation, trans); }); } } #endregion return operateResult; } #region (PDA汇聚)分拣入 /// /// (PDA汇聚)分拣回和搬运 /// /// /// public OperateResult Transport(TN_WM_TASKEntity taskEntity) { return UseTransaction(trans => { CreateDAL>().Add(taskEntity, trans); CreateDAL>().Update(new { CN_S_LOCATION_STATE = Constants.Location_State_InLock }, new { taskEntity.CN_S_END_BIT }, trans); var sendAms = BLLCreator.Create().SendAmsTask(taskEntity); if (!sendAms.Success) throw new Exception(sendAms.Msg); }); } #endregion #region 执行分拣单 /// /// 执行分拣单 /// /// /// public OperateResult ExecuteSorting(TN_WM_SORTING_LISTEntity sortingEntity, List trayItem = null) { return UseTransaction(trans => { //分拣单设为分拣中 CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Being }, new { CN_S_SORTING_NO = sortingEntity.CN_S_SORTING_NO }, trans); //分拣单子表设为分拣中 CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Being }, new { CN_S_SORTING_NO = sortingEntity.CN_S_SORTING_NO }, trans); //波次设为分拣中 CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Being }, new { CN_S_WAVE_NO = sortingEntity.CN_S_FROM_NO }, trans); //出库单分拣中 CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Being }, new { CN_S_WAVE_CODE = sortingEntity.CN_S_FROM_NO }, trans); //生成分拣单明细 //if (sortingEntity.SortingLocationList != null) // CreateDAL>().AddRange(sortingEntity.SortingLocationList, trans); //托盘物料分配量上升 //if (trayItem != null) // CreateDAL().UpdateTrayItemAllocQty(trayItem, trans); //生成任务 if (sortingEntity.Tasks.Any()) { //增加出库任务 CreateDAL>().AddRange(sortingEntity.Tasks, trans); //起点置为预出库锁定,终点预入库锁定 foreach (var task in sortingEntity.Tasks) { CreateDAL>().Update(new { CN_S_LOCATION_STATE = Constants.Location_State_OutLock }, new { CN_S_LOCATION_CODE = task.CN_S_START_BIT }, trans); //存在终点 if (!string.IsNullOrEmpty(task.CN_S_END_BIT)) { CreateDAL>().Update(new { CN_S_LOCATION_STATE = Constants.Location_State_InLock }, new { CN_S_LOCATION_CODE = task.CN_S_END_BIT }, trans); //发送ams任务 var sendAms = BLLCreator.Create().SendAmsTask(task); if (!sendAms.Success) throw new Exception(sendAms.Msg); } } } }); } #endregion #region 合箱 /// /// 合箱 /// /// /// /// public OperateResult MergeBox(List sortingResult, bool sortingPicked, bool wavePicked, string waveNo) { return UseTransaction(trans => { //分拣结果绑定周转箱 CreateDAL().MergeBox(sortingResult, trans); if (sortingPicked) //分拣单设为已分拣 CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_SORTING_NO = sortingResult[0].CN_S_SORTING_NO }, trans); //波次捡完置为已分拣 if (wavePicked) CreateDAL>().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_WAVE_NO = waveNo }, trans); }); } #endregion #region 根据托盘获取分拣中的分拣单数据 /// /// 根据托盘获取分拣中的分拣单数据 /// /// /// public List GetPickDataByTray(string trayCode) { //分拣单 var sortings = CreateDAL().GetPickSortingByTray(trayCode); if (!sortings.Any()) return null; //分拣单子表 var sortingDtls = CreateDAL>().GetList(new { CN_S_SORTING_NO = sortings.Select(s => s.CN_S_SORTING_NO).ToList() }); //分拣明细 var sortingLocations = CreateDAL>().GetList(new { CN_S_SORTING_NO = sortings.Select(s => s.CN_S_SORTING_NO).ToList() }); //分拣结果 var sortingResults = CreateDAL>().GetList(new { CN_S_SORTING_NO = sortings.Select(s => s.CN_S_SORTING_NO).ToList() }); //赋值 sortings.ForEach(e => { e.SortingDtlList = sortingDtls.Where(w => w.CN_S_SORTING_NO == e.CN_S_SORTING_NO).ToList(); e.SortingLocationList = sortingLocations.Where(w => w.CN_S_SORTING_NO == e.CN_S_SORTING_NO).ToList(); e.SortingResultList = sortingResults.Where(w => w.CN_S_SORTING_NO == e.CN_S_SORTING_NO).ToList(); }); return sortings; } #endregion #region (cs端)先拣后播扫物料 /// /// (cs端)先拣后播扫物料 /// /// /// public OperateResult ScanItem(SavePickEntity entity) { var operateResult = UseTransaction(trans => { //保存分拣结果 CreateDAL>().AddRange(entity.SortingResult, trans); //下降托盘物料数据量 Log.Info("ScanItem 下降托盘物料数据量数据:trayItemMstList", JsonConvert.SerializeObject(entity.TrayItemList)); Log.Info("ScanItem 下降托盘物料数据量数据:currentTrayLocation", JsonConvert.SerializeObject(entity.TrayLocation)); CreateDAL().DropTrayItemQty(entity.TrayItemList, entity.TrayLocation, trans); Log.Info("ScanItem ", "下降托盘物料数据量"); }); #region 非自动库才会全部捡完才会解绑托盘和货位关系 var currentArea = CreateDAL().GetStockAreaEntity(entity.CurrentSorting.CN_S_STOCK_AREA); //非自动库才会全部捡完才会解绑托盘和货位关系 if (currentArea != null && currentArea.CN_C_IS_AUTO != Constants.Y && operateResult.Success && entity.TrayLocation != null) { var currentTrayItemMst = CreateDAL>().GetList(new { CN_S_TRAY_CODE = entity.TrayLocation.CN_S_TRAY_CODE }); if (!currentTrayItemMst.Any()) { operateResult = UseTransaction(trans => { CreateDAL().ClearLocationByTrayCode(entity.TrayLocation, trans); }); } } #endregion return operateResult; } #endregion #region (cs端)先拣后播扫周转箱 /// /// (cs端)先拣后播扫周转箱 /// /// /// public OperateResult ScanTurnoverBox(SavePickEntity entity) { return UseTransaction(trans => { //分拣单全部捡完 if (entity.SortingPicked) { //修改分拣单状态为已分拣 CreateDapperDAL().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_SORTING_NO = entity.SortingNo }, trans); //波次值为已分拣 if (entity.WavePicked) { CreateDapperDAL().Update(new { CN_S_STATE = Constants.Sorting_Sorted }, new { CN_S_WAVE_NO = entity.CurrentSorting.CN_S_FROM_NO }, trans); } //外销时 if (entity.IsWx) { //出库订单,减少库存业务表状态置为 “预出库”状态 CreateDapperDAL().Update(new { CN_S_STATE = Constants.State_PreOut }, new { CN_S_OP_NO = entity.OutMst.CN_S_OP_NO }, trans); CreateDapperDAL().Update(new { CN_S_STATE = Constants.State_PreOut }, new { CN_S_OP_NO = entity.OutMst.CN_S_OP_NO }, trans); CreateDapperDAL().Update(new { CN_S_STATE = Constants.State_PreOut }, new { CN_S_FROM_NO = entity.OutMst.CN_S_OP_NO }, trans); } } //合箱 foreach (var s in entity.SortingResult) { CreateDapperDAL().Update(new { CN_S_TURNOVERBOX_CODE = entity.BoxNo }, new { CN_GUID = s.CN_GUID }, trans); } //设置容器状态绑定 CreateDapperDAL().Update(new { CN_S_STATE = Constants.TrayState_InUse, CN_S_SORTING_CODE = entity.SortingNo }, new { CN_S_TRAY_CODE = entity.BoxNo }, trans); //设置分拣单周转箱位置 CreateDapperDAL().Update(new { CN_S_COLLECT_LOCATION = entity.EndBit }, new { CN_S_SORTING_CODE = entity.SortingNo }, trans); //当前位置预出库锁定 CreateDapperDAL().Update(new { CN_S_LOCATION_STATE = Constants.Location_State_OutLock }, new { CN_S_LOCATION_CODE = entity.StartBit }, trans); //终点位置与入库锁定 CreateDapperDAL().Update(new { CN_S_LOCATION_STATE = Constants.Location_State_InLock }, new { CN_S_LOCATION_CODE = entity.EndBit }, trans); }); } #endregion #region 获取任务 /// /// 获取任务 /// /// /// /// public OperateResult GetOutTask(ref TN_WM_SORTING_LISTEntity sortingEntity, ref List endAreas, string endArea = "", string endBit = "") { try { //当前分拣单库区 var currentArea = BLLCreator.Create().GetArea(sortingEntity.CN_S_STOCK_AREA); if (currentArea == null) return OperateResult.Error("未找到库区:" + sortingEntity.CN_S_STOCK_AREA); //托盘货位分组 var trayGroup = sortingEntity.SortingLocationList.GroupBy(g => new { g.CN_S_SORTING_NO, g.CN_S_TRAY_CODE, g.CN_S_LOCATION_CODE }).Select(s => new { s.Key.CN_S_SORTING_NO, s.Key.CN_S_TRAY_CODE, s.Key.CN_S_LOCATION_CODE, CN_F_QUANTITY = s.Sum(m => m.CN_F_QUANTITY) }); List taskList = new List(); //存在非整托货位托盘 var pickTrays = trayGroup .Select(e => new TN_WM_SORTING_LOCATIONEntity() { CN_S_SORTING_NO = e.CN_S_SORTING_NO, CN_S_TRAY_CODE = e.CN_S_TRAY_CODE, CN_S_LOCATION_CODE = e.CN_S_LOCATION_CODE, }).ToList(); if (pickTrays.Any()) { #region 根据终点货位生成任务 if (string.IsNullOrEmpty(endArea)) { //有终点货位,直接找库区 if (!string.IsNullOrEmpty(endBit)) { var locationEntity = CreateDAL().GetLocationModel(endBit); if (locationEntity == null) return OperateResult.Error("未找到货位:" + endBit); endArea = locationEntity.CN_S_AREA_CODE; } else { //非整托任务 WorkflowEntity workflowEntity = new WorkflowEntity(Constants.Workflow_Out) { CirObj = Constants.Tray, StartArea = currentArea.CN_S_AREA_CODE, ReturnList = true }; //找站点 GetWorkPosition var trayWorkflow = BLLCreator.Create().GetWorkPosition(workflowEntity); if (!trayWorkflow.Success) return trayWorkflow; var workAreaPro = trayWorkflow.GetData>(); endAreas.AddRange(workAreaPro.Select(s => s.CN_S_END_AREA_CODE).ToList()); endArea = workAreaPro[0].CN_S_END_AREA_CODE; } } else { endAreas.Add(endArea); } #endregion #region 根据终点库区生成任务 if (string.IsNullOrEmpty(endBit)) { //存在任务调度策略时,不生成货位,通过服务去生成 var taskDispatch = GetStrategy(sortingEntity.CN_S_STOCK_CODE, StrategyKey.TaskDispatch); if (taskDispatch != Constants.Y) { //需要调作业区入库算法,算出货位给出库任务 var inAssignEntity = new InAssignEntity { objectType = InAssignEntity.ObjectType.托盘, objectCode = pickTrays[0].CN_S_TRAY_CODE, lockLocation = false, lstAreaPrior = new List() { { new areaPriorClass{ areaCode = endArea, Prior = 1 } } } }; Log.Info("调用算法InAssign参数", JsonConvert.SerializeObject(inAssignEntity)); InAssignResultEntity inAssignResultEntity = BLLCreator.Create().InAssign(inAssignEntity); Log.Info("调用算法InAssign结果", JsonConvert.SerializeObject(inAssignResultEntity)); if (!inAssignResultEntity.Success) return OperateResult.Error(inAssignResultEntity.Msg); endBit = inAssignResultEntity.locationCode; } } #endregion //分拣出库任务 var pickTasks = GetTaskEntity(sortingEntity.CN_S_STOCK_AREA, endArea, pickTrays, endBit); taskList.AddRange(pickTasks); } sortingEntity.Tasks = taskList; sortingEntity.EndBits = endAreas; return OperateResult.Succeed(null, taskList); } catch (Exception ex) { return OperateResult.Error(ex.Message); } } #endregion #region 获取任务实体 /// /// 获取任务实体 /// /// /// /// private List GetTaskEntity(string startArea, string endArea, List sortingLocations, string endBit = "") { var trayLocationGroup = sortingLocations.GroupBy(g => new { g.CN_S_TRAY_CODE, g.CN_S_LOCATION_CODE, g.CN_S_SORTING_NO }).Select(s => new { s.Key.CN_S_TRAY_CODE, s.Key.CN_S_LOCATION_CODE, s.Key.CN_S_SORTING_NO }); List taskList = new List(); foreach (var task in trayLocationGroup) { string postData = "{\"appCode\":\"" + Constants.appCode + "\",\"ruleName\":\"" + Constants.Rule_OutTaskNo + "\",\"orgId\":\"\",\"orgFlag\":\"\"}"; string taskNo = WebApiManager.HttpAutoBom_Post("api/BillRule/GenBillNo", postData); AutoBomStockAreaEntity startAreaE = CreateDAL().GetStockAreaEntity(startArea); AutoBomStockAreaEntity endAreaE = CreateDAL().GetStockAreaEntity(endArea); TN_WM_TASKEntity taskEntity = new TN_WM_TASKEntity() { CN_S_TASK_NO = taskNo, CN_S_TASK_TYPE = Constants.TaskType_SortingOut, CN_S_FROM_OP = Constants.Out, CN_S_FROM_NO = task.CN_S_SORTING_NO, CN_S_TRAY_CODE = task.CN_S_TRAY_CODE, CN_S_STOCK_CODE = BLLCreator.Create().GetArea(endArea).CN_S_STOCK_CODE, CN_S_START_AREA = startArea, CN_S_START_BIT = task.CN_S_LOCATION_CODE, CN_S_END_AREA = endArea, CN_S_END_BIT = endBit, CN_S_STATE = Constants.TaskState_NoExecuted, CN_T_CREATE = DateTime.Now, CN_T_MODIFY = DateTime.Now, CN_S_START_AREA_TYPE = startAreaE.CN_S_STRUCTURE, CN_S_END_AREA_TYPE = endAreaE.CN_S_STRUCTURE, CN_C_START_IS_CONTROL_QTY = startAreaE.CN_C_IS_CONTROL_QTY, CN_C_END_IS_CONTROL_QTY = endAreaE.CN_C_IS_CONTROL_QTY, CN_S_START_CONTROL_INV = startAreaE.CN_C_IS_INVENTORY, CN_S_END_CONTROL_INV = endAreaE.CN_C_IS_INVENTORY, EndAreaEntity = endAreaE }; taskList.Add(taskEntity); } return taskList; } #endregion #region 出库单获取分拣明细 /// /// 出库单获取分拣明细 /// /// /// public List GetTrayLocationByOut(string outNo) { return CreateDAL().GetTrayLocationByOut(outNo); } #endregion #region 批分托盘物料关联(不含三生拆包部分) /// /// 批分托盘物料关联(不含三生拆包部分) /// /// /// public List BatchesTrayItemByResult(List sortingResult) { //算法策略 List lstStrate = BLLCreator.Create().GetStrateListByAreaOrStock("", "", Constants.Out) .OrderByDescending(a => a.CN_N_PRIORITY).Select(o => o.CN_S_CODE).ToList(); //分拣结果的托盘物料关联数据 var trayItemMstList = BLLCreator.CreateDapper().GetList(new { CN_S_TRAY_CODE = sortingResult.Select(x => x.CN_S_TRAY_CODE).ToList(), CN_S_ITEM_CODE = sortingResult.Select(x => x.CN_S_ITEM_CODE).ToList() }); foreach (var trayItemMst in trayItemMstList) { trayItemMst.TrayItemDtlList = new List(); //属于当前托盘,当前物料的分拣明细 var currentSortingResult = sortingResult.Where(x => x.CN_S_ITEM_CODE == trayItemMst.CN_S_ITEM_CODE && x.CN_S_TRAY_CODE == trayItemMst.CN_S_TRAY_CODE); decimal qty = currentSortingResult.Sum(y => y.CN_F_QUANTITY); if (trayItemMst.CN_F_QUANTITY >= qty && trayItemMst.CN_F_ALLOC_QTY >= qty) { trayItemMst.CN_F_QUANTITY -= qty; trayItemMst.CN_F_ALLOC_QTY -= qty; Log.Info("确认分拣", "0001"); trayItemMst.TrayItemDtlList = BLLCreator.CreateDapper().GetList(new { CN_PARENT_GUID = trayItemMst.CN_GUID }).OrderBy(x => x.CN_S_LOT_NO).ToList(); Log.Info("确认分拣", "0002"); //空的生产批次放后面 currentSortingResult = currentSortingResult.Select(x => new { index = string.IsNullOrEmpty(x.CN_S_PRODUCTION_BATCH) ? 0 : 1, x }).OrderByDescending(y => y.index).ThenBy(z => z.x.CN_S_PRODUCTION_BATCH).Select(m => m.x); Log.Info("确认分拣", "0003"); foreach (string stegy in lstStrate) { //逐个策略进行计算 switch (stegy) { case "FirstInFirstOut": trayItemMst.TrayItemDtlList = trayItemMst.TrayItemDtlList.OrderBy(o => o.CN_S_LOT_NO).ToList(); break; case "FirstWarrantFirstOut": trayItemMst.TrayItemDtlList = trayItemMst.TrayItemDtlList.Select(x => new { index = string.IsNullOrEmpty(x.CN_S_PRODUCTION_BATCH) ? 0 : 1, x }).OrderByDescending(y => y.index).ThenBy(z => z.x.CN_S_PRODUCTION_BATCH).Select(m => m.x).ToList(); break; } } Log.Info("确认分拣", "0004"); foreach (var cs in currentSortingResult) { var csQty = cs.CN_F_QUANTITY; foreach (var trayItemDtl in trayItemMst.TrayItemDtlList) { if (csQty == 0) break; if (trayItemDtl.CN_F_QUANTITY == 0) continue; if (trayItemDtl.CN_F_QUANTITY >= csQty) { trayItemDtl.CN_F_QUANTITY -= csQty; csQty = 0; } else { csQty -= trayItemDtl.CN_F_QUANTITY; trayItemDtl.CN_F_QUANTITY = 0; } } } } } return trayItemMstList; } #endregion #region 根据库区算法结果生成分拣单数据 /// /// 根据库区算法结果生成分拣单数据 /// /// /// /// /// public OperateResult GetSortingData(List outAreaResultList, UserRuleEntity user, string waveNo, string taskEndBit = "") { try { List sortingList = new List(); user.RuleCode = Constants.SortingGroup; //分拣单组别 string sortingGroup = user.GenerateNo(); user.RuleCode = Constants.SortingNo; int sortingIndex = 1; IEnumerable> igOutAreaResult = outAreaResultList.GroupBy(x => new { x.stockCode, x.areaCode }); foreach (var _igOutAreaResult in igOutAreaResult) { //分拣单 TN_WM_SORTING_LISTEntity sortingEntity = new TN_WM_SORTING_LISTEntity() { CN_GUID = Guid.NewGuid().ToString(), CN_S_SORTING_NO = waveNo + "-" + sortingIndex++, CN_S_OP_FROM = Constants.Rule_WaveNo, CN_S_FROM_NO = waveNo, CN_T_OPERATE = DateTime.Now.ToString(),// "", //丢里咯木 CN_S_STOCK_CODE = _igOutAreaResult.Key.stockCode, CN_S_STOCK_AREA = _igOutAreaResult.Key.areaCode, CN_S_STATE = Constants.Sorting_Stay, CN_S_SEEDING_MODE = "", CN_S_GROUP = sortingGroup, CN_S_CREATOR = user.LoginCode, CN_S_CREATOR_BY = user.LoginName, CN_T_CREATE = DateTime.Now, CN_S_MODIFY = user.LoginCode, CN_S_MODIFY_BY = user.LoginName, CN_T_MODIFY = DateTime.Now }; //分拣单子表行索引 int sortingDtlindex = 1; //分拣单子表 sortingEntity.SortingDtlList = new List(); //分拣明细 sortingEntity.SortingLocationList = new List(); foreach (var outArea in _igOutAreaResult.AsEnumerable()) { foreach (var d in outArea.lstItem) { //物料详细 AutoBomItemEntity item = BLLCreator.Create().GetItem(d.itemCode) ?? new AutoBomItemEntity(); //分拣单子行 TN_WM_SORTING_DTLEntity sortingDtlEntity = new TN_WM_SORTING_DTLEntity() { CN_GUID = Guid.NewGuid().ToString(), CN_S_SORTING_NO = sortingEntity.CN_S_SORTING_NO, CN_N_ROW_NO = sortingDtlindex++, CN_F_QUANTITY = d.itemQty, CN_S_ITEM_CODE = d.itemCode, CN_S_ITEM_NAME = item.CN_S_ITEM_NAME, CN_S_STATE = Constants.Sorting_Stay, CN_S_LOT_NO = outArea.batchCode, CN_S_PRODUCTION_BATCH = outArea.prodBatchCode, CN_S_ITEM_STATE = outArea.itemState, CN_S_OWNER = outArea.ownerName, CN_S_MODEL = item.CN_S_MODEL, CN_S_FIGURE_NO = item.CN_S_FIGURE_NO, CN_S_MEASURE_UNIT = item.CN_S_MEASURE_UNIT }; sortingEntity.SortingDtlList.Add(sortingDtlEntity); } } #region 生成分拣明细 //调用算法获取分拣明细,分拣明细改到执行分拣单的时候生成 var sortingLocationResult = BLLCreator.Create().GetSortingLocation(sortingEntity, user); if (!sortingLocationResult.Success) return sortingLocationResult; var sortingLocations = sortingLocationResult.GetData>(); sortingEntity.SortingLocationList.AddRange(sortingLocations); #endregion #region 自动库需要生成出库任务 //生成任务 //List endAreas = new List(); //var outTaskResult = GetOutTask(ref sortingEntity, ref endAreas, taskEndBit); //if (!outTaskResult.Success) //{ // return outTaskResult; //} #endregion sortingList.Add(sortingEntity); } return OperateResult.Succeed(null, sortingList); } catch (Exception ex) { return OperateResult.Error(ex.Message); } } #endregion #region 调算法获取分拣明细 /// ///调算法获取分拣明细 /// /// /// /// public OperateResult GetSortingLocation(TN_WM_SORTING_LISTEntity sortingEntity, UserRuleEntity user) { try { List sortingLocationList = new List(); if (!sortingEntity.SortingDtlList.Any()) sortingEntity.SortingDtlList = BLLCreator.CreateDapper().GetList(new { CN_S_SORTING_NO = sortingEntity.CN_S_SORTING_NO }); //初始化调用算法数据 List algorItems = sortingEntity.SortingDtlList.GroupBy(x => new { x.CN_S_ITEM_CODE, x.CN_S_ITEM_STATE, x.CN_S_OWNER, x.CN_S_LOT_NO, x.CN_S_PRODUCTION_BATCH }).Select(y => new itemQueryClass() { stockCode = sortingEntity.CN_S_STOCK_CODE, areaCode = sortingEntity.CN_S_STOCK_AREA, itemCode = y.Key.CN_S_ITEM_CODE, batchCode = y.Key.CN_S_LOT_NO, prodBatchCode = y.Key.CN_S_PRODUCTION_BATCH, itemState = y.Key.CN_S_ITEM_STATE, ownerName = y.Key.CN_S_OWNER, itemQty = y.Sum(z => z.CN_F_QUANTITY) }).ToList(); var lstAreaPrior = algorItems.Select(x => new areaPriorClass() { areaCode = x.areaCode, Prior = 1 }).ToList(); Log.Info("调用OutNew参数 algorItems", JsonConvert.SerializeObject(algorItems)); var outResult = BLLCreator.Create().OutNew(new OutAlgorEnitty() { lstDevice = new List(), lstAreaPrior = lstAreaPrior, lstQueryItem = algorItems, lockLocation = false }); Log.Info("调用OutNew返回值 outResult", JsonConvert.SerializeObject(outResult)); if (outResult.lstItemNotEnough.Any()) { outResult.lstItemNotEnough.ForEach(x => { var currentNotEnough = sortingEntity.SortingDtlList.Find(s => s.CN_S_ITEM_CODE.Equals(x.itemCode)); if (currentNotEnough != null) x.itemName = currentNotEnough.CN_S_ITEM_NAME; }); return OperateResult.Warning("物料:" + string.Join(";", outResult.lstItemNotEnough.Select(x => x.itemCode)) + "库存不足,请先完成来料区的上架", outResult.lstItemNotEnough); } if (!outResult.Success) return OperateResult.Error("算法异常:" + outResult.Msg); if (sortingEntity.SortingDtlList.Sum(x => x.CN_F_QUANTITY) != Convert.ToDecimal(outResult.itemLocations.Sum(x => x.itemQty))) { return OperateResult.Error("算法异常:返回的物料信息不完整!"); } var locations = outResult.itemLocations.Select(m => { AutoBomItemEntity mm = CreateDAL().GetItemEntity(m.itemCode) ?? new AutoBomItemEntity(); return new TN_WM_SORTING_LOCATIONEntity() { CN_GUID = Guid.NewGuid().ToString(), CN_S_LOT_NO = m.batchCode, CN_S_ITEM_STATE = m.itemState, CN_S_OWNER = m.ownerName, CN_F_QUANTITY = m.itemQty, CN_F_PICKED_QTY = 0, CN_S_ITEM_CODE = m.itemCode, CN_S_LOCATION_CODE = m.locationCode, CN_S_TRAY_CODE = m.trayCode, CN_S_TRAY_GRID = m.trayGrid, CN_S_SORTING_NO = sortingEntity.CN_S_SORTING_NO, CN_S_STATE = sortingEntity.CN_S_STATE, CN_S_ORDER_NO = "", CN_S_CREATOR = user.LoginCode, CN_S_CREATOR_BY = user.LoginName, CN_S_ITEM_NAME = mm.CN_S_ITEM_NAME, CN_S_MODEL = mm.CN_S_MODEL, CN_S_FIGURE_NO = mm.CN_S_FIGURE_NO, CN_S_MEASURE_UNIT = mm.CN_S_MEASURE_UNIT, CN_S_PACKING_UNIT = m.packUnit, CN_F_PACKING_QTY = m.packQty, CN_S_PRODUCTION_BATCH = m.prodBatchCode, CN_T_CREATE = DateTime.Now, CN_T_MODIFY = DateTime.Now }; }).ToList(); sortingLocationList.AddRange(locations); return OperateResult.Succeed(null, sortingLocationList); } catch (Exception ex) { return OperateResult.Error(ex.Message); } } #endregion } }