647556386
2025-11-22 68628c6cc163cddfcc745c225a9f3f34767261ef
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -16,12 +16,17 @@
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using AutoMapper;
using Dm.filter;
using MailKit.Search;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Org.BouncyCastle.Asn1.Ocsp;
using Org.BouncyCastle.Asn1.Pkcs;
using SqlSugar;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading.Tasks;
using System.Xml.Linq;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.OrderEnum;
@@ -31,9 +36,13 @@
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.Allocate;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO.Inbound;
using WIDESEA_DTO.Task;
using WIDESEA_IAllocateService;
using WIDESEA_IBasicService;
using WIDESEA_IInboundService;
using WIDESEA_IOutboundService;
@@ -53,8 +62,17 @@
        private readonly IRepository<Dt_StockInfo> _stockRepository;
        private readonly ILocationInfoService _locationInfoService;
        private readonly IInboundOrderService _inboundOrderService;
        private readonly IInboundOrderDetailService _inboundOrderDetailService;
        private readonly IOutboundOrderService _outboundOrderService;
        private readonly IOutboundOrderDetailService _outboundOrderDetailService;
        private readonly IOutStockLockInfoService _outStockLockInfoService;
        private readonly ILocationStatusChangeRecordService _locationStatusChangeRecordService;
        private readonly IESSApiService _eSSApiService;
        private readonly IStockService _stockService;
        private readonly IRecordService _recordService;
        private readonly IAllocateService _allocateService;
        private readonly IInvokeMESService _invokeMESService;
        public IRepository<Dt_Task> Repository => BaseDal;
        private Dictionary<string, SqlSugar.OrderByType> _taskOrderBy = new()
@@ -66,15 +84,15 @@
        private Dictionary<string, string> stations = new Dictionary<string, string>
        {
            {"3-5","3-9" },
             {"2-5","2-9" },
              {"1-11","1-1" },
            {"2-5","2-9" },
            {"1-11","1-1" },
        };
        public List<int> TaskTypes => typeof(TaskTypeEnum).GetEnumIndexList();
        public List<int> TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList();
        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger) : base(BaseDal)
        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService) : base(BaseDal)
        {
            _mapper = mapper;
            _unitOfWorkManage = unitOfWorkManage;
@@ -84,270 +102,318 @@
            _locationStatusChangeRecordService = locationStatusChangeRecordService;
            _eSSApiService = eSSApiService;
            _logger = logger;
            _stockService = stockService;
            _recordService = recordService;
            _inboundOrderDetailService = inboundOrderDetailService;
            _outboundOrderService = outboundOrderService;
            _outboundOrderDetailService = outboundOrderDetailService;
            _invokeMESService = invokeMESService;
            _outStockLockInfoService = outStockLockInfoService;
            _allocateService = allocateService;
        }
        public async Task<WebResponseContent> RequestInboundTask(string palletCode, string stationCode)
        {
            try
            {
                Dt_Task dbtask = Repository.QueryFirst(x => x.PalletCode == palletCode);
                if (dbtask != null)
                {
                    return WebResponseContent.Instance.Error($"该托盘已生成任务");
                }
                Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == palletCode).Includes(x => x.Details).First();
                if (stockInfo == null)
                {
                    return WebResponseContent.Instance.Error($"未找到组盘信息");
                }
                if (stockInfo.StockStatus != StockStatusEmun.组盘暂存.ObjToInt() && stockInfo.StockStatus != StockStatusEmun.手动组盘暂存.ObjToInt() && stockInfo.StockStatus != StockStatusEmun.拣选完成.ObjToInt())
                {
                    return WebResponseContent.Instance.Error($"该托盘状态不正确,不可申请入库");
                }
                if (!string.IsNullOrEmpty(stockInfo.LocationCode))
                {
                    return WebResponseContent.Instance.Error($"该托盘已绑定货位");
                }
                Dt_LocationInfo? locationInfo = _locationInfoService.AssignLocation();
                if (locationInfo == null)
                {
                    return WebResponseContent.Instance.Error($"货位分配失败,未找到可分配货位");
                }
                var newTask = new Dt_Task()
                {
                    CurrentAddress = stationCode,
                    Grade = 0,
                    NextAddress = stations.GetValueOrDefault(stationCode) ?? "",
                    PalletCode = palletCode,
                    Roadway = locationInfo.RoadwayNo,
                    SourceAddress = stationCode,
                    TargetAddress = locationInfo.LocationCode,
                    TaskType = TaskTypeEnum.Inbound.ObjToInt(),
                    TaskStatus = TaskStatusEnum.New.ObjToInt(),
                    WarehouseId = stockInfo.WarehouseId,
                    PalletType = stockInfo.PalletType,
                };
                if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt())
                {
                    _unitOfWorkManage.BeginTran();
                    int taskId = BaseDal.AddData(newTask);
                    newTask.TaskId = taskId;
                    locationInfo.LocationStatus = LocationStatusEnum.Lock.ObjToInt();
                    _locationInfoService.UpdateData(locationInfo);
                    stockInfo.StockStatus = StockStatusEmun.入库确认.ObjToInt();
                    _stockRepository.UpdateData(stockInfo);
                    _unitOfWorkManage.CommitTran();
                }
                else
                {
                    //获取是否存在入库单
                    Dt_InboundOrder? inboundOrder = null;
                    if (stockInfo != null && stockInfo.Details.Count > 0)
                    {
                        string? orderNo = stockInfo.Details.FirstOrDefault()?.OrderNo ?? "";
                        inboundOrder = _inboundOrderService.Repository.QueryFirst(x => x.InboundOrderNo == orderNo && x.OrderStatus < InOrderStatusEnum.入库完成.ObjToInt());
                    }
                    if (inboundOrder != null)
                    {
                        if (inboundOrder.OrderType == InOrderTypeEnum.Allocat.ObjToInt())
                        {
                            newTask.TaskType = TaskTypeEnum.InAllocate.ObjToInt();
                        }
                        else if (inboundOrder.OrderType == InOrderTypeEnum.Return.ObjToInt())
                        {
                            newTask.TaskType = TaskTypeEnum.ProductionReturn.ObjToInt();
                        }
                    }
                    if (stockInfo.StockStatus == StockStatusEmun.手动组盘暂存.ObjToInt())
                    {
                        stockInfo.StockStatus = StockStatusEmun.手动组盘入库确认.ObjToInt();
                    }
                    else if (stockInfo.StockStatus == StockStatusEmun.MES退库.ObjToInt())
                    {
                        newTask.TaskType = TaskTypeEnum.MesMatReturn.ObjToInt();
                    }
                    else if (stockInfo.StockStatus == StockStatusEmun.拣选完成.ObjToInt())
                    {
                        stockInfo.StockStatus = StockStatusEmun.入库确认.ObjToInt();
                        newTask.TaskType = TaskTypeEnum.InPick.ObjToInt();
                    }
                    else if (stockInfo.StockStatus == StockStatusEmun.送检库存完成.ObjToInt())
                    {
                        stockInfo.StockStatus = StockStatusEmun.手动组盘入库确认.ObjToInt();
                        newTask.TaskType = TaskTypeEnum.InQuality.ObjToInt();
                    }
                    else if (stockInfo.StockStatus == StockStatusEmun.盘点库存完成.ObjToInt())
                    {
                        stockInfo.StockStatus = StockStatusEmun.手动组盘入库确认.ObjToInt();
                        newTask.TaskType = TaskTypeEnum.InInventory.ObjToInt();
                    }
                    else
                    {
                        stockInfo.StockStatus = StockStatusEmun.入库确认.ObjToInt();
                    }
                    LocationStatusEnum lastStatus = (LocationStatusEnum)locationInfo.LocationStatus;
                    _unitOfWorkManage.BeginTran();
                    int taskId = BaseDal.AddData(newTask);
                    newTask.TaskId = taskId;
                    _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, locationInfo.LocationStatus, StockChangeType.Inbound.ObjToInt(), inboundOrder.InboundOrderNo, newTask.TaskNum);
                    locationInfo.LocationStatus = LocationStatusEnum.Lock.ObjToInt();
                    _locationInfoService.UpdateData(locationInfo);
                    _stockRepository.UpdateData(stockInfo);
                    _unitOfWorkManage.CommitTran();
                }
                TaskModel esstask = new TaskModel()
                {
                    taskType = "putaway",
                    taskGroupCode = "",
                    groupPriority = 0,
                    tasks = new List<TasksType>
                    {
                            new()
                            {
                                taskCode=newTask.TaskNum.ToString(),
                                taskPriority=0,
                                taskDescribe=new TaskDescribeType{
                                containerCode=palletCode,
                                containerType= "CT_KUBOT_STANDARD",
                                fromLocationCode=stations.GetValueOrDefault(stationCode)??"",
                                toStationCode="",
                                toLocationCode=locationInfo.LocationCode,
                                deadline=0,storageTag=""
                                }
                            }
                    }
                };
                _logger.LogInformation("创建任务Request:  " + JsonConvert.SerializeObject(esstask));
                var result = await _eSSApiService.CreateTaskAsync(esstask);
                _logger.LogInformation("创建任务返回:  " + result);
                if (result)
                {
                    return WebResponseContent.Instance.OK();
                }
                else
                {
                    return WebResponseContent.Instance.Error("下发机器人任务失败!");
                }
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// å…¥ç©ºç®±
        /// </summary>
        /// <param name="palletCode"></param>
        /// <param name="address"></param>
        /// <param name="WarehouseId"></param>
        /// <returns></returns>
        public WebResponseContent InEmpty(string palletCode, string address, int WarehouseId)
        {
            try
            {
                Dt_Task dbtask = Repository.QueryFirst(x => x.PalletCode == palletCode);
                if (dbtask != null)
                {
                    return WebResponseContent.Instance.Error($"该托盘已生成任务");
                }
                Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == palletCode).First();
                if (stockInfo == null)
                {
                    return WebResponseContent.Instance.Error($"未找到组盘信息");
                }
                if (stockInfo.StockStatus != StockStatusEmun.组盘暂存.ObjToInt() && stockInfo.StockStatus != StockStatusEmun.手动组盘暂存.ObjToInt() && stockInfo.StockStatus != StockStatusEmun.拣选完成.ObjToInt())
                {
                    return WebResponseContent.Instance.Error($"该托盘状态不正确,不可申请入库");
                }
                if (!string.IsNullOrEmpty(stockInfo.LocationCode))
                {
                    return WebResponseContent.Instance.Error($"该托盘已绑定货位");
                }
                //stockInfo = new Dt_StockInfo()
                //{
                //    PalletCode = barcode,
                //    StockStatus = StockStatusEmun.入库确认.ObjToInt(),
                //    WarehouseId = WarehouseId,
                //    PalletType = PalletTypeEnum.Empty.ObjToInt(),
                //    Details = new List<Dt_StockInfoDetail>()
                //};
                var locationInfo = _locationInfoService.AssignLocation();
                if (locationInfo == null)
                {
                    return WebResponseContent.Instance.Error($"货位分配失败,未找到可分配货位");
                }
                Dt_Task newTask = new Dt_Task()
                {
                    CurrentAddress = address,
                    Grade = 0,
                    NextAddress = locationInfo.LocationCode,
                    PalletCode = palletCode,
                    Roadway = locationInfo.RoadwayNo,
                    SourceAddress = address,
                    TargetAddress = locationInfo.LocationCode,
                    TaskType = TaskTypeEnum.InEmpty.ObjToInt(),
                    TaskStatus = TaskStatusEnum.New.ObjToInt(),
                    WarehouseId = stockInfo.WarehouseId,
                    PalletType = stockInfo.PalletType
                };
                locationInfo.LocationStatus = LocationStatusEnum.Lock.ObjToInt();
                _unitOfWorkManage.BeginTran();
                int taskId = BaseDal.AddData(newTask);
                newTask.TaskId = taskId;
                _locationInfoService.UpdateData(locationInfo);
                stockInfo.StockStatus = StockStatusEmun.入库确认.ObjToInt();
                _stockRepository.AddData(stockInfo);
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="taskNum"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> TaskCompleted(int taskNum)
        public async Task<WebResponseContent> TaskCompleted(string taskNum)
        {
            try
            {
                Dt_Task task;
                if (int.TryParse(taskNum, out var newTaskNum))
                {
                    task = BaseDal.QueryFirst(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)
                {
                    WebResponseContent? responseContent = (WebResponseContent?)methodInfo.Invoke(this, new object[] { task });
                    if (responseContent != null)
                    {
                        return responseContent;
                    }
                }
                return WebResponseContent.Instance.Error("未找到任务类型对应业务处理逻辑");
            }
            catch (Exception ex)
            {
                _logger.LogError($"TaskService TaskCompleted:  {ex.Message} ");
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// å…¥åº“完成
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> InboundTaskCompleted(Dt_Task task)
        {
            decimal beforeQuantity = 0;
            //查库存
            Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().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<Dt_InboundOrder>().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);
                }
            }
            stockInfo.LocationCode = task.TargetAddress;
            stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
            stockInfo.Details.ForEach(x =>
            {
                x.Status = 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.人工完成);
            _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
            _recordService.StockQuantityChangeRecordService.AddStockChangeRecord(stockInfo, stockInfo.Details, beforeQuantity, stockInfo.Details.Sum(x => x.StockQuantity) + beforeQuantity, WIDESEA_Common.StockEnum.StockChangeType.MaterielGroup);
            try
            {
                foreach (var inboundOrder in inboundOrders)
                {
                    if (inboundOrder.OrderType == InOrderTypeEnum.Allocat.ObjToInt())//调拨入库
                    {
                        if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt())
                        {
                            var allocate = _allocateService.Repository.QueryData(x => x.OrderNo == inboundOrder.InboundOrderNo).First();
                            var feedmodel = new AllocateDto
                            {
                                ReqCode = Guid.NewGuid().ToString(),
                                ReqTime = DateTime.Now.ToString(),
                                BusinessType = "2",
                                FactoryArea = inboundOrder.FactoryArea,
                                OperationType = 1,
                                Operator = inboundOrder.Operator,
                                OrderNo = inboundOrder.UpperOrderNo,
                                fromWarehouse = allocate?.FromWarehouse??"",
                                toWarehouse = allocate?.ToWarehouse??"",
                                Details = new List<AllocateDtoDetail>()
                            };
                            var groupedData = inboundOrder.Details.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, 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.Unit
                                   }).ToList()
                               }).ToList();
                            feedmodel.Details = groupedData;
                            var result = await _invokeMESService.FeedbackAllocate(feedmodel);
                            if (result != null && result.code == 200)
                            {
                                _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                                .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                            }
                        }
                    }
                    else if (inboundOrder.OrderType == InOrderTypeEnum.ReCheck.ObjToInt()) //重检入库
                    {
                    }
                    else
                    {
                        if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt())
                        {
                            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<FeedbackInboundDetailsModel>()
                            };
                            var groupedData = inboundOrder.Details.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 result = await _invokeMESService.FeedbackInbound(feedmodel);
                            if (result != null && result.code == 200)
                            {
                                _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                                .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogInformation("InboundTaskCompleted å›žå†™MES失败:  " + ex.Message);
            }
            return WebResponseContent.Instance.OK();
        }
        public WebResponseContent 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 outloks = _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>().Where(x => x.TaskNum == task.TaskNum).ToList();
            var stockids = outloks.Select(x => x.StockId).ToList();
            _stockService.StockInfoService.Db.Updateable<Dt_StockInfo>()
                                  .SetColumns(it => new Dt_StockInfo
                                  {
                                      StockStatus = StockStatusEmun.出库锁定.ObjToInt()
                                  })
                                  .Where(it => stockids.Contains(it.Id))
                                  .ExecuteCommand();
            _stockService.StockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>()
                                  .SetColumns(it => new Dt_StockInfoDetail
                                  {
                                      Status = StockStatusEmun.出库锁定.ObjToInt()
                                  })
                                  .Where(it => stockids.Contains(it.StockId))
                                  .ExecuteCommand();
            return WebResponseContent.Instance.OK();
        }
        public async Task<WebResponseContent> InEmptyTaskCompleted(Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_Task task = await Repository.QueryFirstAsync(x => x.TaskNum == taskNum);
                if (task == null)
                {
                    return await Task.FromResult(WebResponseContent.Instance.Error($"未找到任务信息"));
                }
                Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress);
                if (locationInfo == null)
                {
                    return content.Error($"未找到对应的终点货位信息");
                }
                Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == task.PalletCode && x.WarehouseId == task.WarehouseId).Includes(x => x.Details).First();
                Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == task.PalletCode && x.WarehouseId == task.WarehouseId).First();
                if (stockInfo == null)
                {
                    return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息");
@@ -361,13 +427,24 @@
                {
                    return WebResponseContent.Instance.Error($"货位状态不正确");
                }
                LocationStatusEnum lastStatus = (LocationStatusEnum)locationInfo.LocationStatus;
                locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt();
                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);
                Dt_InboundOrder? inboundOrder = _inboundOrderService.Repository.Db.Queryable<Dt_InboundOrder>().Where(x => x.InboundOrderNo == stockInfo.Details.FirstOrDefault().OrderNo).Includes(x => x.Details).First();
                Dt_InboundOrderDetail? inboundOrderDetail = null;
                task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
                BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? WIDESEA_Core.Enums.OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
                return content;
            }
@@ -376,5 +453,307 @@
                return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message));
            }
        }
        public async Task<WebResponseContent> InPickTaskCompleted(Dt_Task task)
        {
            _logger.LogInformation($"TaskService  InPickTaskCompleted: {task.TaskNum}");
            //查库存
            Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.PalletCode == task.PalletCode).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 returnLocks = _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                .Where(it => it.OrderNo == task.OrderNo && it.PalletCode == task.PalletCode && it.Status == (int)OutLockStockStatusEnum.回库中)
                .ToList();
            // æ›´æ–°å‡ºåº“锁定记录状态为回库完成
            foreach (var lockInfo in returnLocks)
            {
                lockInfo.Status = (int)OutLockStockStatusEnum.已回库;
            }
            _outStockLockInfoService.Db.Updateable(returnLocks).ExecuteCommand();
            await DeleteZeroQuantityStockDetails(stockInfo.Id);
            stockInfo.LocationCode = task.TargetAddress;
            stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
            stockInfo.Details.ForEach(x =>
            {
                x.Status = StockStatusEmun.入库完成.ObjToInt();
            });
            _stockService.StockInfoService.Repository.UpdateData(stockInfo);
            _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
            await ProcessStockDetailsForReturn(task, stockInfo.Id);
            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.人工完成);
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// åˆ é™¤åº“存数为0的库存明细记录
        /// </summary>
        private async Task DeleteZeroQuantityStockDetails(int stockId)
        {
            try
            {
                // åˆ é™¤åº“存数量为0的记录
                var deleteCount = await _stockService.StockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
                    .Where(x => x.StockId == stockId &&
                               x.StockQuantity == 0 &&
                               (x.Status==StockStatusEmun.出库完成.ObjToInt()|| x.Status==
                                          StockStatusEmun.入库完成.ObjToInt())) // åªåˆ é™¤å·²å®ŒæˆçŠ¶æ€çš„é›¶åº“å­˜
                    .ExecuteCommandAsync();
                if (deleteCount > 0)
                {
                    _logger.LogInformation($"删除{deleteCount}条零库存明细记录 - StockId: {stockId}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"删除零库存记录失败 - StockId: {stockId}, Error: {ex.Message}");
                // æ³¨æ„ï¼šåˆ é™¤å¤±è´¥ä¸åº”该影响主流程,记录日志后继续
            }
        }
        /// <summary>
        /// å¤„理回库相关的所有库存明细状态变更
        /// </summary>
        private async Task ProcessStockDetailsForReturn(Dt_Task returnTask, int stockId)
        {
            // èŽ·å–è¯¥æ‰˜ç›˜ä¸‹æ‰€æœ‰éœ€è¦å›žåº“çš„åº“å­˜æ˜Žç»†
            var stockDetails = await _stockService.StockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .Where(x => x.StockId == stockId &&
                           x.StockQuantity > 0 &&
                          ( x.Status == StockStatusEmun.出库锁定.ObjToInt()|| x.Status==
                                      StockStatusEmun.入库确认.ObjToInt()))  // åŒ…括出库锁定和入库确认的
                .ToListAsync();
            foreach (var detail in stockDetails)
            {
                detail.Status = StockStatusEmun.入库完成.ObjToInt();
                detail.OutboundQuantity = 0;  // æ¸…空出库数量
                _logger.LogInformation($"更新库存明细状态 - æ¡ç : {detail.Barcode}, æ•°é‡: {detail.StockQuantity}");
            }
            if (stockDetails.Any())
            {
                await _stockService.StockInfoDetailService.Db.Updateable(stockDetails).ExecuteCommandAsync();
                _logger.LogInformation($"共更新{stockDetails.Count}个库存明细状态为入库完成");
            }
        }
        public async Task<WebResponseContent> OutEmptyTaskCompleted(Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().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.人工完成);
                _stockService.StockInfoService.Repository.DeleteAndMoveIntoHty(stockInfo, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
                _stockRepository.Db.Deleteable(stockInfo).ExecuteCommand();
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Outbound.ObjToInt(), stockInfo.Details.FirstOrDefault()?.OrderNo ?? "", task.TaskNum);
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                _logger.LogError($"TaskService OutEmptyTaskCompleted:  {ex.Message} ");
                return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message));
            }
        }
        /// <summary>
        /// å›žåº“完成回调
        public async Task<WebResponseContent> BackToStockComplete(Dt_Task task)
        {
            try
            {
                _unitOfWorkManage.BeginTran();
                // èŽ·å–ç›¸å…³çš„å‡ºåº“é”å®šä¿¡æ¯
                var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .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<Dt_OutboundOrderDetail>()
                            .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<Dt_StockInfo>()
                    .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<Dt_LocationInfo>()
                    .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}");
            }
        }
        /// <summary>
        /// æ¢å¤åº“存出库数量(回库的部分)
        /// </summary>
        private async Task RestoreStockOutboundQuantity(List<Dt_OutStockLockInfo> 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<Dt_StockInfoDetail>()
                    .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();
                }
            }
        }
    }
}