| | |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK($"忶忣æåï¼æ¢å¤æ°éï¼{pickingRecord.PickQuantity}"); |
| | | return WebResponseContent.Instance.OK($"忶忣æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | #endregion |
| | | |
| | | #region åæ¶åæ£ç§ææ¹æ³ |
| | | private async Task<ValidationResult<bool>> ValidateDataConsistencyBeforeCancel(CancelPickingContext context) |
| | | { |
| | | try |
| | | { |
| | | // 1. éªè¯è®¢åæç»æ°æ® |
| | | var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == context.OrderDetail.Id); |
| | | |
| | | if (currentOrderDetail.OverOutQuantity < context.PickingRecord.PickQuantity) |
| | | return ValidationResult<bool>.Error($"订åæç»å·²åºåºæ°é({currentOrderDetail.OverOutQuantity})å°äºåæ¶æ°é({context.PickingRecord.PickQuantity})"); |
| | | |
| | | if (currentOrderDetail.PickedQty < context.PickingRecord.PickQuantity) |
| | | return ValidationResult<bool>.Error($"订åæç»å·²æ£éæ°é({currentOrderDetail.PickedQty})å°äºåæ¶æ°é({context.PickingRecord.PickQuantity})"); |
| | | |
| | | // 2. éªè¯éå®ä¿¡æ¯æ°æ® |
| | | var currentLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == context.LockInfo.Id); |
| | | |
| | | if (currentLockInfo.PickedQty < context.PickingRecord.PickQuantity) |
| | | return ValidationResult<bool>.Error($"éå®ä¿¡æ¯å·²æ£éæ°é({currentLockInfo.PickedQty})å°äºåæ¶æ°é({context.PickingRecord.PickQuantity})"); |
| | | |
| | | // 3. éªè¯åºåæ°æ® |
| | | var currentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .FirstAsync(x => x.Barcode == context.PickingRecord.Barcode && x.StockId == context.PickingRecord.StockId); |
| | | |
| | | if (currentStockDetail == null) |
| | | return ValidationResult<bool>.Error($"æªæ¾å°å¯¹åºçåºåæç»è®°å½"); |
| | | |
| | | if (currentStockDetail.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt() || |
| | | currentStockDetail.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt()) |
| | | return ValidationResult<bool>.Error($"æ¡ç {context.PickingRecord.Barcode}å·²ç»ååºï¼æ æ³åæ¶åæ£"); |
| | | |
| | | // 4. éªè¯ç¶ææµè½¬çåæ³æ§ |
| | | if (!await CanCancelPicking(currentLockInfo, currentStockDetail)) |
| | | return ValidationResult<bool>.Error($"å½åç¶æä¸å
è®¸åæ¶åæ£"); |
| | | |
| | | return ValidationResult<bool>.Success(true); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"åæ¶åæ£æ°æ®ä¸è´æ§éªè¯å¤±è´¥: {ex.Message}"); |
| | | return ValidationResult<bool>.Error($"æ°æ®éªè¯å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | private async Task<bool> CanCancelPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail) |
| | | { |
| | | // éå®ä¿¡æ¯ç¶ææ£æ¥ |
| | | if (lockInfo.Status != (int)OutLockStockStatusEnum.æ£é宿) |
| | | return false; |
| | | |
| | | // åºåç¶ææ£æ¥ |
| | | if (stockDetail.Status == StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | return false; |
| | | |
| | | // å¦ææ¯æå
è®°å½ï¼è¿éè¦æ£æ¥ç¶éå®ä¿¡æ¯ç¶æ |
| | | if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue) |
| | | { |
| | | var parentLock = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .FirstAsync(x => x.Id == lockInfo.ParentLockId.Value); |
| | | |
| | | if (parentLock == null || parentLock.Status == (int)OutLockStockStatusEnum.ååºä¸) |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | private async Task<ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>> ValidateCancelRequest(string orderNo, string palletCode, string barcode) |
| | | { |
| | | // åºç¡åæ°éªè¯ |
| | |
| | | stockDetail.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt(); |
| | | } |
| | | private async Task ExecuteCancelLogic(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, |
| | | Dt_OutboundOrderDetail orderDetail, string orderNo) |
| | | Dt_OutboundOrderDetail orderDetail, string orderNo) |
| | | { |
| | | decimal cancelQty = pickingRecord.PickQuantity; |
| | | |
| | | var currentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == pickingRecord.Barcode && it.StockId == pickingRecord.StockId) |
| | | .FirstAsync(); |
| | | |
| | | if (currentStockDetail != null && |
| | | (currentStockDetail.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt() || |
| | | currentStockDetail.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt())) |
| | | // 1. æ°æ®ä¸è´æ§éªè¯ |
| | | var context = new CancelPickingContext |
| | | { |
| | | throw new Exception($"æ¡ç {pickingRecord.Barcode}å·²ç»ååºï¼æ æ³åæ¶åæ£"); |
| | | } |
| | | // æ£æ¥åæ¶åæ°éä¸ä¼ä¸ºè´æ° |
| | | decimal newOverOutQuantity = orderDetail.OverOutQuantity - cancelQty; |
| | | decimal newPickedQty = orderDetail.PickedQty - cancelQty; |
| | | LockInfo = lockInfo, |
| | | PickingRecord = pickingRecord, |
| | | OrderDetail = orderDetail, |
| | | OrderNo = orderNo, |
| | | CancelQuantity = cancelQty |
| | | }; |
| | | |
| | | if (newOverOutQuantity < 0 || newPickedQty < 0) |
| | | { |
| | | throw new Exception($"忶忣å°å¯¼è´æ°æ®å¼å¸¸ï¼å·²åºåº{newOverOutQuantity}ï¼å·²æ£é{newPickedQty}"); |
| | | } |
| | | var validationResult = await ValidateDataConsistencyBeforeCancel(context); |
| | | if (!validationResult.IsValid) |
| | | throw new Exception(validationResult.ErrorMessage); |
| | | |
| | | // å¤çä¸åç±»åçåæ¶ |
| | | // 2. å¤çä¸åç±»åçåæ¶ |
| | | if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue) |
| | | { |
| | | await HandleSplitBarcodeCancel(lockInfo, pickingRecord, cancelQty); |
| | |
| | | await HandleNormalBarcodeCancel(lockInfo, pickingRecord, cancelQty); |
| | | } |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | // æ´æ°è®¢åæç» |
| | | await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty); |
| | | |
| | | // å 餿£éè®°å½ |
| | | await Db.Deleteable<Dt_PickingRecord>() |
| | | var deleteResult = await Db.Deleteable<Dt_PickingRecord>() |
| | | .Where(x => x.Id == pickingRecord.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // éæ°æ£æ¥è®¢åç¶æ |
| | | await UpdateOrderStatusForReturn(orderNo); |
| | | } |
| | | if (deleteResult <= 0) |
| | | throw new Exception("å 餿£éè®°å½å¤±è´¥"); |
| | | |
| | | _logger.LogInformation($"å 餿£éè®°å½ - è®°å½ID: {pickingRecord.Id}, æ¡ç : {pickingRecord.Barcode}"); |
| | | |
| | | // éæ°æ£æ¥è®¢åç¶æ |
| | | await UpdateOrderStatusForReturn(orderNo); |
| | | |
| | | |
| | | } |
| | | |
| | | private async Task HandleSplitBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty) |
| | | { |
| | | // æ¥æ¾ç¶éå®ä¿¡æ¯ |
| | |
| | | if (parentLockInfo == null) |
| | | throw new Exception("æªæ¾å°ç¶éå®ä¿¡æ¯ï¼æ æ³åæ¶æå
忣"); |
| | | |
| | | // æ£æ¥ç¶æ¡ç åæå
æ¡ç çç¶æ |
| | | if (await IsLockInfoReturned(parentLockInfo)) |
| | | { |
| | | throw new Exception($"ç¶æ¡ç {parentLockInfo.CurrentBarcode}å·²ç»ååºï¼æ æ³åæ¶æå
忣"); |
| | | } |
| | | |
| | | if (await IsLockInfoReturned(lockInfo)) |
| | | { |
| | | throw new Exception($"æå
æ¡ç {lockInfo.CurrentBarcode}å·²ç»ååºï¼æ æ³åæ¶æå
忣"); |
| | | } |
| | | |
| | | // æ¢å¤ç¶éå®ä¿¡æ¯çåé
æ°é |
| | | parentLockInfo.AssignQuantity += cancelQty; |
| | | parentLockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; // æ¢å¤ä¸ºåºåºä¸ç¶æ |
| | | await _outStockLockInfoService.Db.Updateable(parentLockInfo).ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤åºå |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | // æ¢å¤ç¶æ¡ç åºå |
| | | var parentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == parentLockInfo.CurrentBarcode && x.StockId == parentLockInfo.StockId) |
| | | .FirstAsync(); |
| | | |
| | | if (stockDetail != null) |
| | | if (parentStockDetail != null) |
| | | { |
| | | stockDetail.StockQuantity += cancelQty; |
| | | stockDetail.OutboundQuantity = stockDetail.StockQuantity; |
| | | stockDetail.Status = StockStatusEmun.åºåºéå®.ObjToInt(); |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | parentStockDetail.StockQuantity += cancelQty; |
| | | parentStockDetail.OutboundQuantity = parentStockDetail.StockQuantity; |
| | | parentStockDetail.Status = StockStatusEmun.åºåºéå®.ObjToInt(); |
| | | await _stockInfoDetailService.Db.Updateable(parentStockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¢å¤ç¶æ¡ç åºå - æ¡ç : {parentStockDetail.Barcode}, æ¢å¤æ°é: {cancelQty}, æ°åºå: {parentStockDetail.StockQuantity}"); |
| | | } |
| | | |
| | | // å¤çæå
产ççæ°æ¡ç åºå |
| | | var splitStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == lockInfo.CurrentBarcode && x.StockId == lockInfo.StockId) |
| | | .FirstAsync(); |
| | | |
| | | if (splitStockDetail != null) |
| | | { |
| | | // å 餿å
产ççæ°æ¡ç åºåè®°å½ |
| | | await _stockInfoDetailService.Db.Deleteable(splitStockDetail).ExecuteCommandAsync(); |
| | | _logger.LogInformation($"å 餿å
æ°æ¡ç åºå - æ¡ç : {splitStockDetail.Barcode}"); |
| | | } |
| | | |
| | | // æ´æ°æå
è®°å½ç¶æ |
| | | await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>() |
| | | var updateCount = await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>() |
| | | .SetColumns(x => new Dt_SplitPackageRecord |
| | | { |
| | | Status = (int)SplitPackageStatusEnum.å·²æ¤é, |
| | | IsReverted = true, |
| | | Operator = App.User.UserName, |
| | | RevertTime = DateTime.Now |
| | | }) |
| | | .Where(x => x.NewBarcode == lockInfo.CurrentBarcode && !x.IsReverted) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ´æ°æå
è®°å½ç¶æ - æ´æ°è®°å½æ°: {updateCount}"); |
| | | |
| | | // å 餿å
产ççéå®ä¿¡æ¯ |
| | | await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.Id == lockInfo.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty); |
| | | _logger.LogInformation($"å 餿å
éå®ä¿¡æ¯ - éå®ID: {lockInfo.Id}, æ¡ç : {lockInfo.CurrentBarcode}"); |
| | | } |
| | | |
| | | private async Task HandleNormalBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty) |
| | | { |
| | | if (await IsLockInfoReturned(lockInfo)) |
| | | { |
| | | throw new Exception($"æ¡ç {lockInfo.CurrentBarcode}å·²ç»ååºï¼æ æ³åæ¶åæ£"); |
| | | } |
| | | |
| | | // æ¢å¤éå®ä¿¡æ¯ |
| | | lockInfo.PickedQty -= cancelQty; |
| | | if (lockInfo.PickedQty < 0) lockInfo.PickedQty = 0; |
| | | |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | // åªæå½æ£éæ°éå®å
¨åæ¶æ¶ææ¢å¤ç¶æ |
| | | if (lockInfo.PickedQty == 0) |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | } |
| | | |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¢å¤éå®ä¿¡æ¯ - éå®ID: {lockInfo.Id}, æ£åæ£éæ°é: {cancelQty}, æ°å·²æ£éæ°é: {lockInfo.PickedQty}"); |
| | | |
| | | // æ¢å¤åºå |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | |
| | | { |
| | | stockDetail.StockQuantity += cancelQty; |
| | | stockDetail.OutboundQuantity = stockDetail.StockQuantity; |
| | | stockDetail.Status = StockStatusEmun.åºåºéå®.ObjToInt(); |
| | | |
| | | // æ¢å¤åºåç¶æ |
| | | if (stockDetail.Status == StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | { |
| | | stockDetail.Status = StockStatusEmun.åºåºéå®.ObjToInt(); |
| | | } |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¢å¤åºå - æ¡ç : {stockDetail.Barcode}, æ¢å¤æ°é: {cancelQty}, " + |
| | | $"æ°åºå: {stockDetail.StockQuantity}, æ°ç¶æ: {stockDetail.Status}"); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°åºåè®°å½ - æ¡ç : {pickingRecord.Barcode}, åºåID: {pickingRecord.StockId}"); |
| | | } |
| | | } |
| | | |
| | | private async Task UpdateOrderDetailOnCancel(int orderDetailId, decimal cancelQty) |
| | | { |
| | | // è·åææ°ç订åæç»æ°æ® |
| | | // è·åææ°ç订åæç»æ°æ®ï¼å¸¦éï¼ |
| | | var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .With(SqlWith.RowLock) |
| | | .FirstAsync(x => x.Id == orderDetailId); |
| | | |
| | | decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity - cancelQty; |
| | | decimal newPickedQty = currentOrderDetail.PickedQty - cancelQty; |
| | | |
| | | // æ£æ¥åæ¶åæ°éä¸ä¼ä¸ºè´æ° |
| | | if (newOverOutQuantity < 0 || newPickedQty < 0) |
| | | { |
| | | throw new Exception($"忶忣å°å¯¼è´å·²åºåºæ°é({newOverOutQuantity})æå·²æ£éæ°é({newPickedQty})ä¸ºè´æ°"); |
| | | } |
| | | // ä¸¥æ ¼æ£æ¥åæ¶åæ°éä¸ä¼ä¸ºè´æ° |
| | | if (newOverOutQuantity < 0) |
| | | throw new Exception($"忶忣å°å¯¼è´å·²åºåºæ°é({newOverOutQuantity})ä¸ºè´æ°"); |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | if (newPickedQty < 0) |
| | | throw new Exception($"忶忣å°å¯¼è´å·²æ£éæ°é({newPickedQty})ä¸ºè´æ°"); |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | var updateResult = await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity, |
| | | OverOutQuantity = newOverOutQuantity |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | if (updateResult <= 0) |
| | | throw new Exception("æ´æ°è®¢åæç»å¤±è´¥"); |
| | | |
| | | _logger.LogInformation($"æ´æ°è®¢åæç» - OrderDetailId: {orderDetailId}, " + |
| | | $"æ£åå·²åºåº: {cancelQty}, æ°å·²åºåº: {newOverOutQuantity}, " + |
| | | $"æ£åå·²æ£é: {cancelQty}, æ°å·²æ£é: {newPickedQty}"); |
| | | } |
| | | #endregion |
| | | |
| | | #region ååºæä½ç§ææ¹æ³ |
| | |
| | | if (outboundOrder.OrderStatus != newStatus) |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == newStatus) |
| | | .SetColumns( x=> new Dt_OutboundOrder { |
| | | OrderStatus = newStatus, |
| | | Operator = App.User.UserName, |
| | | }) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | |
| | | |
| | | if (outboundOrder.OrderStatus != newStatus) |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == newStatus) |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => new Dt_OutboundOrder |
| | | { |
| | | OrderStatus = newStatus, |
| | | Operator = App.User.UserName, |
| | | }) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | |
| | | .Where(x => x.OrderId == outboundOrder.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 1) |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => new Dt_OutboundOrder |
| | | { |
| | | ReturnToMESStatus = 1, |
| | | Operator = App.User.UserName, |
| | | }) |
| | | |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | |
| | | if (outboundOrder != null && allCompleted && outboundOrder.OrderStatus != (int)OutOrderStatusEnum.åºåºå®æ) |
| | | { |
| | | outboundOrder.OrderStatus = (int)OutOrderStatusEnum.åºåºå®æ; |
| | | outboundOrder.Operator = App.User.UserName; |
| | | await _outboundOrderService.Db.Updateable(outboundOrder).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"订å {orderNo} å·²æ 记为åºåºå®æ"); |
| | |
| | | public bool CanReturn => HasItemsToReturn && !HasActiveTasks; |
| | | public bool CanRemove => IsEmptyPallet && !HasActiveTasks; |
| | | } |
| | | public class PickingContext |
| | | { |
| | | public string OrderNo { get; set; } |
| | | public string PalletCode { get; set; } |
| | | public string Barcode { get; set; } |
| | | public string Operator { get; set; } |
| | | public Dt_OutStockLockInfo LockInfo { get; set; } |
| | | public Dt_OutboundOrderDetail OrderDetail { get; set; } |
| | | public Dt_StockInfoDetail StockDetail { get; set; } |
| | | public decimal ActualQuantity { get; set; } |
| | | public string AdjustedReason { get; set; } |
| | | } |
| | | public class CancelPickingContext |
| | | { |
| | | public string OrderNo { get; set; } |
| | | public string PalletCode { get; set; } |
| | | public string Barcode { get; set; } |
| | | public string Operator { get; set; } |
| | | |
| | | public decimal CancelQuantity { get; set; } |
| | | public Dt_PickingRecord PickingRecord { get; set; } |
| | | public Dt_OutStockLockInfo LockInfo { get; set; } |
| | | public Dt_OutboundOrderDetail OrderDetail { get; set; } |
| | | } |
| | | #endregion |
| | | } |