using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using WMS.Core._02Entity; using WMS.Core.ServiceCore; using WMS.Info; using WMS.Util; namespace WMS.Core.APPBLL { public class TaskBLL : AppCoreBLL { /// /// 发送待下发任务 /// /// /// public ResInfo SendPreExecuteTasks(ETaskComType type, int num) { using (var ctx = SysDbCore.GetDbCtx()) { try { ctx.BeginTran(); IEnumerable tasks; tasks = ctx.Queryable().Where(task => task.F_priority == (int)EPriority.Urgent && (task.F_taskStatus == (int)ETaskStatus.NotIssued || task.F_taskStatus == (int)ETaskStatus.NotExecute || task.F_taskStatus == (int)ETaskStatus.Executing)).ToList(); if (tasks.Any(a => a.F_taskStatus == (int)ETaskStatus.NotIssued)) { tasks = tasks.Where(a => a.F_taskStatus == (int)ETaskStatus.NotIssued); } else if (tasks.Any(a => a.F_taskStatus == (int)ETaskStatus.NotExecute || a.F_taskStatus == (int)ETaskStatus.Executing)) { return SysExCore.GetResSucc(); //有优先任务则不下发其他任务 } else { tasks = ctx.Queryable().Where(t => t.F_taskStatus == (int)ETaskStatus.NotIssued && t.F_taskType == (int)type).Take(num).ToList(); } foreach (var task in tasks) { //如果当前拣选口有任务则不下发当前拣选口任务 if (ctx.Queryable().Any(a => a.F_pickPort == task.F_pickPort && (a.F_taskStatus == (int)ETaskStatus.Executing || a.F_taskStatus == (int)ETaskStatus.NotExecute))) continue; switch ((ETaskOrderType)System.Enum.Parse(typeof(ETaskOrderType), task.F_orderType.ToString())) { //入库绑定托盘后添加库存,此处只需更新货位状态 case ETaskOrderType.EntryOrderTypeMaterial: case ETaskOrderType.EntryOrderTypeOther: case ETaskOrderType.EntryOrderTypeProduct: case ETaskOrderType.EntryOrderTypeTrayGroup: #region 入库任务更新 ctx.Updateable().SetColumns(it => new BILL_ENTRYORDER() { F_editTime = DateTime.Now, F_editUserNo = "AutoTask", F_orderStatus = (int)EOrderState.Executing }).Where(w => w.F_no == task.F_posidTo).ExecuteCommand(); #endregion break; //出库需要扣减库存并更新货位和单据状态 case ETaskOrderType.StockOutOrderTypeEmptyTrayGroup: case ETaskOrderType.StockOutOrderTypeMaterial: case ETaskOrderType.StockOutOrderTypeProduct: case ETaskOrderType.StockOutOrderTypeOther: #region 出库任务更新 ctx.Updateable().SetColumns(it => new BILL_STOCKOUT() { F_editTime = DateTime.Now, F_editUserNo = "AutoTask", F_orderStatus = (int)EOrderState.Executing, }).Where(w => w.F_no == task.F_posidFrom).ExecuteCommand(); #endregion break; case ETaskOrderType.CheckEntryOrderType: #region 盘点入库 ctx.Updateable().SetColumns(it => new BILL_InventoryReport { F_editTime = DateTime.Now, F_editUserNo = "AutoTask", F_checkStatus = (int)ECheckStatus.Checking }); #endregion break; case ETaskOrderType.CheckStockOutOrderType: break; default: break; } PolicyHelper.GetRetryTimesPolicy(3, ex => { task.F_taskStatus = (int)ETaskStatus.TaskFail; task.F_wcsExecuteTime = DateTime.Now; task.F_wcsExecuteResult = ex.Message; }).Execute(() => { SetProperties(task); var res = httpClinet.Post(task.ToJson(), "/api/Task/I_WMS_CreateTasks"); if (res == null || !res.isSuccess) throw SysExCore.ThrowFailException($"调用wcs接口失败{res?.msg}!"); else task.F_taskStatus = (int)ETaskStatus.NotExecute; }); ctx.Updateable().SetColumns(it => new WMS_TASK() { F_taskStatus = task.F_taskStatus }).Where(it => it.F_taskNo == task.F_taskNo).ExecuteCommand(); } ctx.CommitTran(); return SysExCore.GetResSucc("执行成功!"); } catch (Exception e) { ctx.RollbackTran(); throw e; } } } /// /// 创建wms任务 /// /// /// public ResInfo CreateTask(WMS_TASK newTask) { using (var ctx = SysDbCore.GetDbCtx()) { var task = ctx.Insertable(newTask).ExecuteReturnEntity(); return SysExCore.GetResSucc("执行成功!", task); } } public ResInfo GetStockOutTasks(TaskQueryRequest request) { using (var ctx = SysDbCore.GetDbCtx()) { var tasks = ctx.SqlQueryable(@"SELECT s.F_no OrderNo, s.F_orderType OrderType, s.F_orderStatus Status, l.F_matNo MatNo, l.F_matName MatName, SUM(l.F_planQty) PlanQty, s.F_ADDTIME AddTime FROM dbo.BILL_STOCKOUT s JOIN dbo.BILL_STOCKOUTLINE l ON s.F_no = l.F_pNo WHERE s.F_orderStatus<4 GROUP BY s.F_no, s.F_orderType, s.F_orderStatus, l.F_matNo, l.F_matName, s.F_ADDTIME").ToList(); if (!string.IsNullOrWhiteSpace(request.StockOutType)) tasks = tasks.FindAll(t => t.OrderType == (EStockOutOrderType)Enum.Parse(typeof(EStockOutOrderType), request.StockOutType)); if (!string.IsNullOrWhiteSpace(request.KeyWord)) tasks = tasks.FindAll(t => t.OrderNo.Contains(request.KeyWord)); var list = tasks.Skip((request.pagination.page - 1) * request.pagination.rows).Take(request.pagination.rows).ToList(); request.pagination.records = tasks.Count; return SysExCore.GetResSucc("查询成功", data: new { list = list, pageInfo = request.pagination }); } } /// /// 创建出库单任务 /// /// /// public ResInfo CreateTaskByStockOut(TaskExecuteRequest taskExecute) { using (var ctx = SysDbCore.GetDbCtx()) { try { ctx.BeginTran(); var orderLines = new FxStockOutOrderCore().GeSockOutOrderItem(taskExecute.OrderNo); foreach (var item in orderLines) { var stockDetail = ctx.Queryable().Where(c => c.F_pNo == item.F_pNo && c.F_matNo == item.F_matNo).ToList(); var tasks = new List(); //var needQty = item.F_planQty - item.F_actualQty; //var db = ctx.Queryable((ord, loc) => new object[] { JoinType.Inner, ord.F_trayNo == loc.F_trayNo, ord.F_no }) // .Where((ord, loc) => ord.F_matNo == item.F_matNo && ord.F_matType == item.F_matType && loc.F_status == (int)EWareCellState.Out); //var matInventory = db.OrderBy((ord, loc) => new { loc.F_line, loc.F_cell, ord.F_editTime, ord.F_addTime }).Select().ToList(); //if (matInventory.Sum(s => s.F_quantity) < needQty) // throw SysExCore.ThrowFailException($"物料编码:{item.F_matNo}库存不够!"); foreach (var detail in stockDetail) { tasks.Add(new WMS_TASK { F_addTime = DateTime.Now, F_addUserNo = LoginUser.UserNo, F_editTime = DateTime.Now, F_orderNo = taskExecute.OrderNo, F_orderType = taskExecute.OrderType, F_posidcur = detail.F_locationNo, F_posidFrom = detail.F_locationNo, F_pickPort = AllotPickPort(stockDetail.IndexOf(detail) % 2 == 1, taskExecute.PickPort), F_posidTo = AllotPickPort(stockDetail.IndexOf(detail) % 2 == 1, taskExecute.PickPort), F_priority = (int)EPriority.NotUrgent, F_taskStatus = (int)ETaskStatus.NotIssued, F_taskType = taskExecute.OrderType, F_trayNo = detail.F_trayNo, F_posidNext = AllotPickPort(stockDetail.IndexOf(detail) % 2 == 1, taskExecute.PickPort), F_EquipmentType = (int)EEquipmentType.Convey }); ctx.Updateable().SetColumns(it => new BASE_LOCATION() { F_addTime = DateTime.Now, F_editUserNo = LoginUser.UserNo, F_status = (int)EWareCellState.Out, }).Where(w => w.F_no == detail.F_locationNo).ExecuteCommand(); } ctx.Saveable(tasks).ExecuteReturnList(); } ctx.Updateable().SetColumns(it => new BILL_STOCKOUT { F_editTime = DateTime.Now, F_editUserNo = LoginUser.UserNo, F_orderStatus = (int)EOrderState.Executing }); ctx.CommitTran(); return SysExCore.GetResSucc("出库任务生成成功"); } catch (Exception) { ctx.RollbackTran(); throw; } } } /// /// 多个拣选口平均分配 /// /// /// /// private string AllotPickPort(bool IsBaseNumber, List PickPorts) { if (PickPorts.Count > 1) { return IsBaseNumber ? PickPorts[1] : PickPorts[0]; } return PickPorts[0]; } /// /// 更新货位高度并分配货位 /// /// /// public ResInfo AllotLocation(AllotLocationRequest reqData) { using (var ctx = SysDbCore.GetDbCtx()) { try { ctx.BeginTran(); //根据托盘获取当前入库任务 var order = ctx.Queryable((ord, detail) => new object[] { JoinType.Inner, ord.F_no == detail.F_pNo }) .Where((ord, detail) => detail.F_trayNo == reqData.TrayNo).Select().First(); if (order == null) throw SysExCore.ThrowFailException($"获取托盘{reqData.TrayNo}入库单明细失败!"); order.F_matHeight = reqData.Height; var assignLoc = ctx.Queryable().First(f => f.F_trayNo == reqData.TrayNo && f.F_status == (int)EWareCellState.In); if (order.F_matHeight > 0 && assignLoc != null) { return SysExCore.GetResSucc("该托盘已分配货位!", assignLoc); } ctx.Updateable().SetColumns(it => new BILL_ENTRYORDER() { F_matHeight = reqData.Height }).Where(it => it.F_no == order.F_no).ExecuteCommand(); if (!reqData.Layer.Any()) { reqData.Layer = ctx.Queryable().GroupBy(g => g.F_layer).Select(s => s.F_layer).ToList(); } //string layerSqlStr = string.Join(",", reqData.Layer); //var disLayer = ctx.SqlQueryable($@"SELECT TOP 1 * FROM V_DISLOCATION WHERE F_matType={order.F_orderType} and F_layer in({layerSqlStr}) ORDER BY cnt,F_layer").First(); //var loc = ctx.Queryable().Where(w => w.F_layer == disLayer.F_layer && w.F_height >= reqData.Height&& w.F_status== (int)EWareCellState.Empty).OrderBy("F_layer ASC, F_line DESC,F_cell asc").First(); //if (loc == null)//立库第一次使用可能会为null 默认分配第一层 var loc = ctx.Queryable().Where(w => w.F_height >= reqData.Height && w.F_isDelete == 0 && w.F_status == (int)EWareCellState.Empty).WhereIF(reqData.Layer.Any(), w => reqData.Layer.Contains(w.F_layer)).OrderBy("F_layer ASC, F_line DESC,F_cell asc").First(); if (loc == null) throw SysExCore.ThrowFailException($"没有可分配的货位!"); ctx.Updateable().SetColumns(it => new BASE_LOCATION() { F_editTime = DateTime.Now, F_editUserNo = "wcs", F_matHeight = reqData.Height, F_trayNo = order.F_trayNo, F_matType = order.F_orderType == (int)EEntryOrderType.EntryOrderTypeMaterial ? (int)EMatType.Mat : order.F_orderType == (int)EEntryOrderType.EntryOrderTypeProduct ? (int)EMatType.Product : (int)EMatType.Tary, F_status = (int)EWareCellState.In, F_isBonded = order.F_isBonded }).Where(it => it.F_no == loc.F_no).ExecuteCommand(); ctx.Updateable().SetColumns(it => new WMS_TASK() { F_editTime = DateTime.Now, F_posidTo = loc.F_no }).Where(w => w.F_trayNo == reqData.TrayNo && w.F_taskStatus < (int)ETaskStatus.TaskFinish).ExecuteCommand(); ctx.BeginTran(); return SysExCore.GetResSucc("高度更新成功并成功分配货位!", loc); } catch (Exception) { ctx.RollbackTran(); throw; } } } /// /// wcs回传更新 /// /// /// public ResInfo Callback(WcsCallBackRequest reqData, LoginUserInfo userInfo) { try { using (var ctx = SysDbCore.GetDbCtx()) { var task = ctx.Queryable().First(c => c.F_taskNo == reqData.TaskNo); if (task == null) throw SysExCore.ThrowFailException($"任务号{reqData.TaskNo}无效"); if (task.F_taskStatus == (int)ETaskStatus.TaskFinish || task.F_taskStatus == (int)ETaskStatus.TaskManualFinish) return SysExCore.GetResSucc("任务已回传,请勿重复回传!"); List lstInv = new List(); if (reqData.State == 1) { #region 开始执行 ctx.Updateable().SetColumns(it => new WMS_TASK() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_taskStatus = (int)ETaskStatus.Executing }).Where(w => w.F_taskNo == task.F_taskNo).ExecuteCommand(); if (ctx.Queryable().Any(c => c.F_agv == task.F_posidFrom && c.F_status == (int)EPointSatus.Occupied)) { ctx.Updateable().SetColumns(it => new BASE_POINT() { F_status = (int)EPointSatus.Idle }).Where(w => w.F_agv == task.F_posidFrom).ExecuteCommand(); } if (!string.IsNullOrWhiteSpace(task.F_orderNo) && task.F_taskType == (int)ETaskComType.InStock) { ctx.Updateable().SetColumns(it => new BILL_ENTRYORDER() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_orderStatus = (int)EOrderState.Executing }).Where(w => w.F_no == task.F_orderNo).ExecuteCommand(); } if (!string.IsNullOrWhiteSpace(task.F_orderNo) && task.F_taskType == (int)ETaskComType.OutStock) { ctx.Updateable().SetColumns(it => new BILL_STOCKOUT() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_orderStatus = (int)EOrderState.Executing, }).Where(w => w.F_no == task.F_orderNo).ExecuteCommand(); } #endregion } else { #region 执行结束 switch ((ETaskOrderType)System.Enum.Parse(typeof(ETaskOrderType), task.F_orderType.ToString())) { //入库绑定托盘后添加库存,此处只需更新货位状态 case ETaskOrderType.EntryOrderTypeMaterial: case ETaskOrderType.EntryOrderTypeProduct: case ETaskOrderType.EntryOrderTypeTrayGroup: #region 入库任务更新 ctx.Updateable().SetColumns(it => new BASE_LOCATION() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_status = (int)EWareCellState.Stored, F_trayNo = task.F_trayNo }).Where(w => w.F_no == task.F_posidTo).ExecuteCommand(); ctx.Updateable().SetColumns(it => new BILL_ENTRYORDER() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_orderStatus = (int)EOrderState.Executed }).Where(w => w.F_no == task.F_orderNo).ExecuteCommand(); #endregion break; //出库需要扣减库存并更新货位和单据状态 case ETaskOrderType.StockOutOrderTypeEmptyTrayGroup: case ETaskOrderType.StockOutOrderTypeMaterial: case ETaskOrderType.StockOutOrderTypeProduct: case ETaskOrderType.StockOutOrderTypeTray: case ETaskOrderType.StockOutOrderTypeTransfer: #region 出库任务更新 if (ctx.Queryable().Any(a => a.F_no == task.F_posidTo && (a.F_type == (int)EPointType.CPCKJXK || a.F_type == (int)EPointType.YLCKJXK))) { } else { var stockOutDetail = ctx.Queryable((ord, detail) => new object[] { JoinType.Inner, ord.F_no == detail.F_pNo }).Where(ord => ord.F_no == task.F_orderNo).Select().ToList(); foreach (var orderDetail in stockOutDetail) { var point = ctx.Queryable().First(f => f.F_no == task.F_posidTo); if (point.F_type == (int)EPointType.ZPKCK)//整盘口出库需要扣减库存 { var line = ctx.Queryable().First(f => f.F_matNo == orderDetail.F_matNo && f.F_pNo == orderDetail.F_pNo); lstInv.Add(new BILL_INVENTORY { F_matNo = orderDetail.F_matNo, F_matName = orderDetail.F_matName, F_matType = orderDetail.F_matType, F_boxNo = orderDetail.F_boxNo, F_trayNo = orderDetail.F_trayNo, F_quantity = -1 * orderDetail.F_quantity, }); ctx.Updateable().SetColumns(it => new BILL_STOCKOUTLINE() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_actualQty = line.F_actualQty + orderDetail.F_quantity, }).Where(w => w.F_rowNo == line.F_rowNo).ExecuteCommand(); } //ctx.Updateable().SetColumns(it => new BASE_LOCATION() //{ // F_editTime = DateTime.Now, // F_editUserNo = userInfo.UserNo, // F_status = (int)EWareCellState.Empty, // F_trayNo = string.Empty, // F_matHeight = default, // F_matType = default //}).Where(w => w.F_no == task.F_posidTo).ExecuteCommand(); } ctx.Updateable().SetColumns(it => new BILL_STOCKOUT() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_orderStatus = (int)EOrderState.Executed, }).Where(w => w.F_no == task.F_orderNo).ExecuteCommand(); } ctx.Updateable().SetColumns(it => new BASE_LOCATION() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_status = (int)EWareCellState.Empty, F_trayNo = string.Empty, F_matType = default, F_matHeight = default }).Where(w => w.F_no == task.F_posidFrom).ExecuteCommand(); #endregion break; case ETaskOrderType.StockOutOrderTypeHalfTray: ctx.Updateable().SetColumns(it => new BASE_LOCATION() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_status = (int)EWareCellState.Out, //F_trayNo = string.Empty, //F_matType = default, F_matHeight = default }).Where(w => w.F_no == task.F_posidFrom).ExecuteCommand(); break; case ETaskOrderType.CheckEntryOrderType: #region 盘点入库 ctx.Updateable().SetColumns(it => new BASE_LOCATION() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_status = (int)EWareCellState.Stored }).Where(w => w.F_no == task.F_posidTo).ExecuteCommand(); int checkStatus = default; if (!ctx.Queryable().Any(c => c.F_pNo == task.F_orderNo && c.F_actualQty != c.F_quantity && c.F_actualQty > 0)) { checkStatus = (int)ECheckStatus.Checkfinish; RedisCache.Remove("CheckInventory", ERedisCacheNo.System); } else { checkStatus = (int)ECheckStatus.Checking; } ctx.Updateable().SetColumns(it => new BILL_InventoryReport { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_checkStatus = checkStatus }); #endregion break; case ETaskOrderType.CheckStockOutOrderType: #region 盘点出库 var checkDetail = ctx.Queryable((ord, detail) => new object[] { JoinType.Inner, ord.F_no == detail.F_pNo }).Where(ord => ord.F_no == task.F_orderNo).Select().ToList(); foreach (var orderDetail in checkDetail) { var line = ctx.Queryable().First(f => f.F_matNo == orderDetail.F_matNo && f.F_pNo == orderDetail.F_pNo); lstInv.Add(new BILL_INVENTORY { F_matNo = orderDetail.F_matNo, F_matName = orderDetail.F_matName, F_matType = orderDetail.F_matType, F_boxNo = orderDetail.F_boxNo, F_trayNo = orderDetail.F_trayNo, }); } #endregion break; ///agv搬运、空托盘入库无需更新单据 case ETaskOrderType.StockOutOrderTypeOther: case ETaskOrderType.EntryOrderTypeTray: case ETaskOrderType.EntryOrderTypeOther: //ctx.Updateable().SetColumns(it => new BASE_POINT() //{ // F_editTime = DateTime.Now, // F_editUserNo = userInfo.UserNo, // F_status = (int)EPointSatus.Occupied, //}).Where(w => w.F_no == task.F_posidTo).ExecuteCommand(); break; default: break; } //更新库存 UpdateInventory(lstInv, ctx); ctx.Updateable().SetColumns(it => new WMS_TASK() { F_editTime = DateTime.Now, F_editUserNo = userInfo.UserNo, F_taskStatus = (int)ETaskStatus.TaskFinish }).Where(w => w.F_taskNo == task.F_taskNo).ExecuteCommand(); #endregion } ctx.CommitTran(); } return SysExCore.GetResSucc("回传成功!"); } catch (Exception) { throw; } } /// /// 初始化对象 /// /// /// /// /// public void SetProperties(T t) { var properties = t.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); if (properties == null) { return; } foreach (var item in properties) { var ts = item.GetValue(t, null); if (ts == null) { if (item.PropertyType.FullName.Contains("DateTime")) { item.SetValue(t, null); } else { item.SetValue(t, ""); } } } } } }