| | |
| | | // éªè¯åæ£è¯·æ± |
| | | var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode); |
| | | if (!validationResult.IsValid) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | } |
| | | |
| | | var (lockInfo, orderDetail, stockDetail, batch) = validationResult.Data; |
| | | |
| | |
| | | #region å走空箱é»è¾ |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// éªè¯ç©ºç®±åèµ°æ¡ä»¶ |
| | | /// éªè¯ç©ºç®±åèµ°æ¡ä»¶ |
| | | /// </summary> |
| | | private async Task<ValidationResult<List<Dt_OutStockLockInfo>>> ValidateEmptyPalletRemoval(string orderNo, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§éªè¯ç©ºæçåèµ° - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | // è·åæççææéå®è®°å½ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | |
| | | if (!lockInfos.Any()) |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Error("该æç没æéå®è®°å½"); |
| | | |
| | | // æ£æ¥æ¯å¦ææªå®æçéå®è®°å½ |
| | | // è·ååºåä¿¡æ¯ |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°æççåºåä¿¡æ¯ï¼å¯è½å·²è¢«æ¸
ç"); |
| | | // 妿æ¾ä¸å°åºåä¿¡æ¯ï¼åªæ£æ¥éå®è®°å½ |
| | | } |
| | | else |
| | | { |
| | | // æ£æ¥æç䏿¯å¦è¿æåºåè´§ç© |
| | | var remainingStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockInfo.Id && |
| | | x.StockQuantity > 0) // åªæ£æ¥æ°é大äº0çåºå |
| | | .ToListAsync(); |
| | | |
| | | if (remainingStock.Any()) |
| | | { |
| | | var remainingQty = remainingStock.Sum(x => x.StockQuantity); |
| | | var barcodes = string.Join(", ", remainingStock.Select(x => x.Barcode).Take(5)); // åªæ¾ç¤ºå5个 |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Error( |
| | | $"æçä¸è¿æåºåè´§ç©ï¼æ°é{remainingQty}ï¼æ¡ç : {barcodes}ï¼ä¸è½å走空箱"); |
| | | } |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦ææªå®æçéå®è®°å½ï¼ç¶æä¸ºåºåºä¸æååºä¸ï¼ |
| | | var unfinishedLocks = lockInfos.Where(x => |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || |
| | | x.Status == (int)OutLockStockStatusEnum.ååºä¸).ToList(); |
| | |
| | | $"æçè¿æ{unfinishedCount}æ¡æªå®æè®°å½ï¼å©ä½æ°é{unfinishedQty}ï¼ä¸è½å走空箱"); |
| | | } |
| | | |
| | | // æ£æ¥æç䏿¯å¦è¿æåºåè´§ç© |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | |
| | | if (stockInfo != null) |
| | | { |
| | | var remainingStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockInfo.Id && |
| | | x.Status == (int)StockStatusEmun.åºåºéå® && |
| | | x.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | if (remainingStock.Any()) |
| | | { |
| | | var remainingQty = remainingStock.Sum(x => x.StockQuantity); |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Error( |
| | | $"æçä¸è¿æåºåè´§ç©ï¼æ°é{remainingQty}ï¼ä¸è½å走空箱"); |
| | | } |
| | | } |
| | | |
| | | // è·å已宿çéå®è®°å½ |
| | | // è·å已宿çéå®è®°å½ï¼ç¶æä¸ºæ£é宿æå·²åèµ°ï¼ |
| | | var completedLocks = lockInfos.Where(x => |
| | | x.Status == (int)OutLockStockStatusEnum.æ£é宿).ToList(); |
| | | x.Status == (int)OutLockStockStatusEnum.æ£é宿 || |
| | | x.Status == (int)OutLockStockStatusEnum.å·²åèµ°).ToList(); |
| | | |
| | | if (!completedLocks.Any()) |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Error("该æç没æå·²å®ææ£éçè®°å½"); |
| | | |
| | | _logger.LogInformation($"空æçéªè¯éè¿ - æ¾å° {completedLocks.Count} æ¡å·²å®æè®°å½"); |
| | | |
| | | return ValidationResult<List<Dt_OutStockLockInfo>>.Success(completedLocks); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// æ¸
ç已宿çéå®è®°å½ |
| | |
| | | } |
| | | |
| | | /// <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.åºåºå®æ) |
| | | try |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å·²æ¸
ç; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | // æ¥æ¾éå®çåºåæç» |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail != null) |
| | | { |
| | | // è®°å½æ¸
çåçç¶æ |
| | | decimal originalQty = stockDetail.StockQuantity; |
| | | int originalStatus = stockDetail.Status; |
| | | |
| | | // 妿åºåæ°é大äº0ï¼éè¦å
æ¸
é¶ |
| | | if (stockDetail.StockQuantity > 0) |
| | | { |
| | | _logger.LogWarning($"å走空æçæ¶åç°æ¡ç {lockInfo.CurrentBarcode} è¿æåºå {stockDetail.StockQuantity}ï¼èªå¨æ¸
é¶"); |
| | | stockDetail.StockQuantity = 0; |
| | | stockDetail.OutboundQuantity = 0; |
| | | } |
| | | |
| | | // æ 记为已æ¸
çç¶æ |
| | | stockDetail.Status = (int)StockStatusEmun.å·²æ¸
ç; |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¸
çåºåæç» - æ¡ç : {stockDetail.Barcode}, åç¶æ: {originalStatus} -> å·²æ¸
ç, åæ°é: {originalQty} -> 0"); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°æ¡ç 对åºçåºåæç»: {lockInfo.CurrentBarcode}"); |
| | | } |
| | | |
| | | // åæ¶æ¸
ç该æçä¸çææåºåï¼é¿å
éæ¼ï¼ |
| | | var allStockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == lockInfo.StockId && x.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | if (allStockDetails.Any()) |
| | | { |
| | | foreach (var stock in allStockDetails) |
| | | { |
| | | stock.StockQuantity = 0; |
| | | stock.OutboundQuantity = 0; |
| | | stock.Status = (int)StockStatusEmun.å·²æ¸
ç; |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stock).ExecuteCommandAsync(); |
| | | _logger.LogWarning($"æ¸
çéæ¼åºå - æ¡ç : {stock.Barcode}, æ°é: {stock.StockQuantity} -> 0"); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"æ¸
çåºåä¿¡æ¯å¤±è´¥ - éå®ID: {lockInfo.Id}, æ¡ç : {lockInfo.CurrentBarcode}, Error: {ex.Message}"); |
| | | // 䏿åºå¼å¸¸ï¼ç»§ç»å¤çå
¶ä»è®°å½ |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ§è¡æå¨æå
é»è¾ - å¢å¼ºåé
æ°éæ§å¶ |
| | | /// æ§è¡æå¨æå
é»è¾ - 宿´çæ¬ |
| | | /// </summary> |
| | | private async Task<List<SplitResult>> ExecuteManualSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡æå¨æå
é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå
æ°é: {splitQuantity}"); |
| | | |
| | | // éªè¯æå
æ°é |
| | | if (lockInfo.AssignQuantity < splitQuantity) |
| | | try |
| | | { |
| | | throw new InvalidOperationException($"æå
æ°éè¶
è¿éå®ä¿¡æ¯åé
æ°éï¼æå
æ°é: {splitQuantity}, åé
æ°é: {lockInfo.AssignQuantity}"); |
| | | // éªè¯åºåæ°éæ¯å¦è¶³å¤ |
| | | decimal availableStock = stockDetail.StockQuantity; |
| | | if (availableStock < splitQuantity) |
| | | { |
| | | throw new InvalidOperationException($"åºåä¸è¶³ï¼å½ååºå: {availableStock}, éè¦æå
: {splitQuantity}"); |
| | | } |
| | | |
| | | // éªè¯æå
æ°éä¸è½çäºæå¤§äºåéå®ä¿¡æ¯åé
æ°é |
| | | if (splitQuantity >= lockInfo.AssignQuantity) |
| | | { |
| | | throw new InvalidOperationException($"æå
æ°éä¸è½çäºæå¤§äºåéå®ä¿¡æ¯åé
æ°éï¼æå
æ°é: {splitQuantity}, ååé
æ°é: {lockInfo.AssignQuantity}"); |
| | | } |
| | | |
| | | // 计ç®å©ä½æ°é |
| | | decimal remainQty = lockInfo.AssignQuantity - splitQuantity; |
| | | |
| | | // éªè¯å©ä½æ°éæ¯å¦åç |
| | | if (remainQty <= 0) |
| | | { |
| | | throw new InvalidOperationException($"æå
åå©ä½æ°éå¿
须大äº0ï¼å½åå©ä½: {remainQty}"); |
| | | } |
| | | |
| | | _logger.LogInformation($"æå
è®¡ç® - ååé
æ°é: {lockInfo.AssignQuantity}, æå
æ°é: {splitQuantity}, å©ä½æ°é: {remainQty}"); |
| | | _logger.LogInformation($"ååºåä¿¡æ¯ - åºåæ°é: {stockDetail.StockQuantity}, åºåºæ°é: {stockDetail.OutboundQuantity}"); |
| | | |
| | | // çææ°æ¡ç |
| | | string newBarcode = await GenerateNewBarcode(); |
| | | _logger.LogInformation($"çææ°æ¡ç : {newBarcode}"); |
| | | |
| | | // è®°å½æå
åçå
³é®æ°æ® |
| | | decimal originalLockAssignQty = lockInfo.AssignQuantity; |
| | | decimal originalLockOrderQty = lockInfo.OrderQuantity; |
| | | decimal originalStockQty = stockDetail.StockQuantity; |
| | | decimal originalOutboundQty = stockDetail.OutboundQuantity; |
| | | |
| | | // å建æ°åºåæç» |
| | | 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}"); |
| | | |
| | | // ä¿®æ£ï¼æ´æ°ååºåæç» - ç¡®ä¿æ°æ®ä¸è´æ§ |
| | | // ååºååå°æå
æ°éï¼ä½åºåºæ°éä¿æä¸åï¼å ä¸ºæ¯æå¨æå
ï¼ä¸æ¶åå®é
åºåºï¼ |
| | | stockDetail.StockQuantity -= splitQuantity; |
| | | |
| | | // ç¡®ä¿ä¸ä¼ä¸ºè´æ° |
| | | if (stockDetail.StockQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"ååºåæ°éåºç°è´æ°ï¼é置为0"); |
| | | stockDetail.StockQuantity = 0; |
| | | } |
| | | |
| | | // åºåºæ°éä¿æä¸å |
| | | // stockDetail.OutboundQuantity = stockDetail.OutboundQuantity; // ä¿æä¸å |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ´æ°ååºåæç» - æ¡ç : {stockDetail.Barcode}, " + |
| | | $"åºåæ°é: {originalStockQty} -> {stockDetail.StockQuantity}, " + |
| | | $"åºåºæ°é: {originalOutboundQty} -> {stockDetail.OutboundQuantity}"); |
| | | |
| | | // å建æ°éå®ä¿¡æ¯ |
| | | 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}"); |
| | | |
| | | // æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity = remainQty; |
| | | lockInfo.OrderQuantity = remainQty; |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ´æ°åéå®ä¿¡æ¯ - åé
æ°é: {originalLockAssignQty} -> {lockInfo.AssignQuantity}, " + |
| | | $"è®¢åæ°é: {originalLockOrderQty} -> {lockInfo.OrderQuantity}"); |
| | | |
| | | // éè¦ï¼æå¨æå
䏿¹å订åæç»çæ»åé
æ°é |
| | | // éªè¯è®¢åæç»çæ»åé
æ°éæ¯å¦ä¿æä¸å |
| | | await ValidateOrderDetailAllocationAfterSplit(lockInfo.OrderDetailId, originalLockAssignQty); |
| | | |
| | | // è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, false, originalStockQty); |
| | | |
| | | // å建æå
ç»æå表 |
| | | var splitResults = CreateSplitResults(lockInfo, splitQuantity, remainQty, newBarcode, stockDetail.Barcode); |
| | | |
| | | // éªè¯æå
åæ°æ®ä¸è´æ§ |
| | | await ValidateDataConsistencyAfterSplit(lockInfo.OrderDetailId, originalLockAssignQty, originalLockOrderQty); |
| | | |
| | | _logger.LogInformation($"æå¨æå
é»è¾æ§è¡å®æ - åæ¡ç : {stockDetail.Barcode}, æ°æ¡ç : {newBarcode}, æå
æ°é: {splitQuantity}"); |
| | | |
| | | return splitResults; |
| | | } |
| | | |
| | | // çææ°æ¡ç |
| | | string newBarcode = await GenerateNewBarcode(); |
| | | |
| | | // 计ç®å©ä½æ°é |
| | | decimal remainQty = lockInfo.AssignQuantity - splitQuantity; |
| | | |
| | | // å建æ°åºåæç» |
| | | var newStockDetail = new Dt_StockInfoDetail |
| | | catch (Exception ex) |
| | | { |
| | | 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(); |
| | | |
| | | // æ´æ°ååºåæç» |
| | | stockDetail.StockQuantity -= splitQuantity; |
| | | if (stockDetail.StockQuantity < 0) stockDetail.StockQuantity = 0; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | // å建æ°éå®ä¿¡æ¯ |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | _logger.LogError($"æå¨æå
é»è¾æ§è¡å¤±è´¥ - åæ¡ç : {stockDetail.Barcode}, æå
æ°é: {splitQuantity}, Error: {ex.Message}"); |
| | | throw; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// éªè¯æå
å订åæç»çåé
æ°éæ¯å¦ä¿æä¸å |
| | | /// </summary> |
| | | private async Task ValidateOrderDetailAllocationAfterSplit(long orderDetailId, decimal originalTotalAssignQty) |
| | | { |
| | | try |
| | | { |
| | | 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, |
| | | }; |
| | | // è·å订åæç»çææéå®ä¿¡æ¯çæ»åé
æ°é |
| | | var allLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderDetailId == orderDetailId) |
| | | .ToListAsync(); |
| | | |
| | | await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); |
| | | decimal totalLockAssignQty = allLocks.Sum(x => x.AssignQuantity); |
| | | |
| | | // æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity = remainQty; |
| | | lockInfo.OrderQuantity = remainQty; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æå
ååé
æ°ééªè¯ - 订åæç»ID: {orderDetailId}"); |
| | | _logger.LogInformation($"åå§æ»åé
æ°é: {originalTotalAssignQty}, å½åæ»åé
æ°é: {totalLockAssignQty}"); |
| | | |
| | | // éè¦ï¼æå¨æå
䏿¹å订åæç»çæ»åé
æ°é |
| | | // å 为åé
æ°éåªæ¯ä»ä¸ä¸ªéå®ä¿¡æ¯è½¬ç§»å°å¦ä¸ä¸ªéå®ä¿¡æ¯ |
| | | _logger.LogInformation($"æå¨æå
- 订åæç»æ»åé
æ°éä¿æä¸å"); |
| | | // æå¨æå
åæ»åé
æ°éåºè¯¥ä¿æä¸å |
| | | if (Math.Abs(originalTotalAssignQty - totalLockAssignQty) > 0.01m) |
| | | { |
| | | _logger.LogWarning($"æå
åæ»åé
æ°éåçåå - ææ: {originalTotalAssignQty}, å®é
: {totalLockAssignQty}"); |
| | | |
| | | // è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, false); |
| | | |
| | | // å建æå
ç»æå表 |
| | | var splitResults = CreateSplitResults(lockInfo, splitQuantity, remainQty, newBarcode, stockDetail.Barcode); |
| | | |
| | | _logger.LogInformation($"æå¨æå
é»è¾æ§è¡å®æ"); |
| | | |
| | | return splitResults; |
| | | // 妿ååå¾å°ï¼å¯è½æ¯ç²¾åº¦é®é¢ï¼è®°å½ä½ä¸æåºå¼å¸¸ |
| | | if (Math.Abs(originalTotalAssignQty - totalLockAssignQty) > 1.0m) |
| | | { |
| | | throw new InvalidOperationException($"æå
åæ»åé
æ°éå¼å¸¸ååï¼ææ: {originalTotalAssignQty}, å®é
: {totalLockAssignQty}"); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation($"æå
ååé
æ°ééªè¯éè¿ - æ»åé
æ°éä¿æä¸å"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"éªè¯æå
ååé
æ°é失败 - OrderDetailId: {orderDetailId}, Error: {ex.Message}"); |
| | | throw; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// éªè¯æå
åæ°æ®ä¸è´æ§ |
| | |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡åæ¶æå
é»è¾ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}, æå
æ°é: {splitRecord.SplitQty}"); |
| | | |
| | | try |
| | | { |
| | | // æ ¹æ®æå
ç±»åè°ç¨ä¸åçå¤çæ¹æ³ |
| | | if (splitRecord.IsAutoSplit) |
| | | { |
| | | await HandleAutoSplitCancel(splitRecord, originalLockInfo, newLockInfo, newStockDetail); |
| | | } |
| | | else |
| | | { |
| | | await HandleManualSplitCancel(splitRecord, originalLockInfo, newLockInfo, newStockDetail); |
| | | } |
| | | |
| | | // éªè¯åæ¶æå
åæ°æ®ä¸è´æ§ |
| | | await ValidateDataConsistencyAfterCancelSplit(originalLockInfo.OrderDetailId, |
| | | originalLockInfo.AssignQuantity, originalLockInfo.OrderQuantity, |
| | | splitRecord.IsAutoSplit, splitRecord.SplitQty); |
| | | |
| | | // æ£æ¥å¹¶æ´æ°æ¹æ¬¡å订åç¶æ |
| | | await CheckAndUpdateBatchStatus(originalLockInfo.BatchNo); |
| | | await CheckAndUpdateOrderStatus(originalLockInfo.OrderNo); |
| | | |
| | | _logger.LogInformation($"åæ¶æå
é»è¾æ§è¡å®æ"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"åæ¶æå
é»è¾æ§è¡å¤±è´¥: {ex.Message}"); |
| | | throw; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çèªå¨æå
åæ¶ |
| | | /// </summary> |
| | | private async Task HandleAutoSplitCancel(Dt_SplitPackageRecord splitRecord, |
| | | Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo, |
| | | Dt_StockInfoDetail newStockDetail) |
| | | { |
| | | _logger.LogInformation($"å¤çèªå¨æå
åæ¶ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); |
| | | |
| | | // è·å订åæç» |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == originalLockInfo.OrderDetailId); |
| | |
| | | if (orderDetail == null) |
| | | throw new InvalidOperationException("æªæ¾å°è®¢åæç»"); |
| | | |
| | | // è®°å½åæ¶æå
åçå
³é®æ°æ® |
| | | decimal originalOrderDetailAllocatedQty = orderDetail.AllocatedQuantity; |
| | | decimal originalOrderDetailLockQty = orderDetail.LockQuantity; |
| | | // 1. æ¢å¤è®¢åæç»çåé
æ°éï¼èªå¨æå
ä¼å¢å åé
æ°éï¼ |
| | | decimal originalAllocatedQty = orderDetail.AllocatedQuantity; |
| | | decimal originalLockQty = orderDetail.LockQuantity; |
| | | |
| | | _logger.LogInformation($"åæ¶æå
åæ°æ® - 订åæç»åé
æ°é: {originalOrderDetailAllocatedQty}, é宿°é: {originalOrderDetailLockQty}"); |
| | | orderDetail.AllocatedQuantity -= splitRecord.SplitQty; |
| | | orderDetail.LockQuantity -= splitRecord.SplitQty; |
| | | |
| | | // æ¢å¤åéå®ä¿¡æ¯ |
| | | decimal originalAssignQtyBefore = originalLockInfo.AssignQuantity; |
| | | decimal originalOrderQtyBefore = originalLockInfo.OrderQuantity; |
| | | // è¾¹çæ£æ¥ |
| | | if (orderDetail.AllocatedQuantity < 0) orderDetail.AllocatedQuantity = 0; |
| | | if (orderDetail.LockQuantity < 0) orderDetail.LockQuantity = 0; |
| | | |
| | | // æ ¹æ®æå
ç±»åå³å®å¦ä½æ¢å¤ |
| | | if (splitRecord.IsAutoSplit) |
| | | { |
| | | // èªå¨æå
ï¼åéå®ä¿¡æ¯ä¿æä¸åï¼åªéè¦å 餿°éå®ä¿¡æ¯ |
| | | _logger.LogInformation($"åæ¶èªå¨æå
- åéå®ä¿¡æ¯ä¿æä¸å"); |
| | | } |
| | | else |
| | | { |
| | | // æå¨æå
ï¼æ¢å¤åéå®ä¿¡æ¯çåé
æ°é |
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | originalLockInfo.OrderQuantity += splitRecord.SplitQty; |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"èªå¨æå
åæ¶æ¢å¤è®¢åæç» - åé
æ°é: {originalAllocatedQty} -> {orderDetail.AllocatedQuantity}"); |
| | | |
| | | _logger.LogInformation($"åæ¶æå¨æå
- æ¢å¤åéå®ä¿¡æ¯åé
æ°éä» {originalAssignQtyBefore} å¢å å° {originalLockInfo.AssignQuantity}"); |
| | | } |
| | | |
| | | // 妿åéå®ä¿¡æ¯çç¶ææ¯æ£é宿ï¼éè¦éæ°è®¾ç½®ä¸ºåºåºä¸ |
| | | if (originalLockInfo.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | { |
| | | originalLockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | _logger.LogInformation($"åéå®ä¿¡æ¯ç¶æä»æ£é宿æ¢å¤ä¸ºåºåºä¸"); |
| | | } |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤ååºåæç» |
| | | // 2. æ¢å¤ååºåï¼å°æå
çæ°éå åååºåï¼ |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); |
| | | |
| | | if (originalStock != null) |
| | | { |
| | | if (splitRecord.IsAutoSplit) |
| | | decimal originalStockQty = originalStock.StockQuantity; |
| | | originalStock.StockQuantity += splitRecord.SplitQty; |
| | | |
| | | // 妿ååºåç¶ææ¯åºåºå®æï¼æ¢å¤ä¸ºåºåºéå® |
| | | if (originalStock.Status == (int)StockStatusEmun.åºåºå®æ) |
| | | { |
| | | // èªå¨æå
ï¼ååºåæç»ä¿æä¸å |
| | | _logger.LogInformation($"åæ¶èªå¨æå
- ååºåæç»ä¿æä¸å"); |
| | | originalStock.Status = (int)StockStatusEmun.åºåºéå®; |
| | | } |
| | | else |
| | | { |
| | | // æå¨æå
ï¼æ¢å¤ååºåæ°é |
| | | 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(); |
| | | } |
| | | await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"èªå¨æå
åæ¶æ¢å¤ååºå - æ¡ç : {originalStock.Barcode}, æ°é: {originalStockQty} -> {originalStock.StockQuantity}"); |
| | | } |
| | | |
| | | // 3. å 餿°éå®ä¿¡æ¯ååºåæç» |
| | | await DeleteNewSplitRecords(newLockInfo, newStockDetail); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæå¨æå
åæ¶ |
| | | /// </summary> |
| | | private async Task HandleManualSplitCancel(Dt_SplitPackageRecord splitRecord, |
| | | Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo, |
| | | Dt_StockInfoDetail newStockDetail) |
| | | { |
| | | _logger.LogInformation($"å¤çæå¨æå
åæ¶ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); |
| | | |
| | | // 1. æ¢å¤åéå®ä¿¡æ¯çåé
æ°é |
| | | decimal originalAssignQty = originalLockInfo.AssignQuantity; |
| | | decimal originalOrderQty = originalLockInfo.OrderQuantity; |
| | | |
| | | originalLockInfo.AssignQuantity += splitRecord.SplitQty; |
| | | originalLockInfo.OrderQuantity += splitRecord.SplitQty; |
| | | |
| | | // æ¢å¤ç¶æ |
| | | if (originalLockInfo.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | { |
| | | originalLockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | } |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æå¨æå
åæ¶æ¢å¤åéå®ä¿¡æ¯ - åé
æ°é: {originalAssignQty} -> {originalLockInfo.AssignQuantity}"); |
| | | |
| | | // 2. æ¢å¤ååºåæç» |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); |
| | | |
| | | if (originalStock != null) |
| | | { |
| | | decimal originalStockQty = originalStock.StockQuantity; |
| | | originalStock.StockQuantity += splitRecord.SplitQty; |
| | | |
| | | // æ¢å¤åºåç¶æ |
| | | if (originalStock.Status == (int)StockStatusEmun.åºåºå®æ) |
| | | { |
| | | originalStock.Status = (int)StockStatusEmun.åºåºéå®; |
| | | } |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æå¨æå
åæ¶æ¢å¤ååºå - æ¡ç : {originalStock.Barcode}, æ°é: {originalStockQty} -> {originalStock.StockQuantity}"); |
| | | } |
| | | |
| | | // 3. å 餿°éå®ä¿¡æ¯ååºåæç» |
| | | await DeleteNewSplitRecords(newLockInfo, newStockDetail); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å 餿°æå
è®°å½ç¸å
³çæ°æ® |
| | | /// </summary> |
| | | private async Task DeleteNewSplitRecords(Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail) |
| | | { |
| | | // å 餿°éå®ä¿¡æ¯ |
| | | _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(); |
| | | |
| | | // 妿æ¯èªå¨æå
ï¼éè¦åå°è®¢åæç»çåé
æ°éåé宿°é |
| | | if (splitRecord.IsAutoSplit) |
| | | if (newStockDetail != null) |
| | | { |
| | | decimal originalAllocatedBefore = orderDetail.AllocatedQuantity; |
| | | decimal originalLockBefore = orderDetail.LockQuantity; |
| | | |
| | | orderDetail.AllocatedQuantity -= splitRecord.SplitQty; |
| | | orderDetail.LockQuantity -= splitRecord.SplitQty; |
| | | |
| | | // è¾¹çæ£æ¥ï¼ç¡®ä¿æ°éä¸ä¼ä¸ºè´æ° |
| | | if (orderDetail.AllocatedQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"åé
æ°éåºç°è´æ°ï¼é置为0ãåå¼: {orderDetail.AllocatedQuantity + splitRecord.SplitQty}, åå°: {splitRecord.SplitQty}"); |
| | | orderDetail.AllocatedQuantity = 0; |
| | | } |
| | | if (orderDetail.LockQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"é宿°éåºç°è´æ°ï¼é置为0ãåå¼: {orderDetail.LockQuantity + splitRecord.SplitQty}, åå°: {splitRecord.SplitQty}"); |
| | | orderDetail.LockQuantity = 0; |
| | | } |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"åæ¶èªå¨æå
åå°è®¢åæç»æ°é - åé
æ°éä» {originalAllocatedBefore} åå°å° {orderDetail.AllocatedQuantity}"); |
| | | _logger.LogInformation($"åæ¶èªå¨æå
åå°è®¢åæç»æ°é - é宿°éä» {originalLockBefore} åå°å° {orderDetail.LockQuantity}"); |
| | | _logger.LogInformation($"å 餿°åºåæç» - æ¡ç : {newStockDetail.Barcode}, åºåæ°é: {newStockDetail.StockQuantity}"); |
| | | await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == newStockDetail.Barcode) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // æ è®°æå
è®°å½ä¸ºå·²æ¤é |
| | | splitRecord.IsReverted = true; |
| | | splitRecord.RevertTime = DateTime.Now; |
| | | splitRecord.RevertOperator = App.User.UserName; |
| | | await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ è®°æå
è®°å½ä¸ºå·²æ¤é"); |
| | | |
| | | // éªè¯åæ¶æå
åæ°æ®ä¸è´æ§ |
| | | await ValidateDataConsistencyAfterCancelSplit(orderDetail.Id, originalOrderDetailAllocatedQty, originalOrderDetailLockQty, splitRecord.IsAutoSplit, splitRecord.SplitQty); |
| | | |
| | | // æ£æ¥å¹¶æ´æ°æ¹æ¬¡å订åç¶æ |
| | | await CheckAndUpdateBatchStatus(originalLockInfo.BatchNo); |
| | | await CheckAndUpdateOrderStatus(originalLockInfo.OrderNo); |
| | | |
| | | _logger.LogInformation($"åæ¶æå
é»è¾æ§è¡å®æ"); |
| | | } |
| | | /// <summary> |
| | | /// éªè¯åæ¶æå
åæ°æ®ä¸è´æ§ - ææ°çæ¬ |
| | |
| | | /// <summary> |
| | | /// ç»ä¸ååºæ¹æ³ - å¤çæç䏿æå©ä½è´§ç© |
| | | /// </summary> |
| | | //public async Task<WebResponseContent> ExecutePalletReturn(string orderNo, string palletCode, string returnReason = "åæ¹ååº") |
| | | //{ |
| | | // try |
| | | // { |
| | | // int stockId = 0; |
| | | // Dt_StockInfo stockInfo = null; |
| | | // PalletStatusAnalysis statusAnalysis = null; |
| | | // _unitOfWorkManage.BeginTran(); |
| | | |
| | | // if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) |
| | | // return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); |
| | | |
| | | // // è·ååºåä¿¡æ¯ |
| | | // stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | // .FirstAsync(x => x.PalletCode == palletCode); |
| | | // if (stockInfo == null) |
| | | // return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); |
| | | |
| | | // stockId = stockInfo.Id; |
| | | |
| | | // var beforeValidationResult = await ValidateReturnData(orderNo, palletCode, stockId, true); |
| | | // if (!beforeValidationResult) |
| | | // { |
| | | // _logger.LogWarning("ååºåæ°æ®éªè¯åç°é®é¢ï¼ä½ç»§ç»æ§è¡ååºæä½"); |
| | | // } |
| | | // _logger.LogInformation($"æ¥éª¤4宿: ååºåæ°æ®éªè¯{(beforeValidationResult ? "éè¿" : "åç°é®é¢")}"); |
| | | |
| | | |
| | | // // åææçç¶æ |
| | | // statusAnalysis = await AnalyzePalletStatusForReturn(orderNo, palletCode, stockInfo.Id); |
| | | // _logger.LogInformation($"ãæ¥éª¤6ãæçç¶æåæå®æ"); |
| | | // _logger.LogInformation($" - æ¯å¦æååºç©å: {statusAnalysis.HasItemsToReturn}"); |
| | | // _logger.LogInformation($" - æ¯å¦ç©ºæç: {statusAnalysis.IsEmptyPallet}"); |
| | | // _logger.LogInformation($" - æ»ååºæ°é: {statusAnalysis.TotalReturnQty}"); |
| | | // _logger.LogInformation($" - æ¡ç æ°é: {statusAnalysis.AllBarcodes.Count}"); |
| | | |
| | | // if (!statusAnalysis.HasItemsToReturn) |
| | | // { |
| | | // _logger.LogInformation($"ãæ¥éª¤7ãæ ååºç©åï¼å¤ç空æç"); |
| | | // var result = await HandleEmptyPalletReturn(orderNo, palletCode, stockInfo); |
| | | // if (result.Status) |
| | | // { |
| | | // _unitOfWorkManage.CommitTran(); |
| | | // _logger.LogInformation($"ã空æçååºæåã订å: {orderNo}, æç: {palletCode}"); |
| | | // } |
| | | // else |
| | | // { |
| | | // _unitOfWorkManage.RollbackTran(); |
| | | // _logger.LogError($"ã空æçååºå¤±è´¥ãåå : {result.Message}"); |
| | | // } |
| | | // return result; |
| | | // } |
| | | |
| | | // _logger.LogInformation($"å¼å§ååºæä½ - 订å: {orderNo}, æç: {palletCode}, ååºæ°é: {statusAnalysis.TotalReturnQty}"); |
| | | |
| | | // try |
| | | // { |
| | | // // æ§è¡ååºæ°æ®æä½ |
| | | // await ExecuteReturnDataOperations(statusAnalysis); |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // _logger.LogError($"ååºæ°æ®æä½å¤±è´¥: {ex.Message}"); |
| | | // try |
| | | // { |
| | | // await ExecuteSimpleReturnDataOperations(statusAnalysis); |
| | | // _logger.LogInformation($"ç®åååºæ°æ®æä½æå"); |
| | | // } |
| | | // catch (Exception simpleEx) |
| | | // { |
| | | // _logger.LogError($"ç®åååºæ°æ®æä½ä¹å¤±è´¥ - {simpleEx.Message}"); |
| | | // throw new InvalidOperationException($"ååºæ°æ®æä½å¤±è´¥ï¼ä¸»æ¹æ³: {ex.Message}, ç®åæ¹æ³: {simpleEx.Message}", ex); |
| | | // } |
| | | // } |
| | | |
| | | // // æ´æ°è®¢åç¶æ |
| | | // await UpdateOrderStatusAfterReturn(orderNo); |
| | | |
| | | // _unitOfWorkManage.CommitTran(); |
| | | |
| | | // _logger.LogInformation($"æ¥éª¤10: å¼å§ååºåæ°æ®éªè¯"); |
| | | // var afterValidationResult = await ValidateReturnData(orderNo, palletCode, stockId, false); |
| | | // if (!afterValidationResult) |
| | | // { |
| | | // _logger.LogWarning("ååºåæ°æ®éªè¯åç°é®é¢ï¼å»ºè®®æ£æ¥æ°æ®ä¸è´æ§"); |
| | | // } |
| | | // _logger.LogInformation($"æ¥éª¤10宿: ååºåæ°æ®éªè¯{(afterValidationResult ? "éè¿" : "åç°é®é¢")}"); |
| | | |
| | | // try |
| | | // { |
| | | // await CreateReturnTask(orderNo, palletCode, stockInfo); |
| | | // _logger.LogInformation($"æ¥éª¤11æå: ååºä»»å¡å建æå"); |
| | | // } |
| | | // catch (Exception taskEx) |
| | | // { |
| | | // // ä»»å¡å建失败ä¸å½±åååºæ°æ®æä½çæåï¼åªè®°å½é误 |
| | | // _logger.LogError($"æ¥éª¤11è¦å: ååºä»»å¡å建失败 - {taskEx.Message}"); |
| | | // _logger.LogError($"ååºæ°æ®æä½å·²æåï¼ä½ä»»å¡å建失败ï¼å¯è½éè¦æå¨å¤ç"); |
| | | // } |
| | | |
| | | // _logger.LogInformation($"ãååºæåã订å: {orderNo}, æç: {palletCode}, ååºæ°é: {statusAnalysis.TotalReturnQty}"); |
| | | |
| | | // return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{statusAnalysis.TotalReturnQty}", new |
| | | // { |
| | | // ReturnQuantity = statusAnalysis.TotalReturnQty, |
| | | // ReturnBarcodes = statusAnalysis.AllBarcodes, |
| | | // Reason = returnReason, |
| | | // PalletCode = palletCode, |
| | | // OrderNo = orderNo |
| | | // }); |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // _unitOfWorkManage.RollbackTran(); |
| | | // _logger.LogError($"ãååºå¤±è´¥ã订å: {orderNo}, æç: {palletCode}, é误类å: {ex.GetType().Name}"); |
| | | // _logger.LogError($"ãé误信æ¯ã{ex.Message}"); |
| | | // _logger.LogError($"ãå æ ä¿¡æ¯ã{ex.StackTrace}"); |
| | | |
| | | // if (ex.InnerException != null) |
| | | // { |
| | | // _logger.LogError($"ãå
é¨é误ã{ex.InnerException.Message}"); |
| | | // } |
| | | // return WebResponseContent.Instance.Error($"ååºæä½å¤±è´¥: {ex.Message}"); |
| | | // } |
| | | //} |
| | | |
| | | /// <summary> |
| | | /// ç»ä¸ååºæ¹æ³ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> ExecutePalletReturn(string orderNo, string palletCode, string returnReason = "åæ¹ååº") |
| | | { |
| | | try |
| | | { |
| | | _logger.LogInformation($"ãå¢å¼ºååºå¼å§ã订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. åºç¡éªè¯ |
| | | if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) |
| | | return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); |
| | | |
| | | // è·ååºåä¿¡æ¯ |
| | | // 2. è·ååºåä¿¡æ¯ |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); |
| | | |
| | | // åææçç¶æ |
| | | int stockId = stockInfo.Id; |
| | | |
| | | // 3. æ§è¡ååºåæ°æ®éªè¯ |
| | | var validationResult = await ValidateDataBeforeReturn(orderNo, palletCode, stockId); |
| | | if (!validationResult.IsValid) |
| | | { |
| | | _logger.LogWarning($"ååºåæ°æ®éªè¯å¤±è´¥: {validationResult.ErrorMessage}"); |
| | | // å¯ä»¥æ ¹æ®å®é
æ
åµå³å®æ¯å¦ç»§ç» |
| | | } |
| | | |
| | | // 4. åææçç¶æ |
| | | var statusAnalysis = await AnalyzePalletStatusForReturn(orderNo, palletCode, stockInfo.Id); |
| | | |
| | | if (!statusAnalysis.HasItemsToReturn) |
| | | return await HandleEmptyPalletReturn(orderNo, palletCode, stockInfo); |
| | | { |
| | | try |
| | | { |
| | | _logger.LogInformation($"ãæ ååºç©åãå¤ç空æç"); |
| | | var result = await HandleEmptyPalletReturn(orderNo, palletCode, stockInfo); |
| | | _unitOfWorkManage.CommitTran(); |
| | | return result; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"空箱ååºå¤±è´¥: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"空箱ååºå¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"å¼å§ååºæä½ - 订å: {orderNo}, æç: {palletCode}, ååºæ°é: {statusAnalysis.TotalReturnQty}"); |
| | | _logger.LogInformation($"ãå¼å§ååºãæ»ååºæ°é: {statusAnalysis.TotalReturnQty}, æ¡ç æ°: {statusAnalysis.AllBarcodes.Count}"); |
| | | |
| | | // æ§è¡ååºæ°æ®æä½ |
| | | await ExecuteReturnDataOperations(statusAnalysis); |
| | | // 5. æ§è¡ååºæä½ |
| | | try |
| | | { |
| | | await ExecuteEnhancedReturnOperations(statusAnalysis); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"主ååºæ¹æ³å¤±è´¥: {ex.Message}"); |
| | | // å°è¯ç®åæ¹æ³ |
| | | await ExecuteSimpleReturnDataOperations(statusAnalysis); |
| | | } |
| | | |
| | | // æ´æ°è®¢åç¶æ |
| | | // 6. æ´æ°è®¢åç¶æ |
| | | await UpdateOrderStatusAfterReturn(orderNo); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | // å建ååºä»»å¡ï¼AGVï¼ |
| | | await CreateReturnTask(orderNo, palletCode, stockInfo); |
| | | // 7. å建ååºä»»å¡ |
| | | try |
| | | { |
| | | await CreateReturnTask(orderNo, palletCode, stockInfo); |
| | | } |
| | | catch (Exception taskEx) |
| | | { |
| | | _logger.LogError($"ååºä»»å¡å建失败: {taskEx.Message}"); |
| | | // ä»»å¡å建失败ä¸å½±åæ°æ®ååº |
| | | } |
| | | _unitOfWorkManage.CommitTran(); |
| | | // 8. ååºåéªè¯ |
| | | await ValidateDataAfterReturn(orderNo, palletCode, stockId); |
| | | |
| | | return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{statusAnalysis.TotalReturnQty}", new |
| | | return WebResponseContent.Instance.OK($"ååºæåï¼ååºæ°éï¼{statusAnalysis.TotalReturnQty}", new |
| | | { |
| | | ReturnQuantity = statusAnalysis.TotalReturnQty, |
| | | ReturnBarcodes = statusAnalysis.AllBarcodes, |
| | |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"ååºæä½å¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"ååºæä½å¤±è´¥: {ex.Message}"); |
| | | _logger.LogError($"ååºå¤±è´¥: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"ååºå¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¢å¼ºçååºåæ°æ®éªè¯ |
| | | /// </summary> |
| | | private async Task<ValidationResult<bool>> ValidateDataBeforeReturn(string orderNo, string palletCode, int stockId) |
| | | { |
| | | var errors = new List<string>(); |
| | | |
| | | try |
| | | { |
| | | // 1. éªè¯åºåæ°æ® |
| | | var stockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId) |
| | | .ToListAsync(); |
| | | |
| | | // æ£æ¥åºåæ°éæ¯å¦ä¸ºè´æ° |
| | | var negativeStocks = stockDetails.Where(x => x.StockQuantity < 0).ToList(); |
| | | if (negativeStocks.Any()) |
| | | { |
| | | errors.Add($"åç°è´æ°åºå: {string.Join(", ", negativeStocks.Select(x => $"{x.Barcode}:{x.StockQuantity}"))}"); |
| | | } |
| | | |
| | | // 2. éªè¯éå®è®°å½ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | // æ£æ¥å·²æ£éæ°éæ¯å¦å¤§äºåé
æ°é |
| | | var invalidLocks = lockInfos.Where(x => x.PickedQty > x.AssignQuantity).ToList(); |
| | | if (invalidLocks.Any()) |
| | | { |
| | | errors.Add($"åç°å·²æ£éæ°é大äºåé
æ°éçéå®è®°å½"); |
| | | } |
| | | |
| | | // 3. éªè¯æå
è®°å½ |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | // æ£æ¥å¾ªç¯æå
|
| | | var barcodeMap = new Dictionary<string, string>(); |
| | | foreach (var record in splitRecords.Where(x => !x.IsReverted)) |
| | | { |
| | | if (!barcodeMap.ContainsKey(record.OriginalBarcode)) |
| | | barcodeMap[record.OriginalBarcode] = record.NewBarcode; |
| | | } |
| | | |
| | | // æ£æ¥å¾ªç¯å¼ç¨ |
| | | foreach (var record in splitRecords) |
| | | { |
| | | var current = record.OriginalBarcode; |
| | | var visited = new HashSet<string>(); |
| | | |
| | | while (barcodeMap.ContainsKey(current)) |
| | | { |
| | | if (visited.Contains(current)) |
| | | { |
| | | errors.Add($"åç°å¾ªç¯æå
å¼ç¨: {record.OriginalBarcode}"); |
| | | break; |
| | | } |
| | | visited.Add(current); |
| | | current = barcodeMap[current]; |
| | | } |
| | | } |
| | | |
| | | if (errors.Any()) |
| | | { |
| | | return ValidationResult<bool>.Error($"ååºåæ°æ®éªè¯åç°é®é¢: {string.Join("; ", errors)}"); |
| | | } |
| | | |
| | | return ValidationResult<bool>.Success(true); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"æ°æ®éªè¯å¤±è´¥: {ex.Message}"); |
| | | return ValidationResult<bool>.Error($"æ°æ®éªè¯å¼å¸¸: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ§è¡å¢å¼ºçååºæä½ |
| | | /// </summary> |
| | | private async Task ExecuteEnhancedReturnOperations(PalletStatusAnalysis statusAnalysis) |
| | | { |
| | | _logger.LogInformation($"æ§è¡å¢å¼ºååºæä½ - 订å: {statusAnalysis.OrderNo}, æç: {statusAnalysis.PalletCode}"); |
| | | |
| | | // å¤çå·²åé
çéå®è®°å½ |
| | | if (statusAnalysis.HasRemainingLocks) |
| | | { |
| | | await HandleAllocatedLocksReturn(statusAnalysis.RemainingLocks); |
| | | } |
| | | |
| | | // å¤çæªåé
çéå®è®°å½ |
| | | if (statusAnalysis.HasUnallocatedLocks) |
| | | { |
| | | await HandleUnallocatedLocksReturn(statusAnalysis.UnallocatedLocks); |
| | | } |
| | | |
| | | // å¤çæªåé
çåºåè´§ç© |
| | | if (statusAnalysis.HasPalletStockGoods) |
| | | { |
| | | await HandleUnallocatedStockReturn(statusAnalysis.PalletStockGoods); |
| | | } |
| | | |
| | | // å¤çæå
è®°å½ |
| | | if (statusAnalysis.HasSplitRecords) |
| | | { |
| | | await HandleSplitRecordsReturn(statusAnalysis.SplitRecords, statusAnalysis.StockId); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ååºåæ°æ®éªè¯ |
| | | /// </summary> |
| | | private async Task ValidateDataAfterReturn(string orderNo, string palletCode, int stockId) |
| | | { |
| | | try |
| | | { |
| | | _logger.LogInformation($"å¼å§ååºåæ°æ®éªè¯"); |
| | | |
| | | // 1. éªè¯åºåç¶æ |
| | | var stockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId) |
| | | .ToListAsync(); |
| | | |
| | | var stillOutboundLocked = stockDetails.Where(x => |
| | | x.Status == (int)StockStatusEmun.åºåºéå® && x.StockQuantity > 0).ToList(); |
| | | |
| | | if (stillOutboundLocked.Any()) |
| | | { |
| | | _logger.LogWarning($"ååºå仿åºåºéå®ç¶æçåºå: {stillOutboundLocked.Count}个"); |
| | | } |
| | | |
| | | // 2. éªè¯éå®è®°å½ç¶æ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | var notReturnedLocks = lockInfos.Where(x => |
| | | x.Status != (int)OutLockStockStatusEnum.å·²ååº && |
| | | x.Status != (int)OutLockStockStatusEnum.å·²åèµ°).ToList(); |
| | | |
| | | if (notReturnedLocks.Any()) |
| | | { |
| | | _logger.LogWarning($"ååºå仿æªååºç¶æçéå®è®°å½: {notReturnedLocks.Count}æ¡"); |
| | | } |
| | | |
| | | // 3. æ°æ®ä¸è´æ§éªè¯ |
| | | decimal totalStock = stockDetails.Sum(x => x.StockQuantity); |
| | | _logger.LogInformation($"ååºååºåæ»é: {totalStock}"); |
| | | |
| | | _logger.LogInformation($"ååºåæ°æ®éªè¯å®æ"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"ååºåéªè¯å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// éªè¯ååºååæ°æ®ä¸è´æ§ |
| | | /// </summary> |
| | | private async Task<bool> ValidateReturnData(string orderNo, string palletCode, int stockId, bool isBefore = true) |
| | | { |
| | | string phase = isBefore ? "ååºå" : "ååºå"; |
| | | try |
| | | { |
| | | |
| | | _logger.LogInformation($"ã{phase}æ°æ®éªè¯ãå¼å§ - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | // 1. æ£æ¥åºåæç» |
| | | var stockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId) |
| | | .ToListAsync(); |
| | | |
| | | decimal totalStockQty = stockDetails.Sum(x => x.StockQuantity); |
| | | _logger.LogInformation($"{phase}åºåæ»é: {totalStockQty}"); |
| | | |
| | | // 2. æ£æ¥éå®è®°å½ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | // æ£æ¥éå®è®°å½ç¶æåå¸ |
| | | var statusGroups = lockInfos.GroupBy(x => x.Status) |
| | | .Select(g => new { Status = g.Key, Count = g.Count() }) |
| | | .ToList(); |
| | | |
| | | foreach (var group in statusGroups) |
| | | { |
| | | _logger.LogInformation($"{phase}éå®ç¶æ {GetLockStatusName(group.Status)}: {group.Count} æ¡"); |
| | | } |
| | | |
| | | // 3. åºæ¬éªè¯ |
| | | bool isValid = true; |
| | | |
| | | // éªè¯1: 妿éå®è®°å½ç¶æä¸º"æ£é宿"ï¼å¯¹åºåºååºè¯¥ä¸º0 |
| | | var completedLocks = lockInfos.Where(x => x.Status == (int)OutLockStockStatusEnum.æ£é宿).ToList(); |
| | | foreach (var lockInfo in completedLocks) |
| | | { |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | var stock = stockDetails.FirstOrDefault(x => x.Barcode == lockInfo.CurrentBarcode); |
| | | if (stock != null && stock.StockQuantity > 0) |
| | | { |
| | | _logger.LogWarning($"{phase}éªè¯è¦å - éå®ID {lockInfo.Id} æ£é宿ä½åºåä¸ä¸º0: {stock.StockQuantity}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // éªè¯2: åºåç¶æä¸è´æ§ |
| | | foreach (var stock in stockDetails) |
| | | { |
| | | if (stock.Status == (int)StockStatusEmun.åºåºéå® && stock.StockQuantity == 0) |
| | | { |
| | | _logger.LogWarning($"{phase}éªè¯è¦å - æ¡ç {stock.Barcode} ç¶æä¸ºåºåºéå®ä½åºå为0"); |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"ã{phase}æ°æ®éªè¯ã宿 - ç¶æ: {(isValid ? "éè¿" : "æè¦å")}"); |
| | | return isValid; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"{phase} æ°æ®éªè¯å¤±è´¥: {ex.Message}"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | private string GetLockStatusName(int status) |
| | | { |
| | | return status switch |
| | | { |
| | | 1 => "åºåºä¸", |
| | | 2 => "æ£é宿", |
| | | 3 => "å·²ååº", |
| | | 4 => "å·²åèµ°", |
| | | _ => $"æªç¥({status})" |
| | | }; |
| | | } |
| | | /// <summary> |
| | | /// ç®åååºæ°æ®æä½ï¼å½ä¸»æ¹æ³å¤±è´¥æ¶ä½¿ç¨ï¼ |
| | | /// </summary> |
| | | private async Task ExecuteSimpleReturnDataOperations(PalletStatusAnalysis statusAnalysis) |
| | | { |
| | | _logger.LogInformation($"ãç®åååºãå¼å§æ§è¡ç®åååºæä½"); |
| | | |
| | | try |
| | | { |
| | | // è·å该æççæææ¡ç |
| | | var allStockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == statusAnalysis.StockId && x.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | _logger.LogInformation($"æ¾å° {allStockDetails.Count} 个æåºåçæ¡ç "); |
| | | |
| | | foreach (var stockDetail in allStockDetails) |
| | | { |
| | | // æ¢å¤ææåºåç¶æä¸ºå
¥åºå®æ |
| | | if (stockDetail.Status == (int)StockStatusEmun.åºåºéå®) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"ç®åååº - æ¡ç : {stockDetail.Barcode}, æ°é: {stockDetail.StockQuantity}"); |
| | | } |
| | | } |
| | | |
| | | // æ´æ°ææéå®è®°å½ä¸ºå·²ååº |
| | | var allLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == statusAnalysis.OrderNo && |
| | | x.PalletCode == statusAnalysis.PalletCode && |
| | | (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || |
| | | x.Status == (int)OutLockStockStatusEnum.æ£é宿)) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var lockInfo in allLocks) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²ååº; |
| | | lockInfo.Operator = App.User.UserName; |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"ç®åååº - éå®è®°å½: {lockInfo.Id}"); |
| | | } |
| | | |
| | | _logger.LogInformation($"ãç®åååºã宿 - å¤ç {allStockDetails.Count} 个æ¡ç , {allLocks.Count} æ¡éå®è®°å½"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"ç®åååºå¤±è´¥: {ex.Message}"); |
| | | throw; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// æ§è¡ååºæ°æ®æä½ |
| | | /// ç¡®ä¿ä¸ä¼å°çæçæ¡ç æ°éé误ç»å®å°é宿°é |
| | | /// æ§è¡ååºæ°æ®æä½ - ç®åçæ¬ |
| | | /// </summary> |
| | | private async Task ExecuteReturnDataOperations(PalletStatusAnalysis statusAnalysis) |
| | | { |
| | |
| | | |
| | | try |
| | | { |
| | | // ä½¿ç¨ HashSet é¿å
éå¤å¤çæ¡ç |
| | | var processedBarcodes = new HashSet<string>(); |
| | | decimal totalReturnedQty = 0; |
| | | |
| | | // 1. å¤çå·²åé
çæªåæ£éå®è®°å½ |
| | | if (statusAnalysis.HasRemainingLocks) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.RemainingLocks.Count} æ¡å·²åé
æªåæ£éå®è®°å½"); |
| | | await HandleAllocatedLocksReturn(statusAnalysis.RemainingLocks); |
| | | |
| | | foreach (var lockInfo in statusAnalysis.RemainingLocks) |
| | | { |
| | | if (string.IsNullOrEmpty(lockInfo.CurrentBarcode) || processedBarcodes.Contains(lockInfo.CurrentBarcode)) |
| | | { |
| | | _logger.LogInformation($"è·³è¿éå¤æç©ºæ¡ç çéå®è®°å½ - ID: {lockInfo.Id}"); |
| | | continue; |
| | | } |
| | | |
| | | // 计ç®ååºæ°éï¼æªæ£éçé¨åï¼ |
| | | decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | |
| | | if (returnQty > 0) |
| | | { |
| | | _logger.LogInformation($"å¤çéå®è®°å½ååº - ID: {lockInfo.Id}, æ¡ç : {lockInfo.CurrentBarcode}, ååºæ°é: {returnQty}"); |
| | | |
| | | // å¤çåºå |
| | | await ProcessStockForReturn(lockInfo.CurrentBarcode, statusAnalysis.StockId, returnQty); |
| | | |
| | | // æ 记为已ååº |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²ååº; |
| | | lockInfo.Operator = App.User.UserName; |
| | | |
| | | |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // åå°è®¢åæç»çåé
æ°é |
| | | if (lockInfo.OrderDetailId > 0) |
| | | { |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | await ReduceOrderDetailAllocation(orderDetail, returnQty); |
| | | } |
| | | |
| | | processedBarcodes.Add(lockInfo.CurrentBarcode); |
| | | totalReturnedQty += returnQty; |
| | | |
| | | _logger.LogInformation($"éå®è®°å½ååºå®æ - ID: {lockInfo.Id}, ååºæ°é: {returnQty}"); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation($"éå®è®°å½æ éååº - ID: {lockInfo.Id}, å·²æ£é宿"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 2. å¤çæªåé
çéå®è®°å½ï¼å¦èªå¨æå
产ççï¼ |
| | | if (statusAnalysis.HasUnallocatedLocks) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.UnallocatedLocks.Count} æ¡æªåé
éå®è®°å½"); |
| | | await HandleUnallocatedLocksReturn(statusAnalysis.UnallocatedLocks); |
| | | } |
| | | |
| | | // 3. å¤çæªåé
çåºåè´§ç© |
| | | // 2. å¤çæªåé
çåºåè´§ç© |
| | | if (statusAnalysis.HasPalletStockGoods) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.PalletStockGoods.Count} 个æªåé
åºåè´§ç©"); |
| | | await HandleUnallocatedStockReturn(statusAnalysis.PalletStockGoods); |
| | | |
| | | foreach (var stockDetail in statusAnalysis.PalletStockGoods) |
| | | { |
| | | if (string.IsNullOrEmpty(stockDetail.Barcode) || processedBarcodes.Contains(stockDetail.Barcode)) |
| | | { |
| | | _logger.LogInformation($"è·³è¿éå¤æç©ºæ¡ç çåºå - åºåID: {stockDetail.Id}"); |
| | | continue; |
| | | } |
| | | |
| | | if (stockDetail.StockQuantity > 0) |
| | | { |
| | | decimal returnQty = stockDetail.StockQuantity; |
| | | _logger.LogInformation($"å¤çæªåé
åºåååº - æ¡ç : {stockDetail.Barcode}, ååºæ°é: {returnQty}"); |
| | | |
| | | // ç´æ¥æ¢å¤åºåç¶æ |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | processedBarcodes.Add(stockDetail.Barcode); |
| | | totalReturnedQty += returnQty; |
| | | |
| | | _logger.LogInformation($"æªåé
åºåååºå®æ - æ¡ç : {stockDetail.Barcode}, æ°é: {returnQty}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"ååºæ°æ®æä½å®æ - æ»ååºæ°é: {statusAnalysis.TotalReturnQty}"); |
| | | // 3. å¤çæå
è®°å½ç¸å
³çæ¡ç |
| | | if (statusAnalysis.HasSplitRecords) |
| | | { |
| | | _logger.LogInformation($"å¤ç {statusAnalysis.SplitRecords.Count} æ¡æå
è®°å½"); |
| | | |
| | | // æ¶éæå
ç¸å
³çæææ¡ç |
| | | var splitBarcodes = new List<string>(); |
| | | foreach (var splitRecord in statusAnalysis.SplitRecords) |
| | | { |
| | | if (!string.IsNullOrEmpty(splitRecord.OriginalBarcode)) |
| | | splitBarcodes.Add(splitRecord.OriginalBarcode); |
| | | if (!string.IsNullOrEmpty(splitRecord.NewBarcode)) |
| | | splitBarcodes.Add(splitRecord.NewBarcode); |
| | | } |
| | | |
| | | // å»é |
| | | splitBarcodes = splitBarcodes.Distinct().ToList(); |
| | | |
| | | foreach (var barcode in splitBarcodes) |
| | | { |
| | | if (processedBarcodes.Contains(barcode)) |
| | | { |
| | | _logger.LogInformation($"æå
æ¡ç å·²å¤ç: {barcode}"); |
| | | continue; |
| | | } |
| | | |
| | | // æ¥æ¾åºå |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == barcode && x.StockId == statusAnalysis.StockId); |
| | | |
| | | if (stockDetail != null && stockDetail.StockQuantity > 0) |
| | | { |
| | | decimal returnQty = stockDetail.StockQuantity; |
| | | _logger.LogInformation($"å¤çæå
ç¸å
³åºåååº - æ¡ç : {barcode}, ååºæ°é: {returnQty}"); |
| | | |
| | | // æ¢å¤åºåç¶æ |
| | | if (stockDetail.Status == (int)StockStatusEmun.åºåºéå®) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | processedBarcodes.Add(barcode); |
| | | totalReturnedQty += returnQty; |
| | | |
| | | _logger.LogInformation($"æå
åºåååºå®æ - æ¡ç : {barcode}, æ°é: {returnQty}"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"ååºæ°æ®æä½å®æ - æ»ååºæ°é: {totalReturnedQty}, å¤çæ¡ç æ°: {processedBarcodes.Count}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | throw; |
| | | } |
| | | } |
| | | // <summary> |
| | | /// <summary> |
| | | /// å¤çåºåååº - ç®åé»è¾ |
| | | /// </summary> |
| | | private async Task ProcessStockForReturn(string barcode, int stockId, decimal returnQty) |
| | | { |
| | | try |
| | | { |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == barcode && x.StockId == stockId); |
| | | |
| | | if (stockDetail == null) |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°åºåæç» - æ¡ç : {barcode}"); |
| | | return; |
| | | } |
| | | |
| | | // è®°å½åå§å¼ |
| | | decimal originalStockQty = stockDetail.StockQuantity; |
| | | decimal originalOutboundQty = stockDetail.OutboundQuantity; |
| | | int originalStatus = stockDetail.Status; |
| | | |
| | | // ç®åå¤çï¼å¦æåºåæ°é大äº0ï¼æ¢å¤ä¸ºå
¥åºå®æç¶æ |
| | | if (stockDetail.StockQuantity > 0) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | } |
| | | |
| | | // è°æ´åºåºæ°éï¼é¿å
åºç°è´æ°ï¼ |
| | | if (stockDetail.OutboundQuantity > 0) |
| | | { |
| | | stockDetail.OutboundQuantity = Math.Max(0, stockDetail.OutboundQuantity - returnQty); |
| | | } |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"åºåååºå¤ç - æ¡ç : {barcode}, ç¶æ: {originalStatus} -> {stockDetail.Status}, " + |
| | | $"åºå: {originalStockQty} -> {stockDetail.StockQuantity}, " + |
| | | $"åºåº: {originalOutboundQty} -> {stockDetail.OutboundQuantity}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"å¤çåºåååºå¤±è´¥ - æ¡ç : {barcode}, Error: {ex.Message}"); |
| | | throw; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 为éå®è®°å½åå°è®¢åæç»çåé
æ°é |
| | | /// </summary> |
| | | private async Task ReduceOrderDetailAllocationForLock(long orderDetailId, decimal reduceQty) |
| | | { |
| | | if (orderDetailId <= 0) |
| | | return; |
| | | |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == orderDetailId); |
| | | |
| | | if (orderDetail == null) |
| | | return; |
| | | |
| | | decimal originalAllocated = orderDetail.AllocatedQuantity; |
| | | decimal originalLock = orderDetail.LockQuantity; |
| | | |
| | | // éªè¯åå°æ°éä¸ä¼å¯¼è´è´æ° |
| | | if (orderDetail.AllocatedQuantity < reduceQty) |
| | | { |
| | | _logger.LogWarning($"åé
æ°éä¸è¶³ï¼è°æ´åå°æ°é - å计ååå°: {reduceQty}, å®é
å¯ç¨: {orderDetail.AllocatedQuantity}"); |
| | | reduceQty = orderDetail.AllocatedQuantity; |
| | | } |
| | | |
| | | // åå°åé
æ°éåé宿°é |
| | | orderDetail.AllocatedQuantity -= reduceQty; |
| | | orderDetail.LockQuantity -= reduceQty; |
| | | |
| | | // ç¡®ä¿æ°éä¸ä¼ä¸ºè´æ° |
| | | if (orderDetail.AllocatedQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"åé
æ°éåºç°è´æ°ï¼é置为0ãåå¼: {orderDetail.AllocatedQuantity + reduceQty}, åå°: {reduceQty}"); |
| | | orderDetail.AllocatedQuantity = 0; |
| | | } |
| | | |
| | | if (orderDetail.LockQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"é宿°éåºç°è´æ°ï¼é置为0ãåå¼: {orderDetail.LockQuantity + reduceQty}, åå°: {reduceQty}"); |
| | | orderDetail.LockQuantity = 0; |
| | | } |
| | | |
| | | // æ´æ°æ¹æ¬¡åé
ç¶æ |
| | | await UpdateBatchAllocateStatus(orderDetail); |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"åå°è®¢åæç»åé
- OrderDetailId: {orderDetail.Id}, " + |
| | | $"åé
æ°é: {originalAllocated} -> {orderDetail.AllocatedQuantity}, " + |
| | | $"é宿°é: {originalLock} -> {orderDetail.LockQuantity}, " + |
| | | $"åå°æ°é: {reduceQty}"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæªåé
çéå®è®°å½ååº |
| | | /// ä¸éè¦åå°è®¢åæç»çåé
æ°é |
| | | /// </summary> |
| | |
| | | _logger.LogInformation($"å¤çæªåé
éå®è®°å½ååº - éå®ID: {lockInfo.Id}, æ¡ç : {lockInfo.CurrentBarcode}, ååºæ°é: {returnQty}"); |
| | | |
| | | // æ¢å¤åºåç¶æ |
| | | await RestoreStockForLockInfo(lockInfo, returnQty); |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail != null) |
| | | { |
| | | // æ¢å¤åºåæ°é |
| | | decimal originalStockQty = stockDetail.StockQuantity; |
| | | stockDetail.StockQuantity += returnQty; |
| | | |
| | | // æ¢å¤åºåç¶æ |
| | | if (stockDetail.Status == (int)StockStatusEmun.åºåºå®æ) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | } |
| | | else if (stockDetail.Status == (int)StockStatusEmun.åºåºéå®) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | } |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ¢å¤åºå - æ¡ç : {stockDetail.Barcode}, åºåæ°é: {originalStockQty} -> {stockDetail.StockQuantity}"); |
| | | } |
| | | |
| | | // æ´æ°éå®è®°å½ç¶æä¸ºå·²ååº |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²ååº; |
| | |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ´æ°æªåé
éå®ç¶æ - éå®ID: {lockInfo.Id}, ç¶æ: åºåºä¸ -> å·²ååº"); |
| | | |
| | | // éè¦ï¼æªåé
éå®è®°å½ä¸éè¦åå°è®¢åæç»çåé
æ°é |
| | | _logger.LogInformation($"æªåé
éå®è®°å½ååºå®æ - éå®ID: {lockInfo.Id}, ååºæ°é: {returnQty}, æ éæ´æ°è®¢åæç»"); |
| | | } |
| | | |
| | | _logger.LogInformation($"æªåé
éå®è®°å½ååºå¤ç宿 - å
±å¤ç {unallocatedLocks.Count} æ¡è®°å½"); |
| | | } |
| | | |
| | | private async Task HandleAllocatedLocksReturn(List<Dt_OutStockLockInfo> allocatedLocks) |
| | | { |
| | | _logger.LogInformation($"å¼å§å¤çå·²åé
éå®è®°å½ååº - å
± {allocatedLocks.Count} æ¡è®°å½"); |
| | |
| | | PalletType = stockInfo.PalletType, |
| | | WarehouseId = currentTask.WarehouseId |
| | | }; |
| | | var targetAddress = currentTask.TargetAddress; |
| | | |
| | | try |
| | | { |
| | | await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"CreateReturnTaskAndHandleESS åæ¹å é¤åå²ä»»å¡: {orderNo} ï¼ {currentTask.TaskNum}"); |
| | | // å é¤åå§åºåºä»»å¡ |
| | | //_taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.èªå¨å®æ); |
| | | var result = _task_HtyService.DeleteAndMoveIntoHty(currentTask, OperateTypeEnum.人工å é¤); |
| | | await _taskRepository.Db.Deleteable(currentTask).ExecuteCommandAsync(); |
| | | |
| | | if (!result) |
| | | { |
| | | await _taskRepository.Db.Deleteable(currentTask).ExecuteCommandAsync(); |
| | | } |
| | | _logger.LogInformation($"CreateReturnTaskAndHandleESS åæ¹å é¤åå²ä»»å¡: {orderNo} ï¼ {currentTask.TaskNum},å½±åè¡ {result}"); |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogInformation($"å建ååºä»»å¡å¤±è´¥ - 订å: {orderNo}, æç: {palletCode}"); |
| | | throw new Exception($"å建ååºä»»å¡å¤±è´¥ - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | |
| | | } |
| | | // åéESSå½ä»¤ |
| | | await SendESSCommands(palletCode, currentTask.TargetAddress, returnTask); |
| | | await SendESSCommands(palletCode, targetAddress, returnTask); |
| | | |
| | | _logger.LogInformation($"å建ååºä»»å¡æå - 订å: {orderNo}, æç: {palletCode}"); |
| | | } |
| | |
| | | /// åææçç¶æç¨äºååº |
| | | /// ç¡®ä¿ä¸ä¼é误è¯å«éè¦ååºçç©å |
| | | /// </summary> |
| | | |
| | | /// <summary> |
| | | /// åææçç¶æç¨äºååº - 宿´çæ¬ |
| | | /// ç¡®ä¿ä¸ä¼é误è¯å«éè¦ååºçç©åï¼é¿å
éå¤è®¡ç® |
| | | /// </summary> |
| | | private async Task<PalletStatusAnalysis> AnalyzePalletStatusForReturn(string orderNo, string palletCode, int stockId) |
| | | { |
| | | var result = new PalletStatusAnalysis |
| | | { |
| | | OrderNo = orderNo, |
| | | PalletCode = palletCode, |
| | | StockId = stockId |
| | | StockId = stockId, |
| | | AllBarcodes = new List<string>(), |
| | | RemainingLocks = new List<Dt_OutStockLockInfo>(), |
| | | UnallocatedLocks = new List<Dt_OutStockLockInfo>(), |
| | | PalletStockGoods = new List<Dt_StockInfoDetail>(), |
| | | SplitRecords = new List<Dt_SplitPackageRecord>() |
| | | }; |
| | | |
| | | // 1. åææªåæ£çéå®è®°å½ï¼ç¶æä¸ºåºåºä¸ï¼ |
| | | var unfinishedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .ToListAsync(); |
| | | _logger.LogInformation($"å¼å§åææçç¶æç¨äºååº - 订å: {orderNo}, æç: {palletCode}, StockId: {stockId}"); |
| | | |
| | | if (unfinishedLocks.Any()) |
| | | try |
| | | { |
| | | // åºåå·²åé
åæªåé
çéå®è®°å½ |
| | | var allocatedLocks = unfinishedLocks.Where(x => x.IsUnallocated != 1 && x.OrderDetailId > 0).ToList(); |
| | | var unallocatedLocks = unfinishedLocks.Where(x => x.IsUnallocated == 1 || x.OrderDetailId == 0).ToList(); |
| | | |
| | | // å¤çå·²åé
çéå®è®°å½ |
| | | if (allocatedLocks.Any()) |
| | | { |
| | | result.HasRemainingLocks = true; |
| | | result.RemainingLocks = allocatedLocks; |
| | | result.RemainingLocksReturnQty = allocatedLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | foreach (var lockInfo in allocatedLocks) |
| | | { |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | result.AllBarcodes.Add(lockInfo.CurrentBarcode); |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"åç°{allocatedLocks.Count}æ¡å·²åé
æªåæ£éå®è®°å½ï¼æ»æ°é: {result.RemainingLocksReturnQty}"); |
| | | } |
| | | |
| | | // å¤çæªåé
çéå®è®°å½ï¼å¦èªå¨æå
产ççï¼ |
| | | if (unallocatedLocks.Any()) |
| | | { |
| | | result.HasUnallocatedLocks = true; |
| | | result.UnallocatedLocks = unallocatedLocks; |
| | | result.UnallocatedLocksReturnQty = unallocatedLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | foreach (var lockInfo in unallocatedLocks) |
| | | { |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | result.AllBarcodes.Add(lockInfo.CurrentBarcode); |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"åç°{unallocatedLocks.Count}æ¡æªåé
éå®è®°å½ï¼æ»æ°é: {result.UnallocatedLocksReturnQty}"); |
| | | } |
| | | } |
| | | |
| | | // 2. åææçä¸çå©ä½åºåè´§ç©ï¼ç¶æä¸ºåºåºéå®ä½æªåé
ï¼ |
| | | var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId && |
| | | x.Status == (int)StockStatusEmun.åºåºéå® && |
| | | x.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | // è¿æ»¤æå·²ç»è¢«éå®è®°å½å ç¨çåºå |
| | | var lockedBarcodes = unfinishedLocks.Select(x => x.CurrentBarcode).ToList(); |
| | | var unlockedStockGoods = palletStockGoods.Where(x => !lockedBarcodes.Contains(x.Barcode)).ToList(); |
| | | |
| | | // è¿ä¸æ¥è¿æ»¤ï¼æ£æ¥è¿äºåºåæ¯å¦æå
³èçéå®è®°å½ |
| | | var trulyUnallocatedGoods = new List<Dt_StockInfoDetail>(); |
| | | foreach (var stock in unlockedStockGoods) |
| | | { |
| | | var hasLock = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == stock.Barcode && |
| | | // 1. åæææéå®è®°å½ï¼ç¶æä¸ºåºåºä¸ï¼ |
| | | var allUnfinishedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .AnyAsync(); |
| | | .ToListAsync(); |
| | | |
| | | if (!hasLock) |
| | | if (allUnfinishedLocks.Any()) |
| | | { |
| | | trulyUnallocatedGoods.Add(stock); |
| | | } |
| | | } |
| | | _logger.LogInformation($"æ¾å° {allUnfinishedLocks.Count} æ¡åºåºä¸ç¶æçéå®è®°å½"); |
| | | |
| | | if (trulyUnallocatedGoods.Any()) |
| | | // åºåå·²åé
åæªåé
çéå®è®°å½ |
| | | var allocatedLocks = allUnfinishedLocks |
| | | .Where(x => x.IsUnallocated != 1 && x.OrderDetailId > 0) |
| | | .ToList(); |
| | | |
| | | var unallocatedLocks = allUnfinishedLocks |
| | | .Where(x => x.IsUnallocated == 1 || x.OrderDetailId == 0) |
| | | .ToList(); |
| | | |
| | | // å¤çå·²åé
çéå®è®°å½ |
| | | if (allocatedLocks.Any()) |
| | | { |
| | | result.HasRemainingLocks = true; |
| | | result.RemainingLocks = allocatedLocks; |
| | | result.RemainingLocksReturnQty = allocatedLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | foreach (var lockInfo in allocatedLocks) |
| | | { |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | result.AllBarcodes.Add(lockInfo.CurrentBarcode); |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"åç°{allocatedLocks.Count}æ¡å·²åé
æªåæ£éå®è®°å½ï¼æ»æ°é: {result.RemainingLocksReturnQty}"); |
| | | } |
| | | |
| | | // å¤çæªåé
çéå®è®°å½ï¼å¦èªå¨æå
产ççï¼ |
| | | if (unallocatedLocks.Any()) |
| | | { |
| | | result.HasUnallocatedLocks = true; |
| | | result.UnallocatedLocks = unallocatedLocks; |
| | | result.UnallocatedLocksReturnQty = unallocatedLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | foreach (var lockInfo in unallocatedLocks) |
| | | { |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | result.AllBarcodes.Add(lockInfo.CurrentBarcode); |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"åç°{unallocatedLocks.Count}æ¡æªåé
éå®è®°å½ï¼æ»æ°é: {result.UnallocatedLocksReturnQty}"); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation($"æªæ¾å°åºåºä¸ç¶æçéå®è®°å½"); |
| | | } |
| | | |
| | | // 2. åææçä¸çå©ä½åºåè´§ç©ï¼ç¶æä¸ºåºåºéå®ä½æªåé
ï¼ |
| | | var allStockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId && |
| | | x.Status == (int)StockStatusEmun.åºåºéå® && |
| | | x.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | if (allStockDetails.Any()) |
| | | { |
| | | _logger.LogInformation($"æ¾å° {allStockDetails.Count} 个åºåºéå®ç¶æçåºåè´§ç©"); |
| | | |
| | | // è¿æ»¤æå·²ç»è¢«éå®è®°å½å ç¨çåºå |
| | | var lockedBarcodes = allUnfinishedLocks.Select(x => x.CurrentBarcode).Where(b => !string.IsNullOrEmpty(b)).ToList(); |
| | | var unlockedStockGoods = allStockDetails |
| | | .Where(x => !lockedBarcodes.Contains(x.Barcode)) |
| | | .ToList(); |
| | | |
| | | _logger.LogInformation($"è¿æ»¤åå©ä½ {unlockedStockGoods.Count} 个æªè¢«éå®çåºåè´§ç©"); |
| | | |
| | | // è¿ä¸æ¥è¿æ»¤ï¼æ£æ¥è¿äºåºåæ¯å¦æå
³èçéå®è®°å½ï¼å
æ¬ç¶æä¸æ¯åºåºä¸çï¼ |
| | | var trulyUnallocatedGoods = new List<Dt_StockInfoDetail>(); |
| | | foreach (var stock in unlockedStockGoods) |
| | | { |
| | | var hasActiveLock = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == stock.Barcode && |
| | | (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || |
| | | x.Status == (int)OutLockStockStatusEnum.æ£é宿)) |
| | | .AnyAsync(); |
| | | |
| | | if (!hasActiveLock) |
| | | { |
| | | trulyUnallocatedGoods.Add(stock); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation($"æ¡ç {stock.Barcode} ææ´»è·çéå®è®°å½ï¼è·³è¿ä½ä¸ºæªåé
åºå"); |
| | | } |
| | | } |
| | | |
| | | if (trulyUnallocatedGoods.Any()) |
| | | { |
| | | result.HasPalletStockGoods = true; |
| | | result.PalletStockGoods = trulyUnallocatedGoods; |
| | | result.PalletStockReturnQty = trulyUnallocatedGoods.Sum(x => x.StockQuantity); |
| | | |
| | | foreach (var stock in trulyUnallocatedGoods) |
| | | { |
| | | result.AllBarcodes.Add(stock.Barcode); |
| | | } |
| | | |
| | | _logger.LogInformation($"åç°{trulyUnallocatedGoods.Count}ä¸ªçæ£æªåé
åºåè´§ç©ï¼æ»æ°é: {result.PalletStockReturnQty}"); |
| | | |
| | | // è®°å½æ¯ä¸ªè´§ç©ç详ç»ä¿¡æ¯ |
| | | foreach (var stock in trulyUnallocatedGoods) |
| | | { |
| | | _logger.LogInformation($"æªåé
åºå - æ¡ç : {stock.Barcode}, ç©æ: {stock.MaterielCode}, æ°é: {stock.StockQuantity}"); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation($"æªæ¾å°åºåºéå®ç¶æçåºåè´§ç©"); |
| | | } |
| | | |
| | | // 3. åææå
è®°å½ï¼ç¶æä¸æ¯å·²æ£éåå·²ååºçï¼ |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | !x.IsReverted && |
| | | x.Status != (int)SplitPackageStatusEnum.å·²æ£é && |
| | | x.Status != (int)SplitPackageStatusEnum.å·²ååº) |
| | | .ToListAsync(); |
| | | |
| | | if (splitRecords.Any()) |
| | | { |
| | | result.HasSplitRecords = true; |
| | | result.SplitRecords = splitRecords; |
| | | |
| | | // è®¡ç®æå
è®°å½ç¸å
³çååºæ°éï¼é¿å
éå¤è®¡ç®ï¼ |
| | | var splitBarcodes = new HashSet<string>(); |
| | | decimal splitReturnQty = 0; |
| | | |
| | | foreach (var splitRecord in splitRecords) |
| | | { |
| | | // åæ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.OriginalBarcode) && !splitBarcodes.Contains(splitRecord.OriginalBarcode)) |
| | | { |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == stockId); |
| | | |
| | | if (originalStock != null && originalStock.StockQuantity > 0) |
| | | { |
| | | splitReturnQty += originalStock.StockQuantity; |
| | | |
| | | // æ·»å å°æææ¡ç å表ï¼å¦ææ²¡æéå¤ï¼ |
| | | if (!result.AllBarcodes.Contains(splitRecord.OriginalBarcode)) |
| | | { |
| | | result.AllBarcodes.Add(splitRecord.OriginalBarcode); |
| | | } |
| | | |
| | | splitBarcodes.Add(splitRecord.OriginalBarcode); |
| | | _logger.LogInformation($"æå
è®°å½ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°é: {originalStock.StockQuantity}"); |
| | | } |
| | | } |
| | | |
| | | // æ°æ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.NewBarcode) && !splitBarcodes.Contains(splitRecord.NewBarcode)) |
| | | { |
| | | var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.NewBarcode && x.StockId == stockId); |
| | | |
| | | if (newStock != null && newStock.StockQuantity > 0) |
| | | { |
| | | splitReturnQty += newStock.StockQuantity; |
| | | |
| | | // æ·»å å°æææ¡ç å表ï¼å¦ææ²¡æéå¤ï¼ |
| | | if (!result.AllBarcodes.Contains(splitRecord.NewBarcode)) |
| | | { |
| | | result.AllBarcodes.Add(splitRecord.NewBarcode); |
| | | } |
| | | |
| | | splitBarcodes.Add(splitRecord.NewBarcode); |
| | | _logger.LogInformation($"æå
è®°å½ - æ°æ¡ç : {splitRecord.NewBarcode}, æ°é: {newStock.StockQuantity}"); |
| | | } |
| | | } |
| | | |
| | | // è®°å½æå
ä¿¡æ¯ |
| | | _logger.LogInformation($"æå
è®°å½ - ID: {splitRecord.Id}, åæ¡ç : {splitRecord.OriginalBarcode}, " + |
| | | $"æ°æ¡ç : {splitRecord.NewBarcode}, æå
æ°é: {splitRecord.SplitQty}, " + |
| | | $"æ¯å¦èªå¨: {splitRecord.IsAutoSplit}, æ¯å¦æ¤é: {splitRecord.IsReverted}"); |
| | | } |
| | | |
| | | result.SplitReturnQty = splitReturnQty; |
| | | _logger.LogInformation($"åç°{splitRecords.Count}æ¡æå
è®°å½ï¼å
³è {splitBarcodes.Count} 个æ¡ç ï¼æ»æ°é: {splitReturnQty}"); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation($"æªæ¾å°éè¦ååºçæå
è®°å½"); |
| | | } |
| | | |
| | | // 4. è®¡ç®æ»ååºæ°éå空æçç¶æ |
| | | result.TotalReturnQty = result.RemainingLocksReturnQty + |
| | | result.UnallocatedLocksReturnQty + |
| | | result.PalletStockReturnQty + |
| | | result.SplitReturnQty; |
| | | |
| | | result.HasItemsToReturn = result.TotalReturnQty > 0; |
| | | result.IsEmptyPallet = !result.HasItemsToReturn; |
| | | |
| | | // å»éæææ¡ç |
| | | result.AllBarcodes = result.AllBarcodes.Distinct().ToList(); |
| | | |
| | | _logger.LogInformation($"æçç¶æåæå®æ - 订å: {orderNo}, æç: {palletCode}"); |
| | | _logger.LogInformation($"æ±æ»ä¿¡æ¯:"); |
| | | _logger.LogInformation($" - å·²åé
éå®è®°å½: {result.RemainingLocks.Count} æ¡, æ°é: {result.RemainingLocksReturnQty}"); |
| | | _logger.LogInformation($" - æªåé
éå®è®°å½: {result.UnallocatedLocks.Count} æ¡, æ°é: {result.UnallocatedLocksReturnQty}"); |
| | | _logger.LogInformation($" - æªåé
åºåè´§ç©: {result.PalletStockGoods.Count} 个, æ°é: {result.PalletStockReturnQty}"); |
| | | _logger.LogInformation($" - æå
è®°å½: {result.SplitRecords.Count} æ¡, æ°é: {result.SplitReturnQty}"); |
| | | _logger.LogInformation($" - æ»ååºæ°é: {result.TotalReturnQty}"); |
| | | _logger.LogInformation($" - æ¯å¦ç©ºæç: {result.IsEmptyPallet}"); |
| | | _logger.LogInformation($" - æ¶åæ¡ç : {string.Join(", ", result.AllBarcodes)}"); |
| | | |
| | | // 5. é¢å¤çæ°æ®éªè¯ |
| | | await ValidateAnalysisResults(result, stockId); |
| | | |
| | | return result; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | result.HasPalletStockGoods = true; |
| | | result.PalletStockGoods = trulyUnallocatedGoods; |
| | | result.PalletStockReturnQty = trulyUnallocatedGoods.Sum(x => x.StockQuantity); |
| | | _logger.LogError($"æçç¶æåæå¤±è´¥ - 订å: {orderNo}, æç: {palletCode}, Error: {ex.Message}"); |
| | | throw; |
| | | } |
| | | } |
| | | |
| | | foreach (var stock in trulyUnallocatedGoods) |
| | | /// <summary> |
| | | /// éªè¯åæç»æï¼ç¡®ä¿æ°æ®ä¸è´æ§ |
| | | /// </summary> |
| | | private async Task ValidateAnalysisResults(PalletStatusAnalysis analysis, int stockId) |
| | | { |
| | | _logger.LogInformation($"å¼å§éªè¯åæç»æ - 订å: {analysis.OrderNo}, æç: {analysis.PalletCode}"); |
| | | |
| | | try |
| | | { |
| | | // 1. éªè¯éå®è®°å½ååºåæç»çå¹é
|
| | | foreach (var lockInfo in analysis.RemainingLocks.Concat(analysis.UnallocatedLocks)) |
| | | { |
| | | result.AllBarcodes.Add(stock.Barcode); |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId); |
| | | |
| | | if (stockDetail == null) |
| | | { |
| | | _logger.LogWarning($"éå®è®°å½ {lockInfo.Id} çæ¡ç {lockInfo.CurrentBarcode} å¨åºåæç»ä¸ä¸åå¨"); |
| | | } |
| | | else if (stockDetail.StockQuantity <= 0) |
| | | { |
| | | _logger.LogWarning($"éå®è®°å½ {lockInfo.Id} çæ¡ç {lockInfo.CurrentBarcode} åºåæ°é为0æè´æ°"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"åç°{trulyUnallocatedGoods.Count}ä¸ªçæ£æªåé
åºåè´§ç©ï¼æ»æ°é: {result.PalletStockReturnQty}"); |
| | | // 2. éªè¯æ»ååºæ°éçåçæ§ |
| | | // è·åæçä¸çæ»åºåæ°é |
| | | var totalStockOnPallet = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId) |
| | | .SumAsync(x => x.StockQuantity); |
| | | |
| | | if (analysis.TotalReturnQty > totalStockOnPallet) |
| | | { |
| | | _logger.LogWarning($"æ»ååºæ°é {analysis.TotalReturnQty} å¤§äºæçæ»åºå {totalStockOnPallet}ï¼å¯è½åå¨è®¡ç®é误"); |
| | | } |
| | | |
| | | // 3. éªè¯æ¡ç çå¯ä¸æ§ |
| | | var duplicateBarcodes = analysis.AllBarcodes |
| | | .GroupBy(x => x) |
| | | .Where(g => g.Count() > 1) |
| | | .Select(g => g.Key) |
| | | .ToList(); |
| | | |
| | | if (duplicateBarcodes.Any()) |
| | | { |
| | | _logger.LogWarning($"åç°éå¤çæ¡ç : {string.Join(", ", duplicateBarcodes)}"); |
| | | } |
| | | |
| | | _logger.LogInformation($"åæç»æéªè¯å®æ"); |
| | | } |
| | | |
| | | // 3. è®¡ç®æ»ååºæ°é |
| | | result.TotalReturnQty = result.RemainingLocksReturnQty + result.UnallocatedLocksReturnQty + result.PalletStockReturnQty; |
| | | result.HasItemsToReturn = result.TotalReturnQty > 0; |
| | | result.IsEmptyPallet = !result.HasItemsToReturn; |
| | | |
| | | _logger.LogInformation($"æçç¶æåæå®æ - 订å: {orderNo}, æç: {palletCode}, æ»ååºæ°é: {result.TotalReturnQty}"); |
| | | |
| | | return result; |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"åæç»æéªè¯å¤±è´¥ - Error: {ex.Message}"); |
| | | // 䏿åºå¼å¸¸ï¼åªè®°å½é误 |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæªåæ£çéå®è®°å½ååº |
| | | /// ç¡®ä¿ä¸ä¼é误ç»å®æ¡ç æ°éå°é宿°é |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å走空箱 - å
æ§è¡ååºåæ¸
ç - å¢å¼ºçæ¬ |
| | | /// å走空箱 - å
æ§è¡ååºåæ¸
ç |
| | | /// </summary> |
| | | public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | _logger.LogInformation($"ãå走空箱å¼å§ã订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | _logger.LogInformation($"å¼å§å走空箱 - 订å: {orderNo}, æç: {palletCode}"); |
| | | // 1. å
å°è¯æ§è¡ååºæä½ï¼ç¡®ä¿ææç©åé½ååº |
| | | _logger.LogInformation($"æ¥éª¤1: å
æ§è¡ååºæä½"); |
| | | var returnResult = await ExecutePalletReturn(orderNo, palletCode, "å走空箱åååº"); |
| | | if (!returnResult.Status) |
| | | { |
| | | // ååºå¤±è´¥ï¼å¯è½æ¯ç©ºæçæè
æå
¶ä»é®é¢ |
| | | _logger.LogWarning($"ååºæä½å¤±è´¥: {returnResult.Message}"); |
| | | |
| | | // 1. éªè¯ç©ºç®±åèµ°æ¡ä»¶ï¼å¿
é¡»å
¨é¨å®ææ£éï¼ |
| | | // ç»§ç»éªè¯ç©ºç®±åèµ°æ¡ä»¶ |
| | | } |
| | | |
| | | // 2. éªè¯ç©ºç®±åèµ°æ¡ä»¶ï¼å¿
é¡»å
¨é¨å®ææ£éï¼ |
| | | _logger.LogInformation($"æ¥éª¤2: éªè¯ç©ºç®±åèµ°æ¡ä»¶"); |
| | | var validationResult = await ValidateEmptyPalletRemoval(orderNo, palletCode); |
| | | if (!validationResult.IsValid) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"空箱éªè¯å¤±è´¥: {validationResult.ErrorMessage}"); |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | } |
| | | |
| | | var completedLocks = validationResult.Data; |
| | | _logger.LogInformation($"éªè¯éè¿ï¼æ¾å° {completedLocks.Count} æ¡å·²å®æè®°å½"); |
| | | |
| | | // 2. æ¸
ç已宿çéå®è®°å½ï¼æ 记为已åèµ°ï¼ |
| | | await CleanupCompletedLocks(completedLocks); |
| | | // 3. æ¸
ç已宿çéå®è®°å½ï¼æ 记为已åèµ°ï¼ |
| | | _logger.LogInformation($"æ¥éª¤3: æ¸
çéå®è®°å½"); |
| | | foreach (var lockInfo in completedLocks) |
| | | { |
| | | // åªå¤çç¶æä¸ºæ£é宿çè®°å½ï¼å·²åèµ°çè·³è¿ï¼ |
| | | if (lockInfo.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | { |
| | | // æ è®°éå®è®°å½ä¸ºå·²åèµ° |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²åèµ°; |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"éå®è®°å½æ 记为已åèµ° - ID: {lockInfo.Id}"); |
| | | } |
| | | } |
| | | |
| | | // 3. æ¸
ç对åºçåºåè®°å½ç¶æ |
| | | // 4. æ¸
ç对åºçåºåè®°å½ç¶æ |
| | | _logger.LogInformation($"æ¥éª¤4: æ¸
çåºåè®°å½"); |
| | | foreach (var lockInfo in completedLocks) |
| | | { |
| | | await CleanupStockInfo(lockInfo); |
| | | } |
| | | |
| | | // 4. æ´æ°ç¸å
³è®¢åç¶æ |
| | | // 5. æ´æ°ç¸å
³è®¢åç¶æ |
| | | _logger.LogInformation($"æ¥éª¤5: æ´æ°è®¢åç¶æ"); |
| | | await UpdateOrderStatusAfterPalletRemoval(orderNo); |
| | | |
| | | // 5. è®°å½æä½åå² |
| | | // 6. è®°å½æä½åå² |
| | | _logger.LogInformation($"æ¥éª¤6: è®°å½æä½åå²"); |
| | | await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | _logger.LogInformation($"å走空箱æå - 订å: {orderNo}, æç: {palletCode}"); |
| | | _logger.LogInformation($"ãå走空箱æåã订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | return WebResponseContent.Instance.OK("å走空箱æå"); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¶ééè¦ååºçæ¡ç ï¼é¿å
éå¤ï¼ |
| | | /// </summary> |
| | | private async Task<HashSet<string>> CollectBarcodesForReturn(string orderNo, string palletCode, int stockId) |
| | | { |
| | | var barcodes = new HashSet<string>(); |
| | | |
| | | try |
| | | { |
| | | _logger.LogInformation($"å¼å§æ¶éååºæ¡ç - 订å: {orderNo}, æç: {palletCode}, StockId: {stockId}"); |
| | | |
| | | // 1. ä»éå®è®°å½æ¶é |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ |
| | | // || x.Status == (int)OutLockStockStatusEnum.åºåºéå®) |
| | | )) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var lockInfo in lockInfos) |
| | | { |
| | | if (!string.IsNullOrEmpty(lockInfo.CurrentBarcode)) |
| | | { |
| | | barcodes.Add(lockInfo.CurrentBarcode); |
| | | _logger.LogInformation($"ä»éå®è®°å½æ·»å æ¡ç : {lockInfo.CurrentBarcode}"); |
| | | } |
| | | } |
| | | |
| | | // 2. ä»åºåæç»æ¶éï¼ç¶æä¸ºåºåºéå®çï¼ |
| | | var stockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId && |
| | | x.Status == (int)StockStatusEmun.åºåºéå® && |
| | | x.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var stockDetail in stockDetails) |
| | | { |
| | | if (!barcodes.Contains(stockDetail.Barcode) && !string.IsNullOrEmpty(stockDetail.Barcode)) |
| | | { |
| | | barcodes.Add(stockDetail.Barcode); |
| | | _logger.LogInformation($"ä»åºåæç»æ·»å æ¡ç : {stockDetail.Barcode}, æ°é: {stockDetail.StockQuantity}"); |
| | | } |
| | | } |
| | | |
| | | // 3. 仿å
è®°å½æ¶é |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | !x.IsReverted && |
| | | x.Status != (int)SplitPackageStatusEnum.å·²æ£é) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var splitRecord in splitRecords) |
| | | { |
| | | // æ·»å åæ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.OriginalBarcode) && !barcodes.Contains(splitRecord.OriginalBarcode)) |
| | | { |
| | | barcodes.Add(splitRecord.OriginalBarcode); |
| | | _logger.LogInformation($"仿å
è®°å½æ·»å åæ¡ç : {splitRecord.OriginalBarcode}"); |
| | | } |
| | | |
| | | // æ·»å æ°æ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.NewBarcode) && !barcodes.Contains(splitRecord.NewBarcode)) |
| | | { |
| | | barcodes.Add(splitRecord.NewBarcode); |
| | | _logger.LogInformation($"仿å
è®°å½æ·»å æ°æ¡ç : {splitRecord.NewBarcode}"); |
| | | } |
| | | } |
| | | |
| | | _logger.LogInformation($"æ¡ç æ¶é宿 - å
± {barcodes.Count} 个æ¡ç : {string.Join(", ", barcodes)}"); |
| | | |
| | | return barcodes; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"æ¶éååºæ¡ç 失败 - Error: {ex.Message}"); |
| | | return barcodes; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç»ä¸å¤çæ¡ç ååºï¼é¿å
éå¤å¤çï¼ |
| | | /// </summary> |
| | | private async Task ProcessBarcodeReturn(string barcode, int stockId, decimal returnQty, HashSet<string> processedBarcodes) |
| | | { |
| | | if (returnQty <= 0) |
| | | return; |
| | | |
| | | // æ£æ¥æ¯å¦å·²å¤çè¿ |
| | | if (processedBarcodes.Contains(barcode)) |
| | | { |
| | | _logger.LogInformation($"è·³è¿å·²å¤ççæ¡ç : {barcode}"); |
| | | return; |
| | | } |
| | | |
| | | // è·ååºåæç» |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == barcode && x.StockId == stockId); |
| | | |
| | | if (stockDetail == null) |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°æ¡ç 对åºçåºåæç»: {barcode}"); |
| | | return; |
| | | } |
| | | |
| | | // è®°å½åå§å¼ |
| | | decimal originalStockQty = stockDetail.StockQuantity; |
| | | decimal originalOutboundQty = stockDetail.OutboundQuantity; |
| | | int originalStatus = stockDetail.Status; |
| | | |
| | | _logger.LogInformation($"å¤çæ¡ç ååº - {barcode}: åå§åºå={originalStockQty}, åå§åºåº={originalOutboundQty}, ç¶æ={originalStatus}"); |
| | | |
| | | // éªè¯æ°æ®ä¸è´æ§ |
| | | if (originalOutboundQty < returnQty) |
| | | { |
| | | _logger.LogWarning($"åºåºæ°éå°äºååºæ°éï¼è°æ´ååºæ°é - æ¡ç : {barcode}, åºåºæ°é: {originalOutboundQty}, ååºæ°é: {returnQty}"); |
| | | returnQty = originalOutboundQty; |
| | | } |
| | | |
| | | // æ´æ°åºåï¼åºåºæ°éåå°ï¼åºåæ°éå¢å |
| | | stockDetail.OutboundQuantity -= returnQty; |
| | | stockDetail.StockQuantity += returnQty; |
| | | |
| | | // ç¡®ä¿ä¸ä¼åºç°è´æ° |
| | | if (stockDetail.OutboundQuantity < 0) |
| | | { |
| | | _logger.LogWarning($"åºåºæ°éåºç°è´æ°ï¼é置为0 - æ¡ç : {barcode}"); |
| | | stockDetail.OutboundQuantity = 0; |
| | | } |
| | | |
| | | // æ´æ°ç¶æ |
| | | if (stockDetail.OutboundQuantity <= 0 && stockDetail.StockQuantity > 0) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | _logger.LogInformation($"åºåç¶ææ´æ°ä¸ºå
¥åºå®æ - æ¡ç : {barcode}"); |
| | | } |
| | | else if (stockDetail.StockQuantity > 0) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.åºåºéå®; |
| | | _logger.LogInformation($"åºåç¶æä¿æä¸ºåºåºéå® - æ¡ç : {barcode}"); |
| | | } |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | // æ 记为已å¤ç |
| | | processedBarcodes.Add(barcode); |
| | | |
| | | _logger.LogInformation($"æ¡ç ååºå®æ - {barcode}: " + |
| | | $"åºå {originalStockQty} -> {stockDetail.StockQuantity}, " + |
| | | $"åºåº {originalOutboundQty} -> {stockDetail.OutboundQuantity}, " + |
| | | $"ç¶æ {originalStatus} -> {stockDetail.Status}"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæå
è®°å½ååº - é¿å
éå¤ |
| | | /// </summary> |
| | | private async Task HandleSplitRecordsReturn(List<Dt_SplitPackageRecord> splitRecords, int stockId, HashSet<string> processedBarcodes) |
| | | { |
| | | if (!splitRecords.Any()) |
| | | return; |
| | | |
| | | _logger.LogInformation($"å¼å§å¤çæå
è®°å½ååº - å
± {splitRecords.Count} æ¡è®°å½"); |
| | | |
| | | foreach (var splitRecord in splitRecords) |
| | | { |
| | | // åªå¤çæªæ¤éçæå
è®°å½ |
| | | if (splitRecord.IsReverted) |
| | | { |
| | | _logger.LogInformation($"è·³è¿å·²æ¤éçæå
è®°å½ - ID: {splitRecord.Id}"); |
| | | continue; |
| | | } |
| | | |
| | | // å¤çæ°æ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.NewBarcode) && !processedBarcodes.Contains(splitRecord.NewBarcode)) |
| | | { |
| | | var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.NewBarcode && x.StockId == stockId); |
| | | |
| | | if (newStock != null && newStock.StockQuantity > 0) |
| | | { |
| | | // æå
çæ°æ¡ç ååºæ°éåºè¯¥æ¯å
¶åºåæ°é |
| | | await ProcessBarcodeReturn(splitRecord.NewBarcode, stockId, newStock.StockQuantity, processedBarcodes); |
| | | } |
| | | } |
| | | |
| | | // å¤çåæ¡ç |
| | | if (!string.IsNullOrEmpty(splitRecord.OriginalBarcode) && !processedBarcodes.Contains(splitRecord.OriginalBarcode)) |
| | | { |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == stockId); |
| | | |
| | | if (originalStock != null && originalStock.StockQuantity > 0) |
| | | { |
| | | // åæ¡ç çååºæ°éåºè¯¥æ¯æå
åå©ä½çæ°é |
| | | await ProcessBarcodeReturn(splitRecord.OriginalBarcode, stockId, originalStock.StockQuantity, processedBarcodes); |
| | | } |
| | | } |
| | | |
| | | // æ´æ°æå
è®°å½ç¶æä¸ºå·²ååº |
| | | splitRecord.Status = (int)SplitPackageStatusEnum.å·²ååº; |
| | | await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æå
è®°å½ç¶ææ´æ°ä¸ºå·²ååº - è®°å½ID: {splitRecord.Id}"); |
| | | } |
| | | |
| | | _logger.LogInformation($"æå
è®°å½ååºå¤ç宿"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç®åçååºæ¹æ³ - ç»è¿å¤æéªè¯ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> SimplePalletReturn(string orderNo, string palletCode, string returnReason = "ç®åååº") |
| | | { |
| | | try |
| | | { |
| | | _logger.LogInformation($"ãç®åååºå¼å§ã订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. è·ååºåä¿¡æ¯ï¼è·³è¿å¤æéªè¯ï¼ |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); |
| | | } |
| | | |
| | | // 2. ç´æ¥æ¥æ¾éè¦ååºçæ¡ç ï¼ç®åé»è¾ï¼ |
| | | var barcodesToReturn = await GetBarcodesForSimpleReturn(orderNo, palletCode, stockInfo.Id); |
| | | |
| | | if (!barcodesToReturn.Any()) |
| | | { |
| | | try |
| | | { |
| | | _logger.LogInformation($"ãæ ååºç©åãå¤ç空æç"); |
| | | var result = await HandleEmptyPalletReturn(orderNo, palletCode, stockInfo); |
| | | _unitOfWorkManage.CommitTran(); |
| | | return result; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"空箱ååºå¤±è´¥: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"空箱ååºå¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | // 3. ç®åå¤çæ¯ä¸ªæ¡ç |
| | | foreach (var barcode in barcodesToReturn) |
| | | { |
| | | await ProcessSimpleBarcodeReturn(barcode, stockInfo.Id); |
| | | } |
| | | |
| | | // 4. æ´æ°è®¢åç¶æï¼ç®åï¼ |
| | | await UpdateOrderStatusAfterReturn(orderNo); |
| | | |
| | | |
| | | // 5. å建ååºä»»å¡ |
| | | await CreateReturnTask(orderNo, palletCode, stockInfo); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | return WebResponseContent.Instance.OK($"ç®åååºæåï¼å¤ç {barcodesToReturn.Count} 个æ¡ç "); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"ç®åååºå¤±è´¥: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"ååºå¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// ç®åè·åååºæ¡ç |
| | | /// </summary> |
| | | private async Task<List<string>> GetBarcodesForSimpleReturn(string orderNo, string palletCode, int stockId) |
| | | { |
| | | var barcodes = new List<string>(); |
| | | |
| | | try |
| | | { |
| | | // 1. ä»éå®è®°å½è·å |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .Select(x => x.CurrentBarcode) |
| | | .ToListAsync(); |
| | | |
| | | barcodes.AddRange(lockInfos.Where(b => !string.IsNullOrEmpty(b))); |
| | | |
| | | // 2. ä»åºåæç»è·å |
| | | var stockDetails = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId && x.StockQuantity > 0) |
| | | .Select(x => x.Barcode) |
| | | .ToListAsync(); |
| | | |
| | | barcodes.AddRange(stockDetails.Where(b => !string.IsNullOrEmpty(b))); |
| | | |
| | | // å»é |
| | | return barcodes.Distinct().ToList(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"è·åååºæ¡ç 失败: {ex.Message}"); |
| | | return barcodes; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç®åå¤çæ¡ç ååº |
| | | /// </summary> |
| | | private async Task ProcessSimpleBarcodeReturn(string barcode, int stockId) |
| | | { |
| | | try |
| | | { |
| | | // 1. è·ååºåæç» |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == barcode && x.StockId == stockId); |
| | | |
| | | if (stockDetail == null) |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°æ¡ç 对åºçåºåæç»: {barcode}"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 妿æ¯åºåºéå®ç¶æï¼æ¢å¤ä¸ºå
¥åºå®æ |
| | | if (stockDetail.Status == (int)StockStatusEmun.åºåºéå®) |
| | | { |
| | | stockDetail.Status = (int)StockStatusEmun.å
¥åºå®æ; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"æ¡ç ç¶ææ¢å¤ - {barcode}: åºåºéå® -> å
¥åºå®æ"); |
| | | } |
| | | |
| | | // 3. æ´æ°ç¸å
³çéå®è®°å½ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.CurrentBarcode == barcode && |
| | | (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || |
| | | x.Status == (int)OutLockStockStatusEnum.æ£é宿)) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var lockInfo in lockInfos) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²ååº; |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"éå®è®°å½ç¶ææ´æ° - ID: {lockInfo.Id}: å·²ååº"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"å¤çæ¡ç ååºå¤±è´¥ - æ¡ç : {barcode}, Error: {ex.Message}"); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region è¾
婿¹æ³ |
| | |
| | | |
| | | return splitResult; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ§è¡èªå¨æå
é»è¾ |
| | | /// ç¡®ä¿èªå¨æå
ä¸ä¼å½±åååºé»è¾ |
| | | /// </summary> |
| | | private async Task<List<SplitResult>> ExecuteAutoSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQuantity, string palletCode) |
| | | decimal splitQuantity, string palletCode) |
| | | { |
| | | _logger.LogInformation($"å¼å§æ§è¡èªå¨æå
é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå
æ°é: {splitQuantity}"); |
| | | |
| | |
| | | BusinessType = stockDetail.BusinessType, |
| | | InboundOrderRowNo = stockDetail.InboundOrderRowNo, |
| | | }; |
| | | |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°åºåæç» - æ¡ç : {newBarcode}, åºåæ°é: {splitQuantity}"); |
| | | |
| | |
| | | await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å建æ°éå®ä¿¡æ¯ - æ¡ç : {newBarcode}, åé
æ°é: {splitQuantity}, æ 记为æªåé
"); |
| | | |
| | | // èªå¨æå
䏿¹å订åæç»çåé
æ°é |
| | | _logger.LogInformation($"èªå¨æå
- 订åæç»åé
æ°éä¿æä¸å"); |
| | | // éè¦ï¼èªå¨æå
éè¦å¢å 订åæç»çåé
æ°éåé宿°é |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | |
| | | if (orderDetail != null) |
| | | { |
| | | decimal originalAllocated = orderDetail.AllocatedQuantity; |
| | | decimal originalLock = orderDetail.LockQuantity; |
| | | |
| | | orderDetail.AllocatedQuantity += splitQuantity; |
| | | orderDetail.LockQuantity += splitQuantity; |
| | | |
| | | await UpdateBatchAllocateStatus(orderDetail); |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"èªå¨æå
å¢å 订åæç»åé
- åé
æ°é: {originalAllocated} -> {orderDetail.AllocatedQuantity}, " + |
| | | $"é宿°é: {originalLock} -> {orderDetail.LockQuantity}"); |
| | | } |
| | | |
| | | // è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, true, stockDetail.StockQuantity); |
| | |
| | | } |
| | | var targetAddress = originalTask.TargetAddress; |
| | | |
| | | _logger.LogInformation($"CreateReturnTaskAndHandleESS åæ¹å é¤åå²ä»»å¡: {orderNo} ï¼ {originalTask.TaskNum}"); |
| | | // å é¤åå§åºåºä»»å¡ |
| | | //_taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.èªå¨å®æ); |
| | | _task_HtyService.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.人工å é¤); |
| | | var result = _task_HtyService.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.人工å é¤); |
| | | await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | |
| | | if (!result) |
| | | { |
| | | await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | } |
| | | _logger.LogInformation($"CreateReturnTaskAndHandleESS åæ¹å é¤åå²ä»»å¡: {orderNo} ï¼ {originalTask.TaskNum},å½±åè¡ {result}"); |
| | | |
| | | |
| | | // ç» ESS åéæµå¨ä¿¡å·ååå»ºä»»å¡ |