pan
2025-11-19 c84db706e8c8d82a96bb4b4c18c243a42b2976c1
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -17,6 +17,7 @@
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO.Inbound;
using WIDESEA_DTO.Outbound;
using WIDESEA_IBasicService;
using WIDESEA_IOutboundService;
@@ -43,7 +44,7 @@
        private readonly ISplitPackageService _splitPackageService;
        private readonly IRepository<Dt_Task> _taskRepository;
        private readonly IESSApiService _eSSApiService;
        private readonly IInvokeMESService _invokeMESService;
        private readonly ILogger<OutboundPickingService> _logger;
@@ -61,7 +62,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) : base(BaseDal)
        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) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _stockInfoService = stockInfoService;
@@ -75,6 +76,7 @@
            _taskRepository = taskRepository;
            _eSSApiService = eSSApiService;
            _logger = logger;
            _invokeMESService = invokeMESService;
        }
@@ -139,99 +141,6 @@
            }
        }
        /// <summary>
        /// æ‰«ç æ‹£é€‰ç¡®è®¤
        /// </summary>
        public async Task<WebResponseContent> ConfirmPicking(PickingConfirmRequest request)
        {
            try
            {
                _unitOfWorkManage.BeginTran();
                // 1. éªŒè¯æ¡ç æœ‰æ•ˆæ€§
                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(x => x.Barcode == request.Barcode && x.MaterielCode == request.MaterielCode)
                    .FirstAsync();
                if (stockDetail == null)
                    return WebResponseContent.Instance.Error("无效的条码或物料编码");
                // 2. æ£€æŸ¥åº“存可用数量
                decimal availableQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity;
                if (request.PickQuantity > availableQuantity)
                    return WebResponseContent.Instance.Error($"拣选数量超过可用库存,可用数量:{availableQuantity}");
                // 3. æŸ¥æ‰¾ç›¸å…³çš„出库锁定信息(支持拆包后的新条码)
                var lockInfo = await FindLockInfoByBarcode(request.OrderDetailId, request.Barcode, request.MaterielCode);
                if (lockInfo == null)
                    return WebResponseContent.Instance.Error("未找到相关的出库锁定信息");
                // 4. æ£€æŸ¥é”å®šæ•°é‡
                decimal remainingLockQuantity = lockInfo.AssignQuantity - lockInfo.PickedQty;
                if (request.PickQuantity > remainingLockQuantity)
                    return WebResponseContent.Instance.Error($"拣选数量超过锁定数量,剩余可拣选:{remainingLockQuantity}");
                // 5. æ›´æ–°é”å®šä¿¡æ¯çš„已拣选数量
                lockInfo.PickedQty += request.PickQuantity;
                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
                // 6. æ›´æ–°åº“存出库数量 - å®žé™…减少库存
                stockDetail.OutboundQuantity += request.PickQuantity;
                await _stockInfoService.Db.Updateable(stockDetail).ExecuteCommandAsync();
                // 7. æ›´æ–°å‡ºåº“单明细
                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .Where(x => x.Id == request.OrderDetailId)
                    .FirstAsync();
                orderDetail.OverOutQuantity += request.PickQuantity;
                orderDetail.LockQuantity -= request.PickQuantity;
                // æ£€æŸ¥æ˜¯å¦å®Œæˆå‡ºåº“
                if (Math.Abs(orderDetail.OverOutQuantity - orderDetail.OrderQuantity) < 0.001m)
                {
                    orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
                    orderDetail.LockQuantity = 0;
                    // æ›´æ–°ç›¸å…³çš„锁定信息状态为已出库
                    var relatedLockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                        .Where(x => x.OrderDetailId == request.OrderDetailId &&
                                   x.Status == (int)OutLockStockStatusEnum.出库中)
                        .ToListAsync();
                    foreach (var relatedLock in relatedLockInfos)
                    {
                        relatedLock.Status = (int)OutLockStockStatusEnum.已出库;
                    }
                    await _outStockLockInfoService.Db.Updateable(relatedLockInfos).ExecuteCommandAsync();
                }
                await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
                // 8. è®°å½•拣选历史
                var pickHistory = new Dt_PickingRecord
                {
                    OrderDetailId = request.OrderDetailId,
                    Barcode = request.Barcode,
                    PickQuantity = request.PickQuantity,
                    PickTime = DateTime.Now,
                    LocationCode = request.LocationCode,
                    StockId = stockDetail.StockId
                };
                await Db.Insertable(pickHistory).ExecuteCommandAsync();
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK("拣选确认成功");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error($"拣选确认失败: {ex.Message}");
            }
        }
        public async Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode)
        {
@@ -269,6 +178,12 @@
                }
                if (lockInfo.PalletCode != palletCode)
                    throw new Exception($"条码{barcode}不属于托盘{palletCode}");
                var outorderdetail = _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().First(x => x.Id == lockInfo.OrderDetailId);
                if (outorderdetail != null && lockInfo.AssignQuantity > outorderdetail.OrderQuantity)
                {
                    throw new Exception($"条码{barcode}的出库数量大于订单的数量");
                }
                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                        .Where(x => x.Barcode == barcode && x.StockId == lockInfo.StockId)
@@ -341,10 +256,15 @@
        private async Task CheckAndUpdateOrderStatus(string orderNo)
        {
            var orderDetails = _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                      .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id) // å…³è”条件:父表 Id = å­è¡¨ OrderId
                      .Where((o, item) => item.OrderNo == orderNo) // è¿‡æ»¤çˆ¶è¡¨ OrderNo
                      .Select((o, item) => o) // åªè¿”回子表数据
                      .ToList();
            var orderDetails = await _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                .Where(x => x.OrderId == orderNo.ObjToInt())
                .ToListAsync();
            //var orderDetails = await _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
            //    .Where(x => x.OrderId == orderNo.ObjToInt())
            //    .ToListAsync();
            bool allCompleted = true;
            foreach (var detail in orderDetails)
@@ -358,10 +278,72 @@
            if (allCompleted)
            {
                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                    .SetColumns(x => x.OrderStatus == 2) // å·²å®Œæˆ
                    .Where(x => x.OrderNo == orderNo)
                    .ExecuteCommandAsync();
                try
                {
                    await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
                        .SetColumns(x => x.OrderStatus == 2) // å·²å®Œæˆ
                        .Where(x => x.OrderNo == orderNo)
                        .ExecuteCommandAsync();
                    var outboundOrder = _stockInfoService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == orderNo);
                    if (outboundOrder != null && outboundOrder.OrderStatus == OutOrderStatusEnum.出库完成.ObjToInt())
                    {
                        if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt().ObjToInt())//调拨出库
                        {
                        }
                        else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt()) //重检出库
                        {
                        }
                        else
                        {
                            var feedmodel = new FeedbackOutboundRequestModel
                            {
                                reqCode = Guid.NewGuid().ToString(),
                                reqTime = DateTime.Now.ToString(),
                                business_type = outboundOrder.BusinessType,
                                factoryArea = outboundOrder.FactoryArea,
                                operationType = 1,
                                Operator = outboundOrder.Operator,
                                orderNo = outboundOrder.UpperOrderNo,
                                status = outboundOrder.OrderStatus,
                                details = new List<FeedbackOutboundDetailsModel>()
                            };
                            var lists = _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>().Where(x => x.OrderNo == orderNo).ToList();
                            var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.Unit, item.WarehouseCode })
                               .Select(group => new FeedbackOutboundDetailsModel
                               {
                                   materialCode = group.Key.MaterielCode,
                                   lineNo = group.Key.lineNo,
                                   warehouseCode = group.Key.WarehouseCode,
                                   currentDeliveryQty = group.Sum(x => x.OrderQuantity),
                                   // warehouseCode= "1072",
                                   unit = group.Key.Unit,
                                   barcodes = group.Select(row => new WIDESEA_DTO.Outbound.BarcodesModel
                                   {
                                       barcode = row.CurrentBarcode,
                                       supplyCode = row.SupplyCode,
                                       batchNo = row.BatchNo,
                                       unit = row.Unit,
                                       qty = row.AssignQuantity
                                   }).ToList()
                               }).ToList();
                            feedmodel.details = groupedData;
                            _invokeMESService.FeedbackOutbound(feedmodel);
                        }
                    }
                }
                catch (Exception ex) {
                    _logger.LogError(" OutboundPickingService  FeedbackOutbound : " + ex.Message);
                }
            }
        }
@@ -369,165 +351,18 @@
        /// <summary>
        /// å›žåº“操作  
        /// </summary>
        //public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason)
        //{
        //    try
        //    {
        //        // 1. èŽ·å–æ‰€æœ‰æœªåˆ†æ‹£çš„å‡ºåº“é”å®šè®°å½•ï¼ŒåŒ…æ‹¬æ‹†åŒ…äº§ç”Ÿçš„è®°å½•
        //        var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
        //            .Where(it => it.OrderNo == orderNo && it.Status == 1)
        //            .ToListAsync();
        //        if (!remainingLocks.Any())
        //        {
        //            return WebResponseContent.Instance.Error("没有需要回库的剩余货物");
        //        }
        //        var tasks = new List<Dt_Task>();
        //        // æŒ‰æ‰˜ç›˜åˆ†ç»„
        //        var palletGroups = remainingLocks.GroupBy(x => x.PalletCode);
        //        //查询任务表
        //        var task = _taskRepository.QueryData(x => x.TaskNum == remainingLocks.First().TaskNum).FirstOrDefault();
        //        foreach (var group in palletGroups)
        //        {
        //            if (group.Key == palletCode)
        //            {
        //                var totalReturnQty = group.Sum(x => x.AssignQuantity - x.PickedQty);
        //                if (totalReturnQty <= 0) continue;
        //                // åˆ†é…æ–°è´§ä½
        //                var newLocation = _locationInfoService.AssignLocation();
        //                // æ›´æ–°å‡ºåº“锁定记录状态
        //                var lockIds = group.Where(x => x.PalletCode == palletCode).Select(x => x.Id).ToList();
        //                await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>()
        //                    .SetColumns(it => new Dt_OutStockLockInfo { Status = OutLockStockStatusEnum.回库中.ObjToInt() })
        //                    .Where(it => lockIds.Contains(it.Id))
        //                    .ExecuteCommandAsync();
        //                // æ›´æ–°æ‹†åŒ…条码记录状态
        //                var splitBarcodes = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>()
        //                    .Where(it => lockIds.Contains(it.OutStockLockInfoId))
        //                    .ToListAsync();
        //                foreach (var splitBarcode in splitBarcodes)
        //                {
        //                    splitBarcode.Status = 3;
        //                    await _splitPackageService.Db.Updateable(splitBarcode).ExecuteCommandAsync();
        //                }
        //                foreach (var lockInfo in group)
        //                {
        //                    if (lockInfo.PalletCode == palletCode)
        //                    {
        //                        decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty;
        //                        // æ£€æŸ¥åº“存记录是否存在
        //                        var existingStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
        //                            .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
        //                            .FirstAsync();
        //                        if (existingStock != null)
        //                        {
        //                            // åº“存记录存在,恢复锁定数量
        //                            await _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>()
        //                                .SetColumns(it => new Dt_StockInfoDetail
        //                                {
        //                                    OutboundQuantity = it.OutboundQuantity - returnQty
        //                                })
        //                                .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId)
        //                                .ExecuteCommandAsync();
        //                        }
        //                        else
        //                        {
        //                            // åº“存记录不存在(可能是拆包产生的新条码),创建新的库存记录
        //                            var newStockDetail = new Dt_StockInfoDetail
        //                            {
        //                                StockId = lockInfo.StockId,
        //                                MaterielCode = lockInfo.MaterielCode,
        //                                OrderNo = lockInfo.OrderNo,
        //                                BatchNo = lockInfo.BatchNo,
        //                                StockQuantity = returnQty, // å®žé™…库存数量
        //                                OutboundQuantity = 0, // å›žåº“后不再锁定
        //                                Barcode = lockInfo.CurrentBarcode,
        //                                InboundOrderRowNo = "0",
        //                                Status = StockStatusEmun.入库确认.ObjToInt(),
        //                            };
        //                            await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
        //                        }
        //                    }
        //                }
        //                Dt_Task newtask = new()
        //                {
        //                    CurrentAddress = stations[task.TargetAddress],
        //                    Grade = 0,
        //                    PalletCode = palletCode,
        //                    NextAddress = "",
        //                    OrderNo= task.OrderNo,
        //                    Roadway = newLocation.RoadwayNo,
        //                    SourceAddress = stations[task.TargetAddress],
        //                    TargetAddress = newLocation.LocationCode,
        //                    TaskStatus = TaskStatusEnum.New.ObjToInt(),
        //                    TaskType = TaskTypeEnum.InPick.ObjToInt(),
        //                    // TaskNum = BaseDal.GetTaskNum(nameof(SequenceEnum.SeqTaskNum)),
        //                    PalletType = task.PalletType,
        //                    WarehouseId = task.WarehouseId,
        //                };
        //                tasks.Add(newtask);
        //            }
        //        }
        //        try
        //        {
        //            await _taskRepository.Db.Insertable(tasks).ExecuteCommandAsync();
        //            //删除 å‡ºåº“çš„  task
        //            //给 ess  æµåŠ¨ä¿¡å·  å’Œåˆ›å»ºä»»åŠ¡
        //        }
        //        catch (Exception ex)
        //        {
        //        }
        //        return WebResponseContent.Instance.OK();
        //    }
        //    catch (Exception ex)
        //    {
        //        return WebResponseContent.Instance.Error($"回库操作失败: {ex.Message}");
        //    }
        //}
        public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason)
        {
            try
            {
                // 1. èŽ·å–æ‰€æœ‰æœªåˆ†æ‹£çš„å‡ºåº“é”å®šè®°å½•ï¼ŒåŒ…æ‹¬æ‹†åŒ…äº§ç”Ÿçš„è®°å½•
                //  èŽ·å–æ‰€æœ‰æœªåˆ†æ‹£çš„å‡ºåº“é”å®šè®°å½•ï¼ŒåŒ…æ‹¬æ‹†åŒ…äº§ç”Ÿçš„è®°å½•
                var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(it => it.OrderNo == orderNo && it.Status == 1)
                    .ToListAsync();
                var stockinfo = _stockInfoService.Db.Queryable<Dt_StockInfo>().First(x => x.PalletCode == palletCode);
                // 2. æ£€æŸ¥æ‰˜ç›˜ä¸Šæ˜¯å¦æœ‰å…¶ä»–非出库货物(库存货物)
                var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(it => it.StockId == stockinfo.Id && it.Status == StockStatusEmun.入库确认.ObjToInt())
                    .Where(it => it.OutboundQuantity == 0 || it.OutboundQuantity < it.StockQuantity) // æœªå®Œå…¨å‡ºåº“çš„
                    .ToListAsync();
                // 3. å¦‚果没有需要回库的货物(既无未分拣出库货物,也无其他库存货物)
                if (!remainingLocks.Any() && !palletStockGoods.Any())
                {
                    return WebResponseContent.Instance.Error("没有需要回库的剩余货物");
                }
                var tasks = new List<Dt_Task>();
@@ -540,6 +375,21 @@
                {
                    return WebResponseContent.Instance.Error("未找到对应的任务信息");
                }
                //  æ£€æŸ¥æ‰˜ç›˜ä¸Šæ˜¯å¦æœ‰å…¶ä»–非出库货物(库存货物)
                var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(it => it.StockId == stockinfo.Id && (it.Status == StockStatusEmun.入库确认.ObjToInt() || it.Status == StockStatusEmun.入库完成.ObjToInt() || it.Status == StockStatusEmun.出库锁定.ObjToInt()))
                    .Where(it => it.OutboundQuantity == 0 || it.OutboundQuantity < it.StockQuantity) // æœªå®Œå…¨å‡ºåº“çš„
                    .ToListAsync();
                //  å¦‚果没有需要回库的货物(既无未分拣出库货物,也无其他库存货物)
                if (!remainingLocks.Any() && !palletStockGoods.Any())
                {
                    //是否自动回库,把之前出库的任务删除,然后组个空盘入库。
                    return WebResponseContent.Instance.Error("没有需要回库的剩余货物");
                }
                var firstlocation = _locationInfoService.Db.Queryable<Dt_LocationInfo>().First(x => x.LocationCode == task.SourceAddress);
                decimal totalReturnQty = 0;
                var hasRemainingLocks = remainingLocks.Any(x => x.PalletCode == palletCode);
@@ -631,19 +481,20 @@
                    totalReturnQty = palletStockGoods.Sum(x => x.StockQuantity - x.OutboundQuantity);
                }
                // ä¿å­˜ä»»åŠ¡
                // ä¿å­˜ä»»åŠ¡ ç»™ESS下发任务
                if (tasks.Any())
                {
                    try
                    {
                        await _taskRepository.Db.Insertable(tasks).ExecuteCommandAsync();
                        var targetAddress = task.TargetAddress;
                        _taskRepository.DeleteData(task);
                        // ç»™ ESS æµåŠ¨ä¿¡å·å’Œåˆ›å»ºä»»åŠ¡
                        try
                        {
                            var result = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest
                            {
                                slotCode = movestations[task.TargetAddress],
                                slotCode = movestations[targetAddress],
                                containerCode = palletCode
                            });
                            if (result)
@@ -662,7 +513,7 @@
                                            taskDescribe = new TaskDescribeType {
                                                containerCode = palletCode,
                                                containerType = "CT_KUBOT_STANDARD",
                                                fromLocationCode = stations.GetValueOrDefault(task.TargetAddress) ?? "",
                                                fromLocationCode = stations.GetValueOrDefault(targetAddress) ?? "",
                                                toStationCode = "",
                                                toLocationCode = tasks.First().TargetAddress,
                                                deadline = 0, storageTag = ""
@@ -670,7 +521,7 @@
                                        }
                                    }
                                };
                                var resulttask = await _eSSApiService.CreateTaskAsync(esstask);
@@ -682,7 +533,7 @@
                            _logger.LogInformation("ReturnRemaining åˆ›å»ºä»»åŠ¡è¿”å›ž catch err:  " + ex.Message);
                        }
                        return WebResponseContent.Instance.OK($"回库操作成功,共回库数量:{totalReturnQty}");
                    }
@@ -764,7 +615,7 @@
                        .Where(x => x.OrderNo == orderNo &&
                                   x.PalletCode == palletCode &&
                                   x.CurrentBarcode == barcode &&
                                   x.Status == 2)
                                   x.Status == 6)
                        .FirstAsync();
                if (outStockInfo == null)
@@ -775,11 +626,15 @@
                outStockInfo.Status = 1;
                await _outStockLockInfoService.Db.Updateable(outStockInfo).ExecuteCommandAsync();
                //// è¿˜åŽŸåº“å­˜å‡ºåº“æ•°é‡
                //await _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>()
                //        .SetColumns(x => x.OutboundQuantity == x.OutboundQuantity - outStockInfo.AssignQuantity)
                //        .Where(x => x.Barcode == barcode)
                //        .ExecuteCommandAsync();
                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                       .Where(x => x.Barcode == barcode && x.StockId == outStockInfo.StockId)
                       .FirstAsync();
                stockDetail.StockQuantity += outStockInfo.AssignQuantity;
                stockDetail.OutboundQuantity += outStockInfo.AssignQuantity;
                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
                // è¿˜åŽŸå‡ºåº“å•æ˜Žç»†
                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
@@ -787,6 +642,7 @@
                    .FirstAsync();
                orderDetail.OverOutQuantity -= outStockInfo.AssignQuantity;
                orderDetail.PickedQty = 0;
                await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
                // åˆ é™¤æ‹£é€‰åŽ†å²
@@ -802,19 +658,6 @@
            {
                return WebResponseContent.Instance.Error($"取消拣选失败:{ex.Message}");
            }
        }
        /// <summary>
        /// æ ¹æ®æ¡ç æŸ¥æ‰¾é”å®šä¿¡æ¯
        /// </summary>
        private async Task<Dt_OutStockLockInfo> FindLockInfoByBarcode(int orderDetailId, string barcode, string materielCode)
        {
            return await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                .Where(x => x.OrderDetailId == orderDetailId &&
                           x.MaterielCode == materielCode &&
                           x.CurrentBarcode == barcode &&
                           x.Status == (int)OutLockStockStatusEnum.出库中 &&
                           x.AssignQuantity > x.PickedQty)
                .FirstAsync();
        }
        // èŽ·å–æœªæ‹£é€‰åˆ—è¡¨
@@ -896,88 +739,6 @@
                .ToListAsync();
        }
        public async Task GetPalletPickingSummary(string orderNo, string palletCode)
        {
            var summary = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode)
                .GroupBy(x => new { x.PalletCode, x.Status })
                .Select(x => new
                {
                    PalletCode = x.PalletCode,
                    Status = x.Status,
                    TotalAssignQty = SqlFunc.AggregateSum(x.AssignQuantity),
                    TotalPickedQty = SqlFunc.AggregateSum(x.PickedQty)
                })
                .ToListAsync();
            //   return summary;
        }
        /// <summary>
        /// æ’¤é”€æ‹£é€‰
        /// </summary>
        public async Task<WebResponseContent> CancelPicking(CancelPickingRequest request)
        {
            // å®žçŽ°æ’¤é”€æ‹£é€‰çš„é€»è¾‘ï¼Œéœ€è¦ï¼š
            // 1. æ¢å¤åº“存出库数量
            // 2. æ¢å¤é”å®šä¿¡æ¯çš„已拣选数量
            // 3. æ¢å¤å‡ºåº“单明细的已出数量和锁定数量
            // 4. åˆ é™¤æˆ–标记拣选历史记录
            // æ³¨æ„ï¼šè¿™é‡Œéœ€è¦äº‹åŠ¡å¤„ç†
            try
            {
                _unitOfWorkManage.BeginTran();
                var pickHistory = await Db.Queryable<Dt_PickingRecord>()
                    .Where(x => x.Id == request.PickingHistoryId)
                    .FirstAsync();
                if (pickHistory == null)
                    return WebResponseContent.Instance.Error("未找到拣选记录");
                // æ¢å¤åº“å­˜
                var stockDetail = await _stockInfoService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(x => x.Barcode == pickHistory.Barcode && x.StockId == pickHistory.StockId)
                    .FirstAsync();
                if (stockDetail != null)
                {
                    stockDetail.OutboundQuantity -= pickHistory.PickQuantity;
                    await _stockInfoService.Db.Updateable(stockDetail).ExecuteCommandAsync();
                }
                // æ¢å¤é”å®šä¿¡æ¯
                var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(x => x.OrderDetailId == pickHistory.OrderDetailId && x.StockId == pickHistory.StockId)
                    .FirstAsync();
                lockInfo.PickedQty -= pickHistory.PickQuantity;
                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
                // æ¢å¤å‡ºåº“单明细
                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .Where(x => x.Id == pickHistory.OrderDetailId)
                    .FirstAsync();
                orderDetail.OverOutQuantity -= pickHistory.PickQuantity;
                orderDetail.LockQuantity += pickHistory.PickQuantity;
                if (orderDetail.OverOutQuantity < orderDetail.OrderQuantity)
                {
                    orderDetail.OrderDetailStatus = orderDetail.LockQuantity > 0 ?
                        (int)OrderDetailStatusEnum.Outbound : (int)OrderDetailStatusEnum.AssignOverPartial;
                }
                await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
                // åˆ é™¤æ‹£é€‰åŽ†å²è®°å½•
                await Db.Deleteable<Dt_PickingRecord>().Where(x => x.Id == request.PickingHistoryId).ExecuteCommandAsync();
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK("撤销成功");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error($"撤销失败: {ex.Message}");
            }
        }
        /// <summary>
        /// èŽ·å–æ‰˜ç›˜çš„å‡ºåº“çŠ¶æ€ä¿¡æ¯