#region << 版 本 注 释 >> /*---------------------------------------------------------------- * 命名空间:WIDESEA_TaskInfoService * 创建者:胡童庆 * 创建时间:2024/8/2 16:13:36 * 版本:V1.0.0 * 描述: * * ---------------------------------------------------------------- * 修改人: * 修改时间: * 版本:V1.0.1 * 修改说明: * *----------------------------------------------------------------*/ #endregion << 版 本 注 释 >> using AutoMapper; using Dm.filter; using MailKit.Search; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Org.BouncyCastle.Asn1.Ocsp; using Org.BouncyCastle.Asn1.Pkcs; using SqlSugar; using System.Reflection; using System.Reflection.Emit; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using WIDESEA_BasicService; using WIDESEA_Common.AllocateEnum; using WIDESEA_Common.CommonEnum; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.OrderEnum; using WIDESEA_Common.StockEnum; using WIDESEA_Common.TaskEnum; using WIDESEA_Common.WareHouseEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_Core.Util; using WIDESEA_DTO.Allocate; using WIDESEA_DTO.Base; using WIDESEA_DTO.Basic; using WIDESEA_DTO.Inbound; using WIDESEA_DTO.Outbound; using WIDESEA_DTO.ReturnMES; using WIDESEA_DTO.Task; using WIDESEA_IAllocateService; using WIDESEA_IBasicService; using WIDESEA_IInboundService; using WIDESEA_IOutboundService; using WIDESEA_IRecordService; using WIDESEA_IStockService; using WIDESEA_ITaskInfoService; using WIDESEA_Model.Models; using WIDESEA_Model.Models.Basic; using WIDESEA_Model.Models.Check; using WIDESEA_Model.Models.Outbound; using static HslCommunication.Profinet.Knx.KnxCode; namespace WIDESEA_TaskInfoService { public partial class TaskService : ServiceBase>, ITaskService { private readonly ILogger _logger; private readonly IMapper _mapper; private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IRepository _stockRepository; private readonly ILocationInfoService _locationInfoService; private readonly IInboundOrderService _inboundOrderService; private readonly IInboundOrderDetailService _inboundOrderDetailService; private readonly IRepository _allocateOrderDetailRepository; private readonly IRepository _allocateOrderRepository; private readonly IRepository _reCheckOrderRepository; private readonly IRepository _OutboundBatchRepository; private readonly IOutboundOrderService _outboundOrderService; private readonly IOutboundOrderDetailService _outboundOrderDetailService; private readonly IOutStockLockInfoService _outStockLockInfoService; private readonly ILocationStatusChangeRecordService _locationStatusChangeRecordService; private readonly IMaterialUnitService _materialUnitService; private readonly IESSApiService _eSSApiService; private readonly IStockService _stockService; private readonly IRecordService _recordService; private readonly IAllocateService _allocateService; private readonly IInvokeMESService _invokeMESService; private readonly ITask_HtyService _task_HtyService; private readonly IRepository _allocateMaterialInfo; private readonly IRepository _allocateMaterialInfo_Hty; private readonly HttpClientHelper _httpClientHelper; private readonly IBasicService _basicService; private readonly IRepository _takeStockOrder; public readonly IRepository _locationTypeRepository; public readonly IRepository _warehouseAreaRepository; private readonly IRepository _outboundLockInfoRepository; public IRepository Repository => BaseDal; private Dictionary _taskOrderBy = new() { {nameof(Dt_Task.Grade),SqlSugar.OrderByType.Desc }, {nameof(Dt_Task.CreateDate),SqlSugar.OrderByType.Asc}, }; private Dictionary stations = new Dictionary { {"3-5","3-9" }, {"2-5","2-9" }, {"1-11","1-1" }, }; public List TaskTypes => typeof(TaskTypeEnum).GetEnumIndexList(); public List TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList(); public TaskService(IRepository BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService, IRepository outboundBatchRepository, IRepository reCheckOrderRepository, IRepository allocateOrderDetailRepository, IRepository allocateOrderRepository, IMaterialUnitService materialUnitService, ITask_HtyService task_HtyService, IRepository allocateMaterialInfo, IRepository allocateMaterialInfo_Hty, HttpClientHelper httpClientHelper, IBasicService basicService,IRepository takeStockOrder, IRepository locationTypeRepository, IRepository warehouseAreaRepository, IRepository outboundLockInfoRepository) : base(BaseDal) { _mapper = mapper; _unitOfWorkManage = unitOfWorkManage; _stockRepository = stockRepository; _locationInfoService = locationInfoService; _inboundOrderService = inboundOrderService; _locationStatusChangeRecordService = locationStatusChangeRecordService; _eSSApiService = eSSApiService; _logger = logger; _stockService = stockService; _recordService = recordService; _inboundOrderDetailService = inboundOrderDetailService; _outboundOrderService = outboundOrderService; _outboundOrderDetailService = outboundOrderDetailService; _invokeMESService = invokeMESService; _outStockLockInfoService = outStockLockInfoService; _allocateService = allocateService; _OutboundBatchRepository = outboundBatchRepository; _reCheckOrderRepository = reCheckOrderRepository; _allocateOrderDetailRepository = allocateOrderDetailRepository; _allocateOrderRepository = allocateOrderRepository; _materialUnitService = materialUnitService; _task_HtyService = task_HtyService; _allocateMaterialInfo = allocateMaterialInfo; _allocateMaterialInfo_Hty = allocateMaterialInfo_Hty; _httpClientHelper = httpClientHelper; _basicService = basicService; _takeStockOrder = takeStockOrder; _locationTypeRepository = locationTypeRepository; _warehouseAreaRepository = warehouseAreaRepository; _outboundLockInfoRepository = outboundLockInfoRepository; } public async Task TaskStatusChange(string taskNum, TaskStatusEnum taskStatusEnum) { if (int.TryParse(taskNum, out var newTaskNum)) { await Db.Updateable().SetColumns(it => new Dt_Task { TaskStatus = taskStatusEnum.ObjToInt() }) .Where(it => it.TaskNum == newTaskNum) .ExecuteCommandAsync(); } } /// /// /// /// /// public async Task TaskCompleted(string taskNum) { try { Dt_Task task; if (int.TryParse(taskNum, out var newTaskNum)) { task = await BaseDal.QueryFirstAsync(x => x.TaskNum == newTaskNum); if (task == null) { return WebResponseContent.Instance.Error("未找到任务信息"); } } else { return WebResponseContent.Instance.Error("未找到任务信息"); } _logger.LogInformation($"TaskService TaskCompleted: {JsonConvert.SerializeObject(task)} , {task.TaskType} "); MethodInfo? methodInfo = GetType().GetMethod(((TaskTypeEnum)task.TaskType) + "TaskCompleted"); if (methodInfo != null) { object? taskResult = methodInfo.Invoke(this, new object[] { task }); if (taskResult is Task asyncTask) { try { // 3. 异步等待 Task 完成,自动解析出 WebResponseContent WebResponseContent responseContent = await asyncTask; if (responseContent != null) { return responseContent; } } catch (AggregateException ex) { _logger.LogError($"TaskService TaskCompleted taskResult: {ex.Message} "); return WebResponseContent.Instance.Error(ex.Message); } catch (Exception ex) { _logger.LogError(ex, $"Unexpected error in {task.TaskType}"); return WebResponseContent.Instance.Error(ex.Message); } } } return WebResponseContent.Instance.Error("未找到任务类型对应业务处理逻辑"); } catch (Exception ex) { _logger.LogError($"TaskService TaskCompleted: {ex.Message} "); return WebResponseContent.Instance.Error(ex.Message); } } /// /// 入库完成 /// /// /// public async Task InboundTaskCompleted(Dt_Task task) { decimal beforeQuantity = 0; //查库存 Dt_StockInfo stockInfo = _stockRepository.Db.Queryable().Includes(x => x.Details).Where(x => x.PalletCode == task.PalletCode && x.WarehouseId == task.WarehouseId).First(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息"); } if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { return WebResponseContent.Instance.Error($"未找到该托盘库存明细信息"); } //查货位 Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo == null) { return WebResponseContent.Instance.Error($"未找到对应的终点货位信息"); } var ordernos = stockInfo.Details.GroupBy(x => x.OrderNo).Select(o => o.Key).ToList(); var inboundOrders = _inboundOrderService.Repository.Db.Queryable().Where(x => ordernos.Contains(x.InboundOrderNo)).Includes(x => x.Details).ToList(); Dt_InboundOrderDetail? inboundOrderDetail = null; foreach (var inboundOrder in inboundOrders) { //标准入库流程查找入库单据 if (inboundOrder != null && stockInfo.StockStatus == StockStatusEmun.入库确认.ObjToInt()) { foreach (var item in stockInfo.Details.Where(x => x.OrderNo == inboundOrder.InboundOrderNo).ToList()) { var inbounddetail = inboundOrder.Details.Where(x => x.lineNo == item.InboundOrderRowNo && x.Barcode == item.Barcode).FirstOrDefault(); if (inbounddetail != null) { inbounddetail.OverInQuantity += item.StockQuantity; if (inbounddetail.OverInQuantity == inbounddetail.OrderQuantity) { inbounddetail.OrderDetailStatus = OrderDetailStatusEnum.Over.ObjToInt(); } else if (inbounddetail.OrderDetailStatus == OrderDetailStatusEnum.New.ObjToInt()) { inbounddetail.OrderDetailStatus = OrderDetailStatusEnum.Inbounding.ObjToInt(); } _inboundOrderDetailService.UpdateData(inbounddetail); } } if (inboundOrder.Details.Count == inboundOrder.Details.Where(x => x.OrderQuantity == x.OverInQuantity).Count()) { inboundOrder.OrderStatus = InOrderStatusEnum.入库完成.ObjToInt(); } else if (inboundOrder.OrderStatus == InOrderStatusEnum.未开始.ObjToInt()) { inboundOrder.OrderStatus = InOrderStatusEnum.入库中.ObjToInt(); } _inboundOrderService.UpdateData(inboundOrder); } } Dt_OutboundOrder outboundOrder = _outboundOrderService.Db.Queryable().Where(x => x.OrderNo == stockInfo.Details.FirstOrDefault().OrderNo).Includes(x => x.Details).First(); if (outboundOrder != null) { foreach (var item in stockInfo.Details.Where(x => x.OrderNo == outboundOrder.OrderNo).ToList()) { var inbounddetail = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == item.OrderNo && x.Barcode == item.Barcode); if (inbounddetail != null) { var alldelete = _allocateMaterialInfo.DeleteAndMoveIntoHty(inbounddetail, OperateTypeEnum.自动删除); if (!alldelete) { await Db.Deleteable(task).ExecuteCommandAsync(); } } } } stockInfo.LocationCode = task.TargetAddress; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); stockInfo.Details.ForEach(x => { x.Status = inboundOrders.FirstOrDefault().CreateType == (int)OrderCreateTypeEnum.CreateInSystem ? StockStatusEmun.入库完成.ObjToInt():StockStatusEmun.入库确认.ObjToInt(); }); _stockService.StockInfoService.Repository.UpdateData(stockInfo); _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details); beforeQuantity = stockInfo.Details.Where(x => x.Id != 0).Sum(x => x.StockQuantity); int beforeStatus = locationInfo.LocationStatus; if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt()) { locationInfo.LocationStatus = LocationStatusEnum.Pallet.ObjToInt(); } else { locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); } _locationInfoService.Repository.UpdateData(locationInfo); task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); // BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum); } catch (Exception ex) { _logger.LogInformation($"InboundTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } try { foreach (var inboundOrder in inboundOrders) { if (inboundOrder.OrderType == InOrderTypeEnum.AllocatInbound.ObjToInt())//调拨入库 { if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt()) { var allocate = _allocateService.Repository.QueryData(x => x.OrderNo == inboundOrder.InboundOrderNo).First(); var allocatefeedmodel = new AllocateDto { ReqCode = Guid.NewGuid().ToString(), ReqTime = DateTime.Now.ToString(), BusinessType = BusinessTypeEnum.外部仓库调智仓.ObjToInt().ToString(), FactoryArea = inboundOrder.FactoryArea, OperationType = 1, Operator = inboundOrder.Operator, OrderNo = inboundOrder.UpperOrderNo, fromWarehouse = allocate?.FromWarehouse ?? "", toWarehouse = allocate?.ToWarehouse ?? "", Details = new List() }; var query = inboundOrder.Details.AsQueryable(); query = query.Where(item => item.ReturnToMESStatus == 0); var groupedData = query.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new AllocateDtoDetail { MaterialCode = group.Key.MaterielCode, LineNo = group.Key.lineNo, WarehouseCode = group.Key.WarehouseCode, Qty = group.Sum(x => x.BarcodeQty), // warehouseCode= "1072", Unit = group.Key.BarcodeUnit, Barcodes = group.Select(row => new BarcodeInfo { Barcode = row.Barcode, Qty = row.BarcodeQty, BatchNo = row.BatchNo, SupplyCode = row.SupplyCode, Unit = row.BarcodeUnit }).ToList() }).ToList(); allocatefeedmodel.Details = groupedData; var response = responseModel(inboundOrder, 3, null, allocatefeedmodel); if (response != null && response.IsSuccess && response.Data.Code =="200") { var detailStatusList = _inboundOrderDetailService.Db.Queryable() .Where(it => it.OrderId == inboundOrder.Id) .Select(it => it.OrderDetailStatus) .ToList(); bool isAll = detailStatusList.Any() ? detailStatusList.All(x => x == OrderDetailStatusEnum.Over.ObjToInt()) : false; if (isAll) { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } else { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 3, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 3 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } //回传成功库存才可用 _stockRepository.Db.Updateable().SetColumns(it => new Dt_StockInfoDetail { Status = StockStatusEmun.入库完成.ObjToInt() }).Where(it => it.OrderNo == inboundOrder.InboundOrderNo).ExecuteCommand(); } else { var detailStatusList = _inboundOrderDetailService.Db.Queryable() .Where(it => it.OrderId == inboundOrder.Id) .Select(it => it.OrderDetailStatus) .ToList(); bool isAll = detailStatusList.Any() ? detailStatusList.All(x => x == OrderDetailStatusEnum.Over.ObjToInt()) : false; if (isAll) { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } else { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 4, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 4 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } } } } else if (inboundOrder.OrderType == InOrderTypeEnum.ReCheck.ObjToInt()) //重检入库 { //不需要回传。占一个位置。 } else { if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt() && inboundOrder.CreateType == (int)OrderCreateTypeEnum.UpperSystemPush) { var feedmodel = new FeedbackInboundRequestModel { reqCode = Guid.NewGuid().ToString(), reqTime = DateTime.Now.ToString(), business_type = inboundOrder.BusinessType, factoryArea = inboundOrder.FactoryArea, operationType = 1, Operator = inboundOrder.Operator, orderNo = inboundOrder.UpperOrderNo, status = inboundOrder.OrderStatus, details = new List() }; var query = inboundOrder.Details.AsQueryable(); query = query.Where(item => item.ReturnToMESStatus == 0); var groupedData = query.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.lineNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new FeedbackInboundDetailsModel { materialCode = group.Key.MaterielCode, supplyCode = group.Key.SupplyCode, batchNo = group.Key.BatchNo, lineNo = group.Key.lineNo, warehouseCode = group.Key.WarehouseCode, qty = group.Sum(x => x.BarcodeQty), // warehouseCode= "1072", unit = group.Key.BarcodeUnit, barcodes = group.Select(row => new FeedbackBarcodesModel { barcode = row.Barcode, qty = row.BarcodeQty }).ToList() }).ToList(); feedmodel.details = groupedData; //var feedbackresult = await _invokeMESService.FeedbackInbound(feedmodel); var response= responseModel(inboundOrder,2, feedmodel); if (response != null && response.IsSuccess && response.Data.Code == "200") { var detailStatusList = _inboundOrderDetailService.Db.Queryable() .Where(it => it.OrderId == inboundOrder.Id) .Select(it => it.OrderDetailStatus) .ToList(); bool isAll = detailStatusList.Any() ? detailStatusList.All(x => x == OrderDetailStatusEnum.Over.ObjToInt()) : false; if (isAll) { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } else { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 3, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 3 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } //回传成功库存才可用 _stockRepository.Db.Updateable().SetColumns(it => new Dt_StockInfoDetail { Status = StockStatusEmun.入库完成.ObjToInt() }).Where(it => it.OrderNo == inboundOrder.InboundOrderNo).ExecuteCommand(); } else { var detailStatusList = _inboundOrderDetailService.Db.Queryable() .Where(it => it.OrderId == inboundOrder.Id) .Select(it => it.OrderDetailStatus) .ToList(); bool isAll = detailStatusList.Any() ? detailStatusList.All(x => x == OrderDetailStatusEnum.Over.ObjToInt()) : false; if (isAll) { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } else { _inboundOrderService.Db.Updateable().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 4, Remark = "" }) .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); _inboundOrderDetailService.Db.Updateable().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 4 }) .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); } } } } } } catch (Exception ex) { _logger.LogInformation("InboundTaskCompleted 回写MES失败: " + ex.Message); } return WebResponseContent.Instance.OK(); } public async Task RelocationTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { if (task == null || string.IsNullOrEmpty(task.PalletCode) || string.IsNullOrEmpty(task.TargetAddress)) { return WebResponseContent.Instance.Error("移库任务信息不完整(托盘号/目标货位为空)"); } // 2. 查询托盘库存信息 Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘[{task.PalletCode}]对应的组盘信息"); } // 非空托盘必须有明细 if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { _logger.LogInformation($"TaskService RelocationTaskCompleted: 未找到该托盘库存明细信息.{task.TaskNum}"); return WebResponseContent.Instance.Error($"未找到该托盘[{task.PalletCode}]库存明细信息"); } // 3. 查询目标货位+原货位信息 Dt_LocationInfo targetLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (targetLocationInfo == null) { return content.Error($"未找到对应的终点货位[{task.TargetAddress}]信息"); } // 原货位信息 Dt_LocationInfo oldLocationInfo = null; if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { oldLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode); if (oldLocationInfo == null) { return content.Error($"未找到原货位[{stockInfo.LocationCode}]信息"); } } // 4. 货位状态校验 if (targetLocationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"目标货位[{task.TargetAddress}]状态不正确(当前为已占用)"); } // 5. 开启事务处理核心逻辑 _unitOfWorkManage.BeginTran(); // 5.1 记录目标货位原状态,更新为占用 var beforeTargetLocationStatus = targetLocationInfo.LocationStatus; targetLocationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); _locationInfoService.Repository.UpdateData(targetLocationInfo); // 5.2 释放原货位 int beforeOldLocationStatus = 0; if (oldLocationInfo != null) { beforeOldLocationStatus = oldLocationInfo.LocationStatus; // 原货位恢复为空闲 oldLocationInfo.LocationStatus = stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt() ? LocationStatusEnum.Pallet.ObjToInt() : LocationStatusEnum.Free.ObjToInt(); _locationInfoService.Repository.UpdateData(oldLocationInfo); } var stockLockInfo = _outStockLockInfoService.Db.Queryable().Where(x => x.PalletCode == stockInfo.PalletCode && x.TaskNum == task.TaskNum).First(); var allocateOrderToWarehouse = _allocateOrderRepository.Db.Queryable().Where(x => x.OrderNo == stockLockInfo.OrderNo).First(); // 5.3 更新库存明细状态(移库完成) stockInfo.Details.ForEach(x => { x.Status = StockStatusEmun.入库完成.ObjToInt(); x.WarehouseCode = allocateOrderToWarehouse.ToWarehouse; }); _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details); // 5.4 更新库存主信息(绑定新货位) string oldLocationCode = stockInfo.LocationCode; // 记录原货位 stockInfo.LocationCode = targetLocationInfo.LocationCode; // 绑定目标货位 stockInfo.PalletCode = task.PalletCode; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); var name =_warehouseAreaRepository.Db.Queryable().Where(x => x.Code == allocateOrderToWarehouse.ToWarehouse).First(); var locationType =_locationTypeRepository.QueryFirst(x => x.LocationTypeDesc.Equals(name.Name)); if(locationType != null) { stockInfo.LocationType = locationType.LocationType; } _stockRepository.UpdateData(stockInfo); // 5.5 更新任务状态为完成 task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); // 提交事务 _unitOfWorkManage.CommitTran(); // 任务归档失败则直接删除 if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } // 6. 处理出库单+调拨物料信息 Dt_OutboundOrder outboundOrder = null; //var firstDetail = stockInfo.Details.FirstOrDefault(); if (stockLockInfo != null && !string.IsNullOrEmpty(stockLockInfo.OrderNo)) { outboundOrder = _outboundOrderService.Db.Queryable() .Where(x => x.OrderNo == stockLockInfo.OrderNo) .Includes(x => x.Details) .First(); string Operator = outboundOrder.Modifier; if (outboundOrder != null) { var allocatInfo =_allocateMaterialInfo.Db.Queryable().Where(x => x.OrderNo == outboundOrder.OrderNo).ToList(); // 删除调拨物料信息 foreach (var item in allocatInfo) { var inbounddetail = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == item.OrderNo && x.Barcode == item.Barcode); if (inbounddetail != null) { var alldelete = _allocateMaterialInfo.DeleteAndMoveIntoHty(inbounddetail, OperateTypeEnum.自动删除); if (!alldelete) { await Db.Deleteable(task).ExecuteCommandAsync(); } } } if (outboundOrder.Details.All(x => x.OrderDetailStatus == (int)OrderDetailStatusEnum.Over) && !allocatInfo.Any()) { outboundOrder.OrderStatus = (int)InOrderStatusEnum.入库完成; _outboundOrderService.UpdateData(outboundOrder); } // 7. 回调MES HttpResponseResult httpResponseResult = new HttpResponseResult(); string reqCode = Guid.NewGuid().ToString(); string reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string requestData = string.Empty; List lineNos = new List(); Dt_AllocateMaterialInfo allocateMaterialInfo = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo); // 移库场景:出库完成且未回传MES、无调拨物料信息时回调 if (outboundOrder.OrderStatus == OutOrderStatusEnum.出库完成.ObjToInt() && outboundOrder.ReturnToMESStatus == 0 && allocateMaterialInfo == null) { Dt_AllocateOrder allocateOrder = _allocateOrderRepository.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo); if (allocateOrder == null) { return WebResponseContent.Instance.Error($"未找到对应的调拨单[{outboundOrder.OrderNo}]"); } // 构建移库回调数据 AllocationReturnDTO? returnDTO = BuildAllocationFeedbackData( outboundOrder, allocateOrder.FromWarehouse, allocateOrder.ToWarehouse, Operator); if (returnDTO == null) { return WebResponseContent.Instance.Error($"构建移库回调对象失败"); } string apiUrl = AppSettings.GetValue("AllocationFeedbackUrl"); returnDTO.ReqCode = reqCode; returnDTO.ReqTime = reqTime; JsonSerializerSettings settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; requestData = JsonConvert.SerializeObject(returnDTO, settings); lineNos = returnDTO.Details.Select(x => x.LineNo).ToList(); httpResponseResult = _httpClientHelper.Post(apiUrl, requestData); httpResponseResult.ApiUrl = apiUrl; } // 8. 处理MES回调结果 bool isSuccess = httpResponseResult.IsSuccess && httpResponseResult.Data?.Code == "200"; string message = "成功"; if (!isSuccess) { if (!httpResponseResult.IsSuccess) { message = $"MES接口返回错误,HTTP代码:{httpResponseResult.StatusCode},信息:{httpResponseResult.ErrorMessage}"; } else if (httpResponseResult?.Data?.Code != "200") { message = $"调用MES接口失败,代码:{httpResponseResult?.Data?.Code},信息:{httpResponseResult?.Data?.Message}"; } } // 9. 记录MES回传记录 Dt_MesReturnRecord mesReturnRecord = new Dt_MesReturnRecord() { ApiUrl = httpResponseResult.ApiUrl, InterfaceType = outboundOrder.OrderType == 0 ? 1 : 3, // 移库接口类型:复用调拨类型3 OrderId = outboundOrder.Id, OrderNo = outboundOrder.OrderNo, RequestCode = reqCode, RequestData = requestData, FailureReason = message, LastReturnTime = DateTime.Now, HttpStatusCode = httpResponseResult.StatusCode.ObjToInt(), ResponseData = httpResponseResult.Content, ReturnType = 0, ReturnCount = 1, ReturnStatus = isSuccess ? 1 : 2, SuccessTime = isSuccess ? DateTime.Now : null }; // 开启事务保存MES记录+更新出库单状态 _unitOfWorkManage.BeginTran(); _unitOfWorkManage.Db.Insertable(mesReturnRecord).ExecuteCommand(); List outboundOrderDetails = outboundOrder.Details.Where(x => lineNos.Contains(x.lineNo)).ToList(); outboundOrderDetails.ForEach(x => { if (x.OverOutQuantity == x.OrderQuantity - x.MoveQty) { x.ReturnToMESStatus = isSuccess ? 1 : 2; } else { x.ReturnToMESStatus = isSuccess ? 3 : 4; } x.CurrentDeliveryQty = 0; x.ReturnJsonData = ""; }); mesReturnRecord.ReturnType = outboundOrder.Details.Count == outboundOrderDetails.Count ? 1 : 2; if (outboundOrder.Details.Count == outboundOrderDetails.Count && outboundOrderDetails.All(x => x.ReturnToMESStatus == 1 || x.ReturnToMESStatus == 2)) { outboundOrder.ReturnToMESStatus = isSuccess ? 1 : 2; } else { outboundOrder.ReturnToMESStatus = isSuccess ? 3 : 4; } _outboundOrderService.Db.Updateable(outboundOrderDetails).ExecuteCommand(); _outboundOrderService.UpdateData(outboundOrder); _unitOfWorkManage.CommitTran(); } } // 10. 记录货位状态变更(目标货位+原货位) try { // 记录目标货位状态变更 _locationStatusChangeRecordService.AddLocationStatusChangeRecord( targetLocationInfo, beforeTargetLocationStatus, StockChangeType.Inbound.ObjToInt(), $"移库入库(原货位:{oldLocationCode})", task.TaskNum); // 记录原货位状态变更(若有) if (oldLocationInfo != null) { _locationStatusChangeRecordService.AddLocationStatusChangeRecord( oldLocationInfo, beforeOldLocationStatus, StockChangeType.Outbound.ObjToInt(), $"移库出库(目标货位:{targetLocationInfo.LocationCode})", task.TaskNum); } } catch (Exception ex) { _logger.LogInformation($"RelocationTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } return content; } catch (Exception ex) { // 事务回滚 _unitOfWorkManage.RollbackTran(); _logger.LogError($"RelocationTaskCompleted 处理失败:{ex.Message}", ex); return await Task.FromResult(WebResponseContent.Instance.Error($"移库任务处理失败:{ex.Message}")); } } public HttpResponseResult responseModel(Dt_InboundOrder order, int InterfaceType, FeedbackInboundRequestModel model = null, AllocateDto allocateDto = null) { HttpResponseResult httpResponseResult = new HttpResponseResult(); string reqCode = Guid.NewGuid().ToString(); string reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string requestData = string.Empty; string apiUrl = string.Empty; if (model != null) { apiUrl = AppSettings.GetValue("AldMaterialWarehousing"); httpResponseResult = _httpClientHelper.Post(apiUrl, model.Serialize()); requestData = model.Serialize(); } else { apiUrl = AppSettings.GetValue("AldAllocationOperation"); httpResponseResult = _httpClientHelper.Post(apiUrl, allocateDto.Serialize()); requestData = allocateDto.Serialize(); } httpResponseResult.ApiUrl = apiUrl; bool isSuccess = httpResponseResult.IsSuccess && httpResponseResult.Data.Code == "200"; string message = "成功"; if (!isSuccess) { if (!httpResponseResult.IsSuccess) { message = $"MES接口返回错误,HTTP代码:{httpResponseResult.StatusCode},信息:{httpResponseResult.ErrorMessage}"; } else if (httpResponseResult?.Data?.Code != "200") { message = $"调用MES接口失败,代码:{httpResponseResult?.Data?.Code},信息:{httpResponseResult?.Data?.Message}"; } } Dt_MesReturnRecord mesReturnRecord = new Dt_MesReturnRecord() { ApiUrl = httpResponseResult.ApiUrl, InterfaceType = InterfaceType, OrderId = order.Id, OrderNo = order.InboundOrderNo, RequestCode = reqCode, RequestData = requestData, FailureReason = message, LastReturnTime = DateTime.Now, HttpStatusCode = httpResponseResult.StatusCode.ObjToInt(), ResponseData = httpResponseResult.Content, ReturnType = 0, ReturnCount = 1, ReturnStatus = isSuccess ? 1 : 2, SuccessTime = httpResponseResult.IsSuccess ? DateTime.Now : null }; _unitOfWorkManage.Db.Insertable(mesReturnRecord).ExecuteCommand(); return httpResponseResult; } public async Task OutAllocateTaskCompleted(Dt_Task task) { _logger.LogInformation($"TaskService OutAllocateTaskCompleted: {task.TaskNum}"); return await OutboundTaskCompleted(task); } public async Task OutboundTaskCompleted(Dt_Task task) { _logger.LogInformation($"TaskService OutboundTaskCompleted: {task.TaskNum}"); //查货位 Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.SourceAddress); if (locationInfo == null) { return WebResponseContent.Instance.Error($"未找到对应的终点货位信息"); } locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); _locationInfoService.Repository.UpdateData(locationInfo); var stock = _stockService.StockInfoService.Db.Queryable() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .First(); stock.StockStatus = StockStatusEmun.出库完成.ObjToInt(); stock.LocationCode = ""; stock.Details.ForEach(x => { if (x.Status != StockStatusEmun.手动冻结.ObjToInt()) { x.Status = StockStatusEmun.出库完成.ObjToInt(); } }); _stockService.StockInfoService.Db.UpdateNav(stock).IncludesAllFirstLayer().ExecuteCommand(); task.TaskStatus = (int)TaskStatusEnum.Finish; var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } return WebResponseContent.Instance.OK(); } public async Task InEmptyTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo == null) { return content.Error($"未找到对应的终点货位信息"); } Dt_StockInfo stockInfo = _stockRepository.Db.Queryable().Where(x => x.PalletCode == task.PalletCode && x.WarehouseId == task.WarehouseId).First(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息"); } if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { return WebResponseContent.Instance.Error($"该托盘已绑定货位"); } if (locationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"货位状态不正确"); } var beforelocationStatus = locationInfo.LocationStatus; locationInfo.LocationStatus = LocationStatusEnum.Pallet.ObjToInt(); _locationInfoService.Repository.UpdateData(locationInfo); stockInfo.LocationCode = locationInfo.LocationCode; stockInfo.PalletCode = task.PalletCode; stockInfo.LocationCode = task.TargetAddress; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); _stockRepository.UpdateData(stockInfo); //var outboundOrder = _outboundOrderService.Db.Queryable().First(x => x.OrderNo == task.OrderNo); task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum); } catch (Exception ex) { _logger.LogInformation($"InEmptyTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } //if (outboundOrder != null) //{ // await HandleOutboundOrderToMESCompletion(outboundOrder, outboundOrder.OrderNo); //} //else //{ // _logger.LogInformation($"TaskService InEmptyTaskCompleted: {task.TaskNum} ,未找到出库单。 "); //} return content; } catch (Exception ex) { return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message)); } } /// /// 智仓调入智仓完成 /// /// /// public async Task AllocateInWarehouseTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息"); } if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { _logger.LogInformation($"TaskService InPickTaskCompleted: 未找到该托盘库存明细信息.{task.TaskNum}"); return WebResponseContent.Instance.Error($"未找到该托盘库存明细信息"); } Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo == null) { return content.Error($"未找到对应的终点货位信息"); } if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { return WebResponseContent.Instance.Error($"该托盘已绑定货位"); } if (locationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"货位状态不正确"); } _unitOfWorkManage.BeginTran(); var beforelocationStatus = locationInfo.LocationStatus; locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); _locationInfoService.Repository.UpdateData(locationInfo); stockInfo.Details.ForEach(x => { x.Status = StockStatusEmun.入库完成.ObjToInt(); }); _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details); stockInfo.LocationCode = locationInfo.LocationCode; stockInfo.PalletCode = task.PalletCode; stockInfo.LocationCode = task.TargetAddress; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); _stockRepository.UpdateData(stockInfo); task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); _unitOfWorkManage.CommitTran(); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } Dt_OutboundOrder outboundOrder = _outboundOrderService.Db.Queryable().Where(x => x.OrderNo == stockInfo.Details.FirstOrDefault().OrderNo).Includes(x=>x.Details).First(); string Operator = outboundOrder.Modifier; if (outboundOrder != null) { foreach (var item in stockInfo.Details.Where(x => x.OrderNo == outboundOrder.OrderNo).ToList()) { var inbounddetail = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == item.OrderNo && x.Barcode == item.Barcode); if (inbounddetail != null) { var alldelete = _allocateMaterialInfo.DeleteAndMoveIntoHty(inbounddetail, OperateTypeEnum.自动删除); if (!alldelete) { await Db.Deleteable(task).ExecuteCommandAsync(); } } } var allocateMaterialInfos = _allocateMaterialInfo.QueryData(x => x.OrderNo == outboundOrder.OrderNo); if (outboundOrder.Details.All(x => x.OrderDetailStatus == (int)OrderDetailStatusEnum.Over) && !allocateMaterialInfos.Any()) { outboundOrder.OrderStatus = (int)InOrderStatusEnum.入库完成; _outboundOrderService.UpdateData(outboundOrder); } } ///回调MES HttpResponseResult httpResponseResult = new HttpResponseResult(); string reqCode = Guid.NewGuid().ToString(); string reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string requestData = string.Empty; List lineNos = new List(); Dt_AllocateMaterialInfo allocateMaterialInfo = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo); if (outboundOrder.OrderStatus == OutOrderStatusEnum.出库完成.ObjToInt() && outboundOrder.ReturnToMESStatus == 0 && allocateMaterialInfo == null) { Dt_AllocateOrder allocateOrder = _allocateOrderRepository.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo); if (allocateOrder == null) { return WebResponseContent.Instance.Error($"未找到对应的调拨单"); } AllocationReturnDTO? returnDTO = BuildAllocationFeedbackData(outboundOrder, allocateOrder.FromWarehouse, allocateOrder.ToWarehouse, Operator); if (returnDTO == null) { return WebResponseContent.Instance.Error($"构建回调对象失败"); } string apiUrl = AppSettings.GetValue("AllocationFeedbackUrl"); returnDTO.ReqCode = reqCode; returnDTO.ReqTime = reqTime; JsonSerializerSettings settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; requestData = JsonConvert.SerializeObject(returnDTO, settings); lineNos = returnDTO.Details.Select(x => x.LineNo).ToList(); httpResponseResult = _httpClientHelper.Post(apiUrl, requestData); httpResponseResult.ApiUrl = apiUrl; } bool isSuccess = httpResponseResult.IsSuccess && httpResponseResult.Data.Code == "200"; string message = "成功"; if (!isSuccess) { if (!httpResponseResult.IsSuccess) { message = $"MES接口返回错误,HTTP代码:{httpResponseResult.StatusCode},信息:{httpResponseResult.ErrorMessage}"; } else if (httpResponseResult?.Data?.Code != "200") { message = $"调用MES接口失败,代码:{httpResponseResult?.Data?.Code},信息:{httpResponseResult?.Data?.Message}"; } } Dt_MesReturnRecord mesReturnRecord = new Dt_MesReturnRecord() { ApiUrl = httpResponseResult.ApiUrl, InterfaceType = outboundOrder.OrderType == 0 ? 1 : 3, OrderId = outboundOrder.Id, OrderNo = outboundOrder.OrderNo, RequestCode = reqCode, RequestData = requestData, FailureReason = message, LastReturnTime = DateTime.Now, HttpStatusCode = httpResponseResult.StatusCode.ObjToInt(), ResponseData = httpResponseResult.Content, ReturnType = 0, ReturnCount = 1, ReturnStatus = isSuccess ? 1 : 2, SuccessTime = isSuccess ? DateTime.Now : null }; _unitOfWorkManage.BeginTran(); _unitOfWorkManage.Db.Insertable(mesReturnRecord).ExecuteCommand(); List outboundOrderDetails = outboundOrder.Details.Where(x => lineNos.Contains(x.lineNo)).ToList(); outboundOrderDetails.ForEach(x => { if (x.OverOutQuantity == x.OrderQuantity - x.MoveQty) { x.ReturnToMESStatus = isSuccess ? 1 : 2; } else { x.ReturnToMESStatus = isSuccess ? 3 : 4; } x.CurrentDeliveryQty = 0; x.ReturnJsonData = ""; }); mesReturnRecord.ReturnType = outboundOrder.Details.Count == outboundOrderDetails.Count ? 1 : 2; if (outboundOrder.Details.Count == outboundOrderDetails.Count && outboundOrderDetails.All(x => x.ReturnToMESStatus == 1 || x.ReturnToMESStatus == 2)) { outboundOrder.ReturnToMESStatus = isSuccess ? 1 : 2; } else { outboundOrder.ReturnToMESStatus = isSuccess ? 3 : 4; } _outboundOrderService.Db.Updateable(outboundOrderDetails).ExecuteCommand(); _outboundOrderService.UpdateData(outboundOrder); _unitOfWorkManage.CommitTran(); try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum); } catch (Exception ex) { _logger.LogInformation($"InEmptyTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } return content; } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message)); } } public AllocationReturnDTO? BuildAllocationFeedbackData(Dt_OutboundOrder outboundOrder, string fromWarehouse, string toWarehouse,string Operator) { try { List details = outboundOrder.Details; List returnDetails = new List(); foreach (var detail in details) { List? barcodes = JsonConvert.DeserializeObject>(detail.ReturnJsonData); if (barcodes != null && barcodes.Any()) { UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(detail.MaterielCode, detail.Unit, detail.BarcodeUnit, detail.CurrentDeliveryQty); UnitConvertResultDTO totalResult = _basicService.UnitQuantityConvert(detail.MaterielCode, detail.Unit, detail.BarcodeUnit, detail.OrderQuantity); returnDetails.Add(new AllocationDetail { Barcodes = barcodes, BatchNo = detail.BatchNo, LineNo = detail.lineNo, MaterialCode = detail.MaterielCode, Qty = totalResult.ToQuantity, WarehouseCode = detail.WarehouseCode, Unit = detail.BarcodeUnit }); } } AllocationReturnDTO outboundReturnDTO = new AllocationReturnDTO() { Business_type = outboundOrder.BusinessType, Details = returnDetails, FactoryArea = outboundOrder.FactoryArea, OperationType = 1, OrderNo = outboundOrder.UpperOrderNo, FromWarehouse = fromWarehouse, ToWarehouse = toWarehouse, Operator = Operator }; return outboundReturnDTO; } catch (Exception ex) { return null; } } public async Task InPickTaskCompleted(Dt_Task task) { _logger.LogInformation($"TaskService InPickTaskCompleted: {task.TaskNum}"); try { // 查库存 Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (stockInfo == null) { _logger.LogInformation($"TaskService InPickTaskCompleted: 未找到托盘对应的组盘信息.{task.TaskNum}"); return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息"); } if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { _logger.LogInformation($"TaskService InPickTaskCompleted: 未找到该托盘库存明细信息.{task.TaskNum}"); return WebResponseContent.Instance.Error($"未找到该托盘库存明细信息"); } // 查货位 Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo == null) { _logger.LogInformation($"TaskService InPickTaskCompleted: 未找到对应的终点货位信息 {task.TaskNum}."); return WebResponseContent.Instance.Error($"未找到对应的终点货位信息"); } var beforelocationStatus = locationInfo.LocationStatus; // 获取所有回库中的出库锁定记录 //var returnLocks = await _outStockLockInfoService.Db.Queryable() // .Where(it => it.OrderNo == task.OrderNo && // it.PalletCode == task.PalletCode && // it.Status == (int)OutLockStockStatusEnum.回库中) // .ToListAsync(); // 更新出库锁定记录状态为回库完成 //foreach (var lockInfo in returnLocks) //{ // lockInfo.Status = (int)OutLockStockStatusEnum.已回库; //} //if (returnLocks.Any()) //{ // await _outStockLockInfoService.Db.Updateable(returnLocks).ExecuteCommandAsync(); // _logger.LogInformation($"更新{returnLocks.Count}条锁定记录为已回库状态"); //} // 更新库存信息 stockInfo.LocationCode = task.TargetAddress; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); // 更新库存明细状态 if (stockInfo.Details != null && stockInfo.Details.Any()) { foreach (var detail in stockInfo.Details) { if(detail.Status != StockStatusEmun.手动冻结.ObjToInt()&& detail.Status != StockStatusEmun.重检中.ObjToInt()) { detail.Status = StockStatusEmun.入库完成.ObjToInt(); } detail.OutboundQuantity = 0; } _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details); } _stockService.StockInfoService.Repository.UpdateData(stockInfo); // 删除零库存数据 await DeleteZeroQuantityStockDetails(stockInfo.Id); //await UpdateAffectedOrderDetails(task.OrderNo, returnLocks); // 更新货位状态 if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt()) { locationInfo.LocationStatus = LocationStatusEnum.Pallet.ObjToInt(); } else { locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); } _locationInfoService.Repository.UpdateData(locationInfo); task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); // 删除任务记录 //BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); //BaseDal.DeleteData(task); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } //await RecalculateOrderStatus(task.OrderNo); try { // 记录货位状态变更 _locationStatusChangeRecordService.AddLocationStatusChangeRecord( locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum ); } catch (Exception ex) { _logger.LogInformation($"InPickTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } //_logger.LogInformation($"托盘回库完成处理成功 - 任务号: {task.TaskNum}, 托盘: {task.PalletCode}, 订单: {task.OrderNo} 货位状态:{locationInfo.LocationStatus}"); //_ = Task.Run(async () => //{ // try // { // var outboundOrder = await _outboundOrderService.Db.Queryable() // .FirstAsync(x => x.OrderNo == task.OrderNo); // if (outboundOrder != null) // { // // 检查订单是否已完成,只有完成时才向MES反馈 // if (outboundOrder.OrderStatus == (int)OutOrderStatusEnum.出库完成) // { // await HandleOutboundOrderToMESCompletion(outboundOrder, outboundOrder.OrderNo); // } // else // { // _logger.LogInformation($"订单{task.OrderNo}状态为{outboundOrder.OrderStatus},暂不向MES反馈"); // } // } // } // catch (Exception ex) // { // _logger.LogError($"异步MES反馈处理失败 - OrderNo: {task.OrderNo}, Error: {ex.Message}"); // } //}); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); // 回滚事务 _logger.LogError($"TaskService InPickTaskCompleted失败 - TaskNum: {task.TaskNum}, Error: {ex.Message}"); return WebResponseContent.Instance.Error($"回库任务完成处理失败: {ex.Message}"); } return WebResponseContent.Instance.OK(); } // /// 更新受影响的订单明细锁定数量 /// private async Task UpdateAffectedOrderDetails(string orderNo, List returnLocks) { try { // 获取受影响的订单明细ID(去重) //var affectedDetailIds = returnLocks // .Select(x => x.OrderDetailId) // .Distinct() // .ToList(); //if (!affectedDetailIds.Any()) //{ // _logger.LogInformation($"没有受影响的订单明细 - OrderNo: {orderNo}"); // return; //} //_logger.LogInformation($"更新{affectedDetailIds.Count}个受影响的订单明细 - OrderNo: {orderNo}"); //foreach (var detailId in affectedDetailIds) //{ // // 重新计算该订单明细的锁定数量 // decimal currentLockQty = await CalculateOrderDetailLockQuantity(detailId); // // 检查数据一致性 // if (currentLockQty < 0) // { // _logger.LogWarning($"锁定数量计算为负值 - OrderDetailId: {detailId}, 当前值: {currentLockQty},重置为0"); // currentLockQty = 0; // } // // 获取订单明细 // var orderDetail = await _outboundOrderDetailService.Db.Queryable() // .FirstAsync(x => x.Id == detailId); // if (orderDetail == null) // { // _logger.LogWarning($"未找到订单明细 - OrderDetailId: {detailId}"); // continue; // } // // 更新锁定数量 // if (orderDetail.LockQuantity != currentLockQty) // { // await _outboundOrderDetailService.Db.Updateable() // .SetColumns(it => new Dt_OutboundOrderDetail // { // LockQuantity = currentLockQty, // }) // .Where(it => it.Id == detailId) // .ExecuteCommandAsync(); // _logger.LogInformation($"更新订单明细锁定数量 - OrderDetailId: {detailId}, " + // $"旧值: {orderDetail.LockQuantity}, 新值: {currentLockQty}"); // } // // 更新订单明细状态 // await UpdateOrderDetailStatus(orderDetail); //} } catch (Exception ex) { _logger.LogError($"UpdateAffectedOrderDetails失败 - OrderNo: {orderNo}, Error: {ex.Message}"); throw; } } /// /// 重新计算订单明细锁定数量 /// private async Task CalculateOrderDetailLockQuantity(int orderDetailId) { try { // 查找该订单明细下所有状态为"出库中"的锁定记录 var activeLocks = await _outStockLockInfoService.Db.Queryable() .Where(x => x.OrderDetailId == orderDetailId && x.Status == (int)OutLockStockStatusEnum.出库中) .ToListAsync(); // 过滤拆包记录 var filteredLocks = new List(); foreach (var lockInfo in activeLocks) { // 如果是拆包记录,需要特殊处理 if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue) { // 查找父锁定记录 var parentLock = await _outStockLockInfoService.Db.Queryable() .Where(x => x.Id == lockInfo.ParentLockId.Value) .FirstAsync(); // 如果父记录存在且状态也是出库中,则只计算父记录 if (parentLock != null && parentLock.Status == (int)OutLockStockStatusEnum.出库中) { // 父记录已经在列表中,跳过当前拆包记录 continue; } } filteredLocks.Add(lockInfo); } decimal totalLockQty = filteredLocks.Sum(x => x.AssignQuantity - x.PickedQty); _logger.LogDebug($"计算锁定数量 - OrderDetailId: {orderDetailId}, " + $"找到{filteredLocks.Count}个有效锁定记录, " + $"总锁定数量: {totalLockQty}"); return totalLockQty; } catch (Exception ex) { _logger.LogError($"CalculateOrderDetailLockQuantity失败 - OrderDetailId: {orderDetailId}, Error: {ex.Message}"); return 0; } } /// /// 更新订单明细状态 /// private async Task UpdateOrderDetailStatus(Dt_OutboundOrderDetail orderDetail) { try { int newStatus = orderDetail.OrderDetailStatus; // 根据实际枚举值调整 // 检查是否已完成(已出库数量 >= 需求数量) if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity) { newStatus = (int)OrderDetailStatusEnum.Over; // 已完成 } // 检查是否有部分出库或有锁定数量 else if (orderDetail.OverOutQuantity > 0 || orderDetail.LockQuantity > 0) { newStatus = (int)OrderDetailStatusEnum.Outbound; // 部分完成/进行中 } // 否则为新订单 else { newStatus = (int)OrderDetailStatusEnum.New; // 新建 } // 只有状态变化时才更新 if (orderDetail.OrderDetailStatus != newStatus) { await _outboundOrderDetailService.Db.Updateable() .SetColumns(it => new Dt_OutboundOrderDetail { OrderDetailStatus = newStatus, }) .Where(it => it.Id == orderDetail.Id) .ExecuteCommandAsync(); _logger.LogInformation($"更新订单明细状态 - OrderDetailId: {orderDetail.Id}, " + $"旧状态: {orderDetail.OrderDetailStatus}, 新状态: {newStatus}, " + $"已出库: {orderDetail.OverOutQuantity}/{orderDetail.NeedOutQuantity}, " + $"锁定数量: {orderDetail.LockQuantity}"); } } catch (Exception ex) { _logger.LogError($"UpdateOrderDetailStatus失败 - OrderDetailId: {orderDetail.Id}, Error: {ex.Message}"); throw; } } /// /// 重新计算并更新订单状态 /// private async Task RecalculateOrderStatus(string orderNo) { try { // 获取订单的所有明细 var orderDetails = await _outboundOrderDetailService.Db.Queryable() .LeftJoin((o, item) => o.OrderId == item.Id) .Where((o, item) => item.OrderNo == orderNo) .Select((o, item) => o) .ToListAsync(); if (!orderDetails.Any()) { _logger.LogWarning($"未找到订单明细 - OrderNo: {orderNo}"); return; } // 检查状态 bool allCompleted = true; bool hasInProgress = false; foreach (var detail in orderDetails) { // 检查是否完成 if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; } // 检查是否有进行中的任务(锁定或部分拣选) if (detail.LockQuantity > 0 || detail.OrderDetailStatus == (int)OrderDetailStatusEnum.Outbound) { hasInProgress = true; } await UpdateOrderDetailStatus(detail); } var outboundOrder = await _outboundOrderService.Db.Queryable() .FirstAsync(x => x.OrderNo == orderNo); if (outboundOrder == null) { _logger.LogWarning($"未找到出库订单 - OrderNo: {orderNo}"); return; } int newStatus; if (allCompleted) { newStatus = (int)OutOrderStatusEnum.出库完成; } else if (hasInProgress) { newStatus = (int)OutOrderStatusEnum.出库中; } else { newStatus = (int)OutOrderStatusEnum.未开始; } if (outboundOrder.OrderStatus != newStatus) { await _outboundOrderService.Db.Updateable() .SetColumns(x => new Dt_OutboundOrder { OrderStatus = newStatus, }) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); _logger.LogInformation($"更新订单状态 - OrderNo: {orderNo}, 旧状态: {outboundOrder.OrderStatus}, 新状态: {newStatus}"); } } catch (Exception ex) { _logger.LogError($"RecalculateOrderStatus失败 - OrderNo: {orderNo}, Error: {ex.Message}"); throw; } } /// /// 删除零库存数据(增强版) /// private async Task DeleteZeroQuantityStockDetails(int stockId) { try { // 查找库存数量为0的记录 var zeroStockDetails = await _stockService.StockInfoDetailService.Db.Queryable() .Where(x => x.StockId == stockId && x.StockQuantity <= 0) .ToListAsync(); if (zeroStockDetails.Any()) { await _stockService.StockInfoDetailService.Db.Deleteable(zeroStockDetails).ExecuteCommandAsync(); _logger.LogInformation($"删除{zeroStockDetails.Count}条零库存记录 - StockId: {stockId}"); } } catch (Exception ex) { _logger.LogError($"DeleteZeroQuantityStockDetails失败 - StockId: {stockId}, Error: {ex.Message}"); throw; } } private async Task HandleOutboundOrderToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo) { try { var orderDetails = await _outboundOrderDetailService.Db.Queryable() .LeftJoin((o, item) => o.OrderId == item.Id) .Where((o, item) => item.OrderNo == orderNo) .Select((o, item) => o) .ToListAsync(); bool allCompleted = true; foreach (var detail in orderDetails) { _logger.LogInformation($"TaskService HandleOutboundOrderToMESCompletion: {outboundOrder.OrderNo} , {detail.NeedOutQuantity}"); if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; break; } } _logger.LogInformation($"TaskService HandleOutboundOrderToMESCompletion: {outboundOrder.OrderNo} , {allCompleted}"); int newStatus = allCompleted ? (int)OutOrderStatusEnum.出库完成 : (int)OutOrderStatusEnum.出库中; if (outboundOrder.OrderStatus != newStatus) { await _outboundOrderService.Db.Updateable() .SetColumns(x => x.OrderStatus == newStatus) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } //只有正常分拣完成时才向MES反馈 if (allCompleted && newStatus == (int)OutOrderStatusEnum.出库完成) { if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt() || outboundOrder.OrderType == OutOrderTypeEnum.InternalAllocat.ObjToInt()) { var allocate = _allocateService.Repository.QueryData(x => x.UpperOrderNo == outboundOrder.UpperOrderNo).First(); var allocatefeedmodel = new AllocateDto { ReqCode = Guid.NewGuid().ToString(), ReqTime = DateTime.Now.ToString(), BusinessType = "2", FactoryArea = outboundOrder.FactoryArea, OperationType = 1, Operator = outboundOrder.Operator, OrderNo = outboundOrder.UpperOrderNo, // documentsNO = outboundOrder.OrderNo, // status = outboundOrder.OrderStatus, fromWarehouse = allocate?.FromWarehouse ?? "", toWarehouse = allocate?.ToWarehouse ?? "", Details = new List() }; foreach (var detail in orderDetails) { // 获取该明细对应的条码信息(从锁定记录) var detailLocks = await _outStockLockInfoService.Db.Queryable() .Where(x => x.OrderNo == orderNo && x.OrderDetailId == detail.Id && (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库)) .ToListAsync(); var detailModel = new AllocateDtoDetail { MaterialCode = detail.MaterielCode, LineNo = detail.lineNo, WarehouseCode = detail.WarehouseCode, Qty = 0, Unit = detail.BarcodeUnit, Barcodes = new List() }; foreach (var item in detailLocks) { if (item.PickedQty > 0) { var barModel = new BarcodeInfo { Barcode = item.CurrentBarcode, SupplyCode = item.SupplyCode, BatchNo = item.BatchNo, Unit = detail.BarcodeUnit, Qty = 0 }; // 单位不一致时转换 if (detail.BarcodeUnit != detail.Unit) { var convertResult = await _materialUnitService.ConvertAsync(item.MaterielCode, item.PickedQty, detail.Unit, detail.BarcodeUnit); barModel.Unit = convertResult.Unit; barModel.Qty = convertResult.Quantity; } else { barModel.Qty = item.PickedQty; } detailModel.Qty += barModel.Qty; detailModel.Barcodes.Add(barModel); } allocatefeedmodel.Details.Add(detailModel); } var groupedResult = allocatefeedmodel.Details .GroupBy(item => new { item.WarehouseCode, item.MaterialCode, item.Unit, item.LineNo }) .Select(group => { var deduplicatedBarcodes = group.SelectMany(x => x.Barcodes) .GroupBy(b => b.Barcode) .Select(b => new BarcodeInfo { Barcode = b.Key, BatchNo = b.First().BatchNo, SupplyCode = b.First().SupplyCode, Qty = b.Max(x => x.Qty), Unit = b.First().Unit }).ToList(); return new AllocateDtoDetail { WarehouseCode = group.Key.WarehouseCode, MaterialCode = group.Key.MaterialCode, LineNo = group.Key.LineNo, Qty = deduplicatedBarcodes.Sum(b => b.Qty), Unit = group.Key.Unit, Barcodes = deduplicatedBarcodes }; }).ToList(); allocatefeedmodel.Details = groupedResult; var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel); if (result != null && result.code == 200) { await _outboundOrderDetailService.Db.Updateable() .SetColumns(x => x.ReturnToMESStatus == 1) .Where(x => x.OrderId == outboundOrder.Id).ExecuteCommandAsync(); await _outboundOrderService.Db.Updateable() .SetColumns(x => new Dt_OutboundOrder { ReturnToMESStatus = 1, }).Where(x => x.OrderNo == orderNo).ExecuteCommandAsync(); } else { await _outboundOrderDetailService.Db.Updateable() .SetColumns(x => x.ReturnToMESStatus == 2) .Where(x => x.OrderId == outboundOrder.Id) .ExecuteCommandAsync(); await _outboundOrderService.Db.Updateable() .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = result.message }) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } } } else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt()) { //不用回传 } else { if (outboundOrder != null && outboundOrder.IsBatch == 0) { var feedmodel = new FeedbackOutboundRequestModel { reqCode = Guid.NewGuid().ToString(), reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), business_type = outboundOrder.BusinessType, factoryArea = outboundOrder.FactoryArea, operationType = 1, Operator = outboundOrder.Operator, orderNo = outboundOrder.UpperOrderNo, documentsNO = outboundOrder.OrderNo, status = outboundOrder.OrderStatus, details = new List() }; foreach (var detail in orderDetails) { // 获取该明细对应的条码信息(从锁定记录) var detailLocks = await _outStockLockInfoService.Db.Queryable() .Where(x => x.OrderNo == orderNo && x.OrderDetailId == detail.Id && (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库)) .ToListAsync(); var detailModel = new FeedbackOutboundDetailsModel { materialCode = detail.MaterielCode, lineNo = detail.lineNo, // 注意:这里可能需要调整字段名 warehouseCode = detail.WarehouseCode, qty = 0, currentDeliveryQty = 0, unit = detail.Unit, barcodes = new List() }; foreach (var item in detailLocks) { if (item.PickedQty > 0) { var barModel = new WIDESEA_DTO.Outbound.BarcodesModel { barcode = item.CurrentBarcode, supplyCode = item.SupplyCode, batchNo = item.BatchNo, unit = item.BarcodeUnit, qty = item.PickedQty }; // 单位不一致时转换 if (detail.BarcodeUnit != detail.Unit) { var convertResult = await _materialUnitService.ConvertAsync(item.MaterielCode, item.PickedQty, detail.Unit, detail.BarcodeUnit); barModel.unit = convertResult.Unit; barModel.qty = convertResult.Quantity; } else { barModel.qty = item.PickedQty; } detailModel.qty += barModel.qty; detailModel.currentDeliveryQty += barModel.qty; detailModel.barcodes.Add(barModel); } } feedmodel.details.Add(detailModel); } var groupedResult = feedmodel.details .GroupBy(item => new { item.warehouseCode, item.materialCode, item.unit, item.lineNo }) .Select(group => { var deduplicatedBarcodes = group.SelectMany(x => x.barcodes) .GroupBy(b => b.barcode) .Select(b => new WIDESEA_DTO.Outbound.BarcodesModel { barcode = b.Key, batchNo = b.First().batchNo, supplyCode = b.First().supplyCode, qty = b.Max(x => x.qty), unit = b.First().unit }).ToList(); return new FeedbackOutboundDetailsModel { warehouseCode = group.Key.warehouseCode, materialCode = group.Key.materialCode, lineNo = group.Key.lineNo, qty = deduplicatedBarcodes.Sum(b => b.qty), unit = group.Key.unit, barcodes = deduplicatedBarcodes }; }).ToList(); feedmodel.details = groupedResult; var result = await _invokeMESService.FeedbackOutbound(feedmodel); if (result != null && result.code == 200) { await _outboundOrderDetailService.Db.Updateable() .SetColumns(x => x.ReturnToMESStatus == 1) .Where(x => x.OrderId == outboundOrder.Id) .ExecuteCommandAsync(); await _outboundOrderService.Db.Updateable() .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = "" }) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } else { await _outboundOrderDetailService.Db.Updateable() .SetColumns(x => x.ReturnToMESStatus == 2) .Where(x => x.OrderId == outboundOrder.Id) .ExecuteCommandAsync(); await _outboundOrderService.Db.Updateable() .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = result.message }) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } } else if (outboundOrder != null && outboundOrder.IsBatch == 1) { await _invokeMESService.BatchOrderFeedbackToMes(new List() { outboundOrder.OrderNo }, 2); } } } } catch (Exception ex) { _logger.LogError($"CheckAndUpdateOrderStatus失败 - OrderNo: {orderNo}, Error: {ex.Message}"); } } public async Task OutEmptyTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { Dt_StockInfo stockInfo = _stockRepository.Db.Queryable().Where(x => x.PalletCode == task.PalletCode).First(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘对应的库存信息"); } Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.SourceAddress); if (locationInfo == null) { return content.Error($"未找到对应的终点货位信息"); } int beforeStatus = locationInfo.LocationStatus; locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); _locationInfoService.Repository.UpdateData(locationInfo); task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); // BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } var stockresult = _stockService.StockInfoService.Repository.DeleteAndMoveIntoHty(stockInfo, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); if (!stockresult) { _stockRepository.Db.Deleteable(stockInfo).ExecuteCommand(); } _stockService.StockInfoService.DeleteData(stockInfo); try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Outbound.ObjToInt(), stockInfo?.Details.FirstOrDefault()?.OrderNo ?? "", task.TaskNum); } catch (Exception ex) { _logger.LogError($"TaskService OutEmptyTaskCompleted AddLocationStatusChangeRecord: {ex.Message} "); } return await Task.FromResult(WebResponseContent.Instance.OK()); } catch (Exception ex) { _logger.LogError($"TaskService OutEmptyTaskCompleted: {ex.Message} "); return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message)); } } /// /// 回库完成回调 public async Task BackToStockComplete(Dt_Task task) { try { _unitOfWorkManage.BeginTran(); // 获取相关的出库锁定信息 var lockInfos = await _outStockLockInfoService.Db.Queryable() .Where(x => x.TaskNum == task.TaskNum && x.Status == (int)OutLockStockStatusEnum.回库中) .ToListAsync(); if (!lockInfos.Any()) return WebResponseContent.Instance.Error("未找到回库中的锁定信息"); // 恢复库存出库数量(回库的部分) await RestoreStockOutboundQuantity(lockInfos); // 更新出库单明细的锁定数量 var orderDetailGroups = lockInfos.GroupBy(x => x.OrderDetailId); foreach (var group in orderDetailGroups) { var orderDetailId = group.Key; var totalUnpicked = group.Sum(x => x.AssignQuantity - x.PickedQty); if (totalUnpicked > 0) { var orderDetail = await _outboundOrderService.Db.Queryable() .Where(x => x.Id == orderDetailId) .FirstAsync(); orderDetail.LockQuantity -= totalUnpicked; // 恢复状态 if (orderDetail.LockQuantity <= 0 && orderDetail.OverOutQuantity <= 0) { orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.New; } else if (orderDetail.OverOutQuantity > 0) { orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.AssignOverPartial; } await _outboundOrderService.Db.Updateable(orderDetail).ExecuteCommandAsync(); } } // 更新锁定信息状态为已回库 foreach (var lockInfo in lockInfos) { lockInfo.Status = (int)OutLockStockStatusEnum.已回库; } await _outStockLockInfoService.Db.Updateable(lockInfos).ExecuteCommandAsync(); // 6. 更新库存状态 var stockIds = lockInfos.Select(x => x.StockId).Distinct().ToList(); var stocks = await _stockService.StockInfoService.Db.Queryable() .Where(x => stockIds.Contains(x.Id)) .ToListAsync(); foreach (var stock in stocks) { stock.StockStatus = (int)StockStatusEmun.入库完成; stock.LocationCode = task.TargetAddress; // 更新货位 } await _stockService.StockInfoService.Db.Updateable(stocks).ExecuteCommandAsync(); // 7. 更新货位状态 var location = await _locationInfoService.Db.Queryable() .Where(x => x.LocationCode == task.TargetAddress) .FirstAsync(); if (location != null) { location.LocationStatus = (int)LocationStatusEnum.InStock; await _locationInfoService.Db.Updateable(location).ExecuteCommandAsync(); } // 更新任务状态为已完成 task.TaskStatus = (int)TaskStatusEnum.Finish; await Db.Updateable(task).ExecuteCommandAsync(); _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK("回库完成", new { TaskNum = task.TaskNum, PalletCode = task.PalletCode, RestoredQuantity = lockInfos.Sum(x => x.AssignQuantity - x.PickedQty) }); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return WebResponseContent.Instance.Error($"回库完成处理失败: {ex.Message}"); } } /// /// 恢复库存出库数量(回库的部分) /// private async Task RestoreStockOutboundQuantity(List lockInfos) { // 按库存ID和物料分组 var stockGroups = lockInfos.GroupBy(x => new { x.StockId, x.MaterielCode }); foreach (var group in stockGroups) { var stockId = group.Key.StockId; var materielCode = group.Key.MaterielCode; var totalUnpicked = group.Sum(x => x.AssignQuantity - x.PickedQty); if (totalUnpicked <= 0) continue; // 获取该物料在库存中的所有条码 var stockDetails = await _stockService.StockInfoDetailService.Db.Queryable() .Where(x => x.StockId == stockId && x.MaterielCode == materielCode) .ToListAsync(); if (!stockDetails.Any()) continue; // 按出库数量的比例分配恢复数量 var totalOutbound = stockDetails.Sum(x => x.OutboundQuantity); if (totalOutbound <= 0) continue; foreach (var detail in stockDetails) { if (detail.OutboundQuantity <= 0) continue; decimal ratio = detail.OutboundQuantity / totalOutbound; decimal restoreAmount = Math.Min(detail.OutboundQuantity, totalUnpicked * ratio); detail.OutboundQuantity -= restoreAmount; await _stockService.StockInfoDetailService.Db.Updateable(detail).ExecuteCommandAsync(); } } } public Task HandCompleteTask(string TaskNum) { return TaskCompleted(TaskNum); } /// /// 盘点出库完成 /// public async Task OutInventoryTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { task = BaseDal.QueryFirst(x => x.TaskNum == task.TaskNum); if (task == null) { return WebResponseContent.Instance.Error("未找到任务信息"); } var SourceAddress = task.SourceAddress; Dt_StockInfo stockInfo = _stockService.StockInfoService.Repository.QueryFirst(x=>x.PalletCode == task.PalletCode); Dt_LocationInfo locationInfo = _basicService.LocationInfoService.Repository.QueryFirst(x => x.LocationCode == SourceAddress); if (stockInfo == null) return WebResponseContent.Instance.Error("未找到库存信息"); if (locationInfo == null) return WebResponseContent.Instance.Error("未找到货位信息"); //获取对应盘点单 Dt_TakeStockOrder takeStockOrder = _takeStockOrder.Db.Queryable().Where(x => x.OrderNo == task.OrderNo).Includes(x => x.Details).First(); if (takeStockOrder == null) { return content.Error($"盘点单{task.OrderNo}不存在"); } if (takeStockOrder.TakeStockStatus != TakeStockStatusEnum.盘点中.ObjToInt()) { return content.Error($"盘点单{task.OrderNo}盘点已完成或未开始"); } if (stockInfo.StockStatus != StockStatusEmun.出库锁定.ObjToInt()) { return content.Error($"{stockInfo.PalletCode}库存状态不正确"); } if (locationInfo.LocationStatus != LocationStatusEnum.Lock.ObjToInt()) { return content.Error($"{locationInfo.LocationCode}货位状态不正确"); } stockInfo.StockStatus = StockStatusEmun.盘点出库完成.ObjToInt(); stockInfo.LocationCode = ""; task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); int beforeStatus = locationInfo.LocationStatus; locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); _unitOfWorkManage.BeginTran(); //货位变动记录 _basicService.LocationInfoService.UpdateData(locationInfo); _recordService.LocationStatusChangeRecordSetvice.AddLocationStatusChangeRecord(locationInfo, beforeStatus, LocationStatusEnum.Free.ObjToInt(), takeStockOrder?.OrderNo ?? "", task.TaskNum); _stockRepository.UpdateData(stockInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); content.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message)); } return content; } /// /// 盘点入库完成 /// /// /// public async Task InInventoryTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo == null) { return content.Error($"未找到对应的终点货位信息"); } Dt_StockInfo stockInfo = _stockRepository.Db.Queryable().Where(x => x.PalletCode == task.PalletCode && x.WarehouseId == task.WarehouseId).First(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息"); } if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { return WebResponseContent.Instance.Error($"该托盘已绑定货位"); } if (locationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"货位状态不正确"); } var beforelocationStatus = locationInfo.LocationStatus; locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); stockInfo.LocationCode = locationInfo.LocationCode; stockInfo.PalletCode = task.PalletCode; stockInfo.LocationCode = task.TargetAddress; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); _unitOfWorkManage.BeginTran(); _locationInfoService.Repository.UpdateData(locationInfo); _stockRepository.UpdateData(stockInfo); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除); _unitOfWorkManage.CommitTran(); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum); } catch (Exception ex) { _logger.LogInformation($"InEmptyTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } return content; } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message)); } } /// /// 重检入库完成 /// /// /// public async Task InQualityTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息"); } if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { _logger.LogInformation($"TaskService InPickTaskCompleted: 未找到该托盘库存明细信息.{task.TaskNum}"); return WebResponseContent.Instance.Error($"未找到该托盘库存明细信息"); } Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo == null) { return content.Error($"未找到对应的终点货位信息"); } if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { return WebResponseContent.Instance.Error($"该托盘已绑定货位"); } if (locationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"货位状态不正确"); } _unitOfWorkManage.BeginTran(); var beforelocationStatus = locationInfo.LocationStatus; locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); _locationInfoService.Repository.UpdateData(locationInfo); stockInfo.LocationCode = locationInfo.LocationCode; stockInfo.PalletCode = task.PalletCode; stockInfo.LocationCode = task.TargetAddress; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); _stockRepository.UpdateData(stockInfo); task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); _unitOfWorkManage.CommitTran(); if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } Dt_OutboundOrder outboundOrder = _outboundOrderService.Db.Queryable().Where(x => x.OrderNo == stockInfo.Details.FirstOrDefault().OrderNo).Includes(x => x.Details).First(); if (outboundOrder != null) { foreach (var item in stockInfo.Details.Where(x => x.OrderNo == outboundOrder.OrderNo).ToList()) { var inbounddetail = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == item.OrderNo && x.Barcode == item.Barcode); if (inbounddetail != null) { var alldelete = _allocateMaterialInfo.DeleteAndMoveIntoHty(inbounddetail, OperateTypeEnum.自动删除); if (!alldelete) { await Db.Deleteable(task).ExecuteCommandAsync(); } } } } try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum); } catch (Exception ex) { _logger.LogInformation($"InEmptyTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } return content; } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message)); } } /// /// 任务取消 /// /// /// /// public async Task TaskCancel(List taskCodes) { try { if (taskCodes == null || !taskCodes.Any()) { return WebResponseContent.Instance.Error("取消的任务号不能为空"); } //var taskCancelUrl = AppSettings.GetValue("TaskCancelUrl"); //TaskCancelRequest taskc = new TaskCancelRequest(); //taskc.TaskCodes = taskCodes.Select(x => x.ToString()).ToList(); //string json = JsonConvert.SerializeObject(taskc); //using var clientHttp = new HttpClient(); //var content = new StringContent(json, Encoding.UTF8, "application/json"); //HttpResponseMessage response = await clientHttp.PostAsync(taskCancelUrl,content); //string responseJson = await response.Content.ReadAsStringAsync(); //TaskCancelApiResponse apiResponse = JsonConvert.DeserializeObject(responseJson); //if (apiResponse.Code != 0) //{ // return WebResponseContent.Instance.Error($"请求失败:{apiResponse.Msg}"); //} _unitOfWorkManage.BeginTran(); var tasks = await Db.Queryable() .Where(x => taskCodes.Contains(x.TaskNum)) .ToListAsync(); if (!tasks.Any()) { _unitOfWorkManage.RollbackTran(); return WebResponseContent.Instance.Error("未找到对应的任务信息"); } int inPickType = TaskTypeEnum.InPick.ObjToInt(); var inboundTypes = new List { TaskTypeEnum.InAllocate.ObjToInt(), TaskTypeEnum.InEmpty.ObjToInt(), TaskTypeEnum.Inbound.ObjToInt(), TaskTypeEnum.InInventory.ObjToInt(), TaskTypeEnum.InQuality.ObjToInt() }; var outboundTypes = new List { TaskTypeEnum.Outbound.ObjToInt(), TaskTypeEnum.OutAllocate.ObjToInt() }; foreach (var task in tasks) { if (task.TaskStatus == TaskStatusEnum.Cancel.ObjToInt()) continue; var stock = await _stockRepository.QueryFirstAsync(x => x.PalletCode == task.PalletCode); if (stock == null) throw new Exception($"托盘 {task.PalletCode} 未找到库存信息"); if (task.TaskType == inPickType) { stock.StockStatus = StockStatusEmun.出库完成.ObjToInt(); } else if (inboundTypes.Contains(task.TaskType)) { stock.StockStatus = StockStatusEmun.组盘暂存.ObjToInt(); } else if (outboundTypes.Contains(task.TaskType)) { stock.StockStatus = StockStatusEmun.入库完成.ObjToInt(); var outStockLock = await _outStockLockInfoService.Db .Queryable() .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (outStockLock == null) throw new Exception($"托盘 {task.PalletCode} 未找到出库锁定信息"); int detailId = outStockLock.OrderDetailIds.ObjToInt(); var outboundDetail = await _outboundOrderDetailService.Db .Queryable() .Where(x => x.Id == detailId) .FirstAsync(); if (outboundDetail == null) throw new Exception($"出库明细ID {detailId} 不存在"); if (outboundDetail.LockQuantity < outStockLock.AssignQuantity) throw new Exception($"出库明细 {detailId} 锁定数量不足"); outboundDetail.LockQuantity -= outStockLock.AssignQuantity; _outboundOrderDetailService.UpdateData(outboundDetail); _outboundLockInfoRepository.DeleteAndMoveIntoHty(outStockLock, OperateTypeEnum.人工删除); } await _stockRepository.UpdateDataAsync(stock); task.TaskStatus = TaskStatusEnum.Cancel.ObjToInt(); bool archiveSuccess = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除); if (!archiveSuccess) { await Db.Deleteable(task).ExecuteCommandAsync(); } } _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK("任务取消成功"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); _logger.LogError(ex, "任务取消异常"); return WebResponseContent.Instance.Error($"任务取消失败:{ex.Message}"); } } public async Task AreaRelocationTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { if (task == null || string.IsNullOrEmpty(task.PalletCode) || string.IsNullOrEmpty(task.TargetAddress)) { return WebResponseContent.Instance.Error("移库任务信息不完整(托盘号/目标货位为空)"); } // 2. 查询托盘库存信息 Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘[{task.PalletCode}]对应的组盘信息"); } // 非空托盘必须有明细 if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { _logger.LogInformation($"TaskService RelocationTaskCompleted: 未找到该托盘库存明细信息.{task.TaskNum}"); return WebResponseContent.Instance.Error($"未找到该托盘[{task.PalletCode}]库存明细信息"); } // 3. 查询目标货位+原货位信息 Dt_LocationInfo targetLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (targetLocationInfo == null) { return content.Error($"未找到对应的终点货位[{task.TargetAddress}]信息"); } // 原货位信息 Dt_LocationInfo oldLocationInfo = null; if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { oldLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode); if (oldLocationInfo == null) { return content.Error($"未找到原货位[{stockInfo.LocationCode}]信息"); } } // 4. 货位状态校验 if (targetLocationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"目标货位[{task.TargetAddress}]状态不正确(当前为已占用)"); } // 5. 开启事务处理核心逻辑 _unitOfWorkManage.BeginTran(); // 5.1 记录目标货位原状态,更新为占用 var beforeTargetLocationStatus = targetLocationInfo.LocationStatus; targetLocationInfo.LocationStatus = stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt() ? LocationStatusEnum.Pallet.ObjToInt() : LocationStatusEnum.InStock.ObjToInt(); _locationInfoService.Repository.UpdateData(targetLocationInfo); // 5.2 释放原货位 int beforeOldLocationStatus = 0; if (oldLocationInfo != null) { beforeOldLocationStatus = oldLocationInfo.LocationStatus; // 原货位恢复为空闲 oldLocationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); _locationInfoService.Repository.UpdateData(oldLocationInfo); } // 5.4 更新库存主信息(绑定新货位) string oldLocationCode = stockInfo.LocationCode; // 记录原货位 stockInfo.LocationCode = targetLocationInfo.LocationCode; // 绑定目标货位 stockInfo.PalletCode = task.PalletCode; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); _stockRepository.UpdateData(stockInfo); // 5.5 更新任务状态为完成 task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); // 提交事务 _unitOfWorkManage.CommitTran(); // 任务归档失败则直接删除 if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } try { // 记录目标货位状态变更 _locationStatusChangeRecordService.AddLocationStatusChangeRecord( targetLocationInfo, beforeTargetLocationStatus, StockChangeType.Inbound.ObjToInt(), $"移库入库(原货位:{oldLocationCode})", task.TaskNum); // 记录原货位状态变更(若有) if (oldLocationInfo != null) { _locationStatusChangeRecordService.AddLocationStatusChangeRecord( oldLocationInfo, beforeOldLocationStatus, StockChangeType.Outbound.ObjToInt(), $"移库出库(目标货位:{targetLocationInfo.LocationCode})", task.TaskNum); } } catch (Exception ex) { _logger.LogInformation($"RelocationTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); } return content.OK(); } catch (Exception ex) { // 事务回滚 _unitOfWorkManage.RollbackTran(); _logger.LogError($"RelocationTaskCompleted 处理失败:{ex.Message}", ex); return await Task.FromResult(WebResponseContent.Instance.Error($"移库任务处理失败:{ex.Message}")); } } /// /// 跨区域移库任务完成 /// /// /// public async Task CrossAreaRelocationTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { if (task == null || string.IsNullOrEmpty(task.PalletCode) || string.IsNullOrEmpty(task.TargetAddress)) { return WebResponseContent.Instance.Error("跨区域移库任务信息不完整(托盘号/目标货位为空)"); } // 2. 查询托盘库存信息 Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"未找到托盘[{task.PalletCode}]对应的库存信息"); } // 非空托盘必须有明细 if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { _logger.LogInformation($"CrossAreaRelocationTaskCompleted: 未找到该托盘库存明细信息.{task.TaskNum}"); return WebResponseContent.Instance.Error($"未找到该托盘[{task.PalletCode}]库存明细信息"); } // 3. 查询目标货位 + 原货位信息 Dt_LocationInfo targetLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (targetLocationInfo == null) { return content.Error($"未找到对应的终点货位[{task.TargetAddress}]信息"); } // 原货位信息 Dt_LocationInfo oldLocationInfo = null; if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { oldLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode); if (oldLocationInfo == null) { return content.Error($"未找到原货位[{stockInfo.LocationCode}]信息"); } } // 4. 货位状态校验 if (targetLocationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"目标货位[{task.TargetAddress}]状态不正确(当前为已占用)"); } // 5. 开启事务处理核心逻辑 _unitOfWorkManage.BeginTran(); // 5.1 目标货位更新为占用 var beforeTargetLocationStatus = targetLocationInfo.LocationStatus; targetLocationInfo.LocationStatus = stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt() ? LocationStatusEnum.Pallet.ObjToInt() : LocationStatusEnum.InStock.ObjToInt(); _locationInfoService.Repository.UpdateData(targetLocationInfo); // 5.2 原货位释放空闲 int beforeOldLocationStatus = 0; if (oldLocationInfo != null) { beforeOldLocationStatus = oldLocationInfo.LocationStatus; oldLocationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); _locationInfoService.Repository.UpdateData(oldLocationInfo); } // 5.3 更新库存:绑定新货位 + 恢复正常状态 string oldLocationCode = stockInfo.LocationCode; stockInfo.LocationCode = targetLocationInfo.LocationCode; stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt(); stockInfo.LocationType = targetLocationInfo.LocationType; _stockRepository.UpdateData(stockInfo); // 5.4 任务标记为完成 task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); // 提交事务 _unitOfWorkManage.CommitTran(); // 任务归档失败则删除 if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } // 记录货位状态变更日志 try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord( targetLocationInfo, beforeTargetLocationStatus, StockChangeType.Inbound.ObjToInt(), $"跨区域移库入库(原货位:{oldLocationCode})", task.TaskNum); if (oldLocationInfo != null) { _locationStatusChangeRecordService.AddLocationStatusChangeRecord( oldLocationInfo, beforeOldLocationStatus, StockChangeType.Outbound.ObjToInt(), $"跨区域移库出库(目标货位:{targetLocationInfo.LocationCode})", task.TaskNum); } } catch (Exception ex) { _logger.LogInformation($"CrossAreaRelocationTaskCompleted 记录日志异常:{ex.Message}"); } return content.OK("跨区域移库任务完成"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); _logger.LogError($"CrossAreaRelocationTaskCompleted 处理失败:{ex.Message}", ex); return await Task.FromResult(WebResponseContent.Instance.Error($"跨区域移库任务处理失败:{ex.Message}")); } } } }