pan
2025-11-18 e9feb28be7d4417b24bd53a77332846e2cbab734
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/SplitPackageService.cs
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Http;
using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -9,6 +10,7 @@
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_DTO.Outbound;
using WIDESEA_IBasicService;
using WIDESEA_IOutboundService;
using WIDESEA_IStockService;
using WIDESEA_Model.Models;
@@ -23,13 +25,15 @@
        private readonly IStockInfoService _stockInfoService;
        private readonly IStockInfoDetailService _stockInfoDetailService;
        private readonly IOutStockLockInfoService _outStockLockInfoService;
        private readonly IDailySequenceService _dailySequenceService;
        public SplitPackageService(IRepository<Dt_SplitPackageRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService) : base(BaseDal)
        public SplitPackageService(IRepository<Dt_SplitPackageRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, IDailySequenceService dailySequenceService) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _stockInfoService = stockInfoService;
            _outStockLockInfoService = outStockLockInfoService;
            _stockInfoDetailService = stockInfoDetailService;
            _dailySequenceService = dailySequenceService;
        }
        /// <summary>
@@ -42,66 +46,104 @@
                _unitOfWorkManage.BeginTran();
                // 1. éªŒè¯å‡ºåº“锁定信息
                var lockInfo = await _stockInfoDetailService.Db.Queryable<Dt_OutStockLockInfo>()
                var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                          .Where(x => x.OrderNo == request.OrderNo &&
                           x.PalletCode == request.PalletCode &&
                           x.CurrentBarcode == request.OriginalBarcode &&
                           x.Status == 0)
                           x.Status == 1)
                    .FirstAsync();
                if (lockInfo == null)
                    return WebResponseContent.Instance.Error("未找到有效的出库锁定信息");
                // 2. æ£€æŸ¥å‰©ä½™é”å®šæ•°é‡
                decimal remainingLockQuantity = lockInfo.AssignQuantity - lockInfo.PickedQty;
                decimal remainingLockQuantity = lockInfo.OriginalQuantity - lockInfo.PickedQty;
                if (request.SplitQuantity > remainingLockQuantity)
                    return WebResponseContent.Instance.Error($"拆包数量不能大于剩余锁定数量,剩余:{remainingLockQuantity}");
                var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
               .Where(x => x.Barcode == request.OriginalBarcode)
               .Where(x => x.Barcode == request.OriginalBarcode && x.StockId == lockInfo.StockId)
               .FirstAsync();
                if (stockDetail == null)
                    throw new Exception($"未找到条码{request.OriginalBarcode}对应的库存记录");
                stockDetail.StockQuantity = request.SplitQuantity;
                stockDetail.OutboundQuantity = request.SplitQuantity;
                _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>(stockDetail).ExecuteCommand();
                var seq = await _dailySequenceService.GetNextSequenceAsync();
                // 3. ç”Ÿæˆæ–°æ¡ç 
                string newBarcode = "";
                string newBarcode = "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0');
                decimal remainingQty = remainingLockQuantity - request.SplitQuantity;
                // ä¸ºæ‹†åŒ…产生的新条码创建库存记录
                var newStockDetail = new Dt_StockInfoDetail
                {
                    SupplyCode = stockDetail.SupplyCode,
                    WarehouseCode = stockDetail.WarehouseCode,
                    BarcodeQty = stockDetail.BarcodeQty,
                    BarcodeUnit = stockDetail.BarcodeUnit,
                    BusinessType = stockDetail.BusinessType,
                    Unit = stockDetail.Unit,
                    StockId = lockInfo.StockId,
                    MaterielCode = stockDetail.MaterielCode,
                    OrderNo = stockDetail.OrderNo,
                    BatchNo = stockDetail.BatchNo,
                    StockQuantity = remainingQty,
                    OutboundQuantity = remainingQty, // é”å®šå…¨éƒ¨æ•°é‡
                    Barcode = newBarcode,
                    InboundOrderRowNo = stockDetail.InboundOrderRowNo,
                };
                await _outStockLockInfoService.Db.Insertable(newStockDetail).ExecuteCommandAsync();
                // 4. åˆ›å»ºæ–°çš„出库锁定信息(新条码)
                var newLockInfo = new Dt_OutStockLockInfo
                {
                    OrderNo = lockInfo.OrderNo,
                    OrderDetailId = lockInfo.OrderDetailId,
                    BatchNo = lockInfo.BatchNo,
                    MaterielCode = lockInfo.MaterielCode,
                    MaterielName = lockInfo.MaterielName,
                    StockId = lockInfo.StockId,
                    OrderQuantity = lockInfo.OrderQuantity,
                    OriginalQuantity = lockInfo.OriginalQuantity,
                    AssignQuantity = request.SplitQuantity, // æ–°æ¡ç åˆ†é…æ•°é‡
                    OrderQuantity = remainingQty,
                    OriginalQuantity = remainingQty,
                    AssignQuantity = remainingQty, // æ–°æ¡ç åˆ†é…æ•°é‡
                    PickedQty = 0, // æ–°æ¡ç æœªæ‹£é€‰
                    LocationCode = lockInfo.LocationCode,
                    PalletCode = lockInfo.PalletCode,
                    TaskNum = lockInfo.TaskNum,
                    Status = (int)OutLockStockStatusEnum.出库中,
                    Unit = lockInfo.Unit,
                    SupplyCode = lockInfo.SupplyCode,
                    OrderType = lockInfo.OrderType,
                    CurrentBarcode = newBarcode, // æ–°æ¡ç 
                    OriginalLockQuantity = request.SplitQuantity,
                    IsSplitted = 1,
                    ParentLockId = lockInfo.Id // è®°å½•父级锁定ID
                };
                await Db.Insertable(newLockInfo).ExecuteCommandAsync();
                await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync();
                // 5. æ›´æ–°åŽŸé”å®šä¿¡æ¯çš„åˆ†é…æ•°é‡ï¼ˆå‡å°‘æ‹†åŒ…æ•°é‡ï¼‰
                lockInfo.AssignQuantity -= request.SplitQuantity;
                await Db.Updateable(lockInfo).ExecuteCommandAsync();
                lockInfo.AssignQuantity = request.SplitQuantity;
                await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync();
                // 6. è®°å½•拆包历史(用于追踪)
                var splitHistory = new Dt_SplitPackageRecord
                {
                    FactoryArea = lockInfo.FactoryArea,
                    TaskNum = lockInfo.TaskNum,
                    OutStockLockInfoId = lockInfo.Id,
                    StockId = stockDetail?.StockId ?? 0,
                    Operator = App.User.UserName,
                    IsReverted = false,
                    OriginalBarcode = lockInfo.CurrentBarcode,
                    NewBarcode = newBarcode,
                    SplitQty = request.SplitQuantity,
                    RemainQuantity = lockInfo.RemainQuantity - request.SplitQuantity,
                    RemainQuantity = lockInfo.OriginalQuantity - request.SplitQuantity,
                    MaterielCode = lockInfo.MaterielCode,
                    SplitTime = DateTime.Now,
                    OrderNo = request.OrderNo,
@@ -110,10 +152,10 @@
                };
                await Db.Insertable(splitHistory).ExecuteCommandAsync();
                Db.Ado.CommitTran();
                _unitOfWorkManage.CommitTran();
                // 7. å›žä¼ æ–°æ¡ç ç»™MES
               // await SendBarcodeToMES(newBarcode, request.MaterielCode, request.SplitQuantity);
                // await SendBarcodeToMES(newBarcode, request.MaterielCode, request.SplitQuantity);
                return WebResponseContent.Instance.OK("拆包成功", new
                {
@@ -123,83 +165,215 @@
            }
            catch (Exception ex)
            {
                Db.Ado.RollbackTran();
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error($"拆包失败: {ex.Message}");
            }
        }
        // æ’¤é”€æ‹†åŒ…
        //public async Task<WebResponseContent> RevertSplitPackage(string originalBarcode)
        //{
        //    try
        //    {
        //        _unitOfWorkManage.BeginTran();
        //        // 1. æŸ¥æ‰¾æœ€è¿‘的未撤销拆包记录
        //        var splitRecord = await Db.Queryable<Dt_SplitPackageRecord>()
        //                .Where(x => x.OriginalBarcode == originalBarcode && !x.IsReverted)
        //                .OrderByDescending(x => x.SplitTime)
        //                .FirstAsync();
        //        if (splitRecord == null)
        //            return WebResponseContent.Instance.Error("未找到可撤销的拆包记录");
        //        // 2. æ£€æŸ¥æ–°æ¡ç æ˜¯å¦å·²æ‹£é€‰
        //        var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
        //            .Where(x => x.CurrentBarcode == splitRecord.NewBarcode)
        //            .FirstAsync();
        //        if (newLockInfo?.Status ==6) // å‡è®¾çŠ¶æ€2表示已拣选
        //            return WebResponseContent.Instance.Error("新条码已拣选,无法撤销拆包");
        //        // 3. èŽ·å–åŽŸæ¡ç çš„é”å®šä¿¡æ¯
        //        var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
        //            .Where(x => x.CurrentBarcode == originalBarcode)
        //            .FirstAsync();
        //        if (originalLockInfo == null)
        //            return WebResponseContent.Instance.Error("未找到原条码锁定信息");
        //        originalLockInfo.AssignQuantity  += splitRecord.RemainQuantity;
        //       // originalLockInfo.Status = (int)OutLockStockStatusEnum.出库中;
        //        originalLockInfo.IsSplitted = 0; // æ ‡è®°ä¸ºæœªæ‹†åŒ…
        //        await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
        //        // 5. è¿˜åŽŸåŽŸæ¡ç åº“å­˜è®°å½•
        //        var originalStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
        //            .Where(x => x.Barcode == originalBarcode && x.StockId == splitRecord.StockId)
        //            .FirstAsync();
        //        if (originalStockDetail != null)
        //        {
        //            // å°†æ‹†å‡ºçš„æ•°é‡åŠ å›žåˆ°åŽŸæ¡ç åº“å­˜
        //            originalStockDetail.StockQuantity += splitRecord.RemainQuantity;
        //            originalStockDetail.OutboundQuantity += splitRecord.RemainQuantity;
        //            await _stockInfoDetailService.Db.Updateable(originalStockDetail).ExecuteCommandAsync();
        //        }
        //        // 6. åˆ é™¤æ–°æ¡ç çš„锁定信息
        //        if (newLockInfo != null)
        //        {
        //            await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
        //                .Where(x => x.CurrentBarcode == splitRecord.NewBarcode)
        //                .ExecuteCommandAsync();
        //        }
        //        // 7. åˆ é™¤æ–°æ¡ç çš„库存记录
        //        var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
        //            .Where(x => x.Barcode == splitRecord.NewBarcode)
        //            .FirstAsync();
        //        if (newStockDetail != null)
        //        {
        //            await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
        //                .Where(x => x.Barcode == splitRecord.NewBarcode)
        //                .ExecuteCommandAsync();
        //        }
        //        // 8. æ›´æ–°æ‹†åŒ…记录为已撤销
        //        splitRecord.IsReverted = true;
        //        await Db.Updateable(splitRecord).ExecuteCommandAsync();
        //        _unitOfWorkManage.CommitTran();
        //        return WebResponseContent.Instance.OK($"撤销拆包成功,还原数量:{splitRecord.SplitQty}");
        //    }
        //    catch (Exception ex)
        //    {
        //        _unitOfWorkManage.RollbackTran();
        //        return WebResponseContent.Instance.Error($"撤销拆包失败:{ex.Message}");
        //    }
        //}
        public async Task<WebResponseContent> RevertSplitPackage(string originalBarcode)
        {
            try
            {
                _unitOfWorkManage.BeginTran();
                // æŸ¥æ‰¾æœ€è¿‘的未撤销拆包记录
                var splitPackage = await Db.Queryable<Dt_SplitPackageRecord>()
                // 1. æŸ¥æ‰¾æ‰€æœ‰æœªæ’¤é”€çš„æ‹†åŒ…记录
                var splitRecords = await Db.Queryable<Dt_SplitPackageRecord>()
                        .Where(x => x.OriginalBarcode == originalBarcode && !x.IsReverted)
                        .OrderByDescending(x => x.CreateDate)
                        .FirstAsync();
                        .OrderBy(x => x.SplitTime) // æŒ‰æ—¶é—´æ­£åºï¼Œä»Žæœ€æ—©å¼€å§‹æ’¤é”€
                        .ToListAsync();
                    if (splitPackage == null)
                        return  WebResponseContent.Instance.Error("未找到拆包记录");
                if (splitRecords == null || !splitRecords.Any())
                    return WebResponseContent.Instance.Error("未找到可撤销的拆包记录");
                    // æ£€æŸ¥æ–°æ¡ç æ˜¯å¦å·²æ‹£é€‰
                    var newOutStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                        .Where(x => x.CurrentBarcode == splitPackage.NewBarcode)
                        .FirstAsync();
                // 2. æ£€æŸ¥æ‰€æœ‰æ–°æ¡ç æ˜¯å¦å·²æ‹£é€‰
                var newBarcodes = splitRecords.Select(x => x.NewBarcode).ToList();
                var newLockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(x => newBarcodes.Contains(x.CurrentBarcode))
                    .ToListAsync();
                    if (newOutStockInfo.Status == 1)
                        return  WebResponseContent.Instance.Error("新条码已拣选,无法撤销拆包");
                var pickedBarcodes = newLockInfos.Where(x => x.Status == 2).Select(x => x.CurrentBarcode).ToList();
                if (pickedBarcodes.Any())
                    return WebResponseContent.Instance.Error($"以下条码已拣选,无法撤销:{string.Join(",", pickedBarcodes)}");
                    // è¿˜åŽŸåŽŸå‡ºåº“è¯¦æƒ…æ•°é‡
                    var originalOutStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                        .Where(x => x.CurrentBarcode == originalBarcode)
                        .FirstAsync();
                // 3. èŽ·å–åŽŸæ¡ç ä¿¡æ¯
                var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                    .Where(x => x.CurrentBarcode == originalBarcode)
                    .FirstAsync();
                    originalOutStockInfo.AssignQuantity += splitPackage.SplitQty;
                    await _outStockLockInfoService.Db.Updateable(originalOutStockInfo).ExecuteCommandAsync();
                if (originalLockInfo == null)
                    return WebResponseContent.Instance.Error("未找到原条码锁定信息");
                    // åˆ é™¤æ–°å‡ºåº“详情记录
                    await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
                        .Where(x => x.CurrentBarcode == splitPackage.NewBarcode)
                        .ExecuteCommandAsync();
                var originalStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(x => x.Barcode == originalBarcode && x.StockId == originalLockInfo.StockId)
                    .FirstAsync();
                    // æ ‡è®°æ‹†åŒ…记录为已撤销
                    splitPackage.IsReverted = true;
                    await Db.Updateable(splitPackage).ExecuteCommandAsync();
                // 4. èŽ·å–æ‰€æœ‰æ–°æ¡ç çš„åº“å­˜è®°å½•
                var newStockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                    .Where(x => newBarcodes.Contains(x.Barcode))
                    .ToListAsync();
                // 5. è®¡ç®—总还原数量
                decimal totalRevertQty = newStockDetails.Sum(x => x.StockQuantity);
                // 6. è¿˜åŽŸåŽŸæ¡ç åº“å­˜è®°å½•
                if (originalStockDetail != null)
                {
                    // åŽŸæ¡ç å½“å‰æ•°é‡åŠ ä¸Šæ‰€æœ‰æ–°æ¡ç çš„æ•°é‡
                    originalStockDetail.StockQuantity += totalRevertQty;
                    originalStockDetail.OutboundQuantity += totalRevertQty;
                    await _stockInfoDetailService.Db.Updateable(originalStockDetail).ExecuteCommandAsync();
                }
                // 7. è¿˜åŽŸåŽŸæ¡ç é”å®šä¿¡æ¯
                decimal totalAssignQty = newLockInfos.Sum(x => x.AssignQuantity);
                originalLockInfo.AssignQuantity += totalAssignQty;
                if (originalLockInfo.OrderQuantity < originalLockInfo.AssignQuantity)
                {
                    originalLockInfo.AssignQuantity=originalLockInfo.OrderQuantity;
                }
                originalLockInfo.Status = (int)OutLockStockStatusEnum.出库中;
                originalLockInfo.IsSplitted = 0;
                await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync();
                // 8. åˆ é™¤æ‰€æœ‰æ–°æ¡ç çš„锁定信息
                await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>()
                    .Where(x => newBarcodes.Contains(x.CurrentBarcode))
                    .ExecuteCommandAsync();
                // 9. åˆ é™¤æ‰€æœ‰æ–°æ¡ç çš„库存记录
                await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
                    .Where(x => newBarcodes.Contains(x.Barcode))
                    .ExecuteCommandAsync();
                // 10. æ ‡è®°æ‰€æœ‰æ‹†åŒ…记录为已撤销
                foreach (var record in splitRecords)
                {
                    record.IsReverted = true;
                }
                await Db.Updateable(splitRecords).ExecuteCommandAsync();
                _unitOfWorkManage.CommitTran();
                    return  WebResponseContent.Instance.OK("撤销拆包成功");
                return WebResponseContent.Instance.OK($"撤销拆包成功,共还原{splitRecords.Count}次拆包,总数量:{totalRevertQty}");
            }
            catch (Exception ex)
            {
                return  WebResponseContent.Instance.Error($"撤销拆包失败:{ex.Message}");
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error($"撤销拆包失败:{ex.Message}");
            }
        }
        // èŽ·å–æ‹†åŒ…ä¿¡æ¯
        public async Task< WebResponseContent > GetSplitPackageInfo(string orderNo, string palletCode, string barcode)
        public async Task<WebResponseContent> GetSplitPackageInfo(string orderNo, string palletCode, string barcode)
        {
            var outStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
                .Where(x => x.OrderNo == orderNo &&
                           x.PalletCode == palletCode &&
                           x.CurrentBarcode == barcode &&
                           x.Status == 0)
                           x.Status == 1)
                .FirstAsync();
            if (outStockInfo == null)
                return  WebResponseContent.Instance .Error("未找到对应的出库信息");
                return WebResponseContent.Instance.Error("未找到对应的出库信息");
            var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
                .Where(x => x.Barcode == barcode)
                .FirstAsync();
            //var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
            //    .Where(x => x.Barcode == barcode)
            //    .FirstAsync();
            return  WebResponseContent.Instance .OK("",new
            return WebResponseContent.Instance.OK("", new
            {
                MaterielCode = outStockInfo.MaterielCode,
                RemainQuantity = outStockInfo.RemainQuantity,
                Unit = "个" // æ ¹æ®å®žé™…情况获取单位
                Unit = outStockInfo.Unit
            });
        }
        /// <summary>