| | |
| | | using WIDESEA_Common.CommonEnum; |
| | | using WIDESEA_Common.OrderEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.BaseRepository; |
| | | using WIDESEA_Core.BaseServices; |
| | | using WIDESEA_Core.Enums; |
| | | using WIDESEA_DTO.Basic; |
| | | using WIDESEA_DTO.Outbound; |
| | | using WIDESEA_IAllocateService; |
| | | using WIDESEA_IBasicService; |
| | |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.CurrentBarcode == barcode |
| | | //&& x.Status == (int)OutLockStockStatusEnum.åºåºä¸ |
| | | //&& x.Status == (int)OutLockStockStatusEnum.åºåºä¸ |
| | | ) |
| | | .FirstAsync(); |
| | | |
| | |
| | | |
| | | #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 && 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 忹忣 |
| | | |
| | | /// <summary> |
| | |
| | | |
| | | (lockInfo, orderDetail, stockDetail, batch) = refreshedValidation.Data; |
| | | |
| | | // éè¦ä¿®å¤ï¼èªå¨æå
åï¼ç«å³æ§è¡åæ¡ç ç忣 |
| | | |
| | | var actualPickedQty = lockInfo.AssignQuantity; |
| | | var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty); |
| | | |
| | |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("èªå¨æå
并忣æå", new |
| | | { |
| | | AutoSplitted = true, |
| | | NewBarcode = autoSplitResult.NewBarcode, |
| | | OriginalBarcode = barcode, |
| | | SplitQuantity = autoSplitResult.SplitQuantity, |
| | | PickedQuantity = actualPickedQty, |
| | | MaterialCode = lockInfo.MaterielCode |
| | | }); |
| | | return WebResponseContent.Instance.OK("èªå¨æå
并忣æå", autoSplitResult); |
| | | } |
| | | |
| | | // æ£å¸¸åæ£æµç¨ï¼ä¸éè¦èªå¨æå
ï¼ |
| | |
| | | } |
| | | #endregion |
| | | |
| | | #region æå¨æå
|
| | | |
| | | #region æå¨æå
ç¸å
³æ¹æ³ |
| | | #region å走空箱é»è¾ |
| | | |
| | | |
| | | |
| | | /// <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 && 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 |
| | | |
| | | private List<SplitResult> CreateSplitResults(Dt_OutStockLockInfo lockInfo, decimal splitQty, decimal remainQty, string newBarcode, string originalBarcode) |
| | | { |
| | | return new List<SplitResult> |
| | | { |
| | | new SplitResult |
| | | { |
| | | materialCode = lockInfo.MaterielCode, |
| | | supplierCode = lockInfo.SupplyCode, |
| | | quantityTotal = splitQty.ToString("F2"), |
| | | batchNumber = newBarcode, |
| | | batch = lockInfo.BatchNo, |
| | | factory = lockInfo.FactoryArea, |
| | | date = DateTime.Now.ToString("yyyy-MM-dd"), |
| | | }, |
| | | new SplitResult |
| | | { |
| | | materialCode = lockInfo.MaterielCode, |
| | | supplierCode = lockInfo.SupplyCode, |
| | | quantityTotal = remainQty.ToString("F2"), |
| | | batchNumber = originalBarcode, |
| | | batch = lockInfo.BatchNo, |
| | | factory = lockInfo.FactoryArea, |
| | | date = DateTime.Now.ToString("yyyy-MM-dd"), |
| | | } |
| | | }; |
| | | } |
| | | |
| | | |
| | | |
| | | #region æå¨æå
|
| | | |
| | | /// <summary> |
| | | /// æå¨æå
|
| | |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("æå¨æå
æå", new |
| | | { |
| | | NewBarcode = splitResult.NewBarcode, |
| | | OriginalBarcode = originalBarcode, |
| | | SplitQuantity = splitQuantity |
| | | }); |
| | | return WebResponseContent.Instance.OK("æå¨æå
æå", splitResult); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | /// <summary> |
| | | /// æ§è¡æå¨æå
é»è¾ - å¢å¼ºåé
æ°éæ§å¶ |
| | | /// </summary> |
| | | private async Task<SplitResultDto> ExecuteManualSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | private async Task<List<SplitResult>> ExecuteManualSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡æå¨æå
é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå
æ°é: {splitQuantity}"); |
| | |
| | | // è®°å½æå
åçåé
æ°é |
| | | decimal originalAssignQtyBefore = lockInfo.AssignQuantity; |
| | | decimal originalOrderQtyBefore = lockInfo.OrderQuantity; |
| | | |
| | | // 1. å建æ°åºåæç» |
| | | decimal remainQty = originalAssignQtyBefore - splitQuantity; |
| | | if (remainQty < 0) |
| | | { |
| | | throw new InvalidOperationException($"æå
åå©ä½æ°éä¸ºè´æ°ï¼ååé
æ°é: {originalAssignQtyBefore}, æå
æ°é: {splitQuantity}"); |
| | | } |
| | | // å建æ°åºåæç» |
| | | var newStockDetail = new Dt_StockInfoDetail |
| | | { |
| | | StockId = stockDetail.StockId, |
| | |
| | | BarcodeQty = stockDetail.BarcodeQty, |
| | | BarcodeUnit = stockDetail.BarcodeUnit, |
| | | BusinessType = stockDetail.BusinessType, |
| | | InboundOrderRowNo = stockDetail.InboundOrderRowNo, |
| | | InboundOrderRowNo = stockDetail.InboundOrderRowNo, |
| | | }; |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°åºåæç» - æ¡ç : {newBarcode}, åºåæ°é: {splitQuantity}"); |
| | | |
| | | // 2. æ´æ°ååºåæç» |
| | | // æ´æ°ååºåæç» |
| | | decimal originalStockQtyBefore = stockDetail.StockQuantity; |
| | | stockDetail.StockQuantity -= splitQuantity; |
| | | if (stockDetail.StockQuantity < 0) |
| | | { |
| | | stockDetail.StockQuantity = 0; |
| | | _logger.LogWarning($"ååºåæ°éåºç°è´æ°ï¼é置为0"); |
| | | } |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ´æ°ååºåæç» - åºåæ°éä» {originalStockQtyBefore} åå°å° {stockDetail.StockQuantity}"); |
| | | |
| | | // 3. å建æ°éå®ä¿¡æ¯ |
| | | // å建æ°éå®ä¿¡æ¯ |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | OrderNo = lockInfo.OrderNo, |
| | |
| | | lineNo = lockInfo.lineNo, |
| | | WarehouseCode = lockInfo.WarehouseCode, |
| | | BarcodeQty = lockInfo.BarcodeQty, |
| | | BarcodeUnit = lockInfo.BarcodeUnit, |
| | | BarcodeUnit = lockInfo.BarcodeUnit, |
| | | }; |
| | | |
| | | await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°éå®ä¿¡æ¯ - æ¡ç : {newBarcode}, åé
æ°é: {splitQuantity}"); |
| | | |
| | | // 4. æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity -= splitQuantity; |
| | | lockInfo.OrderQuantity -= splitQuantity; |
| | | // æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity = remainQty; |
| | | lockInfo.OrderQuantity = remainQty; |
| | | |
| | | _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); |
| | | |
| | | // å建æå
ç»æå表 |
| | | var splitResults = CreateSplitResults(lockInfo, splitQuantity, remainQty, newBarcode, stockDetail.Barcode); |
| | | |
| | | _logger.LogInformation($"æå¨æå
é»è¾æ§è¡å®æ"); |
| | | |
| | | return new SplitResultDto { NewBarcode = newBarcode }; |
| | | return splitResults; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | #endregion |
| | | |
| | | |
| | |
| | | decimal originalAssignQtyBefore = originalLockInfo.AssignQuantity; |
| | | decimal originalOrderQtyBefore = originalLockInfo.OrderQuantity; |
| | | |
| | | // éè¦ä¿®å¤ï¼æ¢å¤åé
æ°éåè®¢åæ°é |
| | | |
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | originalLockInfo.OrderQuantity += splitRecord.SplitQty; |
| | | |
| | |
| | | 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(); |
| | | if (newLockInfo != null) |
| | | { |
| | | // å 餿°éå®ä¿¡æ¯ |
| | | _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(); |
| | | // å 餿°åºåæç» |
| | | _logger.LogInformation($"å 餿°åºåæç» - æ¡ç : {newStockDetail.Barcode}, åºåæ°é: {newStockDetail.StockQuantity}"); |
| | | await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == newLockInfo.CurrentBarcode) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // æ è®°æå
è®°å½ä¸ºå·²æ¤é |
| | | splitRecord.IsReverted = true; |
| | |
| | | return WebResponseContent.Instance.Error("è·åæ¡ç ç¶æå¤±è´¥"); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// <summary> |
| | | /// è·åæä½å»ºè®® |
| | | /// </summary> |
| | | private List<string> GetOperationSuggestions(BarcodeStatusInfoDto statusInfo) |
| | |
| | | NewBarcode = x.NewBarcode, |
| | | SplitQuantity = x.SplitQty, |
| | | Operator = x.Operator, |
| | | IsReverted = x.IsReverted , |
| | | IsReverted = x.IsReverted, |
| | | IsAutoSplit = x.IsAutoSplit |
| | | }).ToList() |
| | | }; |
| | |
| | | |
| | | #endregion |
| | | |
| | | |
| | | #region åæ¹ååº |
| | | #region ç»ä¸ååºé»è¾ |
| | | private async Task<Dt_Task> GetCurrentTask(string orderNo, string palletCode) |
| | | { |
| | | // å
å°è¯éè¿è®¢åå·åæçå·æ¥æ¾ä»»å¡ |
| | | var task = await _taskRepository.Db.Queryable<Dt_Task>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | |
| | | if (task == null) |
| | | { |
| | | // 妿æ¾ä¸å°ï¼åéè¿æçå·æ¥æ¾ |
| | | task = await _taskRepository.Db.Queryable<Dt_Task>() |
| | | .Where(x => x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | } |
| | | |
| | | return task; |
| | | } |
| | | private async Task<PalletStatusAnalysis> AnalyzePalletStatus(string orderNo, string palletCode, int stockId) |
| | | { |
| | | var result = new PalletStatusAnalysis |
| | | { |
| | | OrderNo = orderNo, |
| | | PalletCode = palletCode, |
| | | StockId = stockId |
| | | }; |
| | | |
| | | // åææªåæ£çåºåºéå®è®°å½ |
| | | var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | it.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .ToListAsync(); |
| | | |
| | | if (remainingLocks.Any()) |
| | | { |
| | | result.HasRemainingLocks = true; |
| | | result.RemainingLocks = remainingLocks; |
| | | result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | _logger.LogInformation($"åç°{remainingLocks.Count}æ¡æªåæ£éå®è®°å½ï¼æ»æ°é: {result.RemainingLocksReturnQty}"); |
| | | } |
| | | |
| | | // åææçä¸çåºåè´§ç© |
| | | var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.StockId == stockId && |
| | | (it.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt() || |
| | | it.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt() || |
| | | it.Status == StockStatusEmun.åºåºéå®.ObjToInt())) |
| | | .Where(it => it.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | if (palletStockGoods.Any()) |
| | | { |
| | | result.HasPalletStockGoods = true; |
| | | result.PalletStockGoods = palletStockGoods; |
| | | result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity); |
| | | _logger.LogInformation($"åç°{palletStockGoods.Count}个åºåè´§ç©ï¼æ»æ°é: {result.PalletStockReturnQty}"); |
| | | |
| | | // è®°å½è¯¦ç»ç¶æåå¸ |
| | | var statusGroups = palletStockGoods.GroupBy(x => x.Status); |
| | | foreach (var group in statusGroups) |
| | | { |
| | | _logger.LogInformation($"åºåç¶æ{group.Key}: {group.Count()}个货ç©ï¼æ°é: {group.Sum(x => x.StockQuantity)}"); |
| | | } |
| | | } |
| | | |
| | | //åææå
è®°å½ |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.å·²æ£é && |
| | | it.Status != (int)SplitPackageStatusEnum.å·²ååº) |
| | | .ToListAsync(); |
| | | |
| | | if (splitRecords.Any()) |
| | | { |
| | | result.HasSplitRecords = true; |
| | | result.SplitRecords = splitRecords; |
| | | result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId); |
| | | |
| | | _logger.LogInformation($"åç°{splitRecords.Count}æ¡æªæ£éæå
è®°å½ï¼æ»æ°é: {result.SplitReturnQty}"); |
| | | } |
| | | |
| | | // 4. è®¡ç®æ»ååºæ°éå空æçç¶æ |
| | | result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty; |
| | | result.HasItemsToReturn = result.TotalReturnQty > 0; |
| | | result.IsEmptyPallet = !result.HasItemsToReturn; |
| | | |
| | | // 5. æ£æ¥æ¯å¦æè¿è¡ä¸çä»»å¡ |
| | | result.HasActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>() |
| | | .Where(x => x.OrderNo == orderNo && x.TaskType == TaskTypeEnum.InPick.ObjToInt() && |
| | | x.PalletCode == palletCode && |
| | | x.TaskStatus == (int)TaskStatusEnum.New) |
| | | .AnyAsync(); |
| | | |
| | | _logger.LogInformation($"æçç¶æåæå®æ - 订å: {orderNo}, æç: {palletCode}, " + |
| | | $"æ»ååºæ°é: {result.TotalReturnQty}, æ¯å¦ç©ºæç: {result.IsEmptyPallet}, " + |
| | | $"æè¿è¡ä¸ä»»å¡: {result.HasActiveTasks}"); |
| | | |
| | | return result; |
| | | } |
| | | private async Task<decimal> CalculateSplitReturnQuantity(List<Dt_SplitPackageRecord> splitRecords, int stockId) |
| | | { |
| | | decimal totalQty = 0; |
| | | var processedBarcodes = new HashSet<string>(); |
| | | |
| | | foreach (var splitRecord in splitRecords) |
| | | { |
| | | if (splitRecord.Status != (int)SplitPackageStatusEnum.å·²æ¤é) |
| | | continue; |
| | | // æ£æ¥åæ¡ç |
| | | if (!processedBarcodes.Contains(splitRecord.OriginalBarcode)) |
| | | { |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId && |
| | | it.Status != StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | .FirstAsync(); |
| | | |
| | | if (originalStock != null && originalStock.StockQuantity > 0) |
| | | { |
| | | totalQty += originalStock.StockQuantity; |
| | | processedBarcodes.Add(splitRecord.OriginalBarcode); |
| | | } |
| | | } |
| | | |
| | | // æ£æ¥æ°æ¡ç |
| | | if (!processedBarcodes.Contains(splitRecord.NewBarcode)) |
| | | { |
| | | var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockId && it.Status != StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | .FirstAsync(); |
| | | |
| | | if (newStock != null && newStock.StockQuantity > 0) |
| | | { |
| | | totalQty += newStock.StockQuantity; |
| | | processedBarcodes.Add(splitRecord.NewBarcode); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return totalQty; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åæ¹ååº - éæ¾æªæ£éçåºå |
| | | /// ç»ä¸ååºæ¹æ³ - å¤çæç䏿æå©ä½è´§ç© |
| | | /// </summary> |
| | | public async Task<WebResponseContent> BatchReturnStock(string orderNo, string palletCode) |
| | | public async Task<WebResponseContent> ExecutePalletReturn(string orderNo, string palletCode, string returnReason = "åæ¹ååº") |
| | | { |
| | | 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 (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) |
| | | return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); |
| | | |
| | | if (!unfinishedLocks.Any()) |
| | | return WebResponseContent.Instance.Error("该æçæ²¡ææªå®æçéå®è®°å½"); |
| | | // è·ååºåä¿¡æ¯ |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>().FirstAsync(x => x.PalletCode == palletCode); |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); |
| | | |
| | | // æåºåºæ¹æ¬¡åç»å¤ç |
| | | var batchGroups = unfinishedLocks.GroupBy(x => x.OutboundBatchNo); // ä½¿ç¨ OutboundBatchNo |
| | | var task = await GetCurrentTask(orderNo, palletCode); |
| | | if (task == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡ä¿¡æ¯"); |
| | | |
| | | foreach (var batchGroup in batchGroups) |
| | | // åææçç¶æ |
| | | var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id); |
| | | if (!statusAnalysis.HasItemsToReturn) |
| | | return await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id); |
| | | |
| | | // æ£æ¥æ¯å¦æè¿è¡ä¸çä»»å¡ |
| | | if (statusAnalysis.HasActiveTasks) |
| | | { |
| | | var outboundBatchNo = batchGroup.Key; |
| | | var batchLocks = batchGroup.ToList(); |
| | | |
| | | // éæ¾åºååéå®è®°å½ |
| | | foreach (var lockInfo in batchLocks) |
| | | { |
| | | await ReleaseLockAndStock(lockInfo); |
| | | } |
| | | |
| | | // æ´æ°æ¹æ¬¡ç¶æ |
| | | await UpdateBatchStatusForReturn(outboundBatchNo, batchLocks); |
| | | |
| | | // æ´æ°è®¢åæç»çå·²åé
æ°é |
| | | await UpdateOrderDetailAfterReturn(batchLocks); |
| | | return WebResponseContent.Instance.Error($"æç {palletCode} æè¿è¡ä¸çä»»å¡ï¼ä¸è½æ§è¡ååºæä½"); |
| | | } |
| | | |
| | | // æ§è¡ååºæä½ |
| | | await ExecuteReturnDataOperations(orderNo, palletCode, stockInfo, task, statusAnalysis); |
| | | |
| | | // éæ¾ææéå®ä»¥ä¾¿éæ°åé
|
| | | await ReleaseAllLocksForReallocation(orderNo, palletCode, statusAnalysis); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK("åæ¹ååºæå"); |
| | | // æ¶éææéè¦ååºçæ¡ç |
| | | var returnBarcodes = await CollectReturnBarcodes(statusAnalysis); |
| | | |
| | | // å建ESSååºä»»å¡ |
| | | if (returnBarcodes.Any()) |
| | | { |
| | | _logger.LogInformation($"å建ååºAGVä»»å¡ - 订å: {orderNo}, æç: {palletCode}, æ¡ç æ°é: {returnBarcodes.Count}, åå : {returnReason}"); |
| | | await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InPick, stockInfo.PalletType); |
| | | } |
| | | |
| | | // æ´æ°è®¢åç¶æï¼ä¸è§¦åMESåä¼ ï¼ |
| | | await UpdateOrderStatusForReturn(orderNo); |
| | | |
| | | return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{statusAnalysis.TotalReturnQty}", new |
| | | { |
| | | ReturnQuantity = statusAnalysis.TotalReturnQty, |
| | | ReturnBarcodes = returnBarcodes, |
| | | Reason = returnReason, |
| | | PalletCode = palletCode, |
| | | OrderNo = orderNo |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"åæ¹ååºå¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¹ååºå¤±è´¥ï¼{ex.Message}"); |
| | | _logger.LogError($"ååºæä½å¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"ååºæä½å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | private async Task ExecuteReturnDataOperations(string orderNo, string palletCode, Dt_StockInfo stockInfo,Dt_Task task, PalletStatusAnalysis statusAnalysis) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡ååºæ°æ®æä½ - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | // 1. å¤çæªåæ£çéå®è®°å½ |
| | | if (statusAnalysis.HasRemainingLocks) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.RemainingLocks.Count} æ¡æªåæ£éå®è®°å½"); |
| | | await HandleRemainingLocksReturn(statusAnalysis.RemainingLocks); |
| | | } |
| | | |
| | | // 2. å¤çæçä¸çåºåè´§ç© |
| | | if (statusAnalysis.HasPalletStockGoods) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.PalletStockGoods.Count} 个åºåè´§ç©"); |
| | | await HandlePalletStockGoodsReturn(statusAnalysis.PalletStockGoods, stockInfo.Id); |
| | | } |
| | | |
| | | // 3. å¤çæå
è®°å½ |
| | | if (statusAnalysis.HasSplitRecords) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.SplitRecords.Count} æ¡æå
è®°å½"); |
| | | await HandleSplitRecordsReturn(statusAnalysis.SplitRecords, stockInfo.Id); |
| | | } |
| | | |
| | | _logger.LogInformation($"ååºæ°æ®æä½å®æ - æ»ååºæ°é: {statusAnalysis.TotalReturnQty}"); |
| | | } |
| | | /// <summary> |
| | | /// åæ¹ååº - è°ç¨ç»ä¸ååºæ¹æ³ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> BatchReturnStock(string orderNo, string palletCode) |
| | | { |
| | | return await ExecutePalletReturn(orderNo, palletCode, "åæ¹ååº"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å©ä½ååº - è°ç¨ç»ä¸ååºæ¹æ³ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason) |
| | | { |
| | | return await ExecutePalletReturn(orderNo, palletCode, reason); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å走空箱 - å
æ§è¡ååºåæ¸
ç - å¢å¼ºçæ¬ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | _logger.LogInformation($"å¼å§å走空箱 - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | // 1. éªè¯ç©ºç®±åèµ°æ¡ä»¶ï¼å¿
é¡»å
¨é¨å®ææ£éï¼ |
| | | var validationResult = await ValidateEmptyPalletRemoval(orderNo, palletCode); |
| | | if (!validationResult.IsValid) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | } |
| | | |
| | | var completedLocks = validationResult.Data; |
| | | |
| | | // 2. æ¸
ç已宿çéå®è®°å½ï¼æ 记为已åèµ°ï¼ |
| | | await CleanupCompletedLocks(completedLocks); |
| | | |
| | | // 3. æ¸
ç对åºçåºåè®°å½ç¶æ |
| | | foreach (var lockInfo in completedLocks) |
| | | { |
| | | await CleanupStockInfo(lockInfo); |
| | | } |
| | | |
| | | // 4. æ´æ°ç¸å
³è®¢åç¶æ |
| | | await UpdateOrderStatusAfterPalletRemoval(orderNo); |
| | | |
| | | // 5. è®°å½æä½åå² |
| | | await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | _logger.LogInformation($"å走空箱æå - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | 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<List<string>> CollectReturnBarcodes(PalletStatusAnalysis status) |
| | | { |
| | | var returnBarcodes = new HashSet<string>(); |
| | | |
| | | try |
| | | { |
| | | _logger.LogInformation($"å¼å§æ¶éååºæ¡ç - 订å: {status.OrderNo}, æç: {status.PalletCode}"); |
| | | |
| | | // 1. æ¶éæªåæ£éå®è®°å½çæ¡ç |
| | | if (status.HasRemainingLocks) |
| | | { |
| | | foreach (var lockInfo in status.RemainingLocks) |
| | | { |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | returnBarcodes.Add(lockInfo.CurrentBarcode); |
| | | _logger.LogInformation($"æ·»å éå®è®°å½æ¡ç : {lockInfo.CurrentBarcode}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 2. æ¶éæçä¸åºåè´§ç©çæ¡ç |
| | | if (status.HasPalletStockGoods) |
| | | { |
| | | foreach (var stockDetail in status.PalletStockGoods) |
| | | { |
| | | if (!string.IsNullOrEmpty(stockDetail.Barcode) && stockDetail.StockQuantity > 0) |
| | | { |
| | | returnBarcodes.Add(stockDetail.Barcode); |
| | | _logger.LogInformation($"æ·»å åºåè´§ç©æ¡ç : {stockDetail.Barcode}, æ°é: {stockDetail.StockQuantity}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 3. æ¶éæå
è®°å½ç¸å
³çæ¡ç |
| | | if (status.HasSplitRecords) |
| | | { |
| | | foreach (var splitRecord in status.SplitRecords) |
| | | { |
| | | // æ·»å åæ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.OriginalBarcode)) |
| | | { |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == status.StockId); |
| | | |
| | | if (originalStock != null && originalStock.StockQuantity > 0) |
| | | { |
| | | returnBarcodes.Add(splitRecord.OriginalBarcode); |
| | | _logger.LogInformation($"æ·»å æå
åæ¡ç : {splitRecord.OriginalBarcode}, æ°é: {originalStock.StockQuantity}"); |
| | | } |
| | | } |
| | | |
| | | // æ·»å æ°æ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.NewBarcode)) |
| | | { |
| | | var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.NewBarcode && x.StockId == status.StockId); |
| | | |
| | | if (newStock != null && newStock.StockQuantity > 0) |
| | | { |
| | | returnBarcodes.Add(splitRecord.NewBarcode); |
| | | _logger.LogInformation($"æ·»å æå
æ°æ¡ç : {splitRecord.NewBarcode}, æ°é: {newStock.StockQuantity}"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"ååºæ¡ç æ¶é宿 - å
± {returnBarcodes.Count} 个æ¡ç : {string.Join(", ", returnBarcodes)}"); |
| | | |
| | | return returnBarcodes.ToList(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"æ¶éååºæ¡ç 失败 - Error: {ex.Message}"); |
| | | return returnBarcodes.ToList(); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region ååºæä½æ ¸å¿æ¹æ³ |
| | | |
| | | /// <summary> |
| | | /// æ§è¡ååºæä½ - å¢å¼ºçæ¬ |
| | | /// </summary> |
| | | private async Task ExecuteReturnOperations(string orderNo, string palletCode, Dt_StockInfo stockInfo, |
| | | Dt_Task task, PalletStatusAnalysis statusAnalysis) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡ååºæä½ - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | // å¤çæªåæ£çéå®è®°å½ |
| | | if (statusAnalysis.HasRemainingLocks) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.RemainingLocks.Count} æ¡æªåæ£éå®è®°å½"); |
| | | await HandleRemainingLocksReturn(statusAnalysis.RemainingLocks); |
| | | } |
| | | |
| | | //å¤çæçä¸çåºåè´§ç© |
| | | if (statusAnalysis.HasPalletStockGoods) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.PalletStockGoods.Count} 个åºåè´§ç©"); |
| | | await HandlePalletStockGoodsReturn(statusAnalysis.PalletStockGoods, stockInfo.Id); |
| | | } |
| | | |
| | | //å¤çæå
è®°å½ |
| | | if (statusAnalysis.HasSplitRecords) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.SplitRecords.Count} æ¡æå
è®°å½"); |
| | | await HandleSplitRecordsReturn(statusAnalysis.SplitRecords, stockInfo.Id); |
| | | } |
| | | |
| | | _logger.LogInformation($"ååºæä½å®æ - æ»ååºæ°é: {statusAnalysis.TotalReturnQty}"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæªåæ£çéå®è®°å½ååº |
| | | /// </summary> |
| | | private async Task HandleRemainingLocksReturn(List<Dt_OutStockLockInfo> remainingLocks) |
| | | { |
| | | foreach (var lockInfo in remainingLocks) |
| | | { |
| | | // 计ç®ååºæ°éï¼æªæ£éçé¨åï¼ |
| | | decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | |
| | | if (returnQty > 0) |
| | | { |
| | | // æ¢å¤åºåç¶æ |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail != null) |
| | | { |
| | | stockDetail.StockQuantity += returnQty; |
| | | stockDetail.OutboundQuantity -= returnQty; |
| | | |
| | | // ç¡®ä¿åºåºæ°éä¸ä¼ä¸ºè´æ° |
| | | if (stockDetail.OutboundQuantity < 0) |
| | | { |
| | | stockDetail.OutboundQuantity = 0; |
| | | } |
| | | |
| | | // ååºååºåç¶ææ¢å¤ä¸ºå
¥åºå®æï¼å¯ç¨ç¶æï¼ |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¢å¤åºå - æ¡ç : {stockDetail.Barcode}, æ°é: {returnQty}, æ°åºå: {stockDetail.StockQuantity}"); |
| | | } |
| | | |
| | | // æ´æ°éå®è®°å½ç¶æä¸ºå·²ååº |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²ååº; |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ´æ°éå®ç¶æ - éå®ID: {lockInfo.Id}, ååºæ°é: {returnQty}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæçä¸çåºåè´§ç©ååº |
| | | /// </summary> |
| | | private async Task HandlePalletStockGoodsReturn(List<Dt_StockInfoDetail> palletStockGoods, int stockId) |
| | | { |
| | | foreach (var stockDetail in palletStockGoods) |
| | | { |
| | | // åªå¤çåºåºéå®ç¶æçåºå |
| | | if (stockDetail.Status == (int)StockStatusEmun.åºåºéå® && stockDetail.StockQuantity > 0) |
| | | { |
| | | // æ¢å¤åºåç¶æä¸ºå¯ç¨ç¶æ |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¢å¤åºåè´§ç© - æ¡ç : {stockDetail.Barcode}, æ°é: {stockDetail.StockQuantity}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæå
è®°å½ååº |
| | | /// </summary> |
| | | private async Task HandleSplitRecordsReturn(List<Dt_SplitPackageRecord> splitRecords, int stockId) |
| | | { |
| | | foreach (var splitRecord in splitRecords) |
| | | { |
| | | // å¤çæ°æ¡ç |
| | | var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == splitRecord.NewBarcode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .FirstAsync(); |
| | | |
| | | if (newLockInfo != null) |
| | | { |
| | | await HandleSingleLockReturn(newLockInfo); |
| | | } |
| | | |
| | | // å¤çåæ¡ç |
| | | var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == splitRecord.OriginalBarcode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .FirstAsync(); |
| | | |
| | | if (originalLockInfo != null) |
| | | { |
| | | await HandleSingleLockReturn(originalLockInfo); |
| | | } |
| | | |
| | | // æ´æ°æå
è®°å½ç¶æä¸ºå·²ååº |
| | | splitRecord.Status = (int)SplitPackageStatusEnum.å·²ååº; |
| | | await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çå个éå®è®°å½ååº |
| | | /// </summary> |
| | | private async Task HandleSingleLockReturn(Dt_OutStockLockInfo lockInfo) |
| | | { |
| | | decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | |
| | | if (returnQty > 0) |
| | | { |
| | | // æ¢å¤åºå |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail != null) |
| | | { |
| | | stockDetail.StockQuantity += returnQty; |
| | | stockDetail.OutboundQuantity -= returnQty; |
| | | |
| | | if (stockDetail.OutboundQuantity < 0) |
| | | { |
| | | stockDetail.OutboundQuantity = 0; |
| | | } |
| | | |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // æ´æ°éå®ç¶æ |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²ååº; |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"å¤çæå
ç¸å
³éå® - æ¡ç : {lockInfo.CurrentBarcode}, ååºæ°é: {returnQty}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éæ¾ææéå®ä»¥ä¾¿éæ°åé
|
| | | /// </summary> |
| | | private async Task ReleaseAllLocksForReallocation(string orderNo, string palletCode, PalletStatusAnalysis statusAnalysis) |
| | | { |
| | | // æ´æ°è®¢åæç»çå·²åé
æ°é |
| | | if (statusAnalysis.HasRemainingLocks) |
| | | { |
| | | var orderDetailGroups = statusAnalysis.RemainingLocks.GroupBy(x => x.OrderDetailId); |
| | | |
| | | foreach (var group in orderDetailGroups) |
| | | { |
| | | var orderDetailId = group.Key; |
| | | var returnedQty = group.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == orderDetailId); |
| | | |
| | | if (orderDetail != null) |
| | | { |
| | | orderDetail.AllocatedQuantity -= returnedQty; |
| | | orderDetail.LockQuantity = orderDetail.AllocatedQuantity; |
| | | |
| | | await UpdateBatchAllocateStatus(orderDetail); |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ´æ°è®¢åæç» - OrderDetailId: {orderDetailId}, åå°åé
æ°é: {returnedQty}"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region è¾
婿¹æ³ |
| | | |
| | | /// <summary> |
| | | /// å¤ç没æååºç©åçæ
åµ |
| | | /// </summary> |
| | | private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode, Dt_Task originalTask, int stockId) |
| | | { |
| | | _logger.LogInformation($"æç {palletCode} 没æéè¦ååºçç©å"); |
| | | |
| | | // æ£æ¥æ¯å¦æ¯ç©ºæç |
| | | var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockId); |
| | | if (statusAnalysis.IsEmptyPallet) |
| | | { |
| | | try |
| | | { |
| | | var locationtype = 0; |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .Where(x => x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>().FirstAsync(x => x.LocationCode == originalTask.SourceAddress); |
| | | locationtype = firstLocation?.LocationType ?? 1; |
| | | } |
| | | else |
| | | { |
| | | locationtype = stockInfo.LocationType; |
| | | _stockInfoService.DeleteData(stockInfo); |
| | | } |
| | | |
| | | var targetAddress = originalTask.TargetAddress; |
| | | |
| | | await CleanupZeroStockData(stockId); |
| | | |
| | | |
| | | var emptystockInfo = new Dt_StockInfo() { PalletType = PalletTypeEnum.Empty.ObjToInt(), StockStatus = StockStatusEmun.ç»çæå.ObjToInt(), PalletCode = palletCode, LocationType = locationtype }; |
| | | emptystockInfo.Details = new List<Dt_StockInfoDetail>(); |
| | | _stockInfoService.AddMaterielGroup(emptystockInfo); |
| | | //空æçå¦ä½å¤ç è¿æä¸ä¸ªåºåºä»»å¡è¦å¤çã |
| | | originalTask.PalletType = PalletTypeEnum.Empty.ObjToInt(); |
| | | |
| | | await CreateReturnTaskAndHandleESS(orderNo, palletCode, originalTask, TaskTypeEnum.InEmpty, PalletTypeEnum.Empty.ObjToInt()); |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($" HandleNoReturnItems 失败: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($" ååºç©ºæç失败ï¼"); |
| | | } |
| | | return WebResponseContent.Instance.OK("空æçååºä»»å¡å建æå"); |
| | | } |
| | | else |
| | | { |
| | | return WebResponseContent.Instance.Error("æçç¶æå¼å¸¸ï¼æç©å使 æ³è®¡ç®ååºæ°é"); |
| | | } |
| | | } |
| | | private async Task CleanupZeroStockData(int stockId) |
| | | { |
| | | try |
| | | { |
| | | // 1. å é¤åºåæ°é为0çæç»è®°å½ |
| | | var deleteDetailCount = await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId && x.StockQuantity == 0 && (x.Status == StockStatusEmun.åºåºå®æ.ObjToInt() || x.Status == |
| | | StockStatusEmun.å
¥åºå®æ.ObjToInt())) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await _stockInfoService.Db.Deleteable<Dt_StockInfo>() |
| | | .Where(x => x.Id == stockId).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¸
çé¶åºåæç»è®°å½ - StockId: {stockId}, å é¤è®°å½æ°: {deleteDetailCount}"); |
| | | |
| | | |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogWarning($"æ¸
çé¶åºåæ°æ®å¤±è´¥ - StockId: {stockId}, Error: {ex.Message}"); |
| | | // 注æï¼æ¸
ç失败ä¸åºè¯¥å½±å主æµç¨ |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// æ´æ°è®¢åç¶æï¼ååºåï¼ |
| | | /// </summary> |
| | | private async Task UpdateOrderStatusForReturn(string orderNo) |
| | | { |
| | | // æ£æ¥è®¢åæ¯å¦æææçé½å·²å®ææå·²ååº |
| | | var allLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ToListAsync(); |
| | | |
| | | var activeLocks = allLocks.Where(x => |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || |
| | | x.Status == (int)OutLockStockStatusEnum.ååºä¸).ToList(); |
| | | |
| | | // å¦ææ²¡ææ´»è·çéå®è®°å½ï¼æ´æ°è®¢åç¶æ |
| | | if (!activeLocks.Any()) |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => new Dt_OutboundOrder |
| | | { |
| | | OrderStatus = (int)OutOrderStatusEnum.åºåºå®æ, |
| | | }) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ´æ°è®¢åç¶æä¸ºåºåºå®æ - 订å: {orderNo}"); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | |
| | | |
| | | #region éªè¯æ¹æ³ |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>> ValidatePickingRequest( |
| | |
| | | /// <summary> |
| | | /// æ£æ¥å¹¶æ§è¡èªå¨æå
ï¼å¦æéè¦ï¼ |
| | | /// </summary> |
| | | private async Task<AutoSplitResult> CheckAndAutoSplitIfNeeded(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, string palletCode) |
| | | private async Task<List<SplitResult>> CheckAndAutoSplitIfNeeded(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, string palletCode) |
| | | { |
| | | // æ£æ¥æ¯å¦éè¦èªå¨æå
çæ¡ä»¶ï¼ |
| | | // 1. åºåæ°é大äºåé
æ°é |
| | |
| | | // æ§è¡èªå¨æå
|
| | | var splitResult = await ExecuteAutoSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); |
| | | |
| | | return new AutoSplitResult |
| | | { |
| | | NewBarcode = splitResult.NewBarcode, |
| | | SplitQuantity = splitQuantity |
| | | }; |
| | | return splitResult; |
| | | } |
| | | /// <summary> |
| | | /// æ§è¡èªå¨æå
é»è¾ |
| | | /// </summary> |
| | | private async Task<SplitResultDto> ExecuteAutoSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | private async Task<List<SplitResult>> ExecuteAutoSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡èªå¨æå
é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå
æ°é: {splitQuantity}"); |
| | |
| | | // éè¦ä¿®å¤ï¼è®°å½æå
åçåé
æ°é |
| | | decimal originalAssignQtyBefore = lockInfo.AssignQuantity; |
| | | decimal originalOrderQtyBefore = lockInfo.OrderQuantity; |
| | | decimal remainQty = originalAssignQtyBefore; // èªå¨æå
ååæ¡ç åé
æ°éä¿æä¸å |
| | | |
| | | // 1. å建æ°åºåæç»ï¼å©ä½é¨åï¼ |
| | | // å建æ°åºåæç»ï¼å©ä½é¨åï¼ |
| | | var newStockDetail = new Dt_StockInfoDetail |
| | | { |
| | | StockId = stockDetail.StockId, |
| | |
| | | BarcodeQty = stockDetail.BarcodeQty, |
| | | BarcodeUnit = stockDetail.BarcodeUnit, |
| | | BusinessType = stockDetail.BusinessType, |
| | | InboundOrderRowNo = stockDetail.InboundOrderRowNo, |
| | | InboundOrderRowNo = stockDetail.InboundOrderRowNo, |
| | | }; |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°åºåæç» - æ¡ç : {newBarcode}, åºåæ°é: {splitQuantity}"); |
| | | |
| | | // 2. æ´æ°ååºåæç» |
| | | // éè¦ä¿®å¤ï¼ååºåæ°é设置为åé
æ°éï¼ä¿æä¸åï¼ |
| | | decimal originalStockQtyBefore = stockDetail.StockQuantity; |
| | | // 注æï¼èªå¨æå
æ¶ï¼ååºåæ°éä¿æä¸åï¼å 为æä»¬è¦åæ£çå°±æ¯åé
æ°é |
| | | // æ´æ°ååºåæç» |
| | | // éè¦ä¿®å¤ï¼èªå¨æå
æ¶ï¼ååºåæ°éä¿æä¸åï¼å 为æä»¬è¦åæ£çå°±æ¯åé
æ°é |
| | | // stockDetail.StockQuantity ä¿æä¸å |
| | | |
| | | _logger.LogInformation($"ååºåæç»ä¿æä¸å - åºåæ°é: {stockDetail.StockQuantity}"); |
| | | |
| | | // 3. å建æ°éå®ä¿¡æ¯ï¼å©ä½é¨åï¼ |
| | | // å建æ°éå®ä¿¡æ¯ï¼å©ä½é¨åï¼ |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | OrderNo = lockInfo.OrderNo, |
| | |
| | | lineNo = lockInfo.lineNo, |
| | | WarehouseCode = lockInfo.WarehouseCode, |
| | | BarcodeQty = lockInfo.BarcodeQty, |
| | | BarcodeUnit = lockInfo.BarcodeUnit, |
| | | BarcodeUnit = lockInfo.BarcodeUnit, |
| | | }; |
| | | |
| | | await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°éå®ä¿¡æ¯ - æ¡ç : {newBarcode}, åé
æ°é: {splitQuantity}"); |
| | | |
| | | // 4. éè¦ä¿®å¤ï¼èªå¨æå
æ¶ï¼åéå®ä¿¡æ¯çåé
æ°éä¿æä¸å |
| | | // èªå¨æå
æ¶ï¼åéå®ä¿¡æ¯çåé
æ°éä¿æä¸å |
| | | // å 为èªå¨æå
åï¼åæ¡ç ä»ç¶éè¦è¢«åæ£ï¼åé
æ°éä¸åºè¯¥æ¹å |
| | | _logger.LogInformation($"åéå®ä¿¡æ¯ä¿æä¸å - åé
æ°é: {lockInfo.AssignQuantity}, è®¢åæ°é: {lockInfo.OrderQuantity}"); |
| | | |
| | | // 5. è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, true, originalStockQtyBefore); |
| | | // è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, true, stockDetail.StockQuantity); |
| | | |
| | | // å建æå
ç»æå表 |
| | | var splitResults = CreateSplitResults(lockInfo, splitQuantity, remainQty, newBarcode, stockDetail.Barcode); |
| | | |
| | | _logger.LogInformation($"èªå¨æå
é»è¾æ§è¡å®æ"); |
| | | |
| | | return new SplitResultDto { NewBarcode = newBarcode }; |
| | | return splitResults; |
| | | } |
| | | |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region æ ¸å¿é»è¾æ¹æ³ |
| | |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡åæ£é»è¾ - æ¡ç : {stockDetail.Barcode}, åé
æ°é: {lockInfo.AssignQuantity}, å®é
æ£é: {actualPickedQty}"); |
| | | |
| | | // éè¦ä¿®å¤ï¼å次éªè¯è®¢åæç»çåé
æ°éï¼é²æ¢å¹¶åæä½ï¼ |
| | | // 忬¡éªè¯è®¢åæç»çåé
æ°éï¼é²æ¢å¹¶åæä½ï¼ |
| | | if (orderDetail.AllocatedQuantity < actualPickedQty) |
| | | { |
| | | throw new InvalidOperationException($"订åæç»åé
æ°éä¸è¶³ï¼éè¦æ£é {actualPickedQty}ï¼å¯ç¨åé
æ°é {orderDetail.AllocatedQuantity}"); |
| | |
| | | throw new InvalidOperationException($"订åæç»é宿°éä¸è¶³ï¼éè¦æ£é {actualPickedQty}ï¼å¯ç¨é宿°é {orderDetail.LockQuantity}"); |
| | | } |
| | | |
| | | // 1. æ´æ°éå®ä¿¡æ¯ |
| | | // æ´æ°éå®ä¿¡æ¯ |
| | | lockInfo.PickedQty += actualPickedQty; |
| | | _logger.LogInformation($"æ´æ°éå®ä¿¡æ¯ - å·²æ£éæ°éä» {lockInfo.PickedQty - actualPickedQty} å¢å å° {lockInfo.PickedQty}"); |
| | | |
| | |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // 2. æ´æ°åºåä¿¡æ¯ |
| | | // æ´æ°åºåä¿¡æ¯ |
| | | decimal originalStockQty = stockDetail.StockQuantity; |
| | | decimal originalOutboundQty = stockDetail.OutboundQuantity; |
| | | |
| | |
| | | StockDetail = stockDetail |
| | | }; |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region æ°æ®æ´æ°æ¹æ³ |
| | |
| | | private async Task UpdateBatchAndOrderData(Dt_OutboundBatch batch, Dt_OutboundOrderDetail orderDetail, decimal pickedQty, string orderNo) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ´æ°æ¹æ¬¡åè®¢åæ°æ® - æ£éæ°é: {pickedQty}"); |
| | | var latestOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().FirstAsync(x => x.Id == orderDetail.Id); |
| | | |
| | | if (latestOrderDetail == null) |
| | | throw new InvalidOperationException("æªæ¾å°è®¢åæç»"); |
| | | |
| | | orderDetail = latestOrderDetail; |
| | | // éè¦ä¿®å¤ï¼éªè¯åé
æ°éä¸ä¼åæè´æ° |
| | | if (orderDetail.AllocatedQuantity < pickedQty) |
| | | { |
| | | throw new InvalidOperationException($"æ´æ°è®¢åæ°æ®æ¶åé
æ°éä¸è¶³ï¼éè¦åå° {pickedQty}ï¼å½ååé
æ°é {orderDetail.AllocatedQuantity}"); |
| | | decimal actualPickedQty = orderDetail.AllocatedQuantity; |
| | | _logger.LogWarning($"åé
æ°éä¸è¶³ï¼è°æ´æ£éæ°é - åéè¦: {pickedQty}, å®é
å¯ç¨: {actualPickedQty}"); |
| | | pickedQty = actualPickedQty; |
| | | } |
| | | |
| | | if (orderDetail.LockQuantity < pickedQty) |
| | | { |
| | | throw new InvalidOperationException($"æ´æ°è®¢åæ°æ®æ¶é宿°éä¸è¶³ï¼éè¦åå° {pickedQty}ï¼å½åé宿°é {orderDetail.LockQuantity}"); |
| | | decimal actualPickedQty = orderDetail.LockQuantity; |
| | | _logger.LogWarning($"é宿°éä¸è¶³ï¼è°æ´æ£éæ°é - åéè¦: {pickedQty}, å®é
å¯ç¨: {actualPickedQty}"); |
| | | pickedQty = actualPickedQty; |
| | | } |
| | | |
| | | // 1. æ´æ°æ¹æ¬¡å®ææ°é |
| | |
| | | } |
| | | await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); |
| | | |
| | | // 2. æ´æ°è®¢åæç» |
| | | // æ´æ°è®¢åæç» |
| | | decimal originalOverOutQty = orderDetail.OverOutQuantity; |
| | | decimal originalAllocatedQty = orderDetail.AllocatedQuantity; |
| | | decimal originalLockQty = orderDetail.LockQuantity; |
| | |
| | | orderDetail.AllocatedQuantity -= pickedQty; |
| | | // LockQuantity 忥åå° |
| | | orderDetail.LockQuantity = orderDetail.AllocatedQuantity; |
| | | |
| | | if (orderDetail.AllocatedQuantity < 0) orderDetail.AllocatedQuantity = 0; |
| | | if (orderDetail.LockQuantity < 0) orderDetail.LockQuantity = 0; |
| | | _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($"æ¹æ¬¡åè®¢åæ°æ®æ´æ°å®æ"); |
| | |
| | | { |
| | | _logger.LogInformation($"å¼å§æ¢å¤æ¹æ¬¡åè®¢åæ°æ®"); |
| | | |
| | | // 1. æ¢å¤æ¹æ¬¡å®ææ°é |
| | | // æ¢å¤æ¹æ¬¡å®ææ°é |
| | | var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() |
| | | .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo); |
| | | |
| | |
| | | { |
| | | decimal originalCompletedQty = batch.CompletedQuantity; |
| | | batch.CompletedQuantity -= pickingRecord.PickQuantity; |
| | | |
| | | if (batch.CompletedQuantity < 0) |
| | | { |
| | | batch.CompletedQuantity = 0; |
| | | _logger.LogWarning($"æ¹æ¬¡å®ææ°éåºç°è´æ°ï¼é置为0"); |
| | | } |
| | | _logger.LogInformation($"æ¢å¤æ¹æ¬¡å®ææ°é - ä» {originalCompletedQty} åå°å° {batch.CompletedQuantity}"); |
| | | |
| | | // éæ°è®¡ç®æ¹æ¬¡ç¶æ |
| | |
| | | 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; |
| | | // 注æï¼AllocatedQuantity å LockQuantity å¨åæ¶åæ£æ¶ä¸åºè¯¥æ¹å |
| | | orderDetail.AllocatedQuantity += pickingRecord.PickQuantity; |
| | | orderDetail.LockQuantity += pickingRecord.PickQuantity; |
| | | if (orderDetail.OverOutQuantity < 0) orderDetail.OverOutQuantity = 0; |
| | | if (orderDetail.AllocatedQuantity < 0) orderDetail.AllocatedQuantity = 0; |
| | | if (orderDetail.LockQuantity < 0) orderDetail.LockQuantity = 0; |
| | | |
| | | _logger.LogInformation($"æ¢å¤è®¢åæç» - å·²åºåºæ°éä» {originalOverOutQty} åå°å° {orderDetail.OverOutQuantity}"); |
| | | _logger.LogInformation($"订åæç»åé
æ°éä¿æä¸å: {originalAllocatedQty}"); |
| | |
| | | } |
| | | #endregion |
| | | |
| | | private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, TaskTypeEnum taskTypeEnum, int palletType) |
| | | { |
| | | var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>() |
| | | .FirstAsync(x => x.LocationCode == originalTask.SourceAddress); |
| | | |
| | | // åé
æ°è´§ä½ |
| | | var newLocation = _locationInfoService.AssignLocation(firstLocation.LocationType); |
| | | |
| | | Dt_Task returnTask = new() |
| | | { |
| | | CurrentAddress = stations[originalTask.TargetAddress], |
| | | Grade = 0, |
| | | PalletCode = palletCode, |
| | | NextAddress = "", |
| | | // OrderNo = originalTask.OrderNo, |
| | | OrderNo = orderNo, |
| | | Roadway = newLocation.RoadwayNo, |
| | | SourceAddress = stations[originalTask.TargetAddress], |
| | | TargetAddress = newLocation.LocationCode, |
| | | TaskStatus = TaskStatusEnum.New.ObjToInt(), |
| | | TaskType = taskTypeEnum.ObjToInt(), |
| | | PalletType = palletType, |
| | | WarehouseId = originalTask.WarehouseId |
| | | |
| | | }; |
| | | // ä¿åååºä»»å¡ |
| | | await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync(); |
| | | var targetAddress = originalTask.TargetAddress; |
| | | |
| | | // å é¤åå§åºåºä»»å¡ |
| | | _taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.èªå¨å®æ); |
| | | // await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | |
| | | |
| | | |
| | | // ç» ESS åéæµå¨ä¿¡å·ååå»ºä»»å¡ |
| | | await SendESSCommands(palletCode, targetAddress, returnTask); |
| | | } |
| | | /// <summary> |
| | | /// ç»ESSä¸ä»»å¡ |
| | | /// </summary> |
| | | /// <param name="palletCode"></param> |
| | | /// <param name="targetAddress"></param> |
| | | /// <param name="returnTask"></param> |
| | | /// <returns></returns> |
| | | /// <exception cref="Exception"></exception> |
| | | private async Task SendESSCommands(string palletCode, string targetAddress, Dt_Task returnTask) |
| | | { |
| | | try |
| | | { |
| | | // 1. åéæµå¨ä¿¡å· |
| | | var moveResult = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest |
| | | { |
| | | slotCode = movestations[targetAddress], |
| | | containerCode = palletCode |
| | | }); |
| | | |
| | | //if (moveResult) |
| | | //{ |
| | | // 2. å建ååºä»»å¡ |
| | | var essTask = new TaskModel() |
| | | { |
| | | taskType = "putaway", |
| | | taskGroupCode = "", |
| | | groupPriority = 0, |
| | | tasks = new List<TasksType>{ new() { |
| | | taskCode = returnTask.TaskNum.ToString(), |
| | | taskPriority = 0, |
| | | taskDescribe = new TaskDescribeType |
| | | { |
| | | containerCode = palletCode, |
| | | containerType = "CT_KUBOT_STANDARD", |
| | | fromLocationCode = stations.GetValueOrDefault(targetAddress) ?? "", |
| | | toStationCode = "", |
| | | toLocationCode = returnTask.TargetAddress, |
| | | deadline = 0, |
| | | storageTag = "" |
| | | } |
| | | } } |
| | | }; |
| | | |
| | | var resultTask = await _eSSApiService.CreateTaskAsync(essTask); |
| | | _logger.LogInformation($"ReturnRemaining åå»ºä»»å¡æå: {resultTask}"); |
| | | //} |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"ReturnRemaining ESSå½ä»¤åé失败: {ex.Message}"); |
| | | throw new Exception($"ESSç³»ç»é信失败: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | |
| | | #region è¾
婿¹æ³ |
| | | |
| | | private async Task<string> GenerateNewBarcode() |
| | |
| | | SplitQty = splitQty, |
| | | SplitTime = DateTime.Now, |
| | | Status = (int)SplitPackageStatusEnum.å·²æå
, |
| | | IsAutoSplit = isAutoSplit , |
| | | IsAutoSplit = isAutoSplit, |
| | | // SplitType = isAutoSplit ? "èªå¨æå
" : "æå¨æå
" |
| | | OriginalStockQuantity = originalStockQuantity ?? stockDetail.StockQuantity, |
| | | //RemainingStockQuantity = stockDetail.StockQuantity - splitQty |
| | |
| | | } |
| | | |
| | | #endregion |
| | | } |
| | | |
| | | |
| | | // æ¯æç±» |
| | | public class SplitResultDto |
| | | { |
| | | public string NewBarcode { get; set; } |
| | | } |
| | | } |