pan
2025-11-30 f8ec9168ceb7883853381ff0c409e1222b62b634
提交
已修改8个文件
366 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_CheckService/ReCheckOrderService.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_CheckService/WIDESEA_CheckService.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/BatchOutBoundDto.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_ICheckService/IReCheckOrderService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs 204 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/BatchPickingConfirm.vue
@@ -83,7 +83,7 @@
              <el-table-column type="selection" width="55"></el-table-column>
              <el-table-column prop="materielCode" label="物料编码" width="120"></el-table-column>
              <el-table-column prop="pickedQty" label="已拣数量" width="100"></el-table-column>
              <el-table-column prop="locationCode" label="货位" width="100"></el-table-column>
              <!-- <el-table-column prop="locationCode" label="货位" width="100"></el-table-column> -->
              <el-table-column prop="currentBarcode" label="条码"></el-table-column>
            </el-table>
          </el-card>
@@ -983,7 +983,8 @@
          palletCode: this.scanData.palletCode
        });
        if (res.status) {
          this.unpickedList = res.data || [];
          //this.unpickedList = res.data || [];
          this.unpickedList = (res.data || []).filter(item => item.canPick === true);
          this.summary.unpickedCount = this.unpickedList.length;
          this.summary.unpickedQuantity = this.unpickedList.reduce((sum, item) => sum + (item.remainQuantity || 0), 0);
        }
@@ -1000,6 +1001,15 @@
        });
        if (res.status) {
          this.pickedList = res.data || [];
          this.pickedList = res.data.map(item => {
  // æ–¹å¼1:保留原barcode字段,新增currentBarcode
  return {
    ...item,
    currentBarcode: item.barcode
  };
});
          this.summary.pickedCount = this.pickedList.length;
        }
      } catch (error) {
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_CheckService/ReCheckOrderService.cs
@@ -1,17 +1,21 @@
using HslCommunication.WebSocket;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Common.OrderEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.CodeConfigEnum;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
using WIDESEA_ICheckService;
using WIDESEA_IOutboundService;
using WIDESEA_Model.Models;
using WIDESEA_Model.Models.Check;
@@ -23,21 +27,24 @@
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly WebSocketServer _webSocketServer;
        private readonly ILogger<ReCheckOrderService> _logger;
        public readonly IOutboundService _outboundService;
        public IRepository<Dt_ReCheckOrder> Repository => BaseDal;
        public ReCheckOrderService(IRepository<Dt_ReCheckOrder> BaseDal, IUnitOfWorkManage unitOfWorkManage, WebSocketServer webSocketServer, ILogger<ReCheckOrderService> logger) : base(BaseDal)
        public ReCheckOrderService(IRepository<Dt_ReCheckOrder> BaseDal, IUnitOfWorkManage unitOfWorkManage, WebSocketServer webSocketServer, ILogger<ReCheckOrderService> logger, IOutboundService outboundService) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _webSocketServer = webSocketServer;
            _logger = logger;
            _outboundService = outboundService;
        }
        public WebResponseContent ReceiveReCheckOrder(Dt_ReCheckOrder models, int operateType)
        public async Task<WebResponseContent> ReceiveReCheckOrder(Dt_ReCheckOrder models, int operateType)
        {
            try
            {
                return operateType switch
                {
                    1 => AddReCheckOrder(models),
                    1 =>await AddReCheckOrder(models),
                    2 => UpdateReCheckOrder(models),
                    3 => DeleteReCheckOrder(models),
@@ -51,7 +58,7 @@
            }
        }
        public WebResponseContent AddReCheckOrder(Dt_ReCheckOrder model)
        public async Task<WebResponseContent> AddReCheckOrder(Dt_ReCheckOrder model)
        {
            try
            {
@@ -64,7 +71,9 @@
                model.Creater = "MES";
                model.CreateDate = DateTime.Now;
                BaseDal.AddData(model);
                var outboundOrders = ConvertToOutboundOrders(model);
                await _outboundService.OutboundOrderService.ReceiveOutboundOrder(outboundOrders, 1);
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
@@ -73,7 +82,7 @@
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public WebResponseContent UpdateReCheckOrder(Dt_ReCheckOrder model)
        public async Task<WebResponseContent> UpdateReCheckOrder(Dt_ReCheckOrder model)
        {
            try
            {
@@ -98,7 +107,13 @@
                BaseDal.UpdateData(recheckOrder);
                _outboundService.OutboundOrderService.Db.Deleteable<Dt_OutboundOrder>().Where(x => x.OrderNo == model.OrderNo).ExecuteCommand();
                _outboundService.OutboundOrderDetailService.Db.Deleteable<Dt_OutboundOrderDetail>()
                 .Where(p => SqlFunc.Subqueryable<Dt_OutboundOrder>().Where(s => s.Id == p.OrderId && s.OrderNo == model.OrderNo).Any()).ExecuteCommand();
                var outboundOrders = ConvertToOutboundOrders(model);
                await _outboundService.OutboundOrderService.ReceiveOutboundOrder(outboundOrders, 1);
                return WebResponseContent.Instance.OK();
            }
@@ -122,6 +137,10 @@
               
                BaseDal.DeleteData(recheckOrder);   
 
                _outboundService.OutboundOrderService.Db.Deleteable<Dt_OutboundOrder>().Where(x => x.OrderNo == model.OrderNo).ExecuteCommand();
                _outboundService.OutboundOrderDetailService.Db.Deleteable<Dt_OutboundOrderDetail>()
                 .Where(p => SqlFunc.Subqueryable<Dt_OutboundOrder>().Where(s => s.Id == p.OrderId && s.OrderNo == model.OrderNo).Any()).ExecuteCommand();
                return WebResponseContent.Instance.OK();
            }
@@ -132,5 +151,49 @@
            }
        }
        public Dt_OutboundOrder ConvertToOutboundOrders(Dt_ReCheckOrder reCheckOrder)
        {
            var outboundOrder = new Dt_OutboundOrder()
            {
                WarehouseId = 0,
                OrderNo = reCheckOrder.OrderNo,
                UpperOrderNo = reCheckOrder.OrderNo,
                OrderType = InOrderTypeEnum.ReCheck.ObjToInt(),
                OrderStatus = 0,
                CreateType = 0,
                BusinessType = "",
                IsBatch = 0,
                FactoryArea = reCheckOrder.FactoryArea,
                Remark = "",
                DepartmentCode = "",
                DepartmentName = "",
                Details = new List<Dt_OutboundOrderDetail>()
            };
            outboundOrder.Details.Add(
                     new Dt_OutboundOrderDetail
                     {
                         OrderId = 0,
                         MaterielCode = reCheckOrder.MaterielCode,
                         MaterielName = "",
                         BatchNo = reCheckOrder.BatchNo,
                         OrderQuantity = reCheckOrder.Qty,
                         BarcodeQty = (decimal)reCheckOrder.Qty,
                         BarcodeUnit = reCheckOrder.Unit,
                         LockQuantity = 0,
                         lineNo = "",
                         OverOutQuantity = 0,
                         OrderDetailStatus = 0,
                         Unit = reCheckOrder.Unit,
                         RowNo = 0,
                         SupplyCode = "",
                         WarehouseCode = reCheckOrder.WarehouseCode,
                     }
                );
            return outboundOrder;
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_CheckService/WIDESEA_CheckService.csproj
@@ -8,6 +8,7 @@
  <ItemGroup>
    <ProjectReference Include="..\WIDESEA_ICheckService\WIDESEA_ICheckService.csproj" />
    <ProjectReference Include="..\WIDESEA_IOutboundService\WIDESEA_IOutboundService.csproj" />
  </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/BatchOutBoundDto.cs
@@ -165,5 +165,28 @@
        public string PalletCode { get; set; }
    }
    #endregion
    #region DTOç±»
    public class SplitPackageChainInfoDto
    {
        public string OriginalBarcode { get; set; }
        public string RootBarcode { get; set; } // æ–°å¢žï¼šæ ¹æ¡ç 
        public int TotalSplitTimes { get; set; }
        public string ChainType { get; set; } // "root" æˆ– "branch"
        public List<SplitChainItemDto> SplitChain { get; set; }
    }
    public class SplitChainItemDto
    {
        public DateTime SplitTime { get; set; }
        public string OriginalBarcode { get; set; }
        public string NewBarcode { get; set; }
        public decimal SplitQuantity { get; set; }
        public string Operator { get; set; }
        public bool IsReverted { get; set; }
    }
    #endregion
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_ICheckService/IReCheckOrderService.cs
@@ -15,6 +15,6 @@
    {
        IRepository<Dt_ReCheckOrder> Repository { get; }
        WebResponseContent ReceiveReCheckOrder(Dt_ReCheckOrder models, int operateType);
        Task<WebResponseContent> ReceiveReCheckOrder(Dt_ReCheckOrder models, int operateType);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs
@@ -52,6 +52,45 @@
        public string CancelOperator { get; set; }
        public string FactoryArea { get; set; }
        /// <summary>
        /// ä»“库
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "warehouseCode", ColumnDescription = "仓库")]
        public string? WarehouseCode { get; set; }
        /// <summary>
        /// è¡Œå·
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "lineNo", ColumnDescription = "行号")]
        public string? lineNo { get; set; }
        /// <summary>
        /// ä¾›åº”商编号
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "supplyCode", ColumnDescription = "供应商编号")]
        public string? SupplyCode { get; set; }
        /// <summary>
        /// æ•°é‡
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "barcodeQty", ColumnDescription = "数量")]
        public decimal BarcodeQty { get; set; }
        /// <summary>
        /// å•位
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "barcodeUnit", ColumnDescription = "单位")]
        public string BarcodeUnit { get; set; } = null!;
        /// <summary>
        ///
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "barcodemoveQty", ColumnDescription = "数量")]
        public decimal BarcodeMoveQty { get; set; }
    }
 
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs
@@ -242,6 +242,8 @@
        #region å–走空箱逻辑
        /// <summary>
        /// å–走空箱 - æ¸…理已完成拣选的托盘数据
        /// </summary>
@@ -265,7 +267,7 @@
                await UpdateOrderStatusAfterPalletRemoval(orderNo);
                //  è®°å½•操作历史
                // await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks);
                await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks);
                _unitOfWorkManage.CommitTran();
@@ -322,13 +324,12 @@
        {
            foreach (var lockInfo in completedLocks)
            {
                // æ ‡è®°é”å®šè®°å½•为已取走(可以新增状态或直接删除,根据业务需求)
                // è¿™é‡Œæˆ‘们将其状态更新为"已取走",并记录取走时间
                // æ ‡è®°é”å®šè®°å½•为已取走
                lockInfo.Status = (int)OutLockStockStatusEnum.已取走;
                lockInfo.Operator = App.User.UserName;
                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
                // åŒæ—¶æ¸…理对应的库存记录状态
                // æ¸…理对应的库存记录状态
                await CleanupStockInfo(lockInfo);
            }
        }
@@ -341,16 +342,13 @@
            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId);
            if (stockDetail != null)
            {
                // å¦‚果库存已经出库完成,标记为已清理
                if (stockDetail.Status == (int)StockStatusEmun.出库完成)
            if (stockDetail != null && stockDetail.Status == (int)StockStatusEmun.出库完成)
                {
                    stockDetail.Status = (int)StockStatusEmun.已清理;
                    await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
                }
            }
        }
        /// <summary>
        /// æ›´æ–°è®¢å•状态
@@ -401,21 +399,7 @@
        #endregion
        #region è¾…助方法
        private string GetPalletStatusText(PalletStatusEnum status)
        {
            return status switch
            {
                PalletStatusEnum.未开始 => "未开始",
                PalletStatusEnum.拣选中 => "拣选中",
                PalletStatusEnum.已完成 => "已完成",
                PalletStatusEnum.无任务 => "无任务",
                _ => "未知"
            };
        }
        #endregion
        #region åˆ†æ‰¹åˆ†æ‹£
        /// <summary>
@@ -484,10 +468,10 @@
                    return WebResponseContent.Instance.Error("未找到分拣记录");
                // æ¢å¤é”å®šä¿¡æ¯å’Œåº“å­˜
                await RevertPickingData(pickingRecord);
                var revertResult = await RevertPickingData(pickingRecord);
                //更新批次和订单数据
                await RevertBatchAndOrderData(pickingRecord);
                await RevertBatchAndOrderData(pickingRecord, revertResult);
                // æ ‡è®°åˆ†æ‹£è®°å½•为已取消
                pickingRecord.IsCancelled = true;
@@ -506,7 +490,6 @@
                return WebResponseContent.Instance.Error($"取消分拣失败:{ex.Message}");
            }
        }
        #endregion
        #region æ‰‹åŠ¨æ‹†åŒ…
@@ -549,12 +532,12 @@
        #endregion
        #region å–消拆包
        #region å–消拆包 - ä¿®å¤ç‰ˆæœ¬
        /// <summary>
        /// å–消拆包 - æ”¯æŒå¤šæ¬¡æ‹†åŒ…的情况
        /// å–消拆包
        /// </summary>
        public async Task<WebResponseContent> CancelSplitPackage(string orderNo, string palletCode, string newBarcode)
        {
@@ -599,7 +582,7 @@
        }
        /// <summary>
        /// æ‰§è¡Œå–消拆包逻辑 - ä¿®å¤ç‰ˆæœ¬
        /// æ‰§è¡Œå–消拆包逻辑
        /// </summary>
        private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord,
            Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo,
@@ -618,7 +601,7 @@
            await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
            // 2. æ¢å¤åŽŸåº“å­˜æ˜Žç»†
            // æ¢å¤åŽŸåº“å­˜æ˜Žç»†
            var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId);
@@ -632,29 +615,29 @@
            await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync();
            // 3. åˆ é™¤æ–°é”å®šä¿¡æ¯
            // åˆ é™¤æ–°é”å®šä¿¡æ¯
            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
                .Where(x => x.Id == newLockInfo.Id)
                .ExecuteCommandAsync();
            // 4. åˆ é™¤æ–°åº“存明细
            // åˆ é™¤æ–°åº“存明细
            await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
                .Where(x => x.Barcode == newLockInfo.CurrentBarcode)
                .ExecuteCommandAsync();
            // 5. æ ‡è®°æ‹†åŒ…记录为已撤销
            //标记拆包记录为已撤销
            splitRecord.IsReverted = true;
            splitRecord.RevertTime = DateTime.Now;
            splitRecord.RevertOperator = App.User.UserName;
            await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync();
            // 6. æ£€æŸ¥å¹¶æ›´æ–°æ‰¹æ¬¡å’Œè®¢å•状态
            // æ£€æŸ¥å¹¶æ›´æ–°æ‰¹æ¬¡å’Œè®¢å•状态
            await CheckAndUpdateBatchStatus(originalLockInfo.BatchNo);
            await CheckAndUpdateOrderStatus(originalLockInfo.OrderNo);
        }
        /// <summary>
        /// éªŒè¯å–消拆包请求 - å¢žå¼ºç‰ˆæœ¬
        /// éªŒè¯å–消拆包请求
        /// </summary>
        private async Task<ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateCancelSplitRequest(
            string orderNo, string palletCode, string newBarcode)
@@ -916,32 +899,8 @@
        #endregion
        #region DTOç±»
      
        public class SplitPackageChainInfoDto
        {
            public string OriginalBarcode { get; set; }
            public string RootBarcode { get; set; } // æ–°å¢žï¼šæ ¹æ¡ç 
            public int TotalSplitTimes { get; set; }
            public string ChainType { get; set; } // "root" æˆ– "branch"
            public List<SplitChainItemDto> SplitChain { get; set; }
        }
        public class SplitChainItemDto
        {
            public DateTime SplitTime { get; set; }
            public string OriginalBarcode { get; set; }
            public string NewBarcode { get; set; }
            public decimal SplitQuantity { get; set; }
            public string Operator { get; set; }
            public bool IsReverted { get; set; }
        }
        #endregion
        #endregion
        #region åˆ†æ‰¹å›žåº“
@@ -954,7 +913,7 @@
            {
                _unitOfWorkManage.BeginTran();
                //  æŸ¥æ‰¾æ‰˜ç›˜ä¸Šæœªå®Œæˆçš„锁定记录
                // æŸ¥æ‰¾æ‰˜ç›˜ä¸Šæœªå®Œæˆçš„锁定记录(只处理出库中的记录)
                var unfinishedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(x => x.OrderNo == orderNo &&
                               x.PalletCode == palletCode &&
@@ -964,12 +923,12 @@
                if (!unfinishedLocks.Any())
                    return WebResponseContent.Instance.Error("该托盘没有未完成的锁定记录");
                // æŒ‰æ‰¹æ¬¡åˆ†ç»„处理
                var batchGroups = unfinishedLocks.GroupBy(x => x.BatchNo);
                // æŒ‰å‡ºåº“批次分组处理
                var batchGroups = unfinishedLocks.GroupBy(x => x.OutboundBatchNo); // ä½¿ç”¨ OutboundBatchNo
                foreach (var batchGroup in batchGroups)
                {
                    var batchNo = batchGroup.Key;
                    var outboundBatchNo = batchGroup.Key;
                    var batchLocks = batchGroup.ToList();
                    // é‡Šæ”¾åº“存和锁定记录
@@ -979,7 +938,7 @@
                    }
                    // æ›´æ–°æ‰¹æ¬¡çŠ¶æ€
                    await UpdateBatchStatusForReturn(batchNo, batchLocks);
                    await UpdateBatchStatusForReturn(outboundBatchNo, batchLocks);
                    // æ›´æ–°è®¢å•明细的已分配数量
                    await UpdateOrderDetailAfterReturn(batchLocks);
@@ -996,7 +955,6 @@
                return WebResponseContent.Instance.Error($"分批回库失败:{ex.Message}");
            }
        }
        #endregion
        #region éªŒè¯æ–¹æ³•
@@ -1030,12 +988,12 @@
                return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error(
                    $"库存数量不足,需要:{lockInfo.AssignQuantity},实际:{stockDetail.StockQuantity}");
            // ä½¿ç”¨ OutboundBatchNo æŸ¥æ‰¾æ‰¹æ¬¡
            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
                .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo);
                .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo); // ä¿®æ­£ä¸º OutboundBatchNo
            return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Success((lockInfo, orderDetail, stockDetail, batch));
        }
        private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest(
            string orderNo, string palletCode, string originalBarcode, decimal splitQuantity)
        {
@@ -1101,7 +1059,17 @@
                .FirstAsync(x => x.Id == pickingRecord.OutStockLockId);
            lockInfo.PickedQty -= pickingRecord.PickQuantity;
            // æ ¹æ®æ‹£é€‰æ•°é‡åˆ¤æ–­çŠ¶æ€
            if (lockInfo.PickedQty <= 0)
            {
            lockInfo.Status = (int)OutLockStockStatusEnum.出库中;
            }
            else if (lockInfo.PickedQty < lockInfo.AssignQuantity)
            {
                lockInfo.Status = (int)OutLockStockStatusEnum.出库中;
            }
            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
            // æ¢å¤åº“å­˜
@@ -1110,7 +1078,13 @@
            stockDetail.StockQuantity += pickingRecord.PickQuantity;
            stockDetail.OutboundQuantity -= pickingRecord.PickQuantity;
            // æ¢å¤åº“存状态
            if (stockDetail.StockQuantity > 0)
            {
            stockDetail.Status = (int)StockStatusEmun.出库锁定;
            }
            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
            return new RevertPickingResult
@@ -1119,7 +1093,6 @@
                StockDetail = stockDetail
            };
        }
        private async Task<SplitResultDto> ExecuteSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,
            decimal splitQuantity, string palletCode)
        {
@@ -1132,7 +1105,7 @@
                StockId = stockDetail.StockId,
                MaterielCode = stockDetail.MaterielCode,
                OrderNo = stockDetail.OrderNo,
                BatchNo = stockDetail.BatchNo,
                BatchNo = stockDetail.BatchNo, // ç‰©æ–™æ‰¹æ¬¡
                StockQuantity = splitQuantity,
                OutboundQuantity = 0,
                Barcode = newBarcode,
@@ -1143,8 +1116,6 @@
                BarcodeUnit=stockDetail.BarcodeUnit,
                BusinessType=stockDetail.BusinessType,
                InboundOrderRowNo=stockDetail.InboundOrderRowNo,
            };
            await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
@@ -1152,17 +1123,16 @@
            stockDetail.StockQuantity -= splitQuantity;
            await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
            // åˆ›å»ºæ–°é”å®šä¿¡æ¯ - ä½¿ç”¨æ­£ç¡®çš„ OutboundBatchNo
            var newLockInfo = new Dt_OutStockLockInfo
            {
                OrderNo = lockInfo.OrderNo,
                OrderDetailId = lockInfo.OrderDetailId,
                BatchNo = lockInfo.BatchNo,
                OutboundBatchNo = lockInfo.OutboundBatchNo, // ä½¿ç”¨ OutboundBatchNo
                MaterielCode = lockInfo.MaterielCode,
                MaterielName = lockInfo.MaterielName,
                StockId = lockInfo.StockId,
                OrderQuantity = splitQuantity,
                //OriginalQuantity = quantity,
                AssignQuantity = splitQuantity,
                PickedQty = 0,
                LocationCode = lockInfo.LocationCode,
@@ -1173,7 +1143,6 @@
                SupplyCode = lockInfo.SupplyCode,
                OrderType = lockInfo.OrderType,
                CurrentBarcode = newBarcode,
               // OriginalLockQuantity = quantity,
                IsSplitted = 1,
                ParentLockId = lockInfo.Id,
                Operator = App.User.UserName,
@@ -1182,7 +1151,6 @@
                WarehouseCode = lockInfo.WarehouseCode,
                BarcodeQty = lockInfo.BarcodeQty,
                BarcodeUnit = lockInfo.BarcodeUnit,
            };
            await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
@@ -1197,7 +1165,6 @@
            return new SplitResultDto { NewBarcode = newBarcode };
        }
        private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord, Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail)
        {
            // æ¢å¤åŽŸåº“å­˜
@@ -1255,15 +1222,28 @@
            await CheckAndUpdateOrderStatus(orderNo);
        }
        private async Task RevertBatchAndOrderData(Dt_PickingRecord pickingRecord)
        private async Task RevertBatchAndOrderData(Dt_PickingRecord pickingRecord, RevertPickingResult revertResult)
        {
            // æ¢å¤æ‰¹æ¬¡å®Œæˆæ•°é‡
            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
                .FirstAsync(x => x.BatchNo == pickingRecord.BatchNo);
                .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo); // ä½¿ç”¨ OutboundBatchNo
            if (batch != null)
            {
            batch.CompletedQuantity -= pickingRecord.PickQuantity;
                // é‡æ–°è®¡ç®—批次状态
                if (batch.CompletedQuantity <= 0)
                {
                    batch.BatchStatus = (int)BatchStatusEnum.分配中;
                }
                else if (batch.CompletedQuantity < batch.BatchQuantity)
                {
            batch.BatchStatus = (int)BatchStatusEnum.执行中;
                }
            await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
            }
            // æ¢å¤è®¢å•明细
            var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
@@ -1276,46 +1256,61 @@
            // é‡æ–°æ£€æŸ¥è®¢å•状态
            await CheckAndUpdateOrderStatus(pickingRecord.OrderNo);
        }
        private async Task ReleaseLockAndStock(Dt_OutStockLockInfo lockInfo)
        {
            // æ¢å¤åº“存状态
            // æ¢å¤åº“存状态 - å›žåº“后库存变为可用状态
            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId);
            if (stockDetail != null)
            {
                // å›žåº“后库存状态恢复为入库完成(可用状态)
                stockDetail.Status = (int)StockStatusEmun.入库完成;
                await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync();
            }
            // æ›´æ–°é”å®šè®°å½•状态为回库
            // æ›´æ–°é”å®šè®°å½•状态为已回库
            lockInfo.Status = (int)OutLockStockStatusEnum.已回库;
            lockInfo.Operator = App.User.UserName;
            await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
        }
        private async Task UpdateBatchStatusForReturn(string batchNo, List<Dt_OutStockLockInfo> returnedLocks)
        /// <summary>
        /// æ›´æ–°æ‰¹æ¬¡çŠ¶æ€ï¼ˆå›žåº“ï¼‰
        /// </summary>
        private async Task UpdateBatchStatusForReturn(string outboundBatchNo, List<Dt_OutStockLockInfo> returnedLocks)
        {
            var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>()
                .FirstAsync(x => x.BatchNo == batchNo);
                .FirstAsync(x => x.BatchNo == outboundBatchNo);
            // è®¡ç®—回库数量
            if (batch != null)
            {
                // è®¡ç®—回库数量(未拣选的部分)
            var returnedQty = returnedLocks.Sum(x => x.AssignQuantity - x.PickedQty);
            batch.CompletedQuantity -= returnedQty;
                // æ›´æ–°æ‰¹æ¬¡çŠ¶æ€
            if (batch.CompletedQuantity <= 0)
            {
                batch.BatchStatus = (int)BatchStatusEnum.已回库;
            }
            else
                else if (batch.CompletedQuantity < batch.BatchQuantity)
            {
                batch.BatchStatus = (int)BatchStatusEnum.执行中;
                }
                else
                {
                    batch.BatchStatus = (int)BatchStatusEnum.已完成;
            }
            batch.Operator = App.User.UserName;
            await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync();
        }
        }
        /// <summary>
        /// æ›´æ–°è®¢å•明细(回库后)
        /// </summary>
        private async Task UpdateOrderDetailAfterReturn(List<Dt_OutStockLockInfo> returnedLocks)
        {
            var orderDetailGroups = returnedLocks.GroupBy(x => x.OrderDetailId);
@@ -1325,13 +1320,16 @@
                var orderDetailId = group.Key;
                var returnedQty = group.Sum(x => x.AssignQuantity - x.PickedQty);
                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
                    .SetColumns(x => x.AllocatedQuantity == x.AllocatedQuantity - returnedQty)
                    .Where(x => x.Id == orderDetailId)
                    .ExecuteCommandAsync();
            }
        }
                var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
                    .FirstAsync(x => x.Id == orderDetailId);
                if (orderDetail != null)
                {
                    orderDetail.AllocatedQuantity -= returnedQty;
                    await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync();
                }
            }
        }
        #endregion
        #region è¾…助方法
@@ -1374,6 +1372,13 @@
                PickTime = DateTime.Now,
                Operator = App.User.UserName,
                OutStockLockId = result.FinalLockInfo.Id,
                BarcodeUnit = result.FinalLockInfo.BarcodeUnit,
                BarcodeQty = result.FinalLockInfo.BarcodeQty,
                BatchNo = result.FinalLockInfo.BatchNo,
                lineNo = result.FinalLockInfo.lineNo,
                SupplyCode = result.FinalLockInfo.SupplyCode,
                WarehouseCode = result.FinalLockInfo.WarehouseCode,
                //  IsCancelled = false
            };
@@ -1397,9 +1402,20 @@
                .Where(x => x.OrderNo == orderNo)
                .ExecuteCommandAsync();
        }
        private string GetPalletStatusText(PalletStatusEnum status)
        {
            return status switch
            {
                PalletStatusEnum.未开始 => "未开始",
                PalletStatusEnum.拣选中 => "拣选中",
                PalletStatusEnum.已完成 => "已完成",
                PalletStatusEnum.无任务 => "无任务",
                _ => "未知"
            };
        }
        #endregion
        #region DTOç±»
        public class PickingResult
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -735,7 +735,15 @@
                PickQuantity = result.ActualPickedQty,
                PickTime = DateTime.Now,
                Operator = App.User.UserName,
                OutStockLockId = result.FinalLockInfo.Id
                OutStockLockId = result.FinalLockInfo.Id,
                BarcodeUnit=result.FinalLockInfo.BarcodeUnit,
                BarcodeQty=result.FinalLockInfo.BarcodeQty,
                BatchNo= result.FinalLockInfo.BatchNo,
                lineNo= result.FinalLockInfo.lineNo ,
                SupplyCode= result.FinalLockInfo.SupplyCode ,
                WarehouseCode = result.FinalLockInfo.WarehouseCode  ,
            };
            await Db.Insertable(pickingHistory).ExecuteCommandAsync();