pan
6 天以前 b0f6f409063cf4373f1f438d947ec8976f208c29
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -1,19 +1,8 @@
using Dm.filter;
using MailKit.Search;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MailKit.Search;
using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using WIDESEA_BasicService;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.OrderEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
@@ -23,7 +12,6 @@
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
using WIDESEA_Core.Utilities;
using WIDESEA_DTO.Allocate;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO.Inbound;
using WIDESEA_DTO.Outbound;
@@ -87,7 +75,7 @@
        public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService,
            IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService,
            IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService, IOutboundOrderService outboundOrderService,
            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService, IRepository<Dt_InboundOrder> inboundOrderRepository, IInboundOrderDetailService inboundOrderDetailService, IRepository<Dt_WarehouseArea> warehouseAreaRepository, IReCheckOrderService reCheckOrderService, ITask_HtyService task_HtyService,IRepository<Dt_InterfaceLog> interfaceLog) : base(BaseDal)
            IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService, IRepository<Dt_InboundOrder> inboundOrderRepository, IInboundOrderDetailService inboundOrderDetailService, IRepository<Dt_WarehouseArea> warehouseAreaRepository, IReCheckOrderService reCheckOrderService, ITask_HtyService task_HtyService, IRepository<Dt_InterfaceLog> interfaceLog) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _stockInfoService = stockInfoService;
@@ -298,15 +286,31 @@
                    return WebResponseContent.Instance.Error("未找到对应的任务信息");
                //分析需要回库的货物
                //var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id);
                //if (!returnAnalysis.HasItemsToReturn)
                //    return await HandleNoReturnItems(orderNo, palletCode, task);
                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
                if (!statusAnalysis.HasItemsToReturn)
                    return await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id);
                {
                    try
                    {
                        var result = await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id);
                        _unitOfWorkManage.CommitTran();
                        if (result.Status)
                        {
                            task.PalletType = PalletTypeEnum.Empty.ObjToInt();
                            await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InEmpty, PalletTypeEnum.Empty.ObjToInt());
                        }
                        return result;
                    }
                    catch (Exception ex)
                    {
                        _unitOfWorkManage.RollbackTran();
                        _logger.LogError($"ReturnRemaining å›žåº“空箱失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                        return WebResponseContent.Instance.Error($"回库空箱操作失败: {ex.Message}");
                    }
                // 4. æ£€æŸ¥æ˜¯å¦æœ‰è¿›è¡Œä¸­çš„任务
                }
                // æ£€æŸ¥æ˜¯å¦æœ‰è¿›è¡Œä¸­çš„任务
                if (statusAnalysis.HasActiveTasks)
                {
                    return WebResponseContent.Instance.Error($"托盘 {palletCode} æœ‰è¿›è¡Œä¸­çš„任务,不能执行回库操作");
@@ -408,16 +412,16 @@
        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>> ValidatePickingRequest(string orderNo, string palletCode, string barcode)
        {
            // 1. åŸºç¡€å‚数验证
            // åŸºç¡€å‚数验证
            if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode) || string.IsNullOrEmpty(barcode))
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error("订单号、托盘码和条码不能为空");
            // 2. æŸ¥æ‰¾æœ‰æ•ˆçš„锁定信息
            // æŸ¥æ‰¾æœ‰æ•ˆçš„锁定信息
            var lockInfo = await FindValidLockInfo(orderNo, palletCode, barcode);
            if (lockInfo == null)
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"未找到有效的锁定信息");
            // 3. æ£€æŸ¥è®¢å•状态
            // æ£€æŸ¥è®¢å•状态
            var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                .Where(x => x.OrderNo == orderNo)
                .FirstAsync();
@@ -425,18 +429,18 @@
            if (order?.OrderStatus == (int)OutOrderStatusEnum.出库完成)
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"订单{orderNo}已完成,不能继续分拣");
            // 4. èŽ·å–è®¢å•æ˜Žç»†
            // èŽ·å–è®¢å•æ˜Žç»†
            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                .FirstAsync(x => x.Id == lockInfo.OrderDetailId);
            if (orderDetail == null)
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"未找到订单明细");
            // 5. æ£€æŸ¥è®¢å•明细数量
            // æ£€æŸ¥è®¢å•明细数量
            if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity)
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"订单明细需求数量已满足");
            // 6. èŽ·å–åº“å­˜æ˜Žç»†
            // èŽ·å–åº“å­˜æ˜Žç»†
            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .Where(x => x.Barcode == barcode && x.StockId == lockInfo.StockId &&
                   x.Status != StockStatusEmun.入库确认.ObjToInt())
@@ -445,14 +449,14 @@
            if (stockDetail == null)
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"无效的条码或物料编码");
            // 7. æ£€æŸ¥åº“存状态和数量
            // æ£€æŸ¥åº“存状态和数量
            if (stockDetail.StockQuantity <= 0)
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"条码{barcode}库存不足");
            if (stockDetail.Status != StockStatusEmun.出库锁定.ObjToInt())
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"条码{barcode}状态不正确,无法分拣");
            // 8. æ£€æŸ¥æ˜¯å¦é‡å¤åˆ†æ‹£
            //检查是否重复分拣
            var existingPicking = await Db.Queryable<Dt_PickingRecord>()
                .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && x.PalletCode == palletCode && x.OutStockLockId == lockInfo.Id)
                .FirstAsync();
@@ -661,13 +665,13 @@
        private async Task HandleFullPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
            decimal actualQty, PickingResult result)
        {
            // 1. æ›´æ–°åº“å­˜
            //  æ›´æ–°åº“å­˜
            stockDetail.StockQuantity = 0;
            stockDetail.OutboundQuantity = 0;
            stockDetail.Status = StockStatusEmun.出库完成.ObjToInt();
            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
            // 2. æ›´æ–°é”å®šä¿¡æ¯
            // æ›´æ–°é”å®šä¿¡æ¯
            lockInfo.PickedQty += actualQty;
            lockInfo.Status = (int)OutLockStockStatusEnum.拣选完成;
            lockInfo.Operator = App.User.UserName;
@@ -680,19 +684,19 @@
            decimal stockOutQty = stockQuantity;
            decimal remainingAssignQty = actualQty - stockQuantity;
            // 1. æ›´æ–°åº“å­˜
            // æ›´æ–°åº“å­˜
            stockDetail.StockQuantity = 0;
            stockDetail.OutboundQuantity = 0;
            stockDetail.Status = StockStatusEmun.出库完成.ObjToInt();
            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
            // 2. æ›´æ–°é”å®šä¿¡æ¯
            // æ›´æ–°é”å®šä¿¡æ¯
            lockInfo.PickedQty += stockOutQty;
            lockInfo.AssignQuantity = remainingAssignQty;
            lockInfo.Operator = App.User.UserName;
            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
            // 3. æ›´æ–°æ‹†åŒ…记录状态
            // æ›´æ–°æ‹†åŒ…记录状态
            await UpdateSplitRecordsStatus(stockDetail.Barcode);
            result.ActualPickedQty = stockOutQty;
@@ -931,22 +935,7 @@
            return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail));
        }
        /// <summary>
        /// æ£€æŸ¥æ¡ç æ˜¯å¦å·²ç»å›žåº“
        /// </summary>
        private async Task<bool> IsBarcodeReturned(string barcode, int stockId)
        {
            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .Where(it => it.Barcode == barcode && it.StockId == stockId)
                .FirstAsync();
            if (stockDetail == null)
                return false;
            // å¦‚果状态是入库确认或入库完成,说明已经回库
            return stockDetail.Status == StockStatusEmun.入库确认.ObjToInt() ||
                   stockDetail.Status == StockStatusEmun.入库完成.ObjToInt();
        }
        /// <summary>
        /// æ£€æŸ¥é”å®šä¿¡æ¯å¯¹åº”的条码是否已经回库
@@ -1185,11 +1174,6 @@
        #region å›žåº“操作私有方法
        private async Task<Dt_StockInfo> GetStockInfo(string palletCode)
        {
            return await _stockInfoService.Db.Queryable<Dt_StockInfo>()
                .FirstAsync(x => x.PalletCode == palletCode);
        }
        /// <summary>
        /// æ£€æŸ¥æ•´ä¸ªæ‰˜ç›˜æ˜¯å¦å·²ç»å›žåº“
        /// </summary>
@@ -1268,23 +1252,6 @@
        private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode, Dt_Task originalTask, int stockInfoId)
        {
            // æ£€æŸ¥æ˜¯å¦æ‰€æœ‰è´§ç‰©éƒ½å·²æ‹£é€‰å®Œæˆ
            //var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
            //    .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode)
            //    .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.拣选完成);
            //if (allPicked)
            //{
            //    // åˆ é™¤åŽŸå§‹å‡ºåº“ä»»åŠ¡ ç»„空盘   ç©ºç›˜å›žåº“
            //    //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
            //    return WebResponseContent.Instance.OK("所有货物已拣选完成,托盘为空");
            //}
            //else
            //{
            //    // åˆ é™¤åŽŸå§‹å‡ºåº“ä»»åŠ¡
            //    //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync();
            //    return WebResponseContent.Instance.Error("没有需要回库的剩余货物");
            //}
            try
            {
                var locationtype = 0;
@@ -1313,8 +1280,6 @@
                _stockInfoService.AddMaterielGroup(emptystockInfo);
                //空托盘如何处理  è¿˜æœ‰ä¸€ä¸ªå‡ºåº“任务要处理。
                originalTask.PalletType = PalletTypeEnum.Empty.ObjToInt();
                await CreateReturnTaskAndHandleESS(orderNo, palletCode, originalTask, TaskTypeEnum.InEmpty, PalletTypeEnum.Empty.ObjToInt());
            }
            catch (Exception ex)
@@ -1382,16 +1347,16 @@
        {
            _logger.LogInformation($"开始释放锁定以便重新分配 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
            // 1. å¤„理未分拣的出库锁定记录 - å®Œå…¨é‡Šæ”¾
            // å¤„理未分拣的出库锁定记录 - å®Œå…¨é‡Šæ”¾
            if (analysis.HasRemainingLocks)
            {
                await ReleaseRemainingLocks(analysis.RemainingLocks);
            }
            // 2. å¤„理已回库的锁定记录 - åˆ é™¤æˆ–标记为无效
            // å¤„理已回库的锁定记录 - åˆ é™¤æˆ–标记为无效
            await CleanupReturnedLocks(orderNo, palletCode);
            // 3. é‡ç½®è®¢å•明细的锁定数量
            // é‡ç½®è®¢å•明细的锁定数量
            await ResetOrderDetailLockQuantities(analysis);
            _logger.LogInformation($"锁定释放完成 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
@@ -1574,37 +1539,6 @@
        }
        private async Task UpdateOrderDetailsOnReturn(List<Dt_OutStockLockInfo> remainingLocks)
        {
            // æŒ‰è®¢å•明细分组
            var orderDetailGroups = remainingLocks.GroupBy(x => x.OrderDetailId);
            foreach (var group in orderDetailGroups)
            {
                var orderDetailId = group.Key;
                var totalReturnQty = group.Sum(x => x.AssignQuantity - x.PickedQty);
                // èŽ·å–å½“å‰è®¢å•æ˜Žç»†
                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .FirstAsync(x => x.Id == orderDetailId);
                if (orderDetail != null)
                {
                    // è°ƒæ•´å·²æ‹£é€‰æ•°é‡å’Œå·²å‡ºåº“数量
                    decimal newPickedQty = Math.Max(0, orderDetail.PickedQty - totalReturnQty);
                    decimal newOverOutQuantity = Math.Max(0, orderDetail.OverOutQuantity - totalReturnQty);
                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                        .SetColumns(it => new Dt_OutboundOrderDetail
                        {
                            PickedQty = newPickedQty,
                            OverOutQuantity = newOverOutQuantity,
                        })
                        .Where(it => it.Id == orderDetailId)
                        .ExecuteCommandAsync();
                }
            }
        }
        private async Task HandlePalletStockGoodsReturn(List<Dt_StockInfoDetail> palletStockGoods)
        {
@@ -1700,7 +1634,7 @@
                    throw new Exception("创建任务失败!");
                }
            }
            catch (Exception ex)
            catch (Exception ex)
            {
                _logger.LogInformation($"CreateReturnTaskAndHandleESS åˆ›å»ºä»»åŠ¡å¤±è´¥: {orderNo} ï¼Œ {palletCode}");
                throw new Exception("创建任务失败!");
@@ -1732,7 +1666,7 @@
        {
            try
            {
                // 1. å‘送流动信号
                // å‘送流动信号
                var moveResult = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest
                {
                    slotCode = movestations[targetAddress],
@@ -1741,7 +1675,7 @@
                //if (moveResult)
                //{
                // 2. åˆ›å»ºå›žåº“任务
                //  åˆ›å»ºå›žåº“任务
                var essTask = new TaskModel()
                {
                    taskType = "putaway",
@@ -1962,147 +1896,6 @@
            }
        }
        private async Task HandleOrderCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
        {
            // è°ƒæ‹¨å‡ºåº“和重检出库不需要反馈MES
            if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt())
            {
                var allocate = _allocateService.Repository.QueryData(x => x.UpperOrderNo == outboundOrder.UpperOrderNo).First();
                var allocatefeedmodel = new AllocateDto
                {
                    ReqCode = Guid.NewGuid().ToString(),
                    ReqTime = DateTime.Now.ToString(),
                    BusinessType = "2",
                    FactoryArea = outboundOrder.FactoryArea,
                    OperationType = 1,
                    Operator = App.User.UserName,
                    OrderNo = outboundOrder.UpperOrderNo,
                    // documentsNO = outboundOrder.OrderNo,
                    // status = outboundOrder.OrderStatus,
                    fromWarehouse = allocate?.FromWarehouse ?? "",
                    toWarehouse = allocate?.ToWarehouse ?? "",
                    Details = new List<AllocateDtoDetail>()
                };
                // åªèŽ·å–å·²æ‹£é€‰å®Œæˆçš„é”å®šè®°å½•
                var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.拣选完成)
                    .ToListAsync();
                var groupedData = lists.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.PickedQty),
                       Unit = group.Key.BarcodeUnit,
                       Barcodes = group.Select(row => new BarcodeInfo
                       {
                           Barcode = row.CurrentBarcode,
                           SupplyCode = row.SupplyCode,
                           BatchNo = row.BatchNo,
                           Unit = row.BarcodeUnit,
                           Qty = row.PickedQty
                       }).ToList()
                   }).ToList();
                allocatefeedmodel.Details = groupedData;
                var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel);
                if (result != null && result.code == 200)
                {
                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                           .SetColumns(x => x.ReturnToMESStatus == 1)
                           .Where(x => x.OrderId == outboundOrder.Id).ExecuteCommandAsync();
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                          .SetColumns(x => new Dt_OutboundOrder
                          {
                              ReturnToMESStatus = 1,
                              Operator = App.User.UserName,
                          }).Where(x => x.OrderNo == orderNo).ExecuteCommandAsync();
                }
            }
            else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
            {
            }
            else
            {
                try
                {
                    var feedmodel = new FeedbackOutboundRequestModel
                    {
                        reqCode = Guid.NewGuid().ToString(),
                        reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                        business_type = outboundOrder.BusinessType,
                        factoryArea = outboundOrder.FactoryArea,
                        operationType = 1,
                        Operator = App.User.UserName,
                        orderNo = outboundOrder.UpperOrderNo,
                        documentsNO = outboundOrder.OrderNo,
                        status = outboundOrder.OrderStatus,
                        details = new List<FeedbackOutboundDetailsModel>()
                    };
                    // åªèŽ·å–å·²æ‹£é€‰å®Œæˆçš„é”å®šè®°å½•
                    var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                        .Where(x => x.OrderNo == orderNo && (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库))
                        .ToListAsync();
                    var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
                       .Select(group => new FeedbackOutboundDetailsModel
                       {
                           materialCode = group.Key.MaterielCode,
                           lineNo = group.Key.lineNo,
                           warehouseCode = group.Key.WarehouseCode,
                           qty = group.Sum(x => x.PickedQty),
                           currentDeliveryQty = group.Sum(x => x.PickedQty),
                           unit = group.Key.BarcodeUnit,
                           barcodes = group.Select(row => new WIDESEA_DTO.Outbound.BarcodesModel
                           {
                               barcode = row.CurrentBarcode,
                               supplyCode = row.SupplyCode,
                               batchNo = row.BatchNo,
                               unit = row.BarcodeUnit,
                               qty = row.PickedQty
                           }).ToList()
                       }).ToList();
                    feedmodel.details = groupedData;
                    var result = await _invokeMESService.FeedbackOutbound(feedmodel);
                    if (result != null && result.code == 200)
                    {
                        await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                            .SetColumns(x => x.ReturnToMESStatus == 1)
                            .Where(x => x.OrderId == outboundOrder.Id)
                            .ExecuteCommandAsync();
                        await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                              .SetColumns(x => new Dt_OutboundOrder
                              {
                                  ReturnToMESStatus = 1,
                                  Operator = App.User.UserName,
                              })
                            .Where(x => x.OrderNo == orderNo)
                            .ExecuteCommandAsync();
                    }
                    _logger.LogError($"FeedbackOutbound成功 - OrderNo: {orderNo}, {JsonSerializer.Serialize(result)}");
                }
                catch (Exception ex)
                {
                    _logger.LogError($"FeedbackOutbound失败 - OrderNo: {orderNo}, Error: {ex.Message}");
                }
            }
        }
        #endregion
        #region ç©ºæ‰˜ç›˜
@@ -2119,8 +1912,7 @@
                    .Where(x => x.StockId == stockId && x.StockQuantity == 0)
                    .ExecuteCommandAsync();
                await _stockInfoService.Db.Deleteable<Dt_StockInfo>()
                   .Where(x => x.Id == stockId).ExecuteCommandAsync();
                _stockInfoService.DeleteData(stockId);
                _logger.LogInformation($"清理零库存明细记录 - StockId: {stockId}, åˆ é™¤è®°å½•æ•°: {deleteDetailCount}");
@@ -2140,7 +1932,7 @@
        {
            try
            {
                // 1. æŸ¥æ‰¾æ‰€æœ‰ä¸Žè¯¥è®¢å•和托盘相关的任务
                //  æŸ¥æ‰¾æ‰€æœ‰ä¸Žè¯¥è®¢å•和托盘相关的任务
                var tasks = await _taskRepository.Db.Queryable<Dt_Task>().Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode).ToListAsync();
                if (tasks.Any())
@@ -2193,7 +1985,7 @@
                    _logger.LogInformation($"订单 {orderNo} è¿˜æœ‰å…¶ä»–托盘在处理,不更新订单状态");
                }
                // 3. æ›´æ–°æ‹£é€‰è®°å½•状态(可选)
                // æ›´æ–°æ‹£é€‰è®°å½•状态(可选)
                await UpdatePickingRecordsStatus(orderNo, palletCode);
            }
@@ -2236,8 +2028,6 @@
                _logger.LogInformation($"订单 {orderNo} å·²æ ‡è®°ä¸ºå‡ºåº“完成");
                // å‘MES反馈订单完成(如果需要)
                //await HandleOrderCompletion(outboundOrder, orderNo);
            }
        }
@@ -2255,7 +2045,6 @@
                // è¿™é‡Œå¯ä»¥æ ¹æ®éœ€è¦æ›´æ–°æ‹£é€‰è®°å½•的状态字段
                // ä¾‹å¦‚:pickingRecord.Status = (int)PickingStatusEnum.已完成;
                _logger.LogInformation($"找到{pickingRecords.Count}条拣选记录 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
            }
@@ -2356,88 +2145,6 @@
            return result;
        }
        /// <summary>
        /// æ£€æŸ¥æ‰˜ç›˜æ˜¯å¦ä¸ºç©º
        /// </summary>
        private async Task<bool> IsPalletEmpty(string orderNo, string palletCode)
        {
            try
            {
                // èŽ·å–åº“å­˜ä¿¡æ¯
                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
                    .Where(x => x.PalletCode == palletCode)
                    .FirstAsync();
                if (stockInfo == null)
                    return false;
                // ä½¿ç”¨ç»Ÿä¸€çš„状态分析
                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
                return statusAnalysis.IsEmptyPallet;
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"检查托盘是否为空失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// æ£€æŸ¥å¹¶å¤„理空托盘
        /// </summary>
        private async Task<bool> CheckAndHandleEmptyPallet(string orderNo, string palletCode)
        {
            try
            {
                // 1. èŽ·å–åº“å­˜ä¿¡æ¯
                var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>()
                    .Where(x => x.PalletCode == palletCode)
                    .FirstAsync();
                if (stockInfo == null)
                {
                    _logger.LogWarning($"未找到托盘 {palletCode} çš„库存信息");
                    return false;
                }
                // 2. ä½¿ç”¨ç»Ÿä¸€çš„状态分析
                var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id);
                // 3. æ£€æŸ¥æ˜¯å¦ä¸ºç©ºæ‰˜ç›˜ä¸”没有进行中的任务
                if (!statusAnalysis.IsEmptyPallet || statusAnalysis.HasActiveTasks)
                {
                    return false;
                }
                _logger.LogInformation($"检测到空托盘,开始自动处理 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
                //// æ¸…理零库存数据
                //await CleanupZeroStockData(stockInfo.Id);
                //// æ›´æ–°åº“存主表状态为空托盘
                //await UpdateStockInfoAsEmpty(stockInfo);
                //// å¤„理出库锁定记录
                //await HandleOutStockLockRecords(orderNo, palletCode);
                //// å¤„理任务状态
                //await HandleTaskStatusForEmptyPallet(orderNo, palletCode);
                //// æ›´æ–°è®¢å•数据
                //await UpdateOrderDataForEmptyPallet(orderNo, palletCode);
                ////记录操作历史
                //await RecordAutoEmptyPalletOperation(orderNo, palletCode);
                _logger.LogInformation($"空托盘自动处理完成 - è®¢å•: {orderNo}, æ‰˜ç›˜: {palletCode}");
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError($"自动处理空托盘失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}");
                return false;
            }
        }
        private async Task<string> GenerateNewBarcode()
        {
@@ -2548,11 +2255,6 @@
                record.Status = (int)SplitPackageStatusEnum.已拣选;
                await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync();
            }
        }
        private async Task<int> GenerateTaskNumber()
        {
            return await _dailySequenceService.GetNextSequenceAsync();
        }
        private WebResponseContent CreatePickingResponse(PickingResult result, string adjustedReason)
@@ -2856,10 +2558,20 @@
                if (result1 != null && result1.code == 200)
                {
                    var orderIds = inboundOrderDetails.Select(x => x.Id).Distinct().ToList();
                    _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
                    .Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
                    if (inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt())
                    {
                        _inboundOrderRepository.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 => orderIds.Contains(it.Id)).ExecuteCommand();
                }
                else
                {
                    _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2, Remark = result1.message })
                    .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();
                }
                //出库回传MES
@@ -2931,13 +2643,31 @@
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                        .SetColumns(x => x.ReturnToMESStatus == 1)
                        .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 1, Remark = "" })
                        .Where(x => x.Id == outboundOrder.Id)
                        .ExecuteCommandAsync();
                    await _interfaceLog.Db.Updateable<Dt_InterfaceLog>()
                        .SetColumns(x => x.ReturnToMESStatus == 1)
                        .Where(x=>x.DocumentNo == documentNo)
                        .Where(x => x.DocumentNo == documentNo)
                        .ExecuteCommandAsync();
                }
                else
                {
                    var uporderIds = outboundOrderDetails.Select(x => x.Id).Distinct().ToList();
                    await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                      .SetColumns(x => x.ReturnToMESStatus == 2)
                       .Where(x => uporderIds.Contains(x.Id))
                      .ExecuteCommandAsync();
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                        .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = result.message })
                         .Where(x => x.Id == outboundOrder.Id)
                        .ExecuteCommandAsync();
                    await _interfaceLog.Db.Updateable<Dt_InterfaceLog>()
                        .SetColumns(x => x.ReturnToMESStatus == 2)
                        .Where(x => x.DocumentNo == documentNo)
                        .ExecuteCommandAsync();
                }
                return WebResponseContent.Instance.OK();
@@ -2945,6 +2675,30 @@
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public WebResponseContent GetPurchaseOrderByBarcode(string barcode)
        {
            try
            {
                Dt_InboundOrderDetail inboundOrderDetail = _stockInfoDetailService.Db.Queryable<Dt_InboundOrderDetail>().Where(x => x.Barcode == barcode && x.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()).First();
                if (inboundOrderDetail == null)
                {
                    return WebResponseContent.Instance.Error($"未找到该条码{barcode}的入库明细或者明细状态已入智仓完成");
                }
                Dt_InboundOrder inboundOrder = _inboundOrderRepository.QueryFirst(x => x.Id == inboundOrderDetail.OrderId && x.OrderStatus != InOrderStatusEnum.入库完成.ObjToInt());
                if (inboundOrder == null)
                {
                    return WebResponseContent.Instance.Error($"该入库单{inboundOrder}状态已入智仓完成");
                }
                var resultData = new { purchaseOrderNo = inboundOrder.UpperOrderNo };
                return WebResponseContent.Instance.OK("查询采购单成功", data: resultData);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
@@ -3016,7 +2770,7 @@
                if (materielGroupDTO.orderTypes == InOrderTypeEnum.ReCheck.ObjToInt())
                {
                    var dborder = _reCheckOrderService.Db.Queryable<Dt_ReCheckOrder>().First(x => x.OrderNo == materielGroupDTO.OrderNo);
                    if (dborder != null && dborder.SignSeq == 0)
                    if (dborder != null && (dborder.SignSeq == 0 || dborder.SignSeq == 1))
                    {
                        return content.Error("只有拿到重检结果才能入库!");
                    }
@@ -3183,8 +2937,6 @@
        #endregion
    }
    #region æ”¯æŒç±»å®šä¹‰
    public class ValidationResult<T>
@@ -3221,20 +2973,6 @@
        public List<SplitResult> SplitResults { get; set; } = new List<SplitResult>();
    }
    public class ReturnAnalysisResult
    {
        public bool HasItemsToReturn { get; set; }
        public bool HasRemainingLocks { get; set; }
        public bool HasPalletStockGoods { get; set; }
        public bool HasSplitRecords { get; set; }
        public decimal RemainingLocksReturnQty { get; set; }
        public decimal PalletStockReturnQty { get; set; }
        public decimal SplitReturnQty { get; set; }
        public decimal TotalReturnQty { get; set; }
        public List<Dt_OutStockLockInfo> RemainingLocks { get; set; } = new List<Dt_OutStockLockInfo>();
        public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>();
        public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>();
    }
    public class PalletStatusAnalysis
    {
        public string OrderNo { get; set; }
@@ -3261,6 +2999,8 @@
        public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>();
        public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>();
        // å·²å¤„理的条码集合(用于避免重复)
        public HashSet<string> ProcessedBarcodes { get; set; } = new HashSet<string>();
        public List<string> AllBarcodes { get; set; } = new List<string>();
        // ç©ºæ‰˜ç›˜ç›¸å…³å±žæ€§
        public bool IsEmptyPallet { get; set; }
@@ -3270,18 +3010,7 @@
        public bool CanReturn => HasItemsToReturn && !HasActiveTasks;
        public bool CanRemove => IsEmptyPallet && !HasActiveTasks;
    }
    public class PickingContext
    {
        public string OrderNo { get; set; }
        public string PalletCode { get; set; }
        public string Barcode { get; set; }
        public string Operator { get; set; }
        public Dt_OutStockLockInfo LockInfo { get; set; }
        public Dt_OutboundOrderDetail OrderDetail { get; set; }
        public Dt_StockInfoDetail StockDetail { get; set; }
        public decimal ActualQuantity { get; set; }
        public string AdjustedReason { get; set; }
    }
    public class CancelPickingContext
    {
        public string OrderNo { get; set; }