| | |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_BasicService; |
| | | using WIDESEA_Common.CommonEnum; |
| | | using WIDESEA_Common.OrderEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.BaseRepository; |
| | | using WIDESEA_Core.BaseServices; |
| | | using WIDESEA_DTO.Outbound; |
| | | using WIDESEA_IAllocateService; |
| | | using WIDESEA_IBasicService; |
| | | using WIDESEA_IOutboundService; |
| | |
| | | using WIDESEA_Model.Models; |
| | | using WIDESEA_Model.Models.Basic; |
| | | using WIDESEA_Model.Models.Outbound; |
| | | using static WIDESEA_OutboundService.OutboundBatchPickingService; |
| | | |
| | | namespace WIDESEA_OutboundService |
| | | { |
| | | public class OutboundBatchPickingService : ServiceBase<Dt_PickingRecord, IRepository<Dt_PickingRecord>> |
| | | public class OutboundBatchPickingService : ServiceBase<Dt_PickingRecord, IRepository<Dt_PickingRecord>>, IOutboundBatchPickingService |
| | | { |
| | | |
| | | |
| | | |
| | | private readonly IUnitOfWorkManage _unitOfWorkManage; |
| | | public IRepository<Dt_PickingRecord> Repository => BaseDal; |
| | | |
| | |
| | | public OutboundBatchPickingService(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) : base(BaseDal) |
| | | IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository) : base(BaseDal) |
| | | { |
| | | _unitOfWorkManage = unitOfWorkManage; |
| | | _stockInfoService = stockInfoService; |
| | |
| | | _invokeMESService = invokeMESService; |
| | | _dailySequenceService = dailySequenceService; |
| | | _allocateService = allocateService; |
| | | _outboundBatchRepository = outboundBatchRepository; |
| | | } |
| | | |
| | | // <summary> |
| | | /// è·åæççéå®ä¿¡æ¯ |
| | | /// </summary> |
| | | public async Task<List<PalletLockInfoDto>> GetPalletLockInfos(string orderNo, string palletCode) |
| | | { |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .Select(x => new |
| | | { |
| | | x.Id, |
| | | x.OrderNo, |
| | | x.BatchNo, |
| | | x.MaterielCode, |
| | | x.CurrentBarcode, |
| | | x.AssignQuantity, |
| | | x.PickedQty, |
| | | x.Status, |
| | | x.LocationCode, |
| | | x.PalletCode |
| | | }).ToListAsync(); |
| | | |
| | | var lockInfoDtos = lockInfos.Select(x => new PalletLockInfoDto |
| | | { |
| | | Id = x.Id, |
| | | OrderNo = x.OrderNo, |
| | | BatchNo = x.BatchNo, |
| | | MaterielCode = x.MaterielCode, |
| | | CurrentBarcode = x.CurrentBarcode, |
| | | AssignQuantity = x.AssignQuantity, |
| | | PickedQty = x.PickedQty, |
| | | Status = x.Status, |
| | | LocationCode = x.LocationCode, |
| | | PalletCode = x.PalletCode, |
| | | CanSplit = (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ && x.AssignQuantity - x.PickedQty > 0), |
| | | CanPick = (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ && x.PickedQty < x.AssignQuantity) |
| | | }).ToList(); |
| | | |
| | | return lockInfoDtos; |
| | | } |
| | | #region æ¥è¯¢æ¹æ³ |
| | | |
| | | /// <summary> |
| | | /// è·åæççå·²æ£éå表 |
| | | /// </summary> |
| | | public async Task<List<PalletPickedInfoDto>> GetPalletPickedList(string orderNo, string palletCode) |
| | | { |
| | | var pickedList = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | !x.IsCancelled) |
| | | .Select(x => new PalletPickedInfoDto |
| | | { |
| | | Id = x.Id, |
| | | OrderNo = x.OrderNo, |
| | | OrderDetailId = x.OrderDetailId, |
| | | PalletCode = x.PalletCode, |
| | | Barcode = x.Barcode, |
| | | MaterielCode = x.MaterielCode, |
| | | PickedQty = x.PickQuantity, |
| | | PickTime = x.PickTime, |
| | | Operator = x.Operator, |
| | | LocationCode = x.LocationCode |
| | | }) |
| | | .ToListAsync(); |
| | | |
| | | return pickedList; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæçç¶æ |
| | | /// </summary> |
| | | public async Task<PalletStatusDto> GetPalletStatus(string orderNo, string palletCode) |
| | | { |
| | | // è·åæççéå®ä¿¡æ¯ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | if (!lockInfos.Any()) |
| | | { |
| | | return new PalletStatusDto |
| | | { |
| | | OrderNo = orderNo, |
| | | PalletCode = palletCode, |
| | | Status = (int)PalletStatusEnum.æ ä»»å¡, |
| | | StatusText = "æ ä»»å¡", |
| | | TotalItems = 0, |
| | | CompletedItems = 0, |
| | | PendingItems = 0 |
| | | }; |
| | | } |
| | | |
| | | var totalItems = lockInfos.Count; |
| | | var completedItems = lockInfos.Count(x => x.Status == (int)OutLockStockStatusEnum.æ£é宿); |
| | | var pendingItems = lockInfos.Count(x => x.Status == (int)OutLockStockStatusEnum.åºåºä¸); |
| | | |
| | | var status = PalletStatusEnum.æ£éä¸; |
| | | if (pendingItems == 0 && completedItems > 0) |
| | | { |
| | | status = PalletStatusEnum.已宿; |
| | | } |
| | | else if (pendingItems > 0 && completedItems == 0) |
| | | { |
| | | status = PalletStatusEnum.æªå¼å§; |
| | | } |
| | | else if (pendingItems > 0 && completedItems > 0) |
| | | { |
| | | status = PalletStatusEnum.æ£éä¸; |
| | | } |
| | | |
| | | return new PalletStatusDto |
| | | { |
| | | OrderNo = orderNo, |
| | | PalletCode = palletCode, |
| | | Status = (int)status, |
| | | StatusText = GetPalletStatusText(status), |
| | | TotalItems = totalItems, |
| | | CompletedItems = completedItems, |
| | | PendingItems = pendingItems |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæå
ä¿¡æ¯ |
| | | /// </summary> |
| | | public async Task<SplitPackageInfoDto> GetSplitPackageInfo(string orderNo, string palletCode, string barcode) |
| | | { |
| | | // æ¥æ¾éå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.CurrentBarcode == barcode |
| | | //&& x.Status == (int)OutLockStockStatusEnum.åºåºä¸ |
| | | ) |
| | | .FirstAsync(); |
| | | |
| | | if (lockInfo == null) |
| | | throw new Exception("æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | |
| | | // 计ç®å©ä½å¯ææ°é |
| | | var remainQuantity = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | |
| | | return new SplitPackageInfoDto |
| | | { |
| | | OrderNo = orderNo, |
| | | PalletCode = palletCode, |
| | | Barcode = barcode, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | RemainQuantity = remainQuantity, |
| | | AssignQuantity = lockInfo.AssignQuantity, |
| | | PickedQty = lockInfo.PickedQty |
| | | }; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region å走空箱é»è¾ |
| | | |
| | | /// <summary> |
| | | /// å走空箱 - æ¸
ç已宿æ£éçæçæ°æ® |
| | | /// </summary> |
| | | public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // éªè¯æçæ¯å¦å¯ä»¥åèµ°ï¼å¿
é¡»å
¨é¨å®ææ£éï¼ |
| | | var validationResult = await ValidateEmptyPalletRemoval(orderNo, palletCode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | var completedLocks = validationResult.Data; |
| | | |
| | | // æ¸
çéå®è®°å½ï¼æ è®°ä¸ºå·²å®æï¼ |
| | | await CleanupCompletedLocks(completedLocks); |
| | | |
| | | // æ´æ°ç¸å
³è®¢åç¶æ |
| | | await UpdateOrderStatusAfterPalletRemoval(orderNo); |
| | | |
| | | // è®°å½æä½åå² |
| | | // await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("å走空箱æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"å走空箱失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"å走空箱失败ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éªè¯ç©ºç®±åèµ°æ¡ä»¶ |
| | | /// </summary> |
| | | private async Task<ValidationResult<List<Dt_OutStockLockInfo>>> ValidateEmptyPalletRemoval(string orderNo, string palletCode) |
| | | { |
| | | // è·åæççææéå®è®°å½ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | if (!lockInfos.Any()) |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Error("该æç没æéå®è®°å½"); |
| | | |
| | | // æ£æ¥æ¯å¦ææªå®æçéå®è®°å½ |
| | | var unfinishedLocks = lockInfos.Where(x => |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || |
| | | x.Status == (int)OutLockStockStatusEnum.ååºä¸).ToList(); |
| | | |
| | | if (unfinishedLocks.Any()) |
| | | { |
| | | var unfinishedCount = unfinishedLocks.Count; |
| | | var unfinishedQty = unfinishedLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Error( |
| | | $"æçè¿æ{unfinishedCount}æ¡æªå®æè®°å½ï¼å©ä½æ°é{unfinishedQty}ï¼ä¸è½å走空箱"); |
| | | } |
| | | |
| | | // è·å已宿çéå®è®°å½ |
| | | var completedLocks = lockInfos.Where(x => |
| | | x.Status == (int)OutLockStockStatusEnum.æ£é宿).ToList(); |
| | | |
| | | if (!completedLocks.Any()) |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Error("该æç没æå·²å®ææ£éçè®°å½"); |
| | | |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Success(completedLocks); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¸
ç已宿çéå®è®°å½ |
| | | /// </summary> |
| | | private async Task CleanupCompletedLocks(List<Dt_OutStockLockInfo> completedLocks) |
| | | { |
| | | foreach (var lockInfo in completedLocks) |
| | | { |
| | | // æ è®°éå®è®°å½ä¸ºå·²åèµ°ï¼å¯ä»¥æ°å¢ç¶ææç´æ¥å é¤ï¼æ ¹æ®ä¸å¡éæ±ï¼ |
| | | // è¿éæä»¬å°å
¶ç¶ææ´æ°ä¸º"å·²åèµ°"ï¼å¹¶è®°å½åèµ°æ¶é´ |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²åèµ°; |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // åæ¶æ¸
ç对åºçåºåè®°å½ç¶æ |
| | | await CleanupStockInfo(lockInfo); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¸
çåºåä¿¡æ¯ |
| | | /// </summary> |
| | | private async Task CleanupStockInfo(Dt_OutStockLockInfo lockInfo) |
| | | { |
| | | 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.åºåºå®æ) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å·²æ¸
ç; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ´æ°è®¢åç¶æ |
| | | /// </summary> |
| | | private async Task UpdateOrderStatusAfterPalletRemoval(string orderNo) |
| | | { |
| | | // æ£æ¥è®¢åæ¯å¦æææçé½å·²å®æ |
| | | var allLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ToListAsync(); |
| | | |
| | | var unfinishedPallets = allLocks |
| | | .GroupBy(x => x.PalletCode) |
| | | .Where(g => g.Any(x => x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || |
| | | x.Status == (int)OutLockStockStatusEnum.ååºä¸)) |
| | | .ToList(); |
| | | |
| | | // å¦ææ²¡ææªå®æçæçï¼æ´æ°è®¢åç¶æä¸ºåºåºå®æ |
| | | if (!unfinishedPallets.Any()) |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => new Dt_OutboundOrder |
| | | { |
| | | OrderStatus = (int)OutOrderStatusEnum.åºåºå®æ, |
| | | }) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è®°å½ç©ºç®±åèµ°åå² |
| | | /// </summary> |
| | | private async Task RecordEmptyPalletRemoval(string orderNo, string palletCode, List<Dt_OutStockLockInfo> completedLocks) |
| | | { |
| | | var removalRecord = new Dt_EmptyPalletRemoval |
| | | { |
| | | OrderNo = orderNo, |
| | | PalletCode = palletCode, |
| | | RemovalTime = DateTime.Now, |
| | | Operator = App.User.UserName, |
| | | CompletedItemsCount = completedLocks.Count, |
| | | TotalPickedQuantity = completedLocks.Sum(x => x.PickedQty) |
| | | }; |
| | | |
| | | await Db.Insertable(removalRecord).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region è¾
婿¹æ³ |
| | | |
| | | private string GetPalletStatusText(PalletStatusEnum status) |
| | | { |
| | | return status switch |
| | | { |
| | | PalletStatusEnum.æªå¼å§ => "æªå¼å§", |
| | | PalletStatusEnum.æ£éä¸ => "æ£éä¸", |
| | | PalletStatusEnum.已宿 => "已宿", |
| | | PalletStatusEnum.æ ä»»å¡ => "æ ä»»å¡", |
| | | _ => "æªç¥" |
| | | }; |
| | | } |
| | | |
| | | #endregion |
| | | #region 忹忣 |
| | | |
| | | /// <summary> |
| | | /// åæ¹åæ£ç¡®è®¤ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> ConfirmBatchPicking(string orderNo, string batchNo, string palletCode, string barcode, decimal actualPickedQty) |
| | | public async Task<WebResponseContent> ConfirmBatchPicking(string orderNo, string palletCode, string barcode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. éªè¯åæ£è¯·æ± |
| | | var validationResult = await ValidateBatchPickingRequest(orderNo, batchNo, palletCode, barcode, actualPickedQty); |
| | | var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | var (lockInfo, orderDetail, stockDetail) = validationResult.Data; |
| | | var (lockInfo, orderDetail, stockDetail, batch) = validationResult.Data; |
| | | |
| | | // 使ç¨éå®ä¿¡æ¯çåé
æ°éä½ä¸ºå®é
忣æ°é |
| | | var actualPickedQty = lockInfo.AssignQuantity; |
| | | |
| | | // 2. æ§è¡åæ£é»è¾ |
| | | var pickingResult = await ExecuteBatchPickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty); |
| | | var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty); |
| | | |
| | | // 3. æ´æ°æ¹æ¬¡å®ææ°é |
| | | await UpdateBatchCompletedQuantity(batchNo, actualPickedQty); |
| | | // 3. æ´æ°æ¹æ¬¡åè®¢åæ°æ® |
| | | await UpdateBatchAndOrderData(batch, orderDetail, actualPickedQty, orderNo); |
| | | |
| | | // 4. æ´æ°è®¢åç¸å
³æ°æ® |
| | | await UpdateOrderRelatedData(orderDetail.Id, actualPickedQty, orderNo); |
| | | |
| | | // 5. è®°å½æ£éåå² |
| | | await RecordPickingHistory(pickingResult, orderNo, palletCode, batchNo); |
| | | // 4. è®°å½æ£éåå² |
| | | await RecordPickingHistory(pickingResult, orderNo, palletCode); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("忹忣æå"); |
| | | return WebResponseContent.Instance.OK("忣æå", new |
| | | { |
| | | PickedQuantity = actualPickedQty, |
| | | Barcode = barcode, |
| | | MaterialCode = lockInfo.MaterielCode |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¹åæ£å¤±è´¥ - OrderNo: {orderNo}, BatchNo: {batchNo}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¹åæ£å¤±è´¥ï¼{ex.Message}"); |
| | | _logger.LogError($"åæ£å¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ£å¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 忶忣 |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // æ¥æ¾åæ£è®°å½ |
| | | var pickingRecord = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Barcode == barcode && |
| | | !x.IsCancelled) |
| | | .OrderByDescending(x => x.PickTime) |
| | | .FirstAsync(); |
| | | |
| | | if (pickingRecord == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°åæ£è®°å½"); |
| | | |
| | | // æ¢å¤éå®ä¿¡æ¯ååºå |
| | | await RevertPickingData(pickingRecord); |
| | | |
| | | //æ´æ°æ¹æ¬¡åè®¢åæ°æ® |
| | | await RevertBatchAndOrderData(pickingRecord); |
| | | |
| | | // æ è®°åæ£è®°å½ä¸ºå·²åæ¶ |
| | | pickingRecord.IsCancelled = true; |
| | | pickingRecord.CancelTime = DateTime.Now; |
| | | pickingRecord.CancelOperator = App.User.UserName; |
| | | await Db.Updateable(pickingRecord).ExecuteCommandAsync(); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("忶忣æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¶åæ£å¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¶åæ£å¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>> ValidateBatchPickingRequest( |
| | | string orderNo, string batchNo, string palletCode, string barcode, decimal actualPickedQty) |
| | | #endregion |
| | | |
| | | #region æå¨æå
|
| | | |
| | | /// <summary> |
| | | /// æå¨æå
|
| | | /// </summary> |
| | | public async Task<WebResponseContent> ManualSplitPackage(string orderNo, string palletCode, string originalBarcode, decimal splitQuantity) |
| | | { |
| | | // æ¥æ¾æ¹æ¬¡éå®ä¿¡æ¯ |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // éªè¯æå
è¯·æ± |
| | | var validationResult = await ValidateSplitRequest(orderNo, palletCode, originalBarcode, splitQuantity); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | var (lockInfo, stockDetail) = validationResult.Data; |
| | | |
| | | // . æ§è¡æå
é»è¾ |
| | | var splitResult = await ExecuteSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("æå¨æå
æå", new |
| | | { |
| | | NewBarcode = splitResult.NewBarcode, |
| | | OriginalBarcode = originalBarcode, |
| | | SplitQuantity = splitQuantity |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"æå¨æå
失败 - OrderNo: {orderNo}, Barcode: {originalBarcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"æå¨æå
失败ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region åæ¶æå
|
| | | |
| | | #region åæ¶æå
- ä¿®å¤çæ¬ |
| | | |
| | | /// <summary> |
| | | /// åæ¶æå
- æ¯æå¤æ¬¡æå
çæ
åµ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CancelSplitPackage(string orderNo, string palletCode, string newBarcode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. æ¥æ¾æå
è®°å½å¹¶éªè¯ |
| | | var validationResult = await ValidateCancelSplitRequest(orderNo, palletCode, newBarcode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | var (splitRecord, newLockInfo, newStockDetail) = validationResult.Data; |
| | | |
| | | // 2. æ¥æ¾åå§éå®ä¿¡æ¯ |
| | | var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId); |
| | | |
| | | // 3. æ£æ¥è¯¥æ¡ç æ¯å¦è¢«å次æå
|
| | | var childSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.OriginalBarcode == newBarcode && !x.IsReverted) |
| | | .ToListAsync(); |
| | | |
| | | if (childSplitRecords.Any()) |
| | | { |
| | | return WebResponseContent.Instance.Error("该æ¡ç å·²è¢«åæ¬¡æå
ï¼è¯·å
åæ¶åç»çæå
æä½"); |
| | | } |
| | | |
| | | // 4. æ§è¡åæ¶æå
é»è¾ |
| | | await ExecuteCancelSplitLogic(splitRecord, originalLockInfo, newLockInfo, newStockDetail); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("åæ¶æå
æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¶æå
失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {newBarcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¶æå
失败ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ§è¡åæ¶æå
é»è¾ - ä¿®å¤çæ¬ |
| | | /// </summary> |
| | | private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord, |
| | | Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo, |
| | | Dt_StockInfoDetail newStockDetail) |
| | | { |
| | | // 1. æ¢å¤åéå®ä¿¡æ¯ |
| | | // 注æï¼è¿ééè¦ç´¯å ï¼è䏿¯ç®åçèµå¼ï¼å 为å¯è½æå¤æ¬¡æå
|
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | originalLockInfo.OrderQuantity += splitRecord.SplitQty; |
| | | |
| | | // 妿åéå®ä¿¡æ¯çç¶ææ¯æ£é宿ï¼éè¦éæ°è®¾ç½®ä¸ºåºåºä¸ |
| | | if (originalLockInfo.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | { |
| | | originalLockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | } |
| | | |
| | | 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); |
| | | |
| | | originalStock.StockQuantity += splitRecord.SplitQty; |
| | | |
| | | // 妿ååºåç¶ææ¯åºåºå®æï¼éè¦éæ°è®¾ç½®ä¸ºåºåºéå® |
| | | if (originalStock.Status == (int)StockStatusEmun.åºåºå®æ) |
| | | { |
| | | originalStock.Status = (int)StockStatusEmun.åºåºéå®; |
| | | } |
| | | |
| | | 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) |
| | | { |
| | | // æ¥æ¾æå
è®°å½ |
| | | var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.NewBarcode == newBarcode && |
| | | x.OrderNo == orderNo && |
| | | !x.IsReverted) |
| | | .FirstAsync(); |
| | | |
| | | if (splitRecord == null) |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°æå
è®°å½"); |
| | | |
| | | // æ¥æ¾æ°éå®ä¿¡æ¯ |
| | | var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == newBarcode && |
| | | x.PalletCode == palletCode && |
| | | x.OrderNo == orderNo) |
| | | .FirstAsync(); |
| | | |
| | | if (newLockInfo == null) |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°æ°éå®ä¿¡æ¯"); |
| | | |
| | | // æ£æ¥æ°æ¡ç æ¯å¦å·²è¢«åæ£ |
| | | var pickingRecord = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == newBarcode && !x.IsCancelled) |
| | | .FirstAsync(); |
| | | |
| | | if (pickingRecord != null) |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("该æ¡ç å·²è¢«åæ£ï¼æ æ³åæ¶æå
"); |
| | | |
| | | // æ£æ¥æ°æ¡ç æ¯å¦è¢«å次æå
|
| | | var childSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.OriginalBarcode == newBarcode && !x.IsReverted) |
| | | .ToListAsync(); |
| | | |
| | | if (childSplitRecords.Any()) |
| | | { |
| | | var childBarcodes = string.Join(", ", childSplitRecords.Select(x => x.NewBarcode)); |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error( |
| | | $"该æ¡ç å·²è¢«åæ¬¡æå
ï¼çæçæ°æ¡ç ï¼{childBarcodes}ï¼è¯·å
åæ¶åç»æå
"); |
| | | } |
| | | |
| | | var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == newBarcode); |
| | | |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((splitRecord, newLockInfo, newStockDetail)); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region æ¹éåæ¶æå
é¾ |
| | | |
| | | /// <summary> |
| | | /// æ¹éåæ¶æå
é¾ - åæ¶æä¸ªæ¡ç åå
¶ææåç»æå
|
| | | /// </summary> |
| | | public async Task<WebResponseContent> CancelSplitPackageChain(string orderNo, string palletCode, string startBarcode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. æ¥æ¾ææç¸å
³çæå
è®°å½ï¼å½¢ææå
é¾ï¼ |
| | | var splitChain = await GetSplitPackageChain(orderNo, startBarcode); |
| | | |
| | | if (!splitChain.Any()) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°æå
è®°å½"); |
| | | |
| | | // 2. ææå
顺åºååºåæ¶ï¼ä»ææ°çå¼å§åæ¶ï¼ |
| | | var reversedChain = splitChain.OrderByDescending(x => x.SplitTime).ToList(); |
| | | |
| | | foreach (var splitRecord in reversedChain) |
| | | { |
| | | await CancelSingleSplitPackage(splitRecord, palletCode); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK($"æååæ¶æå
é¾ï¼å
±{reversedChain.Count}次æå
æä½"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¶æå
é¾å¤±è´¥ - OrderNo: {orderNo}, StartBarcode: {startBarcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¶æå
é¾å¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæå
é¾ - æ¥æ¾æä¸ªæ¡ç çæææå
è®°å½ï¼å
æ¬åç»æå
ï¼ |
| | | /// </summary> |
| | | public async Task<List<Dt_SplitPackageRecord>> GetSplitPackageChain(string orderNo, string startBarcode) |
| | | { |
| | | var allSplitRecords = new List<Dt_SplitPackageRecord>(); |
| | | var visitedBarcodes = new HashSet<string>(); // 鲿¢å¾ªç¯å¼ç¨ |
| | | |
| | | // 使ç¨éåè¿è¡å¹¿åº¦ä¼å
æç´¢ |
| | | var queue = new Queue<string>(); |
| | | queue.Enqueue(startBarcode); |
| | | visitedBarcodes.Add(startBarcode); |
| | | |
| | | while (queue.Count > 0) |
| | | { |
| | | var currentBarcode = queue.Dequeue(); |
| | | |
| | | // æ¥æ¾ä»¥å½åæ¡ç ä¸ºåæ¡ç çæææå
è®°å½ |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.OriginalBarcode == currentBarcode && |
| | | x.OrderNo == orderNo && |
| | | !x.IsReverted) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var record in splitRecords) |
| | | { |
| | | // é¿å
éå¤å¤ç |
| | | if (!visitedBarcodes.Contains(record.NewBarcode)) |
| | | { |
| | | allSplitRecords.Add(record); |
| | | queue.Enqueue(record.NewBarcode); |
| | | visitedBarcodes.Add(record.NewBarcode); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return allSplitRecords; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åæ¶å个æå
è®°å½ |
| | | /// </summary> |
| | | private async Task CancelSingleSplitPackage(Dt_SplitPackageRecord splitRecord, string palletCode) |
| | | { |
| | | // æ¥æ¾ç¸å
³æ°æ® |
| | | var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == splitRecord.NewBarcode && |
| | | x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | |
| | | var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.NewBarcode); |
| | | |
| | | var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId); |
| | | |
| | | // æ§è¡åæ¶é»è¾ |
| | | await ExecuteCancelSplitLogic(splitRecord, originalLockInfo, newLockInfo, newStockDetail); |
| | | } |
| | | #endregion |
| | | |
| | | #region æå
ä¿¡æ¯æ¥è¯¢å¢å¼º |
| | | |
| | | /// <summary> |
| | | /// è·åæå
é¾ä¿¡æ¯ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> GetSplitPackageChainInfo(string orderNo, string barcode) |
| | | { |
| | | try |
| | | { |
| | | var splitChain = await GetSplitPackageChain(orderNo, barcode); |
| | | |
| | | var chainInfo = new SplitPackageChainInfoDto |
| | | { |
| | | OriginalBarcode = barcode, |
| | | TotalSplitTimes = splitChain.Count, |
| | | SplitChain = splitChain.Select(x => new SplitChainItemDto |
| | | { |
| | | SplitTime = x.SplitTime, |
| | | OriginalBarcode = x.OriginalBarcode, |
| | | NewBarcode = x.NewBarcode, |
| | | SplitQuantity = x.SplitQty, |
| | | Operator = x.Operator, |
| | | IsReverted = x.IsReverted |
| | | }).ToList() |
| | | }; |
| | | |
| | | return WebResponseContent.Instance.OK("è·åæå", chainInfo); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"è·åæå
é¾ä¿¡æ¯å¤±è´¥ - OrderNo: {orderNo}, Barcode: {barcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error("è·åæå
é¾ä¿¡æ¯å¤±è´¥"); |
| | | } |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// æ¥æ¾æ ¹æ¡ç |
| | | /// </summary> |
| | | public async Task<string> FindRootBarcode(string orderNo, string startBarcode) |
| | | { |
| | | var currentBarcode = startBarcode; |
| | | var visited = new HashSet<string>(); |
| | | |
| | | while (!string.IsNullOrEmpty(currentBarcode) && !visited.Contains(currentBarcode)) |
| | | { |
| | | visited.Add(currentBarcode); |
| | | |
| | | // æ¥æ¾å½åæ¡ç æ¯å¦æ¯ç±å
¶ä»æ¡ç æå
èæ¥ |
| | | var parentRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.NewBarcode == currentBarcode && |
| | | x.OrderNo == orderNo && |
| | | !x.IsReverted) |
| | | .FirstAsync(); |
| | | |
| | | if (parentRecord == null) |
| | | { |
| | | // 没æç¶çº§æå
è®°å½ï¼è¯´æè¿æ¯æ ¹æ¡ç |
| | | return currentBarcode; |
| | | } |
| | | |
| | | currentBarcode = parentRecord.OriginalBarcode; |
| | | } |
| | | |
| | | // 妿åºç°å¾ªç¯å¼ç¨ï¼è¿åèµ·å§æ¡ç |
| | | return startBarcode; |
| | | } |
| | | #endregion |
| | | |
| | | #region æ´æ°æ¹æ¬¡ç¶ææ£æ¥ |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥å¹¶æ´æ°æ¹æ¬¡ç¶æ |
| | | /// </summary> |
| | | private async Task CheckAndUpdateBatchStatus(string batchNo) |
| | | { |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == batchNo); |
| | | |
| | | if (batch != null) |
| | | { |
| | | // éæ°è®¡ç®æ¹æ¬¡å®ææ°é |
| | | var batchLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.BatchNo == batchNo) |
| | | .ToListAsync(); |
| | | |
| | | var completedQuantity = batchLocks.Where(x => x.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | .Sum(x => x.PickedQty); |
| | | |
| | | batch.CompletedQuantity = completedQuantity; |
| | | |
| | | // æ´æ°æ¹æ¬¡ç¶æ |
| | | if (batch.CompletedQuantity >= batch.BatchQuantity) |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.已宿; |
| | | } |
| | | else if (batch.CompletedQuantity > 0) |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.æ§è¡ä¸; |
| | | } |
| | | else |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.åé
ä¸; |
| | | } |
| | | |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | |
| | | #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 åæ¹ååº |
| | | |
| | | /// <summary> |
| | | /// åæ¹ååº - éæ¾æªæ£éçåºå |
| | | /// </summary> |
| | | public async Task<WebResponseContent> BatchReturnStock(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // æ¥æ¾æç䏿ªå®æçéå®è®°å½ |
| | | var unfinishedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .ToListAsync(); |
| | | |
| | | if (!unfinishedLocks.Any()) |
| | | return WebResponseContent.Instance.Error("该æçæ²¡ææªå®æçéå®è®°å½"); |
| | | |
| | | // ææ¹æ¬¡åç»å¤ç |
| | | var batchGroups = unfinishedLocks.GroupBy(x => x.BatchNo); |
| | | |
| | | foreach (var batchGroup in batchGroups) |
| | | { |
| | | var batchNo = batchGroup.Key; |
| | | var batchLocks = batchGroup.ToList(); |
| | | |
| | | // éæ¾åºååéå®è®°å½ |
| | | foreach (var lockInfo in batchLocks) |
| | | { |
| | | await ReleaseLockAndStock(lockInfo); |
| | | } |
| | | |
| | | // æ´æ°æ¹æ¬¡ç¶æ |
| | | await UpdateBatchStatusForReturn(batchNo, batchLocks); |
| | | |
| | | // æ´æ°è®¢åæç»çå·²åé
æ°é |
| | | await UpdateOrderDetailAfterReturn(batchLocks); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("åæ¹ååºæå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¹ååºå¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¹ååºå¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region éªè¯æ¹æ³ |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>> ValidatePickingRequest( |
| | | string orderNo, string palletCode, string barcode) |
| | | { |
| | | // æ¥æ¾éå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.BatchNo == batchNo && |
| | | x.PalletCode == palletCode && |
| | | x.CurrentBarcode == barcode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .FirstAsync(); |
| | | |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error("æªæ¾å°ææçæ¹æ¬¡éå®ä¿¡æ¯"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | |
| | | if (actualPickedQty <= 0 || actualPickedQty > lockInfo.AssignQuantity - lockInfo.PickedQty) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error("忣æ°éæ æ"); |
| | | // æ£æ¥æ¯å¦å·²ç»åæ£å®æ |
| | | if (lockInfo.PickedQty >= lockInfo.AssignQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("该æ¡ç 已忣宿"); |
| | | |
| | | // è·å订åæç»ååºåæç» |
| | | // è·åå
³èæ°æ® |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == barcode && x.StockId == lockInfo.StockId); |
| | | |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Success((lockInfo, orderDetail, stockDetail)); |
| | | // éªè¯åºåæ°é |
| | | if (stockDetail.StockQuantity < lockInfo.AssignQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( |
| | | $"åºåæ°éä¸è¶³ï¼éè¦ï¼{lockInfo.AssignQuantity}ï¼å®é
ï¼{stockDetail.StockQuantity}"); |
| | | |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo); |
| | | |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Success((lockInfo, orderDetail, stockDetail, batch)); |
| | | } |
| | | |
| | | private async Task<PickingResult> ExecuteBatchPickingLogic( |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest( |
| | | string orderNo, string palletCode, string originalBarcode, decimal splitQuantity) |
| | | { |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.CurrentBarcode == originalBarcode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .FirstAsync(); |
| | | |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail.StockQuantity < splitQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æå
æ°éä¸è½å¤§äºåºåæ°é"); |
| | | |
| | | if (lockInfo.AssignQuantity - lockInfo.PickedQty < splitQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æå
æ°éä¸è½å¤§äºæªæ£éæ°é"); |
| | | |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail)); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region æ ¸å¿é»è¾æ¹æ³ |
| | | |
| | | private async Task<PickingResult> ExecutePickingLogic( |
| | | Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, |
| | | Dt_StockInfoDetail stockDetail, decimal actualPickedQty) |
| | | { |
| | |
| | | }; |
| | | } |
| | | |
| | | private async Task UpdateBatchCompletedQuantity(string batchNo, decimal pickedQty) |
| | | private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord) |
| | | { |
| | | await _outboundBatchRepository.Db.Updateable<Dt_OutboundBatch>() |
| | | .SetColumns(x => x.CompletedQuantity == x.CompletedQuantity + pickedQty) |
| | | .Where(x => x.BatchNo == batchNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ£æ¥æ¹æ¬¡æ¯å¦å®æ |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == batchNo); |
| | | |
| | | if (batch.CompletedQuantity >= batch.BatchQuantity) |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.已宿; |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region æå¨æå
|
| | | |
| | | /// <summary> |
| | | /// æå¨æå
|
| | | /// </summary> |
| | | public async Task<WebResponseContent> ManualSplitPackage(string orderNo, string batchNo, string originalBarcode, decimal splitQuantity) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. éªè¯æå
è¯·æ± |
| | | var validationResult = await ValidateManualSplitRequest(orderNo, batchNo, originalBarcode, splitQuantity); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | var (lockInfo, stockDetail) = validationResult.Data; |
| | | |
| | | // 2. æ§è¡æå
é»è¾ |
| | | var splitResult = await ExecuteManualSplit(lockInfo, stockDetail, splitQuantity, batchNo); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("æå¨æå
æå", new { NewBarcode = splitResult.NewBarcode }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"æå¨æå
失败 - OrderNo: {orderNo}, BatchNo: {batchNo}, Barcode: {originalBarcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"æå¨æå
失败ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateManualSplitRequest( |
| | | string orderNo, string batchNo, string originalBarcode, decimal splitQuantity) |
| | | { |
| | | // æ¢å¤éå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.BatchNo == batchNo && |
| | | x.CurrentBarcode == originalBarcode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .FirstAsync(); |
| | | .FirstAsync(x => x.Id == pickingRecord.OutStockLockId); |
| | | |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | lockInfo.PickedQty -= pickingRecord.PickQuantity; |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤åºå |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId); |
| | | .FirstAsync(x => x.Barcode == pickingRecord.Barcode); |
| | | |
| | | if (stockDetail.StockQuantity < splitQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æå
æ°éä¸è½å¤§äºåºåæ°é"); |
| | | stockDetail.StockQuantity += pickingRecord.PickQuantity; |
| | | stockDetail.OutboundQuantity -= pickingRecord.PickQuantity; |
| | | stockDetail.Status = (int)StockStatusEmun.åºåºéå®; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | if (lockInfo.AssignQuantity - lockInfo.PickedQty < splitQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æå
æ°éä¸è½å¤§äºæªæ£éæ°é"); |
| | | |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail)); |
| | | return new RevertPickingResult |
| | | { |
| | | LockInfo = lockInfo, |
| | | StockDetail = stockDetail |
| | | }; |
| | | } |
| | | |
| | | private async Task<SplitResultDto> ExecuteManualSplit(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string batchNo) |
| | | private async Task<SplitResultDto> ExecuteSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string palletCode) |
| | | { |
| | | // çææ°æ¡ç |
| | | string newBarcode = await GenerateNewBarcode(); |
| | |
| | | Barcode = newBarcode, |
| | | Status = (int)StockStatusEmun.åºåºéå®, |
| | | SupplyCode = stockDetail.SupplyCode, |
| | | Unit = stockDetail.Unit |
| | | Unit = stockDetail.Unit, |
| | | BarcodeQty=stockDetail.BarcodeQty, |
| | | BarcodeUnit=stockDetail.BarcodeUnit, |
| | | BusinessType=stockDetail.BusinessType, |
| | | InboundOrderRowNo=stockDetail.InboundOrderRowNo, |
| | | |
| | | |
| | | }; |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | |
| | |
| | | stockDetail.StockQuantity -= splitQuantity; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | // å建æ°éå®ä¿¡æ¯ |
| | | |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | OrderNo = lockInfo.OrderNo, |
| | | OrderDetailId = lockInfo.OrderDetailId, |
| | | BatchNo = batchNo, |
| | | BatchNo = lockInfo.BatchNo, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | MaterielName = lockInfo.MaterielName, |
| | | StockId = lockInfo.StockId, |
| | | OrderQuantity = splitQuantity, |
| | | //OriginalQuantity = quantity, |
| | | AssignQuantity = splitQuantity, |
| | | 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, |
| | | Operator = App.User.UserName, |
| | | // OriginalLockQuantity = quantity, |
| | | IsSplitted = 1, |
| | | ParentLockId = lockInfo.Id, |
| | | Operator = App.User.UserName, |
| | | FactoryArea = lockInfo.FactoryArea, |
| | | lineNo = lockInfo.lineNo, |
| | | WarehouseCode = lockInfo.WarehouseCode, |
| | | BarcodeQty = lockInfo.BarcodeQty, |
| | | BarcodeUnit = lockInfo.BarcodeUnit, |
| | | |
| | | }; |
| | | |
| | | await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); |
| | | |
| | | // æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity -= splitQuantity; |
| | | lockInfo.OrderQuantity -= splitQuantity; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // è®°å½æå
åå² |
| | |
| | | return new SplitResultDto { NewBarcode = newBarcode }; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region åæ¶æå
|
| | | |
| | | /// <summary> |
| | | /// åæ¶æå
|
| | | /// </summary> |
| | | public async Task<WebResponseContent> CancelSplitPackage(string orderNo, string batchNo, string newBarcode) |
| | | private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord, Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | // æ¢å¤ååºå |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); |
| | | |
| | | // æ¥æ¾æå
è®°å½åæ°éå®ä¿¡æ¯ |
| | | var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.NewBarcode == newBarcode && x.OrderNo == orderNo && !x.IsReverted) |
| | | .FirstAsync(); |
| | | originalStock.StockQuantity += splitRecord.SplitQty; |
| | | await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); |
| | | |
| | | if (splitRecord == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°æå
è®°å½"); |
| | | // æ¢å¤åéå®ä¿¡æ¯ |
| | | var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId); |
| | | |
| | | var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == newBarcode && x.BatchNo == batchNo) |
| | | .FirstAsync(); |
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | originalLockInfo.OrderQuantity += splitRecord.SplitQty; |
| | | await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); |
| | | |
| | | if (newLockInfo == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°æ°éå®ä¿¡æ¯"); |
| | | // å 餿°åºåæç» |
| | | await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == newLockInfo.CurrentBarcode) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤ååºå |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); |
| | | // å 餿°éå®ä¿¡æ¯ |
| | | await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.Id == newLockInfo.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | originalStock.StockQuantity += splitRecord.SplitQty; |
| | | await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤åéå®ä¿¡æ¯ |
| | | var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId); |
| | | |
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); |
| | | |
| | | // å 餿°åºåæç» |
| | | await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == newBarcode) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // å 餿°éå®ä¿¡æ¯ |
| | | await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.Id == newLockInfo.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ è®°æå
è®°å½ä¸ºå·²æ¤é |
| | | splitRecord.IsReverted = true; |
| | | splitRecord.RevertTime = DateTime.Now; |
| | | splitRecord.Operator = App.User.UserName; |
| | | await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("åæ¶æå
æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¶æå
失败 - OrderNo: {orderNo}, BatchNo: {batchNo}, Barcode: {newBarcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¶æå
失败ï¼{ex.Message}"); |
| | | } |
| | | // æ è®°æå
è®°å½ä¸ºå·²æ¤é |
| | | splitRecord.IsReverted = true; |
| | | splitRecord.RevertTime = DateTime.Now; |
| | | splitRecord.RevertOperator = App.User.UserName; |
| | | await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region åæ¹ååº |
| | | #region æ°æ®æ´æ°æ¹æ³ |
| | | |
| | | /// <summary> |
| | | /// åæ¹ååº - éæ¾æªæ£éçåºå |
| | | /// </summary> |
| | | public async Task<WebResponseContent> BatchReturnStock(string orderNo, string batchNo) |
| | | private async Task UpdateBatchAndOrderData(Dt_OutboundBatch batch, Dt_OutboundOrderDetail orderDetail, decimal pickedQty, string orderNo) |
| | | { |
| | | try |
| | | // æ´æ°æ¹æ¬¡å®ææ°é |
| | | batch.CompletedQuantity += pickedQty; |
| | | if (batch.CompletedQuantity >= batch.BatchQuantity) |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. æ¥æ¾æ¹æ¬¡æªå®æçéå®è®°å½ |
| | | var unfinishedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.BatchNo == batchNo && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .ToListAsync(); |
| | | |
| | | if (!unfinishedLocks.Any()) |
| | | return WebResponseContent.Instance.Error("è¯¥æ¹æ¬¡æ²¡ææªå®æçéå®è®°å½"); |
| | | |
| | | // 2. éæ¾åºååéå®è®°å½ |
| | | foreach (var lockInfo in unfinishedLocks) |
| | | { |
| | | await ReleaseLockAndStock(lockInfo); |
| | | } |
| | | |
| | | // 3. æ´æ°æ¹æ¬¡ç¶æ |
| | | await UpdateBatchStatusForReturn(batchNo); |
| | | |
| | | // 4. æ´æ°è®¢åæç»çå·²åé
æ°é |
| | | await UpdateOrderDetailAfterReturn(unfinishedLocks); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("åæ¹ååºæå"); |
| | | batch.BatchStatus = (int)BatchStatusEnum.已宿; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¹ååºå¤±è´¥ - OrderNo: {orderNo}, BatchNo: {batchNo}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¹ååºå¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | orderDetail.OverOutQuantity += pickedQty; |
| | | orderDetail.AllocatedQuantity -= pickedQty; |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | |
| | | // æ£æ¥è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(orderNo); |
| | | } |
| | | |
| | | private async Task RevertBatchAndOrderData(Dt_PickingRecord pickingRecord) |
| | | { |
| | | // æ¢å¤æ¹æ¬¡å®ææ°é |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == pickingRecord.BatchNo); |
| | | |
| | | batch.CompletedQuantity -= pickingRecord.PickQuantity; |
| | | batch.BatchStatus = (int)BatchStatusEnum.æ§è¡ä¸; |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤è®¢åæç» |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == pickingRecord.OrderDetailId); |
| | | |
| | | orderDetail.OverOutQuantity -= pickingRecord.PickQuantity; |
| | | orderDetail.AllocatedQuantity += pickingRecord.PickQuantity; |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | |
| | | // éæ°æ£æ¥è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(pickingRecord.OrderNo); |
| | | } |
| | | |
| | | private async Task ReleaseLockAndStock(Dt_OutStockLockInfo lockInfo) |
| | |
| | | } |
| | | |
| | | // æ´æ°éå®è®°å½ç¶æä¸ºååº |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.ååºä¸; |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²ååº; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | private async Task UpdateBatchStatusForReturn(string batchNo) |
| | | private async Task UpdateBatchStatusForReturn(string batchNo, List<Dt_OutStockLockInfo> returnedLocks) |
| | | { |
| | | await _outboundBatchRepository.Db.Updateable<Dt_OutboundBatch>() |
| | | .SetColumns(x => new Dt_OutboundBatch |
| | | { |
| | | BatchStatus = (int)BatchStatusEnum.å·²ååº, |
| | | Operator = App.User.UserName |
| | | }) |
| | | .Where(x => x.BatchNo == batchNo) |
| | | .ExecuteCommandAsync(); |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == batchNo); |
| | | |
| | | // 计ç®ååºæ°é |
| | | var returnedQty = returnedLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | batch.CompletedQuantity -= returnedQty; |
| | | |
| | | if (batch.CompletedQuantity <= 0) |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.å·²ååº; |
| | | } |
| | | else |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.æ§è¡ä¸; |
| | | } |
| | | |
| | | batch.Operator = App.User.UserName; |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | private async Task UpdateOrderDetailAfterReturn(List<Dt_OutStockLockInfo> returnedLocks) |
| | |
| | | private async Task<string> GenerateNewBarcode() |
| | | { |
| | | var seq = await _dailySequenceService.GetNextSequenceAsync(); |
| | | return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0'); |
| | | return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString().PadLeft(5, '0'); |
| | | } |
| | | |
| | | private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail,decimal splitQty, string newBarcode) |
| | | private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQty, string newBarcode) |
| | | { |
| | | var splitHistory = new Dt_SplitPackageRecord |
| | | { |
| | |
| | | await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | private async Task RecordPickingHistory(PickingResult result, string orderNo, string palletCode, string batchNo) |
| | | private async Task RecordPickingHistory(PickingResult result, string orderNo, string palletCode) |
| | | { |
| | | var pickingRecord = new Dt_PickingRecord |
| | | { |
| | | OrderNo = orderNo, |
| | | // BatchNo = batchNo, |
| | | // BatchNo = result.FinalLockInfo.BatchNo, |
| | | OrderDetailId = result.FinalLockInfo.OrderDetailId, |
| | | PalletCode = palletCode, |
| | | Barcode = result.FinalLockInfo.CurrentBarcode, |
| | |
| | | PickQuantity = result.ActualPickedQty, |
| | | PickTime = DateTime.Now, |
| | | Operator = App.User.UserName, |
| | | OutStockLockId = result.FinalLockInfo.Id |
| | | OutStockLockId = result.FinalLockInfo.Id, |
| | | // IsCancelled = false |
| | | }; |
| | | |
| | | await Db.Insertable(pickingRecord).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | private async Task UpdateOrderRelatedData(int orderDetailId, decimal pickedQty, string orderNo) |
| | | { |
| | | // æ´æ°è®¢åæç»çå·²åºåºæ°é |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(x => new Dt_OutboundOrderDetail |
| | | { |
| | | OverOutQuantity = x.OverOutQuantity + pickedQty, |
| | | AllocatedQuantity = x.AllocatedQuantity - pickedQty |
| | | }) |
| | | .Where(x => x.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ£æ¥è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(orderNo); |
| | | } |
| | | |
| | | private async Task CheckAndUpdateOrderStatus(string orderNo) |
| | | { |
| | | var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id) |
| | | .Where((o, item) => item.OrderNo == orderNo) |
| | | .Select((o, item) => o) |
| | | .ToListAsync(); |
| | | |
| | | |
| | | .LeftJoin<Dt_OutboundOrder>((detail, order) => detail.OrderId == order.Id) |
| | | .Where((detail, order) => order.OrderNo == orderNo) |
| | | .Select((detail, order) => detail) |
| | | .ToListAsync(); |
| | | |
| | | bool allCompleted = orderDetails.All(x => x.OverOutQuantity >= x.NeedOutQuantity); |
| | | |
| | | if (allCompleted) |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => new Dt_OutboundOrder { OrderStatus = (int)OutOrderStatusEnum.åºåºå®æ }) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | var orderStatus = allCompleted ? (int)OutOrderStatusEnum.åºåºå®æ : (int)OutOrderStatusEnum.åºåºä¸; |
| | | |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == orderStatus) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region DTOç±» |
| | | |
| | | public class PickingResult |
| | | { |
| | | public Dt_OutStockLockInfo FinalLockInfo { get; set; } |
| | | public decimal ActualPickedQty { get; set; } |
| | | } |
| | | |
| | | public class RevertPickingResult |
| | | { |
| | | public Dt_OutStockLockInfo LockInfo { get; set; } |
| | | public Dt_StockInfoDetail StockDetail { get; set; } |
| | | } |
| | | |
| | | public class SplitResultDto |
| | | { |
| | | public string NewBarcode { get; set; } |
| | | } |
| | | |
| | | public class ValidationResult<T> |
| | | { |
| | | public bool IsValid { get; set; } |
| | | public string ErrorMessage { get; set; } |
| | | public T Data { get; set; } |
| | | |
| | | public static ValidationResult<T> Success(T data) => new ValidationResult<T> { IsValid = true, Data = data }; |
| | | public static ValidationResult<T> Error(string message) => new ValidationResult<T> { IsValid = false, ErrorMessage = message }; |
| | | } |
| | | |
| | | #endregion |
| | | } |
| | | |
| | | |
| | | |
| | | // æ¯æç±» |
| | | public class SplitResultDto |
| | | { |