heshaofeng
7 天以前 461524a7a1def4532b9af4ab40733f899f360db7
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -21,11 +21,13 @@
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;
@@ -41,10 +43,13 @@
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;
@@ -54,8 +59,10 @@
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
{
@@ -85,6 +92,14 @@
        private readonly IAllocateService _allocateService;
        private readonly IInvokeMESService _invokeMESService;
        private readonly ITask_HtyService _task_HtyService;
        private readonly IRepository<Dt_AllocateMaterialInfo> _allocateMaterialInfo;
        private readonly IRepository<Dt_AllocateMaterialInfo_Hty> _allocateMaterialInfo_Hty;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IBasicService _basicService;
        private readonly IRepository<Dt_TakeStockOrder> _takeStockOrder;
        public readonly IRepository<Dt_LocationType> _locationTypeRepository;
        public readonly IRepository<Dt_WarehouseArea> _warehouseAreaRepository;
        private readonly IRepository<Dt_OutStockLockInfo> _outboundLockInfoRepository;
        public IRepository<Dt_Task> Repository => BaseDal;
        private Dictionary<string, SqlSugar.OrderByType> _taskOrderBy = new()
@@ -104,7 +119,7 @@
        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, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository, IRepository<Dt_ReCheckOrder> reCheckOrderRepository, IRepository<Dt_AllocateOrderDetail> allocateOrderDetailRepository, IRepository<Dt_AllocateOrder> allocateOrderRepository, IMaterialUnitService materialUnitService, ITask_HtyService task_HtyService) : 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, IRepository<Dt_OutboundBatch> outboundBatchRepository, IRepository<Dt_ReCheckOrder> reCheckOrderRepository, IRepository<Dt_AllocateOrderDetail> allocateOrderDetailRepository, IRepository<Dt_AllocateOrder> allocateOrderRepository, IMaterialUnitService materialUnitService, ITask_HtyService task_HtyService, IRepository<Dt_AllocateMaterialInfo> allocateMaterialInfo, IRepository<Dt_AllocateMaterialInfo_Hty> allocateMaterialInfo_Hty, HttpClientHelper httpClientHelper, IBasicService basicService,IRepository<Dt_TakeStockOrder> takeStockOrder, IRepository<Dt_LocationType> locationTypeRepository, IRepository<Dt_WarehouseArea> warehouseAreaRepository, IRepository<Dt_OutStockLockInfo> outboundLockInfoRepository) : base(BaseDal)
        {
            _mapper = mapper;
            _unitOfWorkManage = unitOfWorkManage;
@@ -128,6 +143,14 @@
            _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)
@@ -267,11 +290,28 @@
                    _inboundOrderService.UpdateData(inboundOrder);
                }
            }
            Dt_OutboundOrder outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().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 = StockStatusEmun.入库完成.ObjToInt();
                x.Status = inboundOrders.FirstOrDefault().CreateType == (int)OrderCreateTypeEnum.CreateInSystem ? StockStatusEmun.入库完成.ObjToInt():StockStatusEmun.入库确认.ObjToInt();
            });
            _stockService.StockInfoService.Repository.UpdateData(stockInfo);
            _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
@@ -292,14 +332,19 @@
            task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
            //  BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
            var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除);
            var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
            if (!result)
            {
                await Db.Deleteable(task).ExecuteCommandAsync();
            }
            _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
            {
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
            }
            catch (Exception ex)
            {
                _logger.LogInformation($"InboundTaskCompleted AddLocationStatusChangeRecord : {ex.Message} ");
            }
            try
            {
                foreach (var inboundOrder in inboundOrders)
@@ -323,8 +368,9 @@
                                Details = new List<AllocateDtoDetail>()
                            };
                            var groupedData = inboundOrder.Details.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
                            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,
@@ -344,13 +390,63 @@
                               }).ToList();
                            allocatefeedmodel.Details = groupedData;
                            var feedbackresult = await _invokeMESService.FeedbackAllocate(allocatefeedmodel);
                            if (feedbackresult != null && feedbackresult.code == 200)
                            var response = responseModel(inboundOrder, 3, null, allocatefeedmodel);
                            if (response != null && response.IsSuccess && response.Data.Code =="200")
                            {
                                _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
                                var detailStatusList = _inboundOrderDetailService.Db.Queryable<Dt_InboundOrderDetail>()
                                .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<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1, Remark = "" })
                                .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();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                                else
                                {
                                    _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 3, Remark = "" })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 3 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                                //回传成功库存才可用
                                _stockRepository.Db.Updateable<Dt_StockInfoDetail>().SetColumns(it => new Dt_StockInfoDetail
                                {
                                    Status = StockStatusEmun.入库完成.ObjToInt()
                                }).Where(it => it.OrderNo == inboundOrder.InboundOrderNo).ExecuteCommand();
                            }
                            else
                            {
                                var detailStatusList = _inboundOrderDetailService.Db.Queryable<Dt_InboundOrderDetail>()
                                .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<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2, Remark = "" })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                                else
                                {
                                    _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 4, Remark = "" })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 4 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                            }
                        }
                    }
@@ -358,62 +454,9 @@
                    {
                        //不需要回传。占一个位置。
                    }
                    else if (inboundOrder.OrderType == InOrderTypeEnum.InternalAllocat.ObjToInt()) //智仓调智仓
                    {
                        _logger.LogInformation($"InboundTaskCompleted å›žå†™MES  : {inboundOrder.InboundOrderNo}  ,ordertype: {InOrderTypeEnum.InternalAllocat.ObjToInt()} ");
                        // BusinessTypeEnum.智仓调智仓
                        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<AllocateDtoDetail>()
                            };
                            var groupedData = inboundOrder.Details.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 feedbackresult = await _invokeMESService.FeedbackAllocate(allocatefeedmodel);
                            if (feedbackresult != null && feedbackresult.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 != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt())
                        if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt() && inboundOrder.CreateType == (int)OrderCreateTypeEnum.UpperSystemPush)
                        {
                            var feedmodel = new FeedbackInboundRequestModel
                            {
@@ -428,8 +471,9 @@
                                details = new List<FeedbackInboundDetailsModel>()
                            };
                            var groupedData = inboundOrder.Details.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
                            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,
@@ -448,20 +492,67 @@
                               }).ToList();
                            feedmodel.details = groupedData;
                            var feedbackresult = await _invokeMESService.FeedbackInbound(feedmodel);
                            if (feedbackresult != null && feedbackresult.code == 200)
                            //var feedbackresult = await _invokeMESService.FeedbackInbound(feedmodel);
                            var response= responseModel(inboundOrder,2, feedmodel);
                            if (response != null && response.IsSuccess && response.Data.Code == "200")
                            {
                                _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1, Remark = "" })
                                var detailStatusList = _inboundOrderDetailService.Db.Queryable<Dt_InboundOrderDetail>()
                                .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<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1, Remark = "" })
                                .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();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                                else
                                {
                                    _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 3, Remark = "" })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 3 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                                //回传成功库存才可用
                                _stockRepository.Db.Updateable<Dt_StockInfoDetail>().SetColumns(it => new Dt_StockInfoDetail
                                {
                                    Status = StockStatusEmun.入库完成.ObjToInt()
                                }).Where(it => it.OrderNo == inboundOrder.InboundOrderNo).ExecuteCommand();
                            }
                            else
                            {
                                _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2, Remark = feedbackresult.message })
                                var detailStatusList = _inboundOrderDetailService.Db.Queryable<Dt_InboundOrderDetail>()
                                .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<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2, Remark = "" })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 })
                               .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                                else
                                {
                                    _inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 4, Remark = "" })
                                .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                                    _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 4 })
                                    .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
                                }
                            }
                        }
                    }
@@ -474,6 +565,354 @@
            }
            return WebResponseContent.Instance.OK();
        }
        public async Task<WebResponseContent> 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<Dt_StockInfo>()
                    .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<Dt_OutboundLockInfo_Hty>().Where(x => x.PalletCode == stockInfo.PalletCode && x.TaskNum == task.TaskNum).First();
                var allocateOrderToWarehouse = _allocateOrderRepository.Db.Queryable<Dt_AllocateOrder>().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<Dt_WarehouseArea>().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<Dt_OutboundOrder>()
                        .Where(x => x.OrderNo == stockLockInfo.OrderNo)
                        .Includes(x => x.Details)
                        .First();
                    string Operator = outboundOrder.Modifier;
                    if (outboundOrder != null)
                    {
                        var allocatInfo =_allocateMaterialInfo.Db.Queryable<Dt_AllocateMaterialInfo>().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<MesResponseDTO> httpResponseResult = new HttpResponseResult<MesResponseDTO>();
                        string reqCode = Guid.NewGuid().ToString();
                        string reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        string requestData = string.Empty;
                        List<string> lineNos = new List<string>();
                        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<MesResponseDTO>(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<Dt_OutboundOrderDetail> 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<MesResponseDTO> responseModel(Dt_InboundOrder order, int InterfaceType, FeedbackInboundRequestModel model = null, AllocateDto allocateDto = null)
        {
            HttpResponseResult<MesResponseDTO> httpResponseResult = new HttpResponseResult<MesResponseDTO>();
            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<MesResponseDTO>(apiUrl, model.Serialize());
                requestData = model.Serialize();
            }
            else
            {
                apiUrl = AppSettings.GetValue("AldAllocationOperation");
                httpResponseResult = _httpClientHelper.Post<MesResponseDTO>(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;
        }
@@ -495,27 +934,32 @@
            locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt();
            _locationInfoService.Repository.UpdateData(locationInfo);
            var outloks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>().Where(x => x.TaskNum == task.TaskNum).ToListAsync();
            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();
            var stock = _stockService.StockInfoService.Db.Queryable<Dt_StockInfo>()
                                  .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();
@@ -559,32 +1003,290 @@
                stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
                _stockRepository.UpdateData(stockInfo);
                var outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == task.OrderNo);
                //var outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == task.OrderNo);
                task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
                // BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? WIDESEA_Core.Enums.OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
                var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除);
                if (!result)
                {
                    await Db.Deleteable(task).ExecuteCommandAsync();
                }
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
                if (outboundOrder != null)
                try
                {
                    await HandleOutboundOrderToMESCompletion(outboundOrder, outboundOrder.OrderNo);
                    _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
                }
                else
                catch (Exception ex)
                {
                    _logger.LogInformation($"TaskService  InEmptyTaskCompleted: {task.TaskNum} ,未找到出库单。  ");
                    _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));
            }
        }
        /// <summary>
        /// æ™ºä»“调入智仓完成
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> AllocateInWarehouseTaskCompleted(Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable<Dt_StockInfo>()
                    .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<Dt_OutboundOrder>().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<MesResponseDTO> httpResponseResult = new HttpResponseResult<MesResponseDTO>();
                string reqCode = Guid.NewGuid().ToString();
                string reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                string requestData = string.Empty;
                List<string> lineNos = new List<string>();
                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<MesResponseDTO>(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<Dt_OutboundOrderDetail> 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<Dt_OutboundOrderDetail> details = outboundOrder.Details;
                List<AllocationDetail> returnDetails = new List<AllocationDetail>();
                foreach (var detail in details)
                {
                    List<Barcodes>? barcodes = JsonConvert.DeserializeObject<List<Barcodes>>(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;
            }
        }
@@ -623,23 +1325,23 @@
                var beforelocationStatus = locationInfo.LocationStatus;
                // èŽ·å–æ‰€æœ‰å›žåº“ä¸­çš„å‡ºåº“é”å®šè®°å½•
                var returnLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(it => it.OrderNo == task.OrderNo &&
                               it.PalletCode == task.PalletCode &&
                               it.Status == (int)OutLockStockStatusEnum.回库中)
                    .ToListAsync();
                //var returnLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                //    .Where(it => it.OrderNo == task.OrderNo &&
                //               it.PalletCode == task.PalletCode &&
                //               it.Status == (int)OutLockStockStatusEnum.回库中)
                //    .ToListAsync();
                // æ›´æ–°å‡ºåº“锁定记录状态为回库完成
                foreach (var lockInfo in returnLocks)
                {
                    lockInfo.Status = (int)OutLockStockStatusEnum.已回库;
                }
                //foreach (var lockInfo in returnLocks)
                //{
                //    lockInfo.Status = (int)OutLockStockStatusEnum.已回库;
                //}
                if (returnLocks.Any())
                {
                    await _outStockLockInfoService.Db.Updateable(returnLocks).ExecuteCommandAsync();
                    _logger.LogInformation($"更新{returnLocks.Count}条锁定记录为已回库状态");
                }
                //if (returnLocks.Any())
                //{
                //    await _outStockLockInfoService.Db.Updateable(returnLocks).ExecuteCommandAsync();
                //    _logger.LogInformation($"更新{returnLocks.Count}条锁定记录为已回库状态");
                //}
                // æ›´æ–°åº“存信息
                stockInfo.LocationCode = task.TargetAddress;
@@ -650,8 +1352,11 @@
                {
                    foreach (var detail in stockInfo.Details)
                    {
                        detail.Status = StockStatusEmun.入库完成.ObjToInt();
                        detail.OutboundQuantity = 0; // å…¥åº“完成时出库数量清零
                        if(detail.Status != StockStatusEmun.手动冻结.ObjToInt()&& detail.Status != StockStatusEmun.重检中.ObjToInt())
                        {
                            detail.Status = StockStatusEmun.入库完成.ObjToInt();
                        }
                        detail.OutboundQuantity = 0;
                    }
                    _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
                }
@@ -660,7 +1365,7 @@
                // åˆ é™¤é›¶åº“存数据
                await DeleteZeroQuantityStockDetails(stockInfo.Id);
                await UpdateAffectedOrderDetails(task.OrderNo, returnLocks);
                //await UpdateAffectedOrderDetails(task.OrderNo, returnLocks);
                // æ›´æ–°è´§ä½çŠ¶æ€
                if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt())
                {
@@ -683,43 +1388,50 @@
                {
                    await Db.Deleteable(task).ExecuteCommandAsync();
                }
                // è®°å½•货位状态变更
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(
                    locationInfo,
                    beforelocationStatus,
                    StockChangeType.Inbound.ObjToInt(),
                    "",
                    task.TaskNum
                );
                await RecalculateOrderStatus(task.OrderNo);
                _logger.LogInformation($"托盘回库完成处理成功 - ä»»åŠ¡å·: {task.TaskNum}, æ‰˜ç›˜: {task.PalletCode}, è®¢å•: {task.OrderNo}");
                _ = Task.Run(async () =>
                //await RecalculateOrderStatus(task.OrderNo);
                try
                {
                    try
                    {
                        var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                            .FirstAsync(x => x.OrderNo == task.OrderNo);
                    // è®°å½•货位状态变更
                    _locationStatusChangeRecordService.AddLocationStatusChangeRecord(
                        locationInfo,
                        beforelocationStatus,
                        StockChangeType.Inbound.ObjToInt(),
                        "",
                        task.TaskNum
                    );
                }
                catch (Exception ex)
                {
                    _logger.LogInformation($"InPickTaskCompleted AddLocationStatusChangeRecord : {ex.Message} ");
                }
                        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}");
                    }
                });
                //_logger.LogInformation($"托盘回库完成处理成功 - ä»»åŠ¡å·: {task.TaskNum}, æ‰˜ç›˜: {task.PalletCode}, è®¢å•: {task.OrderNo} è´§ä½çŠ¶æ€ï¼š{locationInfo.LocationStatus}");
                //_ = Task.Run(async () =>
                //{
                //    try
                //    {
                //        var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                //            .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)
            {
@@ -737,8 +1449,8 @@
        {
            try
            {
                // èŽ·å–å—å½±å“çš„è®¢å•æ˜Žç»†ID(去重)
                //var affectedDetailIds = returnLocks
                //    .Select(x => x.OrderDetailId)
@@ -979,7 +1691,7 @@
                    _logger.LogInformation($"更新订单状态 - OrderNo: {orderNo}, æ—§çŠ¶æ€: {outboundOrder.OrderStatus}, æ–°çŠ¶æ€: {newStatus}");
                }
            }
            catch (Exception ex)
            {
@@ -1116,6 +1828,34 @@
                                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)
@@ -1130,6 +1870,19 @@
                                          ReturnToMESStatus = 1,
                                      }).Where(x => x.OrderNo == orderNo).ExecuteCommandAsync();
                            }
                            else
                            {
                                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                                 .SetColumns(x => x.ReturnToMESStatus == 2)
                                 .Where(x => x.OrderId == outboundOrder.Id)
                                 .ExecuteCommandAsync();
                                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                                    .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = result.message })
                                     .Where(x => x.OrderNo == orderNo)
                                    .ExecuteCommandAsync();
                            }
                        }
                    }
                    else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
@@ -1202,6 +1955,33 @@
                                }
                                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)
@@ -1284,8 +2064,14 @@
                    _stockRepository.Db.Deleteable(stockInfo).ExecuteCommand();
                }
                _stockService.StockInfoService.DeleteData(stockInfo);
                _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Outbound.ObjToInt(), stockInfo.Details.FirstOrDefault()?.OrderNo ?? "", task.TaskNum);
                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());
            }
@@ -1440,5 +2226,623 @@
            }
        }
        public Task<WebResponseContent> HandCompleteTask(string TaskNum)
        {
            return TaskCompleted(TaskNum);
        }
        /// <summary>
        /// ç›˜ç‚¹å‡ºåº“完成
        /// </summary>
        public async Task<WebResponseContent> 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<Dt_TakeStockOrder>().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;
        }
        /// <summary>
        /// ç›˜ç‚¹å…¥åº“完成
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> 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<Dt_StockInfo>().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));
            }
        }
        /// <summary>
        /// é‡æ£€å…¥åº“完成
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> InQualityTaskCompleted(Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable<Dt_StockInfo>()
                    .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<Dt_OutboundOrder>().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));
            }
        }
        /// <summary>
        /// ä»»åŠ¡å–æ¶ˆ
        /// </summary>
        /// <param name="taskCodes"></param>
        /// <returns></returns>
        /// <summary>
        public async Task<WebResponseContent> TaskCancel(List<int> 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<TaskCancelApiResponse>(responseJson);
                //if (apiResponse.Code != 0)
                //{
                //    return WebResponseContent.Instance.Error($"请求失败:{apiResponse.Msg}");
                //}
                _unitOfWorkManage.BeginTran();
                var tasks = await Db.Queryable<Dt_Task>()
                                    .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<int>
        {
            TaskTypeEnum.InAllocate.ObjToInt(),
            TaskTypeEnum.InEmpty.ObjToInt(),
            TaskTypeEnum.Inbound.ObjToInt(),
            TaskTypeEnum.InInventory.ObjToInt(),
            TaskTypeEnum.InQuality.ObjToInt()
        };
                var outboundTypes = new List<int>
        {
            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<Dt_OutStockLockInfo>()
                            .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<Dt_OutboundOrderDetail>()
                            .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<WebResponseContent> 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<Dt_StockInfo>()
                    .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}"));
            }
        }
        /// <summary>
        /// è·¨åŒºåŸŸç§»åº“任务完成
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> 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<Dt_StockInfo>()
                    .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}"));
            }
        }
    }
}