using Mapster; using System.Collections.Generic; using WIDESEA_DTO.MOM; using WIDESEA_DTO.WMS; using WIDESEA_IStoragIntegrationServices; using WIDESEA_StoragIntegrationServices; namespace WIDESEA_StorageOutTaskServices; public class Dt_TaskService : ServiceBase, IDt_TaskService { private readonly LogFactory LogFactory = new LogFactory(); private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IDt_OutOrderRepository _outOrderRepository; private readonly IStockInfoRepository _stockInfoRepository; private readonly IDt_Task_HtyRepository _task_HtyRepository; private readonly IDt_OutOrderAndStockRepository _outOrderAndStockRepository; private readonly IDt_OutOrderAndStock_HtyRepository _outOrderAndStock_HtyRepository; private readonly IMapper _mapper; private readonly IDt_MaterielInfoRepository _materielInfoRepository; private readonly ILocationInfoRepository _locationRepository; private readonly IDt_WareAreaInfoRepository _wareAreaInfoRepository; private readonly IPointStackerRelationRepository _pointStackerRelationRepository; private readonly ITaskExecuteDetailRepository _taskExecuteDetailRepository; private readonly ILocationStatusChangeRecordRepository _locationStatusChangeRecordRepository; private readonly IBoxingInfoRepository _boxingInfoRepository; private readonly ICellStateService _cellStateService; private readonly IProcessApplyService _processApplyService; public Dt_TaskService(IDt_TaskRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IDt_OutOrderRepository outOrderRepository, IStockInfoRepository stockInfoRepository, IDt_OutOrderAndStockRepository dt_OutOrderAndStockRepository, IDt_OutOrderAndStock_HtyRepository dt_OutOrderAndStock_HtyRepository, IDt_Task_HtyRepository task_HtyRepository, IMapper mapper, IDt_MaterielInfoRepository materielInfoRepository, ILocationInfoRepository locationRepository, IDt_WareAreaInfoRepository wareAreaInfoRepository, IPointStackerRelationRepository pointStackerRelationRepository, ITaskExecuteDetailRepository taskExecuteDetailRepository, ILocationStatusChangeRecordRepository locationStatusChangeRecordRepository, IBoxingInfoRepository boxingInfoRepository, ICellStateService cellStateService, IProcessApplyService processApplyService) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _outOrderRepository = outOrderRepository; _stockInfoRepository = stockInfoRepository; _outOrderAndStockRepository = dt_OutOrderAndStockRepository; _outOrderAndStock_HtyRepository = dt_OutOrderAndStock_HtyRepository; _task_HtyRepository = task_HtyRepository; _mapper = mapper; _materielInfoRepository = materielInfoRepository; _locationRepository = locationRepository; _wareAreaInfoRepository = wareAreaInfoRepository; _pointStackerRelationRepository = pointStackerRelationRepository; _taskExecuteDetailRepository = taskExecuteDetailRepository; _locationStatusChangeRecordRepository = locationStatusChangeRecordRepository; _boxingInfoRepository = boxingInfoRepository; _cellStateService = cellStateService; _processApplyService = processApplyService } #region 外部接口方法 #region 堆垛机出库任务完成 /// /// 堆垛机出库任务完成 /// /// 任务数据合集 /// 返回结果集 public async Task CompleteStackTaskAsync(Dt_Task task, DtStockInfo stock) { WebResponseContent content = new WebResponseContent(); try { // 更新库存状态 // 设置库位状态为空闲 stock.LocationInfo.LocationStatus = LocationEnum.Free.ObjToInt(); // 设置库存状态为出库 stock.StockInfoDetails.ForEach(x => { x.Status = 2; }); // 更新任务状态 task.TaskState = TaskOutStatusEnum.SC_OutFinish.ObjToInt(); task.CurrentAddress = task.NextAddress; task.NextAddress = task.TargetAddress; LogFactory.GetLog("任务完成").InfoFormat(true, "堆垛机出库完成", "更新库存状态与任务状态"); // 事务处理 // 开始事务 _unitOfWorkManage.BeginTran(); // 更新库存信息 var isStockUpdated = _stockInfoRepository.UpdateData(stock); // 更新任务信息 var isTaskUpdated = await Update(task); // 如果库存信息和任务信息都更新成功 if (isStockUpdated && isTaskUpdated) { // 记录日志 LogFactory.GetLog("任务完成").InfoFormat(true, "堆垛机出库完成", $"事务处理完成,库存状态更新:{isStockUpdated},任务状态更新:{isTaskUpdated}"); // 提交事务 _unitOfWorkManage.CommitTran(); // 返回成功结果 return content.OK("任务完成成功"); } else { // 记录日志 LogFactory.GetLog("任务完成").InfoFormat(true, "堆垛机出库完成", $"事务处理失败,库存状态更新:{isStockUpdated},任务状态更新:{isTaskUpdated}"); // 回滚事务 _unitOfWorkManage.RollbackTran(); // 返回失败结果 return content.Error("任务或库存更新失败"); } } catch (Exception err) { LogFactory.GetLog("任务完成").InfoFormat(true, $"系统异常,异常信息:{err.Message}", ""); Console.WriteLine(err.Message); return content.Error(err.Message); } } #endregion 堆垛机出库任务完成 #region 移库任务完成 /// /// 移库任务完成 /// /// 任务数据合集 /// 返回结果集 public async Task CompleteTransferTaskAsync(Dt_Task task, DtStockInfo stock) { WebResponseContent content = new WebResponseContent(); try { // 更新货位和库存信息 (DtStockInfo updateStock, DtLocationInfo locationInf) = UpdateStockLocation(stock, task.NextAddress); var taskHty = CreateHistoricalTask(task); LogFactory.GetLog("任务完成").InfoFormat(true, "移库任务完成", $"货位地址:{task.TargetAddress},修改后库存数据:{JsonConvert.SerializeObject(updateStock)},原先货位数据:{locationInf}"); // 执行数据库事务 bool isResult = await ExecuteTransaction(updateStock, taskHty, locationInf, task.TaskId); if (isResult) content.OK("移库任务完成成功"); else content.Error("移库任务完成失败"); } catch (Exception err) { Console.WriteLine(err.Message.ToString()); } return content; } #endregion 移库任务完成 #region 入库任务完成 /// /// 入库任务完成 /// /// 任务数据合集 /// 返回结果集 public async Task CompleteInboundTaskAsync(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { var boxing = await _boxingInfoRepository.QueryFirstNavAsync(x => x.PalletCode == task.PalletCode); var boxDetail = boxing.BoxingInfoDetails.Adapt>(); // 创建库存实例模型 DtStockInfo stock = new DtStockInfo() { PalletCode = task.PalletCode, LocationCode = task.TargetAddress, CreateDate = DateTime.Now, Creater = "system", IsFull = boxing.IsFull, StockInfoDetails = boxDetail, LocationInfo = new DtLocationInfo() }; // 创建历史任务实例模型 var taskHty = CreateHistoricalTask(task); // 修改货位信息为有货 var locationInf = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.TargetAddress); locationInf.LocationStatus = (int)LocationEnum.Lock; LogFactory.GetLog("任务完成").InfoFormat(true, "入库任务完成", $"货位地址:{task.TargetAddress},修改后货位数据:{locationInf}"); // 执行数据库事务 bool isResult = await ExecuteTransaction(stock, taskHty, locationInf, task.TaskId); if (isResult) content.OK("入库任务完成成功"); else content.Error("入库任务完成失败"); } catch (Exception err) { Console.WriteLine(err.Message.ToString()); } return content; } #endregion 入库任务完成 #region 任务完成 /// /// 任务完成 /// /// 任务号 /// public async Task CompleteAsync(int taskNum) { WebResponseContent content = new WebResponseContent(); // 提取任务数据 LogFactory.GetLog("任务完成").InfoFormat(true, "提取任务数据", $"任务号:{taskNum}"); // 验证任务是否存在 var task = await GetByTaskNum(taskNum); if (task == null) { return content.Error("任务不存在"); } LogFactory.GetLog("任务完成").InfoFormat(true, "验证任务是否存在", JsonConvert.SerializeObject(task)); // 验证库存是否存在 var stock = await _stockInfoRepository.QueryFirstAsync(x => x.PalletCode == task.PalletCode); if (stock == null) { LogFactory.GetLog("任务完成").InfoFormat(true, "库存不存在存在,判断是否是入库任务", $"{task.TaskType}"); if (task.TaskType == (int)TaskTypeEnum.Inbound) { LogFactory.GetLog("任务完成").InfoFormat(true, "入库任务", ""); return await CompleteInboundTaskAsync(task); } else { LogFactory.GetLog("任务完成").InfoFormat(true, "库存不存在也不是入库任务", ""); return content.Error("库存不存在"); } } LogFactory.GetLog("任务完成").InfoFormat(true, "验证库存是否存在", JsonConvert.SerializeObject(stock)); if (task.TaskType == (int)TaskTypeEnum.Outbound) { LogFactory.GetLog("任务完成").InfoFormat(true, "出库任务", ""); if (task.TaskState == TaskOutStatusEnum.SC_OutExecuting.ObjToInt()) { LogFactory.GetLog("任务完成").InfoFormat(true, "堆垛机出库完成", ""); return await CompleteStackTaskAsync(task, stock); } else { LogFactory.GetLog("任务完成").InfoFormat(true, "库存不存在也不是入库任务", ""); return content.Error("库存不存在"); } } else if (task.TaskType == (int)TaskTypeEnum.RelocationIn) { LogFactory.GetLog("任务完成").InfoFormat(true, "移库任务完成", ""); return await CompleteTransferTaskAsync(task, stock); } else { LogFactory.GetLog("任务完成").InfoFormat(true, $"任务状态异常", "无参数"); return content.Error("任务状态异常"); } } #endregion 任务完成 #region 请求任务 /// /// 请求任务 /// /// 请求模型 /// 包含任务信息的响应内容 public async Task RequestTaskAsync(RequestTaskDto input) { WebResponseContent content = new WebResponseContent(); try { // 根据托盘获取库存信息 //var stockInfo = await _stockInfoRepository.QueryFirstAsync(x => x.PalletCode == input.PalletCode); TrayCellsStatusDto trayCells = new TrayCellsStatusDto() { TrayBarcode = input.PalletCode }; content = await _cellStateService.GetTrayCellStatusAsync(trayCells); if (content.Status) { ResultTrayCellsStatus result = JsonConvert.DeserializeObject(content.Data.ToString()); ProcessApplyDto process = new ProcessApplyDto() { WipOrderNo = result.BindCode, SerialNos = result.SerialNos.Select(item => new SerialNos { SerialNo = item.SerialNo }).ToList() }; content = await _processApplyService.GetProcessApplyAsync(process); if (content.Status) { var X = SqlSugarHelper.Db.Queryable().Where(x => x.EquipmentType == "CH").ToList(); } } // 获取仓库区域信息 var areaInfo = await _wareAreaInfoRepository.QueryFirstAsync(x => x.WareAreaCode == input.AreaCode); // 查询是否已有任务 var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == input.PalletCode); if (task != null) { // 更新现有任务 content = await UpdateExistingTask(input, areaInfo.AreaID, task); } else { // 创建新任务 content = await CreateNewTask(input, areaInfo.AreaID); } } catch (Exception err) { // 错误处理 content.Error(err.Message); Console.WriteLine(err.Message); } return content; } #endregion 请求任务 #endregion 外部接口方法 #region 内部调用方法 /// /// 创建一个新的任务 /// /// 任务模型 /// 创建的任务 public async Task Create(Dt_Task model) { return await BaseDal.Create(model); } /// /// 批量创建任务 /// /// 任务模型列表 /// 是否创建成功 public async Task Create(List models) { return await BaseDal.Create(models); } /// /// 删除一个任务 /// /// 任务ID /// 是否删除成功 public async Task Delete(int id) { return await BaseDal.Delete(id); } /// /// 批量删除任务 /// /// 任务ID列表 /// 是否删除成功 public async Task Delete(List ids) { return await BaseDal.Delete(ids); } /// /// 通过ID获取任务 /// /// 任务ID /// 任务模型 public async Task GetById(int id) { return await BaseDal.GetById(id); } /// /// 获取所有任务列表 /// /// 任务模型列表 public async Task> GetList() { return await BaseDal.GetList(); } /// /// 根据出库订单ID获取任务列表 /// /// 出库订单ID /// 任务模型列表 public async Task> GetListByOutOrder(int outOrderId) { return await BaseDal.GetListByOutOrder(outOrderId); } /// /// 根据出库订单ID和状态获取任务列表 /// /// 出库订单ID /// 任务状态 /// 任务模型列表 public async Task> GetListByOutOrderAndStatus(int outOrderId, int status) { return await BaseDal.GetListByOutOrderAndStatus(outOrderId, status); } /// /// 根据状态获取任务列表 /// /// 任务状态 /// 任务模型列表 public async Task> GetListByStatus(int status) { return await BaseDal.GetListByStatus(status); } /// /// 更新一个任务 /// /// 任务模型 /// 是否更新成功 public async Task Update(Dt_Task model) { return await BaseDal.Update(model); } /// /// 批量更新任务 /// /// 任务模型列表 /// 是否更新成功 public async Task Update(List models) { return await BaseDal.Update(models); } /// /// 检查任务是否存在 /// /// 托盘编码 /// 任务是否存在 public bool IsExist(string palletCode) { return Db.Queryable().Any(x => x.PalletCode == palletCode); } /// /// 根据货位ID获取任务 /// /// /// public async Task GetByLocation(string locationID) { return await Db.Queryable().Where(x => x.SourceAddress == locationID).FirstAsync(); } /// /// 根据任务号获取任务 /// /// /// public async Task GetByTaskNum(int taskNum) { return await Db.Queryable().Where(x => x.TaskNum == taskNum).FirstAsync(); } #endregion 内部调用方法 #region private 内部方法 /// /// 更新出库订单和库存信息 /// /// 库存实例 /// 条码 /// 更新后的订单和库存信息 private async Task UpdateOrderAndStockAsync(DtStockInfo stock, string barCode) { //根据PalletCode获取订单和库存信息 var orderStock = await _outOrderAndStockRepository.GetOrderAndStock(palletCode: barCode); //完成数量增加 orderStock.CompletedQuantity += stock.StockInfoDetails.Sum(x => x.StockQuantity); //订单详情完成数量增加 orderStock.OrderList.OrderDetailList.CompletedQuantity += stock.StockInfoDetails.Sum(x => x.StockQuantity); //返回更新后的订单和库存信息 return orderStock; } /// /// 判断订单是否完成 /// /// 订单和库存信息 /// 是否完成 // 判断订单是否完成 private bool IsOrderComplete(Dt_OutOrderAndStock orderStock) { // 如果出库数量等于完成出库数量,则订单完成 return orderStock.CompletedQuantity == orderStock.OutboundQuantity; } /// /// 创建历史任务记录 /// /// /// private Dt_Task_Hty CreateHistoricalTask(Dt_Task task) { // 更新任务状态 task.TaskState = TaskOutStatusEnum.OutFinish.ObjToInt(); task.CurrentAddress = task.NextAddress; // 创建历史任务 var taskHty = _mapper.Map(task); taskHty.FinishTime = DateTime.Now; taskHty.TaskId = 0; taskHty.OperateType = (int)OperateTypeEnum.自动完成; taskHty.SourceId = task.TaskId; taskHty.TaskState = TaskOutStatusEnum.OutFinish.ObjToInt(); return taskHty; } /// /// 更新库存位置 /// /// 库存对象 /// 目标位置 // 更新库存和位置信息 private (DtStockInfo, DtLocationInfo) UpdateStockLocation(DtStockInfo stock, string toLocation) { // 获取库存信息 var locationInfo = _locationRepository.QueryFirst(x => x.LocationCode == stock.LocationCode); // 将库存状态设置为在库 locationInfo.LocationStatus = LocationEnum.InStock.ObjToInt(); // 将库存位置设置为目标位置 stock.LocationCode = toLocation; // 将库存状态设置为在库 stock.LocationInfo.LocationStatus = LocationEnum.InStock.ObjToInt(); // 返回更新后的库存和位置信息 return (stock, locationInfo); } /// /// 执行数据库事务 /// /// 库存对象 /// 历史任务对象 /// 任务ID /// private async Task ExecuteTransaction(DtStockInfo stock, Dt_Task_Hty taskHty, DtLocationInfo locationInfo, int taskId) { _unitOfWorkManage.BeginTran(); try { var isUpdateStock = true; if (taskHty.TaskType == (int)TaskTypeEnum.Outbound) { // 更新库存 isUpdateStock = await _stockInfoRepository.UpdateDataAsync(stock); } else { // 添加库存 isUpdateStock = await _stockInfoRepository.AddDataNavAsync(stock); } // 添加历史任务 var isTaskHtyAdd = await _task_HtyRepository.AddDataAsync(taskHty) > 0; // 修改移库前货位状态 var isUpdateLoc = _locationRepository.UpdateData(locationInfo); // 删除任务数据 var isTaskDelete = await Delete(taskId); // 提交或回滚事务 if (isUpdateStock && isTaskHtyAdd && isTaskDelete && isUpdateLoc) { LogFactory.GetLog("任务完成").InfoFormat(true, "任务完成", $"事务处理完成,提交事务。添加历史任务:{isTaskHtyAdd},删除任务数据:{isTaskDelete},更新或添加库存:{isUpdateStock},修改移库前货位状态:{isUpdateLoc}"); _unitOfWorkManage.CommitTran(); return true; } else { LogFactory.GetLog("任务完成").InfoFormat(true, "任务完成", $"数据处理失败,请检查数据是否正确,数据回滚。添加历史任务:{isTaskHtyAdd},删除任务数据:{isTaskDelete},更新库存:{isUpdateStock},修改移库前货位状态:{isUpdateLoc}"); _unitOfWorkManage.RollbackTran(); return false; } } catch (Exception err) { LogFactory.GetLog("任务完成").InfoFormat(true, $"移库任务完成,系统异常,异常信息:{err.Message}", "无参数"); _unitOfWorkManage.RollbackTran(); throw; // 抛出异常以便外部捕获 } } #region 任务请求方法 /// /// 更新现有任务 /// /// 请求模型 /// 区域ID /// 任务实例 /// 响应内容 /// private async Task UpdateExistingTask(RequestTaskDto input, int areaId, Dt_Task task) { // 创建WebResponseContent对象 WebResponseContent content = new WebResponseContent(); // 定义变量 string toAddress; int taskState; string original = task.CurrentAddress; DtLocationInfo location = new DtLocationInfo(); int beforeStatus = 0; // 根据任务类型判断是出库任务还是入库任务 if (input.Type == (int)TaskTypeEnum.Outbound) { // 处理出库任务 toAddress = await GetRoadWayAsync(areaId, task.Roadway, input.Direction, input.Area, input.Type); taskState = (int)TaskOutStatusEnum.SC_OutFinish; } else { // 处理入库任务 location = await GetLocationDistributeAsync(areaId, task.Roadway); toAddress = location.LocationCode; taskState = (int)TaskInStatusEnum.Line_InFinish; beforeStatus = location.LocationStatus; // 更新货位信息 location.LocationStatus = (int)LocationEnum.Lock; } // 更新任务信息 task.SourceAddress = input.Position; task.CurrentAddress = input.Position; task.TargetAddress = toAddress; task.NextAddress = toAddress; task.TaskState = taskState; // 开始事务 _unitOfWorkManage.BeginTran(); // 定义变量 bool isUpdateLo = true; bool isUpdateChange = true; // 尝试更新任务 bool isResult = await BaseDal.UpdateDataAsync(task); bool isTaskDetail = await _taskExecuteDetailRepository.AddDetailAsync(task, false, TaskDescription.GetTaskUpdateDescription(task.PalletCode, original, input.Position, TaskInStatusEnum.Line_InFinish.GetIntegralRuleTypeEnumDesc())); if (input.Type != (int)TaskTypeEnum.Outbound) { // 创建LocationChangeRecordDto对象 LocationChangeRecordDto changeRecordDto = new LocationChangeRecordDto() { // 设置变量 AfterStatus = location.LocationStatus, BeforeStatus = beforeStatus, TaskNum = task.TaskNum.Value, LocationId = location.Id, LocationCode = location.LocationCode, ChangeType = (int)StatusChangeTypeEnum.AutomaticStorage, }; // 更新位置状态 isUpdateChange = _locationStatusChangeRecordRepository.AddStatusChangeRecord(changeRecordDto); isUpdateLo = await _locationRepository.UpdateDataAsync(location); } if (isResult && isUpdateLo && isTaskDetail) { // 提交事务 _unitOfWorkManage.CommitTran(); content.OK(data: task); } else { // 回滚事务 _unitOfWorkManage.RollbackTran(); content.Error("更新任务失败"); } return content; } /// /// 创建新任务 /// /// 请求模型 /// 区域ID /// 响应内容 /// private async Task CreateNewTask(RequestTaskDto input, int areaId) { WebResponseContent content = new WebResponseContent(); // 获取目标地址 string ToAddress = await GetRoadWayAsync(areaId, input.Position, input.Direction, input.Area, input.Type); // 创建新任务实例 var task = new Dt_Task { CurrentAddress = input.Position, Grade = 1, Roadway = ToAddress, TargetAddress = ToAddress, Dispatchertime = DateTime.Now, MaterialNo = "", NextAddress = ToAddress, OrderNo = null, PalletCode = input.PalletCode, SourceAddress = input.Position, TaskState = (int)TaskInStatusEnum.InNew, TaskType = (int)TaskTypeEnum.Inbound, TaskNum = await BaseDal.GetTaskNo(), Creater = "Systeam" }; // 尝试添加新任务 var taskId = await BaseDal.AddDataAsync(task); bool isResult = taskId > 0; if (isResult) { task.TaskId = taskId; isResult = await _taskExecuteDetailRepository.AddDetailAsync(task, false, TaskDescription.GetTaskUpdateDescription(input.PalletCode, input.Position, ToAddress, TaskInStatusEnum.InNew.GetIntegralRuleTypeEnumDesc())); if (isResult) { WMSTaskDTO taskDTO = new WMSTaskDTO() { TaskNum = 0, Grade = 1, PalletCode = DateTime.Now.ToString("MMddHHmmss"), RoadWay = task.Roadway, SourceAddress = "001-001-001", TargetAddress = task.Roadway, TaskState = (int)TaskInStatusEnum.InNew, Id = 0, TaskType = (int)TaskInboundTypeEnum.Inbound, }; content.OK(data: taskDTO); } else content.Error("添加任务失败"); } else content.Error("添加任务失败"); return content; } /// /// 查找货位 /// /// 区域主键 /// 巷道 /// public async Task GetLocationDistributeAsync(int areaId, string roadWay) { #region 获取货位 try { var locations = await _locationRepository.QueryDataAsync(x => x.AreaId == areaId && x.LocationStatus == (int)LocationEnum.Free && x.RoadwayNo == roadWay); if (locations == null) { return null; } return locations.OrderBy(x => x.Layer).ThenBy(x => x.Column).ThenBy(x => x.Row).FirstOrDefault(); } catch (Exception err) { Console.WriteLine(err.Message.ToString()); return null; } #endregion 获取货位 } /// /// 获取巷道或站台 /// /// 货位区域ID /// 站台 /// 方向 /// 关系区域 /// public async Task GetRoadWayAsync(int areaId, string position, string Direction, string area, int type) { var point = new PointStackerRelation(); if (type == (int)TaskTypeEnum.Inbound) { point = await _pointStackerRelationRepository.QueryFirstAsync(x => x.Direction == Direction && x.PointCode == position && x.Area == area); if (point == null) { return null; } var locationInfos = await _locationRepository.QueryDataAsync(x => x.AreaId == areaId && point.StackerCode.Contains(x.RoadwayNo)); var groupWithMinCount = locationInfos.GroupBy(x => x.RoadwayNo).OrderBy(x => x.Count()).FirstOrDefault(); if (groupWithMinCount != null) return groupWithMinCount.Key; else return null; } else if (type == (int)TaskTypeEnum.Outbound) { point = await _pointStackerRelationRepository.QueryFirstAsync(x => x.Direction == Direction && position == x.StackerCode && x.Area == area); if (point == null) { return null; } string station = point.PointCodeList[0]; var rList = point.PointCodeList; rList.Remove(station); rList.Add(station); point.PointCodeList = rList; return station; } else { return null; } } #endregion 任务请求方法 #endregion private 内部方法 }