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