| | |
| | | using Microsoft.Extensions.Logging; |
| | | using SqlSugar; |
| | | using SqlSugar.Extensions; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | |
| | | await UpdateOrderStatusAfterPalletRemoval(orderNo); |
| | | |
| | | // è®°å½æä½åå² |
| | | await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks); |
| | | // await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. éªè¯åæ£è¯·æ± |
| | | // éªè¯åæ£è¯·æ± |
| | | var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | var (lockInfo, orderDetail, stockDetail, batch) = validationResult.Data; |
| | | |
| | | // 使ç¨éå®ä¿¡æ¯çåé
æ°éä½ä¸ºå®é
忣æ°é |
| | | var actualPickedQty = lockInfo.AssignQuantity; |
| | | // æ£æ¥æ¯å¦éè¦èªå¨æå
|
| | | var autoSplitResult = await CheckAndAutoSplitIfNeeded(lockInfo, stockDetail, palletCode); |
| | | if (autoSplitResult != null) |
| | | { |
| | | // 妿æ§è¡äºèªå¨æå
ï¼éæ°è·åææ°çéå®ä¿¡æ¯ååºåä¿¡æ¯ |
| | | var refreshedValidation = await ValidatePickingRequest(orderNo, palletCode, barcode); |
| | | if (!refreshedValidation.IsValid) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error(refreshedValidation.ErrorMessage); |
| | | } |
| | | |
| | | // 2. æ§è¡åæ£é»è¾ |
| | | (lockInfo, orderDetail, stockDetail, batch) = refreshedValidation.Data; |
| | | |
| | | // éè¦ä¿®å¤ï¼èªå¨æå
åï¼ç«å³æ§è¡åæ¡ç ç忣 |
| | | var actualPickedQty = lockInfo.AssignQuantity; |
| | | var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty); |
| | | |
| | | // 3. æ´æ°æ¹æ¬¡åè®¢åæ°æ® |
| | | // æ´æ°æ¹æ¬¡åè®¢åæ°æ® |
| | | await UpdateBatchAndOrderData(batch, orderDetail, actualPickedQty, orderNo); |
| | | |
| | | // 4. è®°å½æ£éåå² |
| | | // è®°å½æ£éåå² |
| | | await RecordPickingHistory(pickingResult, orderNo, palletCode); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("èªå¨æå
并忣æå", new |
| | | { |
| | | AutoSplitted = true, |
| | | NewBarcode = autoSplitResult.NewBarcode, |
| | | OriginalBarcode = barcode, |
| | | SplitQuantity = autoSplitResult.SplitQuantity, |
| | | PickedQuantity = actualPickedQty, |
| | | MaterialCode = lockInfo.MaterielCode |
| | | }); |
| | | } |
| | | |
| | | // æ£å¸¸åæ£æµç¨ï¼ä¸éè¦èªå¨æå
ï¼ |
| | | var normalPickedQty = lockInfo.AssignQuantity; |
| | | var normalPickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, normalPickedQty); |
| | | |
| | | // æ´æ°æ¹æ¬¡åè®¢åæ°æ® |
| | | await UpdateBatchAndOrderData(batch, orderDetail, normalPickedQty, orderNo); |
| | | |
| | | // è®°å½æ£éåå² |
| | | await RecordPickingHistory(normalPickingResult, orderNo, palletCode); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("忣æå", new |
| | | { |
| | | PickedQuantity = actualPickedQty, |
| | | PickedQuantity = normalPickedQty, |
| | | Barcode = barcode, |
| | | MaterialCode = lockInfo.MaterielCode |
| | | MaterialCode = lockInfo.MaterielCode, |
| | | AutoSplitted = false |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | |
| | | |
| | | #region æå¨æå
|
| | | |
| | | #region æå¨æå
ç¸å
³æ¹æ³ |
| | | |
| | | /// <summary> |
| | | /// æå¨æå
|
| | | /// </summary> |
| | |
| | | |
| | | var (lockInfo, stockDetail) = validationResult.Data; |
| | | |
| | | // . æ§è¡æå
é»è¾ |
| | | var splitResult = await ExecuteSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); |
| | | // æ§è¡æå
é»è¾ |
| | | var splitResult = await ExecuteManualSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | |
| | | return WebResponseContent.Instance.Error($"æå¨æå
失败ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éªè¯æå
è¯·æ± - å¢å¼ºåé
æ°éæ§å¶ |
| | | /// </summary> |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest( |
| | | string orderNo, string palletCode, string originalBarcode, decimal splitQuantity) |
| | | { |
| | | _logger.LogInformation($"å¼å§éªè¯æå
è¯·æ± - 订å: {orderNo}, æç: {palletCode}, åæ¡ç : {originalBarcode}, æå
æ°é: {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) |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°ææçéå®ä¿¡æ¯ - 订å: {orderNo}, æç: {palletCode}, æ¡ç : {originalBarcode}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | } |
| | | |
| | | _logger.LogInformation($"æ¾å°éå®ä¿¡æ¯ - åé
æ°é: {lockInfo.AssignQuantity}, å·²æ£é: {lockInfo.PickedQty}, è®¢åæ°é: {lockInfo.OrderQuantity}"); |
| | | |
| | | // è·å订åæç» |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | |
| | | if (orderDetail == null) |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°è®¢åæç» - OrderDetailId: {lockInfo.OrderDetailId}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°è®¢åæç»"); |
| | | } |
| | | |
| | | _logger.LogInformation($"æ¾å°è®¢åæç» - å·²åé
æ°é: {orderDetail.AllocatedQuantity}, é宿°é: {orderDetail.LockQuantity}"); |
| | | |
| | | // è·ååºåä¿¡æ¯ |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail == null) |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°åºåä¿¡æ¯ - æ¡ç : {originalBarcode}, StockId: {lockInfo.StockId}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°å¯¹åºçåºåä¿¡æ¯"); |
| | | } |
| | | |
| | | _logger.LogInformation($"æ¾å°åºåä¿¡æ¯ - åºåæ°é: {stockDetail.StockQuantity}, åºåºæ°é: {stockDetail.OutboundQuantity}"); |
| | | |
| | | // éè¦ä¿®å¤ï¼éªè¯æå
æ°éä¸è½å¤§äºåºåæ°é |
| | | if (stockDetail.StockQuantity < splitQuantity) |
| | | { |
| | | _logger.LogWarning($"æå
æ°é大äºåºåæ°é - æå
æ°é: {splitQuantity}, åºåæ°é: {stockDetail.StockQuantity}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå
æ°éä¸è½å¤§äºåºåæ°éï¼å½ååºåï¼{stockDetail.StockQuantity}"); |
| | | } |
| | | |
| | | // éè¦ä¿®å¤ï¼éªè¯æå
æ°éä¸è½å¤§äºéå®ä¿¡æ¯çåé
æ°é |
| | | if (lockInfo.AssignQuantity < splitQuantity) |
| | | { |
| | | _logger.LogWarning($"æå
æ°é大äºåé
æ°é - æå
æ°é: {splitQuantity}, åé
æ°é: {lockInfo.AssignQuantity}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå
æ°éä¸è½å¤§äºåé
æ°éï¼å½ååé
æ°éï¼{lockInfo.AssignQuantity}"); |
| | | } |
| | | |
| | | // éè¦ä¿®å¤ï¼éªè¯æå
æ°éä¸è½å¤§äºéå®ä¿¡æ¯çæªæ£éæ°é |
| | | decimal remainingToPick = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | if (remainingToPick < splitQuantity) |
| | | { |
| | | _logger.LogWarning($"æå
æ°éå¤§äºæªæ£éæ°é - æå
æ°é: {splitQuantity}, æªæ£éæ°é: {remainingToPick}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå
æ°éä¸è½å¤§äºæªæ£éæ°éï¼å½åæªæ£éï¼{remainingToPick}"); |
| | | } |
| | | |
| | | // éè¦ä¿®å¤ï¼éªè¯æå
ååéå®ä¿¡æ¯çåé
æ°éä¸ä¼ä¸ºè´æ° |
| | | if (lockInfo.AssignQuantity - splitQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"æå
ååé
æ°éä¸ºè´æ° - å½ååé
æ°é: {lockInfo.AssignQuantity}, æå
æ°é: {splitQuantity}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå
ååé
æ°éä¸è½ä¸ºè´æ°"); |
| | | } |
| | | |
| | | // éè¦ä¿®å¤ï¼éªè¯è®¢åæç»çåé
æ°éæ¯å¦è¶³å¤ |
| | | // 注æï¼æå¨æå
ä¸ä¼æ¹å订åæç»çåé
æ°éï¼å 为æ»åé
æ°éä¸å |
| | | // åªæ¯ä»ä¸ä¸ªéå®ä¿¡æ¯è½¬ç§»å°å¦ä¸ä¸ªéå®ä¿¡æ¯ |
| | | decimal totalLockAssignQuantity = await GetTotalLockAssignQuantity(orderDetail.Id); |
| | | if (orderDetail.AllocatedQuantity != totalLockAssignQuantity) |
| | | { |
| | | _logger.LogWarning($"订åæç»åé
æ°éä¸éå®ä¿¡æ¯ä¸ä¸è´ - 订åæç»åé
æ°é: {orderDetail.AllocatedQuantity}, éå®ä¿¡æ¯æ»åé
æ°é: {totalLockAssignQuantity}"); |
| | | // è¿éä¸ç´æ¥è¿åé误ï¼å 为æå
æä½æ¬èº«ä¸ä¼å¯¼è´ä¸ä¸è´ï¼åªæ¯è®°å½è¦å |
| | | } |
| | | |
| | | _logger.LogInformation($"æå
éªè¯éè¿ - åæ¡ç : {originalBarcode}, æå
æ°é: {splitQuantity}"); |
| | | |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail)); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·å订åæç»çææéå®ä¿¡æ¯çæ»åé
æ°é |
| | | /// </summary> |
| | | private async Task<decimal> GetTotalLockAssignQuantity(long orderDetailId) |
| | | { |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderDetailId == orderDetailId) |
| | | .ToListAsync(); |
| | | |
| | | return lockInfos.Sum(x => x.AssignQuantity); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ§è¡æå¨æå
é»è¾ - å¢å¼ºåé
æ°éæ§å¶ |
| | | /// </summary> |
| | | private async Task<SplitResultDto> ExecuteManualSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡æå¨æå
é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå
æ°é: {splitQuantity}"); |
| | | |
| | | // éè¦ä¿®å¤ï¼è·å订åæç»å¹¶éªè¯åé
æ°é |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | |
| | | if (orderDetail == null) |
| | | throw new InvalidOperationException("æªæ¾å°è®¢åæç»"); |
| | | |
| | | // éªè¯æå
æ°éä¸ä¼å¯¼è´åé
æ°éä¸ºè´æ° |
| | | if (lockInfo.AssignQuantity < splitQuantity) |
| | | { |
| | | throw new InvalidOperationException($"æå
æ°éè¶
è¿éå®ä¿¡æ¯åé
æ°éï¼æå
æ°é: {splitQuantity}, åé
æ°é: {lockInfo.AssignQuantity}"); |
| | | } |
| | | |
| | | // çææ°æ¡ç |
| | | string newBarcode = await GenerateNewBarcode(); |
| | | |
| | | // è®°å½æå
åçåé
æ°é |
| | | decimal originalAssignQtyBefore = lockInfo.AssignQuantity; |
| | | decimal originalOrderQtyBefore = lockInfo.OrderQuantity; |
| | | |
| | | // 1. å建æ°åºåæç» |
| | | var newStockDetail = new Dt_StockInfoDetail |
| | | { |
| | | StockId = stockDetail.StockId, |
| | | MaterielCode = stockDetail.MaterielCode, |
| | | OrderNo = stockDetail.OrderNo, |
| | | BatchNo = stockDetail.BatchNo, |
| | | StockQuantity = splitQuantity, |
| | | OutboundQuantity = 0, |
| | | Barcode = newBarcode, |
| | | Status = (int)StockStatusEmun.åºåºéå®, |
| | | SupplyCode = stockDetail.SupplyCode, |
| | | Unit = stockDetail.Unit, |
| | | BarcodeQty = stockDetail.BarcodeQty, |
| | | BarcodeUnit = stockDetail.BarcodeUnit, |
| | | BusinessType = stockDetail.BusinessType, |
| | | InboundOrderRowNo = stockDetail.InboundOrderRowNo, |
| | | }; |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°åºåæç» - æ¡ç : {newBarcode}, åºåæ°é: {splitQuantity}"); |
| | | |
| | | // 2. æ´æ°ååºåæç» |
| | | decimal originalStockQtyBefore = stockDetail.StockQuantity; |
| | | stockDetail.StockQuantity -= splitQuantity; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ´æ°ååºåæç» - åºåæ°éä» {originalStockQtyBefore} åå°å° {stockDetail.StockQuantity}"); |
| | | |
| | | // 3. å建æ°éå®ä¿¡æ¯ |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | OrderNo = lockInfo.OrderNo, |
| | | OrderDetailId = lockInfo.OrderDetailId, |
| | | OutboundBatchNo = lockInfo.OutboundBatchNo, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | MaterielName = lockInfo.MaterielName, |
| | | StockId = lockInfo.StockId, |
| | | OrderQuantity = splitQuantity, |
| | | 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, |
| | | 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(); |
| | | _logger.LogInformation($"å建æ°éå®ä¿¡æ¯ - æ¡ç : {newBarcode}, åé
æ°é: {splitQuantity}"); |
| | | |
| | | // 4. æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity -= splitQuantity; |
| | | lockInfo.OrderQuantity -= splitQuantity; |
| | | |
| | | _logger.LogInformation($"æ´æ°åéå®ä¿¡æ¯ - åé
æ°éä» {originalAssignQtyBefore} åå°å° {lockInfo.AssignQuantity}"); |
| | | _logger.LogInformation($"æ´æ°åéå®ä¿¡æ¯ - è®¢åæ°éä» {originalOrderQtyBefore} åå°å° {lockInfo.OrderQuantity}"); |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // éè¦ä¿®å¤ï¼æå¨æå
ä¸ä¼æ¹å订åæç»çåé
æ°éï¼å 为æ»åé
æ°éä¸å |
| | | // åªæ¯ä»ä¸ä¸ªéå®ä¿¡æ¯è½¬ç§»å°å¦ä¸ä¸ªéå®ä¿¡æ¯ |
| | | _logger.LogInformation($"订åæç»åé
æ°éä¿æä¸å - å·²åé
æ°é: {orderDetail.AllocatedQuantity}"); |
| | | |
| | | // 5. è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, false); |
| | | |
| | | _logger.LogInformation($"æå¨æå
é»è¾æ§è¡å®æ"); |
| | | |
| | | return new SplitResultDto { NewBarcode = newBarcode }; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #endregion |
| | | |
| | |
| | | Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo, |
| | | Dt_StockInfoDetail newStockDetail) |
| | | { |
| | | // 1. æ¢å¤åéå®ä¿¡æ¯ |
| | | // 注æï¼è¿ééè¦ç´¯å ï¼è䏿¯ç®åçèµå¼ï¼å 为å¯è½æå¤æ¬¡æå
|
| | | _logger.LogInformation($"å¼å§æ§è¡åæ¶æå
é»è¾ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}, æå
æ°é: {splitRecord.SplitQty}"); |
| | | |
| | | // æ¢å¤åéå®ä¿¡æ¯ |
| | | decimal originalAssignQtyBefore = originalLockInfo.AssignQuantity; |
| | | decimal originalOrderQtyBefore = originalLockInfo.OrderQuantity; |
| | | |
| | | // éè¦ä¿®å¤ï¼æ¢å¤åé
æ°éåè®¢åæ°é |
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | originalLockInfo.OrderQuantity += splitRecord.SplitQty; |
| | | |
| | | _logger.LogInformation($"æ¢å¤åéå®ä¿¡æ¯ - åé
æ°éä» {originalAssignQtyBefore} å¢å å° {originalLockInfo.AssignQuantity}"); |
| | | _logger.LogInformation($"æ¢å¤åéå®ä¿¡æ¯ - è®¢åæ°éä» {originalOrderQtyBefore} å¢å å° {originalLockInfo.OrderQuantity}"); |
| | | |
| | | // 妿åéå®ä¿¡æ¯çç¶ææ¯æ£é宿ï¼éè¦éæ°è®¾ç½®ä¸ºåºåºä¸ |
| | | if (originalLockInfo.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | { |
| | | originalLockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | _logger.LogInformation($"åéå®ä¿¡æ¯ç¶æä»æ£é宿æ¢å¤ä¸ºåºåºä¸"); |
| | | } |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); |
| | |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); |
| | | |
| | | if (originalStock != null) |
| | | { |
| | | decimal originalStockQtyBefore = originalStock.StockQuantity; |
| | | originalStock.StockQuantity += splitRecord.SplitQty; |
| | | |
| | | _logger.LogInformation($"æ¢å¤ååºåæç» - åºåæ°éä» {originalStockQtyBefore} å¢å å° {originalStock.StockQuantity}"); |
| | | |
| | | // 妿ååºåç¶ææ¯åºåºå®æï¼éè¦éæ°è®¾ç½®ä¸ºåºåºéå® |
| | | if (originalStock.Status == (int)StockStatusEmun.åºåºå®æ) |
| | | { |
| | | originalStock.Status = (int)StockStatusEmun.åºåºéå®; |
| | | _logger.LogInformation($"ååºåç¶æä»åºåºå®ææ¢å¤ä¸ºåºåºéå®"); |
| | | } |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // å 餿°éå®ä¿¡æ¯ |
| | | _logger.LogInformation($"å 餿°éå®ä¿¡æ¯ - æ¡ç : {newLockInfo.CurrentBarcode}, åé
æ°é: {newLockInfo.AssignQuantity}"); |
| | | await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.Id == newLockInfo.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // å 餿°åºåæç» |
| | | _logger.LogInformation($"å 餿°åºåæç» - æ¡ç : {newStockDetail.Barcode}, åºåæ°é: {newStockDetail.StockQuantity}"); |
| | | await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == newLockInfo.CurrentBarcode) |
| | | .ExecuteCommandAsync(); |
| | |
| | | splitRecord.RevertTime = DateTime.Now; |
| | | splitRecord.RevertOperator = App.User.UserName; |
| | | await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ è®°æå
è®°å½ä¸ºå·²æ¤é"); |
| | | |
| | | // æ£æ¥å¹¶æ´æ°æ¹æ¬¡å订åç¶æ |
| | | await CheckAndUpdateBatchStatus(originalLockInfo.BatchNo); |
| | | await CheckAndUpdateOrderStatus(originalLockInfo.OrderNo); |
| | | |
| | | _logger.LogInformation($"åæ¶æå
é»è¾æ§è¡å®æ"); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | private async Task<ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateCancelSplitRequest( |
| | | string orderNo, string palletCode, string newBarcode) |
| | | { |
| | | _logger.LogInformation($"å¼å§éªè¯åæ¶æå
è¯·æ± - 订å: {orderNo}, æç: {palletCode}, æ¡ç : {newBarcode}"); |
| | | |
| | | // æ¥æ¾æå
è®°å½ |
| | | var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.NewBarcode == newBarcode && |
| | |
| | | |
| | | if (splitRecord == null) |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°æå
è®°å½"); |
| | | |
| | | _logger.LogInformation($"æ¾å°æå
è®°å½ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}, æå
æ°é: {splitRecord.SplitQty}"); |
| | | |
| | | // æ¥æ¾æ°éå®ä¿¡æ¯ |
| | | var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | |
| | | 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(); |
| | | _logger.LogInformation($"æ¾å°æ°éå®ä¿¡æ¯ - ç¶æ: {newLockInfo.Status}, å·²æ£é: {newLockInfo.PickedQty}, åé
æ°é: {newLockInfo.AssignQuantity}"); |
| | | |
| | | if (pickingRecord != null) |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("该æ¡ç å·²è¢«åæ£ï¼æ æ³åæ¶æå
"); |
| | | // éè¦ä¿®å¤ï¼æ£æ¥æ°æ¡ç æ¯å¦å·²è¢«åæ£ |
| | | var newBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == newBarcode && x.OrderNo == orderNo && !x.IsCancelled) |
| | | .ToListAsync(); |
| | | |
| | | if (newBarcodePickingRecords.Any()) |
| | | { |
| | | var totalPickedQty = newBarcodePickingRecords.Sum(x => x.PickQuantity); |
| | | _logger.LogWarning($"æ°æ¡ç {newBarcode} å·²è¢«åæ£ï¼æ»æ£éæ°é: {totalPickedQty}"); |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error( |
| | | $"æ°æ¡ç å·²è¢«åæ£ï¼å·²æ£éæ°éï¼{totalPickedQty}ï¼ï¼è¯·å
忶忣ï¼ç¶åååæ¶æå
"); |
| | | } |
| | | |
| | | // éè¦ä¿®å¤ï¼æ£æ¥åæ¡ç æ¯å¦å·²è¢«åæ£ |
| | | var originalBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == splitRecord.OriginalBarcode && x.OrderNo == orderNo && !x.IsCancelled) |
| | | .ToListAsync(); |
| | | |
| | | if (originalBarcodePickingRecords.Any()) |
| | | { |
| | | var totalPickedQty = originalBarcodePickingRecords.Sum(x => x.PickQuantity); |
| | | _logger.LogWarning($"åæ¡ç {splitRecord.OriginalBarcode} å·²è¢«åæ£ï¼æ»æ£éæ°é: {totalPickedQty}"); |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error( |
| | | $"åæ¡ç å·²è¢«åæ£ï¼å·²æ£éæ°éï¼{totalPickedQty}ï¼ï¼è¯·å
忶忣ï¼ç¶åååæ¶æå
"); |
| | | } |
| | | |
| | | _logger.LogInformation($"æ°æ§æ¡ç åæªè¢«åæ£ï¼å¯ä»¥åæ¶æå
"); |
| | | |
| | | // æ£æ¥æ°æ¡ç æ¯å¦è¢«å次æå
|
| | | var childSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | |
| | | if (childSplitRecords.Any()) |
| | | { |
| | | var childBarcodes = string.Join(", ", childSplitRecords.Select(x => x.NewBarcode)); |
| | | _logger.LogWarning($"æ¡ç {newBarcode} å·²è¢«åæ¬¡æå
ï¼çæçæ°æ¡ç : {childBarcodes}"); |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error( |
| | | $"该æ¡ç å·²è¢«åæ¬¡æå
ï¼çæçæ°æ¡ç ï¼{childBarcodes}ï¼è¯·å
åæ¶åç»æå
"); |
| | | } |
| | | |
| | | var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == newBarcode); |
| | | |
| | | if (newStockDetail == null) |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°æ°åºåæç»"); |
| | | |
| | | _logger.LogInformation($"åæ¶æå
éªè¯éè¿ - æ¡ç : {newBarcode}"); |
| | | |
| | | return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((splitRecord, newLockInfo, newStockDetail)); |
| | | } |
| | |
| | | if (!splitChain.Any()) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°æå
è®°å½"); |
| | | |
| | | // 2. ææå
顺åºååºåæ¶ï¼ä»ææ°çå¼å§åæ¶ï¼ |
| | | _logger.LogInformation($"æ¾å°æå
é¾ï¼å
± {splitChain.Count} æ¡è®°å½"); |
| | | |
| | | // 2. æ¶éæå
é¾ä¸æ¶åçæææ¡ç ï¼å
æ¬åæ¡ç åæ°æ¡ç ï¼ |
| | | var allBarcodesInChain = new List<string> { startBarcode }; |
| | | allBarcodesInChain.AddRange(splitChain.Select(x => x.NewBarcode)); |
| | | |
| | | // 3. æ£æ¥æå
é¾ä¸æ¯å¦æå·²è¢«åæ£çæ¡ç |
| | | var pickedBarcodesInfo = await GetPickedBarcodesInfo(orderNo, allBarcodesInChain); |
| | | |
| | | if (pickedBarcodesInfo.Any()) |
| | | { |
| | | var pickedBarcodes = string.Join(", ", pickedBarcodesInfo.Select(x => $"{x.Barcode}(å·²æ£é{x.PickedQty})")); |
| | | return WebResponseContent.Instance.Error( |
| | | $"以䏿¡ç å·²è¢«åæ£ï¼è¯·å
忶忣ï¼{pickedBarcodes}"); |
| | | } |
| | | |
| | | // 4. ææå
顺åºååºåæ¶ï¼ä»ææ°çå¼å§åæ¶ï¼ |
| | | var reversedChain = splitChain.OrderByDescending(x => x.SplitTime).ToList(); |
| | | |
| | | foreach (var splitRecord in reversedChain) |
| | | { |
| | | _logger.LogInformation($"åæ¶æå
è®°å½ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); |
| | | await CancelSingleSplitPackage(splitRecord, palletCode); |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæ¡ç çæå
忣éç¶æ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> GetBarcodeSplitAndPickStatus(string orderNo, string barcode) |
| | | { |
| | | try |
| | | { |
| | | // 1. è·åæå
ä¿¡æ¯ |
| | | var splitChain = await GetSplitPackageChain(orderNo, barcode); |
| | | var isOriginalBarcode = !splitChain.Any(x => x.NewBarcode == barcode); |
| | | |
| | | // 2. è·åæ£éä¿¡æ¯ |
| | | var pickingRecords = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && !x.IsCancelled) |
| | | .ToListAsync(); |
| | | |
| | | var totalPickedQty = pickingRecords.Sum(x => x.PickQuantity); |
| | | |
| | | // 3. è·åéå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == barcode && x.OrderNo == orderNo) |
| | | .FirstAsync(); |
| | | |
| | | // 4. è·ååºåä¿¡æ¯ |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == barcode) |
| | | .FirstAsync(); |
| | | |
| | | var statusInfo = new BarcodeStatusInfoDto |
| | | { |
| | | Barcode = barcode, |
| | | OrderNo = orderNo, |
| | | IsOriginalBarcode = isOriginalBarcode, |
| | | SplitChainCount = splitChain.Count, |
| | | HasBeenPicked = pickingRecords.Any(), |
| | | TotalPickedQuantity = totalPickedQty, |
| | | PickRecordCount = pickingRecords.Count, |
| | | LockInfoStatus = lockInfo?.Status ?? 0, |
| | | LockInfoPickedQty = lockInfo?.PickedQty ?? 0, |
| | | LockInfoAssignQty = lockInfo?.AssignQuantity ?? 0, |
| | | StockQuantity = stockDetail?.StockQuantity ?? 0, |
| | | StockStatus = stockDetail?.Status ?? 0, |
| | | CanCancelSplit = !pickingRecords.Any(), // æªè¢«åæ£æè½åæ¶æå
|
| | | NeedCancelPickFirst = pickingRecords.Any() // éè¦å
忶忣 |
| | | }; |
| | | |
| | | // 5. è·åæä½å»ºè®® |
| | | statusInfo.OperationSuggestions = GetOperationSuggestions(statusInfo); |
| | | |
| | | return WebResponseContent.Instance.OK("è·åç¶ææå", statusInfo); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"è·åæ¡ç ç¶æå¤±è´¥ - OrderNo: {orderNo}, Barcode: {barcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error("è·åæ¡ç ç¶æå¤±è´¥"); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// è·åæä½å»ºè®® |
| | | /// </summary> |
| | | private List<string> GetOperationSuggestions(BarcodeStatusInfoDto statusInfo) |
| | | { |
| | | var suggestions = new List<string>(); |
| | | |
| | | if (statusInfo.HasBeenPicked) |
| | | { |
| | | suggestions.Add($"该æ¡ç å·²è¢«åæ£ï¼æ°éï¼{statusInfo.TotalPickedQuantity}ï¼ï¼å¦éåæ¶æå
ï¼è¯·å
忶忣"); |
| | | |
| | | if (statusInfo.IsOriginalBarcode) |
| | | { |
| | | suggestions.Add("è¿æ¯åæ¡ç ï¼åæ¶åæ£åå°æ¢å¤ä¸ºå¯åæ£ç¶æ"); |
| | | } |
| | | else |
| | | { |
| | | suggestions.Add("è¿æ¯æå
çæçæ°æ¡ç ï¼åæ¶åæ£åæè½åæ¶æå
"); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (statusInfo.IsOriginalBarcode && statusInfo.SplitChainCount > 0) |
| | | { |
| | | suggestions.Add("è¿æ¯åæ¡ç ï¼å¯ä»¥åæ¶æå
é¾"); |
| | | } |
| | | else if (!statusInfo.IsOriginalBarcode) |
| | | { |
| | | suggestions.Add("è¿æ¯æå
çæçæ°æ¡ç ï¼å¯ä»¥åç¬åæ¶æå
"); |
| | | } |
| | | } |
| | | |
| | | if (statusInfo.LockInfoStatus == (int)OutLockStockStatusEnum.æ£é宿) |
| | | { |
| | | suggestions.Add("éå®ç¶æï¼æ£é宿"); |
| | | } |
| | | else if (statusInfo.LockInfoStatus == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | { |
| | | suggestions.Add("éå®ç¶æï¼åºåºä¸"); |
| | | } |
| | | |
| | | return suggestions; |
| | | } |
| | | /// <summary> |
| | | /// è·åå·²è¢«åæ£çæ¡ç ä¿¡æ¯ |
| | | /// </summary> |
| | | private async Task<List<PickedBarcodeInfo>> GetPickedBarcodesInfo(string orderNo, List<string> barcodes) |
| | | { |
| | | var pickedBarcodes = new List<PickedBarcodeInfo>(); |
| | | |
| | | foreach (var barcode in barcodes) |
| | | { |
| | | var pickingRecords = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && !x.IsCancelled) |
| | | .ToListAsync(); |
| | | |
| | | if (pickingRecords.Any()) |
| | | { |
| | | var totalPickedQty = pickingRecords.Sum(x => x.PickQuantity); |
| | | pickedBarcodes.Add(new PickedBarcodeInfo |
| | | { |
| | | Barcode = barcode, |
| | | PickedQty = totalPickedQty, |
| | | PickRecordCount = pickingRecords.Count |
| | | }); |
| | | } |
| | | } |
| | | |
| | | return pickedBarcodes; |
| | | } |
| | | /// <summary> |
| | | /// è·åæå
é¾ - æ¥æ¾æä¸ªæ¡ç çæææå
è®°å½ï¼å
æ¬åç»æå
ï¼ |
| | | /// </summary> |
| | |
| | | /// </summary> |
| | | private async Task CancelSingleSplitPackage(Dt_SplitPackageRecord splitRecord, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§åæ¶å个æå
è®°å½ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); |
| | | |
| | | // 忬¡éªè¯åæ£ç¶æï¼é²æ¢å¹¶åæä½ï¼ |
| | | var newBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == splitRecord.NewBarcode && !x.IsCancelled) |
| | | .ToListAsync(); |
| | | |
| | | if (newBarcodePickingRecords.Any()) |
| | | { |
| | | throw new InvalidOperationException($"æ°æ¡ç {splitRecord.NewBarcode} å¨éªè¯åè¢«åæ£ï¼æ æ³åæ¶æå
"); |
| | | } |
| | | |
| | | var originalBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == splitRecord.OriginalBarcode && !x.IsCancelled) |
| | | .ToListAsync(); |
| | | |
| | | if (originalBarcodePickingRecords.Any()) |
| | | { |
| | | throw new InvalidOperationException($"åæ¡ç {splitRecord.OriginalBarcode} å¨éªè¯åè¢«åæ£ï¼æ æ³åæ¶æå
"); |
| | | } |
| | | |
| | | // æ¥æ¾ç¸å
³æ°æ® |
| | | var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == splitRecord.NewBarcode && |
| | |
| | | |
| | | // æ§è¡åæ¶é»è¾ |
| | | await ExecuteCancelSplitLogic(splitRecord, originalLockInfo, newLockInfo, newStockDetail); |
| | | |
| | | _logger.LogInformation($"åæ¶å个æå
è®°å½å®æ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); |
| | | } |
| | | #endregion |
| | | |
| | |
| | | NewBarcode = x.NewBarcode, |
| | | SplitQuantity = x.SplitQty, |
| | | Operator = x.Operator, |
| | | IsReverted = x.IsReverted |
| | | IsReverted = x.IsReverted , |
| | | IsAutoSplit = x.IsAutoSplit |
| | | }).ToList() |
| | | }; |
| | | |
| | |
| | | #endregion |
| | | |
| | | |
| | | |
| | | |
| | | #region åæ¹ååº |
| | | |
| | | /// <summary> |
| | |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>> ValidatePickingRequest( |
| | | string orderNo, string palletCode, string barcode) |
| | | { |
| | | _logger.LogInformation($"å¼å§éªè¯åæ£è¯·æ± - 订å: {orderNo}, æç: {palletCode}, æ¡ç : {barcode}"); |
| | | |
| | | // æ¥æ¾éå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | |
| | | _logger.LogInformation($"æ¾å°éå®ä¿¡æ¯ - åé
æ°é: {lockInfo.AssignQuantity}, å·²æ£é: {lockInfo.PickedQty}"); |
| | | |
| | | // æ£æ¥æ¯å¦å·²ç»åæ£å®æ |
| | | 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); |
| | | |
| | | if (orderDetail == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("æªæ¾å°è®¢åæç»"); |
| | | |
| | | _logger.LogInformation($"æ¾å°è®¢åæç» - å·²åé
æ°é: {orderDetail.AllocatedQuantity}, é宿°é: {orderDetail.LockQuantity}"); |
| | | |
| | | // éè¦ä¿®å¤ï¼æ£æ¥è®¢åæç»çå·²åé
æ°éæ¯å¦è¶³å¤ |
| | | decimal remainingToPick = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | if (orderDetail.AllocatedQuantity < remainingToPick) |
| | | { |
| | | _logger.LogWarning($"订åæç»å·²åé
æ°éä¸è¶³ - éè¦æ£é: {remainingToPick}, å¯ç¨åé
æ°é: {orderDetail.AllocatedQuantity}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( |
| | | $"订åæç»åé
æ°éä¸è¶³ï¼éè¦æ£éï¼{remainingToPick}ï¼å¯ç¨åé
æ°éï¼{orderDetail.AllocatedQuantity}"); |
| | | } |
| | | |
| | | // éè¦ä¿®å¤ï¼æ£æ¥é宿°éæ¯å¦è¶³å¤ |
| | | if (orderDetail.LockQuantity < remainingToPick) |
| | | { |
| | | _logger.LogWarning($"订åæç»é宿°éä¸è¶³ - éè¦æ£é: {remainingToPick}, å¯ç¨é宿°é: {orderDetail.LockQuantity}"); |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( |
| | | $"订åæç»é宿°éä¸è¶³ï¼éè¦æ£éï¼{remainingToPick}ï¼å¯ç¨é宿°éï¼{orderDetail.LockQuantity}"); |
| | | } |
| | | |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == barcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("æªæ¾å°å¯¹åºçåºåä¿¡æ¯"); |
| | | |
| | | // éªè¯åºåæ°é |
| | | if (stockDetail.StockQuantity < lockInfo.AssignQuantity) |
| | | if (stockDetail.StockQuantity < remainingToPick) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( |
| | | $"åºåæ°éä¸è¶³ï¼éè¦ï¼{lockInfo.AssignQuantity}ï¼å®é
ï¼{stockDetail.StockQuantity}"); |
| | | $"åºåæ°éä¸è¶³ï¼éè¦æ£éï¼{remainingToPick}ï¼å®é
åºåï¼{stockDetail.StockQuantity}"); |
| | | |
| | | // éªè¯åºåç¶æ |
| | | if (stockDetail.Status != (int)StockStatusEmun.åºåºéå®) |
| | | { |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( |
| | | $"åºåç¶æå¼å¸¸ï¼å½åç¶æï¼{stockDetail.Status}ï¼ææç¶æï¼åºåºéå®"); |
| | | } |
| | | |
| | | // ä½¿ç¨ OutboundBatchNo æ¥æ¾æ¹æ¬¡ |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo); // ä¿®æ£ä¸º OutboundBatchNo |
| | | .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo); |
| | | |
| | | _logger.LogInformation($"忣éªè¯éè¿ - æ¡ç : {barcode}, å©ä½éæ£é: {remainingToPick}, å¯ç¨åºå: {stockDetail.StockQuantity}"); |
| | | |
| | | 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) |
| | | |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥å¹¶æ§è¡èªå¨æå
ï¼å¦æéè¦ï¼ |
| | | /// </summary> |
| | | private async Task<AutoSplitResult> CheckAndAutoSplitIfNeeded(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, string palletCode) |
| | | { |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.CurrentBarcode == originalBarcode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .FirstAsync(); |
| | | // æ£æ¥æ¯å¦éè¦èªå¨æå
çæ¡ä»¶ï¼ |
| | | // 1. åºåæ°é大äºåé
æ°é |
| | | // 2. éå®ä¿¡æ¯ç¶æä¸ºåºåºä¸ |
| | | // 3. æªæ£éæ°éçäºåé
æ°éï¼è¡¨ç¤ºè¿æªå¼å§æ£éï¼ |
| | | bool needAutoSplit = stockDetail.StockQuantity > lockInfo.AssignQuantity && |
| | | lockInfo.Status == (int)OutLockStockStatusEnum.åºåºä¸ && |
| | | lockInfo.PickedQty == 0; |
| | | |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | if (!needAutoSplit) |
| | | return null; |
| | | |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId); |
| | | // è®¡ç®æå
æ°é = åºåæ°é - åé
æ°é |
| | | decimal splitQuantity = stockDetail.StockQuantity - lockInfo.AssignQuantity; |
| | | |
| | | if (stockDetail.StockQuantity < splitQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æå
æ°éä¸è½å¤§äºåºåæ°é"); |
| | | // æ§è¡èªå¨æå
|
| | | var splitResult = await ExecuteAutoSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); |
| | | |
| | | 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) |
| | | return new AutoSplitResult |
| | | { |
| | | // æ´æ°éå®ä¿¡æ¯ |
| | | lockInfo.PickedQty += actualPickedQty; |
| | | if (lockInfo.PickedQty >= lockInfo.AssignQuantity) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.æ£é宿; |
| | | } |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // æ´æ°åºå |
| | | stockDetail.StockQuantity -= actualPickedQty; |
| | | stockDetail.OutboundQuantity += actualPickedQty; |
| | | |
| | | if (stockDetail.StockQuantity <= 0) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.åºåºå®æ; |
| | | } |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | return new PickingResult |
| | | { |
| | | FinalLockInfo = lockInfo, |
| | | ActualPickedQty = actualPickedQty |
| | | NewBarcode = splitResult.NewBarcode, |
| | | SplitQuantity = splitQuantity |
| | | }; |
| | | } |
| | | |
| | | private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord) |
| | | { |
| | | // æ¢å¤éå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .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(); |
| | | |
| | | // æ¢å¤åºå |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == pickingRecord.Barcode); |
| | | |
| | | 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 |
| | | { |
| | | LockInfo = lockInfo, |
| | | StockDetail = stockDetail |
| | | }; |
| | | } |
| | | private async Task<SplitResultDto> ExecuteSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | /// <summary> |
| | | /// æ§è¡èªå¨æå
é»è¾ |
| | | /// </summary> |
| | | private async Task<SplitResultDto> ExecuteAutoSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡èªå¨æå
é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå
æ°é: {splitQuantity}"); |
| | | |
| | | // çææ°æ¡ç |
| | | string newBarcode = await GenerateNewBarcode(); |
| | | |
| | | // å建æ°åºåæç» |
| | | // éè¦ä¿®å¤ï¼è®°å½æå
åçåé
æ°é |
| | | decimal originalAssignQtyBefore = lockInfo.AssignQuantity; |
| | | decimal originalOrderQtyBefore = lockInfo.OrderQuantity; |
| | | |
| | | // 1. å建æ°åºåæç»ï¼å©ä½é¨åï¼ |
| | | var newStockDetail = new Dt_StockInfoDetail |
| | | { |
| | | StockId = stockDetail.StockId, |
| | | MaterielCode = stockDetail.MaterielCode, |
| | | OrderNo = stockDetail.OrderNo, |
| | | BatchNo = stockDetail.BatchNo, // ç©ææ¹æ¬¡ |
| | | BatchNo = stockDetail.BatchNo, |
| | | StockQuantity = splitQuantity, |
| | | OutboundQuantity = 0, |
| | | Barcode = newBarcode, |
| | |
| | | InboundOrderRowNo = stockDetail.InboundOrderRowNo, |
| | | }; |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°åºåæç» - æ¡ç : {newBarcode}, åºåæ°é: {splitQuantity}"); |
| | | |
| | | // æ´æ°ååºåæç» |
| | | stockDetail.StockQuantity -= splitQuantity; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | // 2. æ´æ°ååºåæç» |
| | | // éè¦ä¿®å¤ï¼ååºåæ°é设置为åé
æ°éï¼ä¿æä¸åï¼ |
| | | decimal originalStockQtyBefore = stockDetail.StockQuantity; |
| | | // 注æï¼èªå¨æå
æ¶ï¼ååºåæ°éä¿æä¸åï¼å 为æä»¬è¦åæ£çå°±æ¯åé
æ°é |
| | | // stockDetail.StockQuantity ä¿æä¸å |
| | | |
| | | // å建æ°éå®ä¿¡æ¯ - ä½¿ç¨æ£ç¡®ç OutboundBatchNo |
| | | _logger.LogInformation($"ååºåæç»ä¿æä¸å - åºåæ°é: {stockDetail.StockQuantity}"); |
| | | |
| | | // 3. å建æ°éå®ä¿¡æ¯ï¼å©ä½é¨åï¼ |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | OrderNo = lockInfo.OrderNo, |
| | | OrderDetailId = lockInfo.OrderDetailId, |
| | | OutboundBatchNo = lockInfo.OutboundBatchNo, // ä½¿ç¨ OutboundBatchNo |
| | | OutboundBatchNo = lockInfo.OutboundBatchNo, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | MaterielName = lockInfo.MaterielName, |
| | | StockId = lockInfo.StockId, |
| | |
| | | }; |
| | | |
| | | await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°éå®ä¿¡æ¯ - æ¡ç : {newBarcode}, åé
æ°é: {splitQuantity}"); |
| | | |
| | | // æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity -= splitQuantity; |
| | | lockInfo.OrderQuantity -= splitQuantity; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | // 4. éè¦ä¿®å¤ï¼èªå¨æå
æ¶ï¼åéå®ä¿¡æ¯çåé
æ°éä¿æä¸å |
| | | // å 为èªå¨æå
åï¼åæ¡ç ä»ç¶éè¦è¢«åæ£ï¼åé
æ°éä¸åºè¯¥æ¹å |
| | | _logger.LogInformation($"åéå®ä¿¡æ¯ä¿æä¸å - åé
æ°é: {lockInfo.AssignQuantity}, è®¢åæ°é: {lockInfo.OrderQuantity}"); |
| | | |
| | | // è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode); |
| | | // 5. è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, true, originalStockQtyBefore); |
| | | |
| | | _logger.LogInformation($"èªå¨æå
é»è¾æ§è¡å®æ"); |
| | | |
| | | return new SplitResultDto { NewBarcode = newBarcode }; |
| | | } |
| | | private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord, Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail) |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region æ ¸å¿é»è¾æ¹æ³ |
| | | |
| | | private async Task<PickingResult> ExecutePickingLogic( |
| | | Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, |
| | | Dt_StockInfoDetail stockDetail, decimal actualPickedQty) |
| | | { |
| | | // æ¢å¤ååºå |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); |
| | | _logger.LogInformation($"å¼å§æ§è¡åæ£é»è¾ - æ¡ç : {stockDetail.Barcode}, åé
æ°é: {lockInfo.AssignQuantity}, å®é
æ£é: {actualPickedQty}"); |
| | | |
| | | originalStock.StockQuantity += splitRecord.SplitQty; |
| | | await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); |
| | | // éè¦ä¿®å¤ï¼å次éªè¯è®¢åæç»çåé
æ°éï¼é²æ¢å¹¶åæä½ï¼ |
| | | if (orderDetail.AllocatedQuantity < actualPickedQty) |
| | | { |
| | | throw new InvalidOperationException($"订åæç»åé
æ°éä¸è¶³ï¼éè¦æ£é {actualPickedQty}ï¼å¯ç¨åé
æ°é {orderDetail.AllocatedQuantity}"); |
| | | } |
| | | |
| | | // æ¢å¤åéå®ä¿¡æ¯ |
| | | var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId); |
| | | if (orderDetail.LockQuantity < actualPickedQty) |
| | | { |
| | | throw new InvalidOperationException($"订åæç»é宿°éä¸è¶³ï¼éè¦æ£é {actualPickedQty}ï¼å¯ç¨é宿°é {orderDetail.LockQuantity}"); |
| | | } |
| | | |
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | originalLockInfo.OrderQuantity += splitRecord.SplitQty; |
| | | await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); |
| | | // 1. æ´æ°éå®ä¿¡æ¯ |
| | | lockInfo.PickedQty += actualPickedQty; |
| | | _logger.LogInformation($"æ´æ°éå®ä¿¡æ¯ - å·²æ£éæ°éä» {lockInfo.PickedQty - actualPickedQty} å¢å å° {lockInfo.PickedQty}"); |
| | | |
| | | // å 餿°åºåæç» |
| | | await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == newLockInfo.CurrentBarcode) |
| | | .ExecuteCommandAsync(); |
| | | // åç¡®å¤ææ£éå®æç¶æ |
| | | if (Math.Abs(lockInfo.PickedQty - lockInfo.AssignQuantity) < 0.001m) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.æ£é宿; |
| | | _logger.LogInformation($"éå®ä¿¡æ¯ç¶ææ´æ°ä¸ºæ£é宿"); |
| | | } |
| | | else if (lockInfo.PickedQty > 0) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | _logger.LogInformation($"éå®ä¿¡æ¯ç¶æä¿æä¸ºåºåºä¸ï¼é¨åæ£éï¼"); |
| | | } |
| | | |
| | | // å 餿°éå®ä¿¡æ¯ |
| | | await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.Id == newLockInfo.Id) |
| | | .ExecuteCommandAsync(); |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // æ è®°æå
è®°å½ä¸ºå·²æ¤é |
| | | splitRecord.IsReverted = true; |
| | | splitRecord.RevertTime = DateTime.Now; |
| | | splitRecord.RevertOperator = App.User.UserName; |
| | | await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); |
| | | // 2. æ´æ°åºåä¿¡æ¯ |
| | | decimal originalStockQty = stockDetail.StockQuantity; |
| | | decimal originalOutboundQty = stockDetail.OutboundQuantity; |
| | | |
| | | stockDetail.StockQuantity -= actualPickedQty; |
| | | stockDetail.OutboundQuantity += actualPickedQty; |
| | | |
| | | _logger.LogInformation($"æ´æ°åºåä¿¡æ¯ - åºåæ°éä» {originalStockQty} åå°å° {stockDetail.StockQuantity}"); |
| | | _logger.LogInformation($"æ´æ°åºåä¿¡æ¯ - åºåºæ°éä» {originalOutboundQty} å¢å å° {stockDetail.OutboundQuantity}"); |
| | | |
| | | // åç¡®å¤æåºåç¶æ |
| | | if (stockDetail.StockQuantity <= 0) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.åºåºå®æ; |
| | | _logger.LogInformation($"åºåç¶ææ´æ°ä¸ºåºåºå®æ"); |
| | | } |
| | | else |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.åºåºéå®; |
| | | _logger.LogInformation($"åºåç¶æä¿æä¸ºåºåºéå®"); |
| | | } |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"忣é»è¾æ§è¡å®æ - æ¡ç : {stockDetail.Barcode}"); |
| | | |
| | | return new PickingResult |
| | | { |
| | | FinalLockInfo = lockInfo, |
| | | ActualPickedQty = actualPickedQty |
| | | }; |
| | | } |
| | | |
| | | private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ¢å¤æ£éæ°æ® - æ£éè®°å½ID: {pickingRecord.Id}, æ¡ç : {pickingRecord.Barcode}, æ£éæ°é: {pickingRecord.PickQuantity}"); |
| | | |
| | | // 1. æ¢å¤éå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == pickingRecord.OutStockLockId); |
| | | |
| | | if (lockInfo == null) |
| | | { |
| | | throw new InvalidOperationException($"æªæ¾å°å¯¹åºçéå®ä¿¡æ¯ï¼ID: {pickingRecord.OutStockLockId}"); |
| | | } |
| | | |
| | | decimal originalPickedQty = lockInfo.PickedQty; |
| | | decimal originalAssignQty = lockInfo.AssignQuantity; // è®°å½åå§åé
æ°é |
| | | |
| | | // éè¦ä¿®å¤ï¼åªæ¢å¤å·²æ£éæ°éï¼ä¸ä¿®æ¹åé
æ°é |
| | | lockInfo.PickedQty -= pickingRecord.PickQuantity; |
| | | |
| | | // ç¡®ä¿å·²æ£éæ°éä¸ä¼ä¸ºè´æ° |
| | | if (lockInfo.PickedQty < 0) |
| | | { |
| | | _logger.LogWarning($"å·²æ£éæ°éåºç°è´æ°ï¼é置为0ãåå¼: {lockInfo.PickedQty + pickingRecord.PickQuantity}, æ¢å¤æ°é: {pickingRecord.PickQuantity}"); |
| | | lockInfo.PickedQty = 0; |
| | | } |
| | | |
| | | _logger.LogInformation($"æ¢å¤éå®ä¿¡æ¯ - å·²æ£éæ°éä» {originalPickedQty} åå°å° {lockInfo.PickedQty}"); |
| | | _logger.LogInformation($"éå®ä¿¡æ¯åé
æ°éä¿æä¸å: {originalAssignQty}"); |
| | | |
| | | // æ¢å¤éå®ç¶æ |
| | | if (lockInfo.PickedQty <= 0) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | _logger.LogInformation($"éå®ä¿¡æ¯ç¶ææ¢å¤ä¸ºåºåºä¸"); |
| | | } |
| | | else if (lockInfo.PickedQty < lockInfo.AssignQuantity) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; // é¨åæ£éç¶æ |
| | | _logger.LogInformation($"éå®ä¿¡æ¯ç¶ææ¢å¤ä¸ºåºåºä¸ï¼é¨åæ£éï¼"); |
| | | } |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // 2. æ¢å¤åºåä¿¡æ¯ |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == pickingRecord.Barcode); |
| | | |
| | | if (stockDetail == null) |
| | | { |
| | | throw new InvalidOperationException($"æªæ¾å°å¯¹åºçåºåä¿¡æ¯ï¼æ¡ç : {pickingRecord.Barcode}"); |
| | | } |
| | | |
| | | decimal originalStockQty = stockDetail.StockQuantity; |
| | | decimal originalOutboundQty = stockDetail.OutboundQuantity; |
| | | |
| | | stockDetail.StockQuantity += pickingRecord.PickQuantity; |
| | | stockDetail.OutboundQuantity -= pickingRecord.PickQuantity; |
| | | |
| | | // ç¡®ä¿åºåºæ°éä¸ä¼ä¸ºè´æ° |
| | | if (stockDetail.OutboundQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"åºåºæ°éåºç°è´æ°ï¼é置为0ãåå¼: {stockDetail.OutboundQuantity + pickingRecord.PickQuantity}, æ¢å¤æ°é: {pickingRecord.PickQuantity}"); |
| | | stockDetail.OutboundQuantity = 0; |
| | | } |
| | | |
| | | _logger.LogInformation($"æ¢å¤åºåä¿¡æ¯ - åºåæ°éä» {originalStockQty} å¢å å° {stockDetail.StockQuantity}"); |
| | | _logger.LogInformation($"æ¢å¤åºåä¿¡æ¯ - åºåºæ°éä» {originalOutboundQty} åå°å° {stockDetail.OutboundQuantity}"); |
| | | |
| | | // æ¢å¤åºåç¶æ |
| | | if (stockDetail.StockQuantity > 0) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.åºåºéå®; |
| | | _logger.LogInformation($"åºåç¶ææ¢å¤ä¸ºåºåºéå®"); |
| | | } |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¢å¤æ£éæ°æ®å®æ - æ¡ç : {pickingRecord.Barcode}"); |
| | | |
| | | return new RevertPickingResult |
| | | { |
| | | LockInfo = lockInfo, |
| | | StockDetail = stockDetail |
| | | }; |
| | | } |
| | | |
| | | #endregion |
| | |
| | | |
| | | private async Task UpdateBatchAndOrderData(Dt_OutboundBatch batch, Dt_OutboundOrderDetail orderDetail, decimal pickedQty, string orderNo) |
| | | { |
| | | // æ´æ°æ¹æ¬¡å®ææ°é |
| | | _logger.LogInformation($"å¼å§æ´æ°æ¹æ¬¡åè®¢åæ°æ® - æ£éæ°é: {pickedQty}"); |
| | | |
| | | // éè¦ä¿®å¤ï¼éªè¯åé
æ°éä¸ä¼åæè´æ° |
| | | if (orderDetail.AllocatedQuantity < pickedQty) |
| | | { |
| | | throw new InvalidOperationException($"æ´æ°è®¢åæ°æ®æ¶åé
æ°éä¸è¶³ï¼éè¦åå° {pickedQty}ï¼å½ååé
æ°é {orderDetail.AllocatedQuantity}"); |
| | | } |
| | | |
| | | if (orderDetail.LockQuantity < pickedQty) |
| | | { |
| | | throw new InvalidOperationException($"æ´æ°è®¢åæ°æ®æ¶é宿°éä¸è¶³ï¼éè¦åå° {pickedQty}ï¼å½åé宿°é {orderDetail.LockQuantity}"); |
| | | } |
| | | |
| | | // 1. æ´æ°æ¹æ¬¡å®ææ°é |
| | | decimal originalBatchCompletedQty = batch.CompletedQuantity; |
| | | batch.CompletedQuantity += pickedQty; |
| | | |
| | | _logger.LogInformation($"æ´æ°æ¹æ¬¡å®ææ°é - ä» {originalBatchCompletedQty} å¢å å° {batch.CompletedQuantity}"); |
| | | |
| | | if (batch.CompletedQuantity >= batch.BatchQuantity) |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.已宿; |
| | | _logger.LogInformation($"æ¹æ¬¡ç¶ææ´æ°ä¸ºå·²å®æ"); |
| | | } |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | // 2. æ´æ°è®¢åæç» |
| | | decimal originalOverOutQty = orderDetail.OverOutQuantity; |
| | | decimal originalAllocatedQty = orderDetail.AllocatedQuantity; |
| | | decimal originalLockQty = orderDetail.LockQuantity; |
| | | |
| | | orderDetail.OverOutQuantity += pickedQty; |
| | | orderDetail.AllocatedQuantity -= pickedQty; |
| | | // LockQuantity 忥åå° |
| | | orderDetail.LockQuantity = orderDetail.AllocatedQuantity; |
| | | |
| | | _logger.LogInformation($"æ´æ°è®¢åæç» - å·²åºåºæ°éä» {originalOverOutQty} å¢å å° {orderDetail.OverOutQuantity}"); |
| | | _logger.LogInformation($"æ´æ°è®¢åæç» - å·²åé
æ°éä» {originalAllocatedQty} åå°å° {orderDetail.AllocatedQuantity}"); |
| | | _logger.LogInformation($"æ´æ°è®¢åæç» - é宿°éä» {originalLockQty} åå°å° {orderDetail.LockQuantity}"); |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | |
| | | // æ£æ¥è®¢åç¶æ |
| | | // 3. æ£æ¥è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(orderNo); |
| | | |
| | | _logger.LogInformation($"æ¹æ¬¡åè®¢åæ°æ®æ´æ°å®æ"); |
| | | } |
| | | |
| | | private async Task RevertBatchAndOrderData(Dt_PickingRecord pickingRecord, RevertPickingResult revertResult) |
| | | { |
| | | // æ¢å¤æ¹æ¬¡å®ææ°é |
| | | _logger.LogInformation($"å¼å§æ¢å¤æ¹æ¬¡åè®¢åæ°æ®"); |
| | | |
| | | // 1. æ¢å¤æ¹æ¬¡å®ææ°é |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo); // ä½¿ç¨ OutboundBatchNo |
| | | .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo); |
| | | |
| | | if (batch != null) |
| | | { |
| | | decimal originalCompletedQty = batch.CompletedQuantity; |
| | | batch.CompletedQuantity -= pickingRecord.PickQuantity; |
| | | |
| | | _logger.LogInformation($"æ¢å¤æ¹æ¬¡å®ææ°é - ä» {originalCompletedQty} åå°å° {batch.CompletedQuantity}"); |
| | | |
| | | // éæ°è®¡ç®æ¹æ¬¡ç¶æ |
| | | if (batch.CompletedQuantity <= 0) |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.åé
ä¸; |
| | | _logger.LogInformation($"æ¹æ¬¡ç¶ææ¢å¤ä¸ºåé
ä¸"); |
| | | } |
| | | else if (batch.CompletedQuantity < batch.BatchQuantity) |
| | | { |
| | | batch.BatchStatus = (int)BatchStatusEnum.æ§è¡ä¸; |
| | | _logger.LogInformation($"æ¹æ¬¡ç¶ææ¢å¤ä¸ºæ§è¡ä¸"); |
| | | } |
| | | |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // æ¢å¤è®¢åæç» |
| | | // 2. æ¢å¤è®¢åæç» |
| | | 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(); |
| | | if (orderDetail != null) |
| | | { |
| | | decimal originalOverOutQty = orderDetail.OverOutQuantity; |
| | | decimal originalAllocatedQty = orderDetail.AllocatedQuantity; |
| | | decimal originalLockQty = orderDetail.LockQuantity; |
| | | |
| | | // éæ°æ£æ¥è®¢åç¶æ |
| | | // éè¦ä¿®å¤ï¼åªæ¢å¤ç¸å
³æ°éï¼åé
æ°éä¿æä¸å |
| | | orderDetail.OverOutQuantity -= pickingRecord.PickQuantity; |
| | | // 注æï¼AllocatedQuantity å LockQuantity å¨åæ¶åæ£æ¶ä¸åºè¯¥æ¹å |
| | | |
| | | _logger.LogInformation($"æ¢å¤è®¢åæç» - å·²åºåºæ°éä» {originalOverOutQty} åå°å° {orderDetail.OverOutQuantity}"); |
| | | _logger.LogInformation($"订åæç»åé
æ°éä¿æä¸å: {originalAllocatedQty}"); |
| | | _logger.LogInformation($"订åæç»é宿°éä¿æä¸å: {originalLockQty}"); |
| | | |
| | | await UpdateBatchAllocateStatus(orderDetail); |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // 3. éæ°æ£æ¥è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(pickingRecord.OrderNo); |
| | | |
| | | _logger.LogInformation($"æ¢å¤æ¹æ¬¡åè®¢åæ°æ®å®æ"); |
| | | } |
| | | |
| | | private async Task UpdateBatchAllocateStatus(Dt_OutboundOrderDetail orderDetail) |
| | | { |
| | | if (orderDetail.AllocatedQuantity >= orderDetail.NeedOutQuantity) |
| | | { |
| | | orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.AssignOver.ObjToInt(); |
| | | } |
| | | else if (orderDetail.AllocatedQuantity > 0) |
| | | { |
| | | orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.AssignOverPartial.ObjToInt(); |
| | | } |
| | | else |
| | | { |
| | | orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.New.ObjToInt(); |
| | | } |
| | | } |
| | | private async Task ReleaseLockAndStock(Dt_OutStockLockInfo lockInfo) |
| | | { |
| | |
| | | if (orderDetail != null) |
| | | { |
| | | orderDetail.AllocatedQuantity -= returnedQty; |
| | | // LockQuantity 忥åå°ï¼ä¿æä¸å·²åé
æ°éä¸è´ |
| | | orderDetail.LockQuantity = orderDetail.AllocatedQuantity; |
| | | |
| | | await UpdateBatchAllocateStatus(orderDetail); |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | |
| | | 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, bool isAutoSplit, decimal? originalStockQuantity = null) |
| | | { |
| | | var splitHistory = new Dt_SplitPackageRecord |
| | | { |
| | |
| | | NewBarcode = newBarcode, |
| | | SplitQty = splitQty, |
| | | SplitTime = DateTime.Now, |
| | | Status = (int)SplitPackageStatusEnum.å·²æå
|
| | | Status = (int)SplitPackageStatusEnum.å·²æå
, |
| | | IsAutoSplit = isAutoSplit , |
| | | // SplitType = isAutoSplit ? "èªå¨æå
" : "æå¨æå
" |
| | | OriginalStockQuantity = originalStockQuantity ?? stockDetail.StockQuantity, |
| | | //RemainingStockQuantity = stockDetail.StockQuantity - splitQty |
| | | }; |
| | | |
| | | await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync(); |
| | |
| | | |
| | | |
| | | #region DTOç±» |
| | | /// <summary> |
| | | /// æ¡ç ç¶æä¿¡æ¯DTO |
| | | /// </summary> |
| | | public class BarcodeStatusInfoDto |
| | | { |
| | | public string Barcode { get; set; } |
| | | public string OrderNo { get; set; } |
| | | public bool IsOriginalBarcode { get; set; } |
| | | public int SplitChainCount { get; set; } |
| | | public bool HasBeenPicked { get; set; } |
| | | public decimal TotalPickedQuantity { get; set; } |
| | | public int PickRecordCount { get; set; } |
| | | public int LockInfoStatus { get; set; } |
| | | public decimal LockInfoPickedQty { get; set; } |
| | | public decimal LockInfoAssignQty { get; set; } |
| | | public decimal StockQuantity { get; set; } |
| | | public int StockStatus { get; set; } |
| | | public bool CanCancelSplit { get; set; } |
| | | public bool NeedCancelPickFirst { get; set; } |
| | | public List<string> OperationSuggestions { get; set; } = new List<string>(); |
| | | } |
| | | public class PickedBarcodeInfo |
| | | { |
| | | public string Barcode { get; set; } |
| | | public decimal PickedQty { get; set; } |
| | | public int PickRecordCount { get; set; } |
| | | } |
| | | /// <summary> |
| | | /// èªå¨æå
ç»æ |
| | | /// </summary> |
| | | public class AutoSplitResult |
| | | { |
| | | public string NewBarcode { get; set; } |
| | | public decimal SplitQuantity { get; set; } |
| | | } |
| | | |
| | | public class PickingResult |
| | | { |