| | |
| | | using Dm.filter; |
| | | using MailKit.Search; |
| | | using Microsoft.AspNetCore.Http; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using MailKit.Search; |
| | | using Microsoft.Extensions.Logging; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_Common.LocationEnum; |
| | | using WIDESEA_BasicService; |
| | | using WIDESEA_Common.CommonEnum; |
| | | using WIDESEA_Common.OrderEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.BaseRepository; |
| | | using WIDESEA_Core.BaseServices; |
| | | using WIDESEA_Core.Enums; |
| | | using WIDESEA_Core.Helper; |
| | | using WIDESEA_Core.Utilities; |
| | | using WIDESEA_DTO.Basic; |
| | | using WIDESEA_DTO.Inbound; |
| | | using WIDESEA_DTO.Outbound; |
| | | using WIDESEA_IAllocateService; |
| | | using WIDESEA_IBasicService; |
| | | using WIDESEA_ICheckService; |
| | | using WIDESEA_IInboundService; |
| | | using WIDESEA_IOutboundService; |
| | | using WIDESEA_IStockService; |
| | | using WIDESEA_ITaskInfoService; |
| | | using WIDESEA_Model.Models; |
| | | using WIDESEA_Model.Models.Basic; |
| | | using WIDESEA_Model.Models.Check; |
| | | using WIDESEA_Model.Models.Outbound; |
| | | |
| | | namespace WIDESEA_OutboundService |
| | | { |
| | |
| | | private readonly IESSApiService _eSSApiService; |
| | | private readonly IInvokeMESService _invokeMESService; |
| | | private readonly IDailySequenceService _dailySequenceService; |
| | | private readonly IAllocateService _allocateService; |
| | | private readonly IRepository<Dt_InboundOrder> _inboundOrderRepository; |
| | | private readonly IInboundOrderDetailService _inboundOrderDetailService; |
| | | private readonly IRepository<Dt_WarehouseArea> _warehouseAreaRepository; |
| | | private readonly IReCheckOrderService _reCheckOrderService; |
| | | private readonly ITask_HtyService _task_HtyService; |
| | | private readonly ILogger<OutboundPickingService> _logger; |
| | | private readonly IRepository<Dt_InterfaceLog> _interfaceLog; |
| | | |
| | | private Dictionary<string, string> stations = new Dictionary<string, string> |
| | | { |
| | |
| | | public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService, |
| | | IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService, |
| | | IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService, IOutboundOrderService outboundOrderService, |
| | | IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IRepository<Dt_InboundOrder> inboundOrderRepository, IInboundOrderDetailService inboundOrderDetailService) : base(BaseDal) |
| | | IRepository<Dt_Task> taskRepository, IESSApiService eSSApiService, ILogger<OutboundPickingService> logger, IInvokeMESService invokeMESService, IDailySequenceService dailySequenceService, IAllocateService allocateService, IRepository<Dt_InboundOrder> inboundOrderRepository, IInboundOrderDetailService inboundOrderDetailService, IRepository<Dt_WarehouseArea> warehouseAreaRepository, IReCheckOrderService reCheckOrderService, ITask_HtyService task_HtyService, IRepository<Dt_InterfaceLog> interfaceLog) : base(BaseDal) |
| | | { |
| | | _unitOfWorkManage = unitOfWorkManage; |
| | | _stockInfoService = stockInfoService; |
| | |
| | | _logger = logger; |
| | | _invokeMESService = invokeMESService; |
| | | _dailySequenceService = dailySequenceService; |
| | | _allocateService = allocateService; |
| | | _inboundOrderRepository = inboundOrderRepository; |
| | | _inboundOrderDetailService = inboundOrderDetailService; |
| | | _warehouseAreaRepository = warehouseAreaRepository; |
| | | _reCheckOrderService = reCheckOrderService; |
| | | _task_HtyService = task_HtyService; |
| | | _interfaceLog = interfaceLog; |
| | | } |
| | | |
| | | |
| | | #region æ¥è¯¢æ¹æ³ |
| | | // è·åæªæ£éå表 |
| | | public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode) |
| | | { |
| | |
| | | return summary; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region æ ¸å¿ä¸å¡æµç¨ |
| | | /// <summary> |
| | | /// æ£é |
| | |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | |
| | | var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | |
| | | return WebResponseContent.Instance.Error(overPickingValidation.ErrorMessage); |
| | | } |
| | | |
| | | // æ§è¡åæ£é»è¾ |
| | | // æ§è¡åæ£é»è¾ï¼åªå¤çåºååéå®ï¼ä¸å¤ç订åï¼ |
| | | var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, orderNo, palletCode, barcode, actualQty); |
| | | |
| | | // æ´æ°ç¸å
³æ°æ® |
| | | // ç»ä¸æ´æ°è®¢åæ°æ®ï¼ææåæ¯é½å¨è¿éæ´æ°ï¼ |
| | | await UpdateOrderRelatedData(orderDetail.Id, pickingResult.ActualPickedQty, orderNo); |
| | | |
| | | // è®°å½æä½åå² |
| | |
| | | return WebResponseContent.Instance.Error($"æ£é确认失败ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åæ¶æ£é |
| | | /// </summary> |
| | |
| | | } |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. åç½®éªè¯ |
| | | // åç½®éªè¯ |
| | | var validationResult = await ValidateCancelRequest(orderNo, palletCode, barcode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | var (pickingRecord, lockInfo, orderDetail) = validationResult.Data; |
| | | |
| | | // 2. æ§è¡åæ¶é»è¾ |
| | | //æ§è¡åæ¶é»è¾ |
| | | await ExecuteCancelLogic(lockInfo, pickingRecord, orderDetail, orderNo); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | return WebResponseContent.Instance.OK($"忶忣æåï¼æ¢å¤æ°éï¼{pickingRecord.PickQuantity}"); |
| | | return WebResponseContent.Instance.OK($"忶忣æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | { |
| | | _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) |
| | |
| | | if (task == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡ä¿¡æ¯"); |
| | | |
| | | // 3. åæéè¦ååºçè´§ç© |
| | | var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id); |
| | | if (!returnAnalysis.HasItemsToReturn) |
| | | return await HandleNoReturnItems(orderNo, palletCode,task); |
| | | //åæéè¦ååºçè´§ç© |
| | | var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id); |
| | | if (!statusAnalysis.HasItemsToReturn) |
| | | { |
| | | try |
| | | { |
| | | var result = await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id); |
| | | _unitOfWorkManage.CommitTran(); |
| | | if (result.Status) |
| | | { |
| | | task.PalletType = PalletTypeEnum.Empty.ObjToInt(); |
| | | await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InEmpty, PalletTypeEnum.Empty.ObjToInt()); |
| | | } |
| | | return result; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"ReturnRemaining ååºç©ºç®±å¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"ååºç©ºç®±æä½å¤±è´¥: {ex.Message}"); |
| | | } |
| | | |
| | | // 4. æ§è¡ååºæä½ |
| | | await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, returnAnalysis); |
| | | |
| | | // 5. å建ååºä»»å¡ |
| | | await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, returnAnalysis); |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦æè¿è¡ä¸çä»»å¡ |
| | | if (statusAnalysis.HasActiveTasks) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æç {palletCode} æè¿è¡ä¸çä»»å¡ï¼ä¸è½æ§è¡ååºæä½"); |
| | | } |
| | | |
| | | //æ§è¡ååºæä½ |
| | | await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, statusAnalysis); |
| | | |
| | | await ReleaseAllLocksForReallocation(orderNo, palletCode, statusAnalysis); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | // 6. æ´æ°è®¢åç¶æï¼ä¸è§¦åMESåä¼ ï¼ |
| | | |
| | | // å建ååºä»»å¡ |
| | | await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InPick, task.PalletType); |
| | | |
| | | // æ´æ°è®¢åç¶æï¼ä¸è§¦åMESåä¼ ï¼ |
| | | await UpdateOrderStatusForReturn(orderNo); |
| | | |
| | | return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{returnAnalysis.TotalReturnQty}"); |
| | | return WebResponseContent.Instance.OK($"ååºæä½æå"); |
| | | //return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{statusAnalysis.TotalReturnQty}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 空æçåèµ°æ¥å£ï¼å¸¦è®¢åå·ï¼ |
| | | /// éªè¯æçæ¯å¦ççä¸ºç©ºï¼æ¸
çæ°æ®ï¼æ´æ°è®¢åç¶æï¼å建åæçä»»å¡ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) |
| | | return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); |
| | | |
| | | // æ£æ¥è®¢åæ¯å¦åå¨ |
| | | var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .FirstAsync(); |
| | | |
| | | if (order == null) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°è®¢å {orderNo}"); |
| | | |
| | | //æ£æ¥æçæ¯å¦åå¨ä¸å±äºè¯¥è®¢å |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .Where(x => x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); |
| | | |
| | | var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id); |
| | | |
| | | if (!statusAnalysis.CanRemove) |
| | | { |
| | | if (!statusAnalysis.IsEmptyPallet) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æç {palletCode} ä¸è¿æè´§ç©ï¼ä¸è½åèµ°"); |
| | | } |
| | | if (statusAnalysis.HasActiveTasks) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æç {palletCode} è¿æè¿è¡ä¸çä»»å¡ï¼ä¸è½åèµ°"); |
| | | } |
| | | } |
| | | // æ¸
çé¶åºåæ°æ® |
| | | await CleanupZeroStockData(stockInfo.Id); |
| | | |
| | | // å 餿忶ç¸å
³ä»»å¡ |
| | | await HandleTaskCleanup(orderNo, palletCode); |
| | | |
| | | // æ´æ°è®¢åç¸å
³æ°æ® |
| | | await UpdateOrderData(orderNo, palletCode); |
| | | |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | _logger.LogInformation($"空æçåèµ°æä½æå - 订å: {orderNo}, æç: {palletCode}, æä½äºº: {App.User.UserName}"); |
| | | |
| | | return WebResponseContent.Instance.OK("空æçåèµ°æä½æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"RemoveEmptyPallet失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"空æçå走失败: {ex.Message}"); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region åæ£ç¡®è®¤ç§ææ¹æ³ |
| | | |
| | | private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>> ValidatePickingRequest(string orderNo, string palletCode, string barcode) |
| | | { |
| | | // 1. åºç¡åæ°éªè¯ |
| | | // åºç¡åæ°éªè¯ |
| | | if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode) || string.IsNullOrEmpty(barcode)) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error("订åå·ãæçç åæ¡ç ä¸è½ä¸ºç©º"); |
| | | |
| | | // 2. æ¥æ¾ææçéå®ä¿¡æ¯ |
| | | // æ¥æ¾ææçéå®ä¿¡æ¯ |
| | | var lockInfo = await FindValidLockInfo(orderNo, palletCode, barcode); |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"æªæ¾å°ææçéå®ä¿¡æ¯"); |
| | | |
| | | // 3. æ£æ¥è®¢åç¶æ |
| | | // æ£æ¥è®¢åç¶æ |
| | | var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .FirstAsync(); |
| | |
| | | if (order?.OrderStatus == (int)OutOrderStatusEnum.åºåºå®æ) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"订å{orderNo}已宿ï¼ä¸è½ç»§ç»åæ£"); |
| | | |
| | | // 4. è·å订åæç» |
| | | // è·å订åæç» |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | |
| | | if (orderDetail == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"æªæ¾å°è®¢åæç»"); |
| | | |
| | | // 5. æ£æ¥è®¢åæç»æ°é |
| | | // æ£æ¥è®¢åæç»æ°é |
| | | if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"订åæç»éæ±æ°é已满足"); |
| | | |
| | | // 6. è·ååºåæç» |
| | | // è·ååºåæç» |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == barcode && x.StockId == lockInfo.StockId && |
| | | x.Status != StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt()) |
| | |
| | | if (stockDetail == null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"æ æçæ¡ç æç©æç¼ç "); |
| | | |
| | | // 7. æ£æ¥åºåç¶æåæ°é |
| | | // æ£æ¥åºåç¶æåæ°é |
| | | if (stockDetail.StockQuantity <= 0) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"æ¡ç {barcode}åºåä¸è¶³"); |
| | | |
| | | if (stockDetail.Status != StockStatusEmun.åºåºéå®.ObjToInt()) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"æ¡ç {barcode}ç¶æä¸æ£ç¡®ï¼æ æ³åæ£"); |
| | | |
| | | // 8. æ£æ¥æ¯å¦éå¤åæ£ |
| | | //æ£æ¥æ¯å¦éå¤åæ£ |
| | | var existingPicking = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && x.PalletCode == palletCode && x.OutStockLockId == lockInfo.Id) |
| | | .FirstAsync(); |
| | |
| | | { |
| | | // æ¥æ¾åä¸è®¢åä¸çè®°å½ |
| | | lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && it.CurrentBarcode == barcode && it.Status == (int)OutLockStockStatusEnum.åºåºä¸ && it.AssignQuantity > it.PickedQty).FirstAsync(); |
| | | .Where(it => it.OrderNo == orderNo && it.CurrentBarcode == barcode && it.Status == (int)OutLockStockStatusEnum.åºåºä¸ && it.AssignQuantity > it.PickedQty).FirstAsync(); |
| | | |
| | | if (lockInfo == null) |
| | | { |
| | |
| | | var completedLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.CurrentBarcode == barcode && |
| | | (it.Status == (int)OutLockStockStatusEnum.æ£é宿 || |
| | | it.Status == (int)OutLockStockStatusEnum.已鿾 || |
| | | it.Status == (int)OutLockStockStatusEnum.å·²åèµ° || |
| | | it.PickedQty >= it.AssignQuantity)).FirstAsync(); |
| | | |
| | | if (completedLockInfo != null) |
| | | throw new Exception($"æ¡ç {barcode}å·²ç»å®æåæ£ï¼ä¸è½éå¤åæ£"); |
| | | { |
| | | string statusMsg = completedLockInfo.Status switch |
| | | { |
| | | (int)OutLockStockStatusEnum.æ£é宿 => "å·²ç»å®æåæ£", |
| | | (int)OutLockStockStatusEnum.已鿾 => "å·²ç»éæ¾", |
| | | (int)OutLockStockStatusEnum.å·²åèµ° => "å·²ç»åèµ°", |
| | | _ => "å·²ç»å®æåæ£" |
| | | }; |
| | | throw new Exception($"æ¡ç {barcode}{statusMsg}ï¼ä¸è½éå¤åæ£"); |
| | | } |
| | | else |
| | | return null; |
| | | } |
| | |
| | | adjustedReason = adjustedReason != null |
| | | ? $"{adjustedReason}ï¼é²è¶
æ£éå¶ï¼æç»è°æ´ä¸º{actualQty}" |
| | | : $"é²è¶
æ£éå¶ï¼ä»{plannedQty}è°æ´ä¸º{actualQty}"; |
| | | } |
| | | } |
| | | |
| | | if (adjustedReason != null) |
| | | { |
| | |
| | | |
| | | return ValidationResult<bool>.Success(true); |
| | | } |
| | | |
| | | |
| | | private async Task<PickingResult> ExecutePickingLogic( |
| | | Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail, |
| | | string orderNo, string palletCode, string barcode, decimal actualQty) |
| | | Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail, |
| | | string orderNo, string palletCode, string barcode, decimal actualQty) |
| | | { |
| | | decimal stockQuantity = stockDetail.StockQuantity; |
| | | var result = new PickingResult |
| | |
| | | if (actualQty < stockQuantity) |
| | | { |
| | | await HandleSplitPacking(lockInfo, stockDetail, actualQty, stockQuantity, result); |
| | | // æå
åºæ¯è¿åå®é
æ£éæ°é |
| | | result.ActualPickedQty = actualQty; |
| | | } |
| | | else if (actualQty == stockQuantity) |
| | | { |
| | | await HandleFullPicking(lockInfo, stockDetail, actualQty, result); |
| | | // æ´å
æ£éè¿åå®é
æ£éæ°é |
| | | result.ActualPickedQty = actualQty; |
| | | } |
| | | else |
| | | { |
| | | await HandlePartialPicking(lockInfo, stockDetail, actualQty, stockQuantity, result); |
| | | // é¨åæ£éè¿åè°æ´åçæ°é |
| | | result.ActualPickedQty = result.ActualPickedQty; // å·²ç»å¨æ¹æ³å
è°æ´ |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | private async Task HandleSplitPacking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal actualQty, decimal stockQuantity, PickingResult result) |
| | | decimal actualQty, decimal stockQuantity, PickingResult result) |
| | | { |
| | | decimal remainingStockQty = stockQuantity - actualQty; |
| | | |
| | | // 1. æ´æ°åæ¡ç åºå |
| | | // æ´æ°åæ¡ç åºå |
| | | stockDetail.StockQuantity = remainingStockQty; |
| | | stockDetail.OutboundQuantity = remainingStockQty; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | // 2. çææ°æ¡ç |
| | | // çææ°æ¡ç |
| | | string newBarcode = await GenerateNewBarcode(); |
| | | |
| | | // 3. å建æ°éå®ä¿¡æ¯ |
| | | // å建æ°éå®ä¿¡æ¯ |
| | | var newLockInfo = await CreateSplitLockInfo(lockInfo, actualQty, newBarcode); |
| | | |
| | | // 4. è®°å½æå
åå² |
| | | // è®°å½æå
åå² |
| | | await RecordSplitHistory(lockInfo, stockDetail, actualQty, remainingStockQty, newBarcode); |
| | | |
| | | // 5. æ´æ°åéå®ä¿¡æ¯ |
| | | // æ´æ°åéå®ä¿¡æ¯ |
| | | lockInfo.AssignQuantity = remainingStockQty; |
| | | lockInfo.PickedQty = 0; |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // 6. è®¾ç½®ç»æ |
| | | // è®¾ç½®ç»æ |
| | | result.FinalLockInfo = newLockInfo; |
| | | result.FinalBarcode = newBarcode; |
| | | result.SplitResults.AddRange(CreateSplitResults(lockInfo, actualQty, remainingStockQty, newBarcode, stockDetail.Barcode)); |
| | | } |
| | | |
| | | |
| | | |
| | | _logger.LogInformation($"æå
忣宿 - OrderDetailId: {lockInfo.OrderDetailId}, 忣æ°é: {actualQty}"); |
| | | } |
| | | private async Task HandleFullPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal actualQty, PickingResult result) |
| | | { |
| | | // 1. æ´æ°åºå |
| | | // æ´æ°åºå |
| | | stockDetail.StockQuantity = 0; |
| | | stockDetail.OutboundQuantity = 0; |
| | | stockDetail.Status = StockStatusEmun.åºåºå®æ.ObjToInt(); |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | // 2. æ´æ°éå®ä¿¡æ¯ |
| | | // æ´æ°éå®ä¿¡æ¯ |
| | | lockInfo.PickedQty += actualQty; |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.æ£é宿; |
| | | lockInfo.Operator = App.User.UserName; |
| | |
| | | decimal stockOutQty = stockQuantity; |
| | | decimal remainingAssignQty = actualQty - stockQuantity; |
| | | |
| | | // 1. æ´æ°åºå |
| | | // æ´æ°åºå |
| | | stockDetail.StockQuantity = 0; |
| | | stockDetail.OutboundQuantity = 0; |
| | | stockDetail.Status = StockStatusEmun.åºåºå®æ.ObjToInt(); |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | // 2. æ´æ°éå®ä¿¡æ¯ |
| | | // æ´æ°éå®ä¿¡æ¯ |
| | | lockInfo.PickedQty += stockOutQty; |
| | | lockInfo.AssignQuantity = remainingAssignQty; |
| | | lockInfo.Operator = App.User.UserName; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // 3. æ´æ°æå
è®°å½ç¶æ |
| | | // æ´æ°æå
è®°å½ç¶æ |
| | | await UpdateSplitRecordsStatus(stockDetail.Barcode); |
| | | |
| | | result.ActualPickedQty = stockOutQty; |
| | |
| | | |
| | | if (newOverOutQuantity > currentOrderDetail.NeedOutQuantity) |
| | | { |
| | | |
| | | _logger.LogError($"é²è¶
æ£æ£æ¥å¤±è´¥ - OrderDetailId: {orderDetailId}, å·²åºåº: {newOverOutQuantity}, éæ±: {currentOrderDetail.NeedOutQuantity}, æ¬æ¬¡åæ£: {pickedQty}"); |
| | | |
| | | |
| | | decimal adjustedQty = currentOrderDetail.NeedOutQuantity - currentOrderDetail.OverOutQuantity; |
| | | |
| | | if (adjustedQty > 0) |
| | |
| | | _logger.LogWarning($"èªå¨è°æ´åæ£æ°é鲿¢è¶
æ£ï¼ä»{pickedQty}è°æ´ä¸º{adjustedQty}"); |
| | | newOverOutQuantity = currentOrderDetail.NeedOutQuantity; |
| | | newPickedQty = currentOrderDetail.PickedQty + adjustedQty; |
| | | pickedQty = adjustedQty; // æ´æ°å®é
æ£éæ°é |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | // æ´æ°è®¢åæç»æ°éåç¶æ |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity, |
| | | OrderDetailStatus = newOverOutQuantity >= currentOrderDetail.NeedOutQuantity ? |
| | | OrderDetailStatusEnum.Over.ObjToInt() : |
| | | OrderDetailStatusEnum.Outbound.ObjToInt() |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ´æ°é宿°é |
| | | await UpdateOrderDetailLockQuantity(orderDetailId); |
| | | |
| | | // æ£æ¥å¹¶æ´æ°è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(orderNo); |
| | |
| | | PickQuantity = result.ActualPickedQty, |
| | | PickTime = DateTime.Now, |
| | | Operator = App.User.UserName, |
| | | OutStockLockId = result.FinalLockInfo.Id |
| | | OutStockLockId = result.FinalLockInfo.Id, |
| | | BarcodeUnit = result.FinalLockInfo.BarcodeUnit, |
| | | BarcodeQty = result.FinalLockInfo.BarcodeQty, |
| | | BatchNo = result.FinalLockInfo.BatchNo, |
| | | lineNo = result.FinalLockInfo.lineNo, |
| | | SupplyCode = result.FinalLockInfo.SupplyCode, |
| | | WarehouseCode = result.FinalLockInfo.WarehouseCode, |
| | | |
| | | |
| | | }; |
| | | |
| | | await Db.Insertable(pickingHistory).ExecuteCommandAsync(); |
| | |
| | | #endregion |
| | | |
| | | #region åæ¶åæ£ç§ææ¹æ³ |
| | | private async Task<ValidationResult<bool>> ValidateDataConsistencyBeforeCancel(CancelPickingContext context) |
| | | { |
| | | try |
| | | { |
| | | // éªè¯è®¢åæç»æ°æ® |
| | | 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})"); |
| | | |
| | | // éªè¯éå®ä¿¡æ¯æ°æ® |
| | | 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})"); |
| | | |
| | | ////// éªè¯åºåæ°æ® |
| | | ////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}å·²ç»ååºï¼æ æ³åæ¶åæ£"); |
| | | |
| | | // éªè¯ç¶ææµè½¬çåæ³æ§ |
| | | if (!await CanCancelPicking(currentLockInfo, null)) |
| | | 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.已鿾 || lockInfo.Status == (int)OutLockStockStatusEnum.å·²åèµ°) |
| | | return false; |
| | | // éå®ä¿¡æ¯ç¶ææ£æ¥ |
| | | if (lockInfo.Status != (int)OutLockStockStatusEnum.æ£é宿) |
| | | 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.ååºä¸ || |
| | | parentLock.Status == (int)OutLockStockStatusEnum.已鿾 || |
| | | 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) |
| | | { |
| | | // åºç¡åæ°éªè¯ |
| | |
| | | |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("æªæ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯"); |
| | | |
| | | |
| | | if (lockInfo.PickedQty < pickingRecord.PickQuantity) |
| | | { |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error( |
| | |
| | | { |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"æ¡ç {barcode}å·²ç»ååºï¼ä¸è½åæ¶åæ£"); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail)); |
| | | } |
| | | /// <summary> |
| | | /// æ£æ¥æ¡ç æ¯å¦å·²ç»ååº |
| | | /// </summary> |
| | | private async Task<bool> IsBarcodeReturned(string barcode, int stockId) |
| | | { |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == barcode && it.StockId == stockId) |
| | | .FirstAsync(); |
| | | |
| | | if (stockDetail == null) |
| | | return false; |
| | | |
| | | // å¦æç¶ææ¯å
¥åºç¡®è®¤æå
¥åºå®æï¼è¯´æå·²ç»ååº |
| | | return stockDetail.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt() || |
| | | stockDetail.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥éå®ä¿¡æ¯å¯¹åºçæ¡ç æ¯å¦å·²ç»ååº |
| | |
| | | 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())) |
| | | // æ°æ®ä¸è´æ§éªè¯ |
| | | 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); |
| | | |
| | | // å¤çä¸åç±»åçåæ¶ |
| | | // å¤çä¸åç±»åçåæ¶ |
| | | 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(); |
| | | |
| | | // éæ°æ£æ¥è®¢åç¶æ |
| | | 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(); |
| | | } |
| | | |
| | | _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) |
| | | // ä¸¥æ ¼æ£æ¥åæ¶åæ°éä¸ä¼ä¸ºè´æ° |
| | | if (newOverOutQuantity < 0) |
| | | throw new Exception($"忶忣å°å¯¼è´å·²åºåºæ°é({newOverOutQuantity})ä¸ºè´æ°"); |
| | | |
| | | if (newPickedQty < 0) |
| | | throw new Exception($"忶忣å°å¯¼è´å·²æ£éæ°é({newPickedQty})ä¸ºè´æ°"); |
| | | |
| | | // ç¡®å®æ°çç¶æ |
| | | int newStatus; |
| | | if (newOverOutQuantity >= currentOrderDetail.NeedOutQuantity) |
| | | { |
| | | throw new Exception($"忶忣å°å¯¼è´å·²åºåºæ°é({newOverOutQuantity})æå·²æ£éæ°é({newPickedQty})ä¸ºè´æ°"); |
| | | newStatus = OrderDetailStatusEnum.Over.ObjToInt(); |
| | | } |
| | | else if (newOverOutQuantity > 0) |
| | | { |
| | | newStatus = OrderDetailStatusEnum.Outbound.ObjToInt(); |
| | | } |
| | | else |
| | | { |
| | | newStatus = OrderDetailStatusEnum.New.ObjToInt(); |
| | | } |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | // æ´æ°è®¢åæç» |
| | | var updateResult = await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity, |
| | | OrderDetailStatus = newStatus |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | if (updateResult <= 0) |
| | | throw new Exception("æ´æ°è®¢åæç»å¤±è´¥"); |
| | | |
| | | // æ´æ°é宿°é |
| | | await UpdateOrderDetailLockQuantity(orderDetailId); |
| | | |
| | | _logger.LogInformation($"æ´æ°è®¢åæç» - OrderDetailId: {orderDetailId}, " + |
| | | $"æ£åå·²åºåº: {cancelQty}, æ°å·²åºåº: {newOverOutQuantity}, " + |
| | | $"æ£åå·²æ£é: {cancelQty}, æ°å·²æ£é: {newPickedQty}, " + |
| | | $"æ°ç¶æ: {newStatus}"); |
| | | } |
| | | #endregion |
| | | |
| | | #region ååºæä½ç§ææ¹æ³ |
| | | |
| | | private async Task<Dt_StockInfo> GetStockInfo(string palletCode) |
| | | { |
| | | return await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | } |
| | | /// <summary> |
| | | /// æ£æ¥æ´ä¸ªæçæ¯å¦å·²ç»ååº |
| | | /// </summary> |
| | |
| | | return task; |
| | | } |
| | | |
| | | private async Task<ReturnAnalysisResult> AnalyzeReturnItems(string orderNo, string palletCode, int stockId) |
| | | { |
| | | var result = new ReturnAnalysisResult(); |
| | | |
| | | // æ
åµ1ï¼è·åæªåæ£çåºåºéå®è®°å½ |
| | | var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | it.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .ToListAsync(); |
| | | |
| | | if (remainingLocks.Any()) |
| | | { |
| | | result.HasRemainingLocks = true; |
| | | result.RemainingLocks = remainingLocks; |
| | | result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | } |
| | | |
| | | // æ
åµ2ï¼æ£æ¥æç䏿¯å¦æå
¶ä»åºåè´§ç© |
| | | var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.StockId == stockId && |
| | | (it.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt() || |
| | | it.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt() || |
| | | it.Status == StockStatusEmun.åºåºéå®.ObjToInt())) |
| | | .Where(it => it.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | if (palletStockGoods.Any()) |
| | | { |
| | | result.HasPalletStockGoods = true; |
| | | result.PalletStockGoods = palletStockGoods; |
| | | result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity); |
| | | } |
| | | |
| | | // æ
åµ3ï¼æ£æ¥æå
è®°å½ |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.å·²ååº) |
| | | .ToListAsync(); |
| | | |
| | | if (splitRecords.Any()) |
| | | { |
| | | result.HasSplitRecords = true; |
| | | result.SplitRecords = splitRecords; |
| | | result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId); |
| | | } |
| | | |
| | | result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty; |
| | | result.HasItemsToReturn = result.TotalReturnQty > 0; |
| | | |
| | | return result; |
| | | } |
| | | |
| | | private async Task<decimal> CalculateSplitReturnQuantity(List<Dt_SplitPackageRecord> splitRecords, int stockId) |
| | | { |
| | | decimal totalQty = 0; |
| | |
| | | |
| | | foreach (var splitRecord in splitRecords) |
| | | { |
| | | if (splitRecord.Status != (int)SplitPackageStatusEnum.å·²æ¤é) |
| | | continue; |
| | | // æ£æ¥åæ¡ç |
| | | if (!processedBarcodes.Contains(splitRecord.OriginalBarcode)) |
| | | { |
| | | var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId) |
| | | .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockId && |
| | | it.Status != StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | .FirstAsync(); |
| | | |
| | | if (originalStock != null && originalStock.StockQuantity > 0) |
| | |
| | | if (!processedBarcodes.Contains(splitRecord.NewBarcode)) |
| | | { |
| | | var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockId) |
| | | .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockId && it.Status != StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | .FirstAsync(); |
| | | |
| | | if (newStock != null && newStock.StockQuantity > 0) |
| | |
| | | return totalQty; |
| | | } |
| | | |
| | | private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode,Dt_Task originalTask) |
| | | private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode, Dt_Task originalTask, int stockInfoId) |
| | | { |
| | | // æ£æ¥æ¯å¦ææè´§ç©é½å·²æ£é宿 |
| | | var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode) |
| | | .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.æ£é宿); |
| | | try |
| | | { |
| | | var locationtype = 0; |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .Where(x => x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | |
| | | if (allPicked) |
| | | { |
| | | // å é¤åå§åºåºä»»å¡ |
| | | await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | return WebResponseContent.Instance.OK("ææè´§ç©å·²æ£éå®æï¼æç为空"); |
| | | if (stockInfo == null) |
| | | { |
| | | var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>().FirstAsync(x => x.LocationCode == originalTask.SourceAddress); |
| | | locationtype = firstLocation?.LocationType ?? 1; |
| | | } |
| | | else |
| | | { |
| | | locationtype = stockInfo.LocationType; |
| | | _stockInfoService.DeleteData(stockInfo); |
| | | } |
| | | |
| | | var targetAddress = originalTask.TargetAddress; |
| | | |
| | | await CleanupZeroStockData(stockInfoId); |
| | | |
| | | |
| | | var emptystockInfo = new Dt_StockInfo() { PalletType = PalletTypeEnum.Empty.ObjToInt(), StockStatus = StockStatusEmun.ç»çæå.ObjToInt(), PalletCode = palletCode, LocationType = locationtype }; |
| | | emptystockInfo.Details = new List<Dt_StockInfoDetail>(); |
| | | _stockInfoService.AddMaterielGroup(emptystockInfo); |
| | | //空æçå¦ä½å¤ç è¿æä¸ä¸ªåºåºä»»å¡è¦å¤çã |
| | | originalTask.PalletType = PalletTypeEnum.Empty.ObjToInt(); |
| | | |
| | | } |
| | | else |
| | | catch (Exception ex) |
| | | { |
| | | // å é¤åå§åºåºä»»å¡ |
| | | await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | return WebResponseContent.Instance.Error("没æéè¦ååºçå©ä½è´§ç©"); |
| | | _logger.LogError($" HandleNoReturnItems 失败: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($" ååºç©ºæç失败ï¼"); |
| | | } |
| | | //空æçå¦ä½å¤ç è¿æä¸ä¸ªåºåºä»»å¡è¦å¤çã |
| | | |
| | | return WebResponseContent.Instance.OK("空æçååºä»»å¡å建æå"); |
| | | |
| | | } |
| | | |
| | | private async Task ExecuteReturnOperations(string orderNo, string palletCode, Dt_StockInfo stockInfo, |
| | | Dt_Task task, ReturnAnalysisResult analysis) |
| | | Dt_Task task, PalletStatusAnalysis analysis) |
| | | { |
| | | // æ
åµ1ï¼å¤çæªåæ£çåºåºéå®è®°å½ |
| | | if (analysis.HasRemainingLocks) |
| | | { |
| | | await HandleRemainingLocksReturn(analysis.RemainingLocks, stockInfo.Id); |
| | | |
| | | // å
³é®ï¼æ´æ°è®¢åæç»çå·²æ£éæ°é |
| | | await UpdateOrderDetailsOnReturn(analysis.RemainingLocks); |
| | | // await UpdateOrderDetailsOnReturn(analysis.RemainingLocks); |
| | | } |
| | | |
| | | // å¤çæçä¸å
¶ä»åºåè´§ç© |
| | | if (analysis.HasPalletStockGoods) |
| | | { |
| | | await HandlePalletStockGoodsReturn(analysis.PalletStockGoods); |
| | | var validStockGoods = analysis.PalletStockGoods |
| | | .Where(x => x.Status != StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | .ToList(); |
| | | |
| | | if (validStockGoods.Any()) |
| | | { |
| | | await HandlePalletStockGoodsReturn(analysis.PalletStockGoods); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation("æ²¡æææçåºåè´§ç©éè¦ååº"); |
| | | } |
| | | } |
| | | |
| | | // å¤çæå
è®°å½ |
| | | if (analysis.HasSplitRecords) |
| | | { |
| | | await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode); |
| | | var validSplitRecords = analysis.SplitRecords |
| | | .Where(x => x.Status != (int)SplitPackageStatusEnum.å·²æ£é) |
| | | .ToList(); |
| | | |
| | | if (validSplitRecords.Any()) |
| | | { |
| | | await HandleSplitRecordsReturn(analysis.SplitRecords, orderNo, palletCode); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation("æ²¡æææçæå
è®°å½éè¦å¤ç"); |
| | | } |
| | | } |
| | | |
| | | // æ´æ°åºåä¸»è¡¨ç¶æ |
| | | await UpdateStockInfoStatus(stockInfo); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å®å
¨éæ¾éå®ï¼å
è®¸éæ°åé
åºå |
| | | /// </summary> |
| | | private async Task ReleaseAllLocksForReallocation(string orderNo, string palletCode, PalletStatusAnalysis analysis) |
| | | { |
| | | _logger.LogInformation($"å¼å§éæ¾éå®ä»¥ä¾¿éæ°åé
- 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | // å¤çæªåæ£çåºåºéå®è®°å½ - å®å
¨éæ¾ |
| | | if (analysis.HasRemainingLocks) |
| | | { |
| | | await ReleaseRemainingLocks(analysis.RemainingLocks); |
| | | } |
| | | |
| | | // å¤çå·²ååºçéå®è®°å½ - å 餿æ è®°ä¸ºæ æ |
| | | await CleanupReturnedLocks(orderNo, palletCode); |
| | | |
| | | // é置订åæç»çé宿°é |
| | | await ResetOrderDetailLockQuantities(analysis); |
| | | |
| | | _logger.LogInformation($"éå®éæ¾å®æ - 订å: {orderNo}, æç: {palletCode}"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éæ¾æªåæ£çéå®è®°å½ |
| | | /// </summary> |
| | | private async Task ReleaseRemainingLocks(List<Dt_OutStockLockInfo> remainingLocks) |
| | | { |
| | | var lockIds = remainingLocks.Select(x => x.Id).ToList(); |
| | | |
| | | // å°éå®è®°å½ç¶ææ¹ä¸º"已鿾"ï¼æè
ç´æ¥å é¤ |
| | | // æ è®°ä¸ºå·²éæ¾ |
| | | await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>() |
| | | .SetColumns(it => new Dt_OutStockLockInfo |
| | | { |
| | | Status = (int)OutLockStockStatusEnum.已鿾, |
| | | |
| | | Operator = App.User.UserName |
| | | }) |
| | | .Where(it => lockIds.Contains(it.Id)) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // ç´æ¥å é¤ï¼æ´å½»åºï¼ |
| | | // await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() |
| | | // .Where(it => lockIds.Contains(it.Id)) |
| | | // .ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"éæ¾{remainingLocks.Count}æ¡æªåæ£éå®è®°å½"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¸
çå·²ååºçéå®è®°å½ |
| | | /// </summary> |
| | | private async Task CleanupReturnedLocks(string orderNo, string palletCode) |
| | | { |
| | | // æ¥æ¾ææç¶æä¸ºååºä¸çéå®è®°å½å¹¶éæ¾ |
| | | var returnedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | it.Status == (int)OutLockStockStatusEnum.ååºä¸) |
| | | .ToListAsync(); |
| | | |
| | | if (returnedLocks.Any()) |
| | | { |
| | | var returnedLockIds = returnedLocks.Select(x => x.Id).ToList(); |
| | | |
| | | await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>() |
| | | .SetColumns(it => new Dt_OutStockLockInfo |
| | | { |
| | | Status = (int)OutLockStockStatusEnum.已鿾, |
| | | //ReleaseTime = DateTime.Now, |
| | | Operator = App.User.UserName |
| | | }) |
| | | .Where(it => returnedLockIds.Contains(it.Id)) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ¸
ç{returnedLocks.Count}æ¡ååºä¸éå®è®°å½"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// é置订åæç»çé宿°é |
| | | /// </summary> |
| | | private async Task ResetOrderDetailLockQuantities(PalletStatusAnalysis analysis) |
| | | { |
| | | // æ¶éææåå½±åç订åæç»ID |
| | | var affectedOrderDetailIds = new HashSet<int>(); |
| | | |
| | | if (analysis.HasRemainingLocks) |
| | | { |
| | | foreach (var lockInfo in analysis.RemainingLocks) |
| | | { |
| | | affectedOrderDetailIds.Add(lockInfo.OrderDetailId); |
| | | } |
| | | } |
| | | |
| | | // éç½®è¿äºè®¢åæç»çé宿°é |
| | | foreach (var orderDetailId in affectedOrderDetailIds) |
| | | { |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | LockQuantity = 0, // éç½®é宿°é |
| | | OrderDetailStatus = OrderDetailStatusEnum.New.ObjToInt() // éç½®ç¶æä¸ºæ°å»º |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | _logger.LogInformation($"éç½®{affectedOrderDetailIds.Count}个订åæç»çé宿°é"); |
| | | } |
| | | private async Task HandleRemainingLocksReturn(List<Dt_OutStockLockInfo> remainingLocks, int stockId) |
| | | { |
| | | var lockIds = remainingLocks.Select(x => x.Id).ToList(); |
| | |
| | | foreach (var lockInfo in remainingLocks) |
| | | { |
| | | decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | if (returnQty <= 0) |
| | | { |
| | | _logger.LogWarning($"éå®è®°å½{lockInfo.Id}æ éååºï¼åé
æ°é: {lockInfo.AssignQuantity}, å·²æ£é: {lockInfo.PickedQty}"); |
| | | continue; |
| | | } |
| | | |
| | | _logger.LogInformation($"å¤çéå®è®°å½ååº - éå®ID: {lockInfo.Id}, æ¡ç : {lockInfo.CurrentBarcode}, ååºæ°é: {returnQty}"); |
| | | // æ¥æ¾å¯¹åºçåºåæç» |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId) |
| | |
| | | |
| | | if (stockDetail != null) |
| | | { |
| | | stockDetail.StockQuantity += returnQty; |
| | | // æ¢å¤åºåç¶æ |
| | | stockDetail.OutboundQuantity = Math.Max(0, stockDetail.OutboundQuantity - returnQty); |
| | | stockDetail.Status = StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt(); |
| | |
| | | } |
| | | else |
| | | { |
| | | _logger.LogWarning($"æªæ¾å°å¯¹åºçåºåæç» - æ¡ç : {lockInfo.CurrentBarcode}, åºåID: {lockInfo.StockId}"); |
| | | // å建æ°çåºåè®°å½ |
| | | var newStockDetail = new Dt_StockInfoDetail |
| | | { |
| | | StockId = lockInfo.StockId, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | MaterielName = lockInfo.MaterielName, |
| | | OrderNo = lockInfo.OrderNo, |
| | | BatchNo = lockInfo.BatchNo, |
| | | StockQuantity = returnQty, |
| | | OutboundQuantity = 0, |
| | | Barcode = lockInfo.CurrentBarcode, |
| | | InboundOrderRowNo = "", |
| | | Status = StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt(), |
| | | SupplyCode = lockInfo.SupplyCode, |
| | | WarehouseCode = lockInfo.WarehouseCode, |
| | | Unit = lockInfo.Unit, |
| | | }; |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | //var newStockDetail = new Dt_StockInfoDetail |
| | | //{ |
| | | // StockId = lockInfo.StockId, |
| | | // MaterielCode = lockInfo.MaterielCode, |
| | | // MaterielName = lockInfo.MaterielName, |
| | | // OrderNo = lockInfo.OrderNo, |
| | | // BatchNo = lockInfo.BatchNo, |
| | | // StockQuantity = returnQty, |
| | | // OutboundQuantity = 0, |
| | | // Barcode = lockInfo.CurrentBarcode, |
| | | // InboundOrderRowNo = "", |
| | | // Status = StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt(), |
| | | // SupplyCode = lockInfo.SupplyCode, |
| | | // WarehouseCode = lockInfo.WarehouseCode, |
| | | // Unit = lockInfo.Unit, |
| | | //}; |
| | | //await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private async Task UpdateOrderDetailsOnReturn(List<Dt_OutStockLockInfo> remainingLocks) |
| | | { |
| | | // æè®¢åæç»åç» |
| | | var orderDetailGroups = remainingLocks.GroupBy(x => x.OrderDetailId); |
| | | |
| | | foreach (var group in orderDetailGroups) |
| | | { |
| | | var orderDetailId = group.Key; |
| | | var totalReturnQty = group.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | // è·åå½å订åæç» |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == orderDetailId); |
| | | |
| | | if (orderDetail != null) |
| | | try |
| | | { |
| | | // è°æ´å·²æ£éæ°éåå·²åºåºæ°é |
| | | decimal newPickedQty = Math.Max(0, orderDetail.PickedQty - totalReturnQty); |
| | | decimal newOverOutQuantity = Math.Max(0, orderDetail.OverOutQuantity - totalReturnQty); |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity, |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | if (orderDetail != null) |
| | | { |
| | | decimal newLockQuantity = Math.Max(0, orderDetail.LockQuantity - returnQty); |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | LockQuantity = newLockQuantity |
| | | }) |
| | | .Where(it => it.Id == lockInfo.OrderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"æ´æ°è®¢åæç»é宿°é - OrderDetailId: {lockInfo.OrderDetailId}, " + |
| | | $"æ£åéå®: {returnQty}, æ°é宿°é: {newLockQuantity}"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"æ´æ°è®¢åæç»é宿°é失败 - OrderDetailId: {lockInfo.OrderDetailId}, Error: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | private async Task HandlePalletStockGoodsReturn(List<Dt_StockInfoDetail> palletStockGoods) |
| | | { |
| | |
| | | foreach (var stockGood in palletStockGoods) |
| | | { |
| | | _logger.LogInformation($"å¾
ååºè´§ç© - æ¡ç : {stockGood.Barcode}, æ°é: {stockGood.StockQuantity}, å½åç¶æ: {stockGood.Status}"); |
| | | |
| | | // æ¢å¤åºåç¶æ |
| | | stockGood.OutboundQuantity = 0; |
| | | stockGood.Status = StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt(); |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync(); |
| | | if (stockGood.Status != StockStatusEmun.åºåºå®æ.ObjToInt()) |
| | | { |
| | | stockGood.OutboundQuantity = 0; |
| | | stockGood.Status = StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt(); |
| | | await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"åºåè´§ç©ååºå®æ - æ¡ç : {stockGood.Barcode}, æ°ç¶æ: {stockGood.Status}"); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogWarning($"è·³è¿å·²åºåºå®æçè´§ç© - æ¡ç : {stockGood.Barcode}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private async Task HandleSplitRecordsReturn(List<Dt_SplitPackageRecord> splitRecords, string orderNo, string palletCode) |
| | | { |
| | | var validRecords = splitRecords.Where(x => x.Status != (int)SplitPackageStatusEnum.å·²æ£é).ToList(); |
| | | |
| | | if (!validRecords.Any()) |
| | | { |
| | | _logger.LogInformation("没æéè¦ååºçæå
è®°å½"); |
| | | return; |
| | | } |
| | | |
| | | _logger.LogInformation($"æ´æ°{validRecords.Count}æ¡æå
è®°å½ç¶æä¸ºå·²ååº"); |
| | | |
| | | // æ´æ°æå
è®°å½ç¶æ |
| | | await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>() |
| | | .SetColumns(x => new Dt_SplitPackageRecord |
| | | { |
| | | Status = (int)SplitPackageStatusEnum.å·²ååº, |
| | | Operator = App.User.UserName |
| | | }) |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && !x.IsReverted) |
| | | .Where(x => validRecords.Select(r => r.Id).Contains(x.Id)) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | |
| | | /// <param name="originalTask"></param> |
| | | /// <param name="analysis"></param> |
| | | /// <returns></returns> |
| | | private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, ReturnAnalysisResult analysis) |
| | | private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, TaskTypeEnum taskTypeEnum, int palletType) |
| | | { |
| | | var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>() |
| | | .FirstAsync(x => x.LocationCode == originalTask.SourceAddress); |
| | |
| | | Grade = 0, |
| | | PalletCode = palletCode, |
| | | NextAddress = "", |
| | | OrderNo = originalTask.OrderNo, |
| | | // OrderNo = originalTask.OrderNo, |
| | | OrderNo = orderNo, |
| | | Roadway = newLocation.RoadwayNo, |
| | | SourceAddress = stations[originalTask.TargetAddress], |
| | | TargetAddress = newLocation.LocationCode, |
| | | TaskStatus = TaskStatusEnum.New.ObjToInt(), |
| | | TaskType = TaskTypeEnum.InPick.ObjToInt(), |
| | | PalletType = originalTask.PalletType, |
| | | TaskType = taskTypeEnum.ObjToInt(), |
| | | PalletType = palletType, |
| | | WarehouseId = originalTask.WarehouseId |
| | | |
| | | }; |
| | | // ä¿åååºä»»å¡ |
| | | await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync(); |
| | | var targetAddress = originalTask.TargetAddress; |
| | | |
| | | try |
| | | { |
| | | // ä¿åååºä»»å¡ |
| | | var insertcount = await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync(); |
| | | if (insertcount <= 0) |
| | | { |
| | | throw new Exception("å建任å¡å¤±è´¥ï¼"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogInformation($"CreateReturnTaskAndHandleESS å建任å¡å¤±è´¥: {orderNo} ï¼ {palletCode}"); |
| | | throw new Exception("å建任å¡å¤±è´¥ï¼"); |
| | | } |
| | | var targetAddress = originalTask.TargetAddress; |
| | | |
| | | _logger.LogInformation($"CreateReturnTaskAndHandleESS å é¤åå²ä»»å¡: {orderNo} ï¼ {originalTask.TaskNum}"); |
| | | // å é¤åå§åºåºä»»å¡ |
| | | await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | // _taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.èªå¨å®æ); |
| | | var result = _task_HtyService.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.人工å é¤); |
| | | if (!result) |
| | | { |
| | | await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | } |
| | | _logger.LogInformation($"CreateReturnTaskAndHandleESS å é¤åå²ä»»å¡: {orderNo} ï¼ {originalTask.TaskNum},å½±åè¡ {result}"); |
| | | |
| | | // ç» ESS åéæµå¨ä¿¡å·ååå»ºä»»å¡ |
| | | await SendESSCommands(palletCode, targetAddress, returnTask); |
| | |
| | | { |
| | | try |
| | | { |
| | | // 1. åéæµå¨ä¿¡å· |
| | | // åéæµå¨ä¿¡å· |
| | | var moveResult = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest |
| | | { |
| | | slotCode = movestations[targetAddress], |
| | | containerCode = palletCode |
| | | }); |
| | | |
| | | if (moveResult) |
| | | //if (moveResult) |
| | | //{ |
| | | // å建ååºä»»å¡ |
| | | var essTask = new TaskModel() |
| | | { |
| | | // 2. å建ååºä»»å¡ |
| | | var essTask = new TaskModel() |
| | | { |
| | | taskType = "putaway", |
| | | taskGroupCode = "", |
| | | groupPriority = 0, |
| | | tasks = new List<TasksType> |
| | | { |
| | | new() |
| | | { |
| | | taskType = "putaway", |
| | | taskGroupCode = "", |
| | | groupPriority = 0, |
| | | tasks = new List<TasksType>{ new() { |
| | | taskCode = returnTask.TaskNum.ToString(), |
| | | taskPriority = 0, |
| | | taskDescribe = new TaskDescribeType |
| | |
| | | deadline = 0, |
| | | storageTag = "" |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | } } |
| | | }; |
| | | |
| | | var resultTask = await _eSSApiService.CreateTaskAsync(essTask); |
| | | _logger.LogInformation($"ReturnRemaining åå»ºä»»å¡æå: {resultTask}"); |
| | | } |
| | | var resultTask = await _eSSApiService.CreateTaskAsync(essTask); |
| | | _logger.LogInformation($"ReturnRemaining åå»ºä»»å¡æå: {resultTask}"); |
| | | //} |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | .ToListAsync(); |
| | | |
| | | bool allCompleted = true; |
| | | bool hasPartial = false; |
| | | bool hasLocked = false; |
| | | |
| | | foreach (var detail in orderDetails) |
| | | { |
| | | if (detail.OverOutQuantity < detail.NeedOutQuantity) |
| | | { |
| | | allCompleted = false; |
| | | break; |
| | | } |
| | | |
| | | if (detail.OrderDetailStatus == OrderDetailStatusEnum.Outbound.ObjToInt()) |
| | | { |
| | | hasPartial = true; |
| | | } |
| | | |
| | | //if (detail.OrderDetailStatus == OrderDetailStatusEnum.Locked.ObjToInt()) |
| | | //{ |
| | | // hasLocked = true; |
| | | //} |
| | | } |
| | | |
| | | var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | |
| | | |
| | | if (outboundOrder == null) return; |
| | | |
| | | int newStatus = allCompleted ? (int)OutOrderStatusEnum.åºåºå®æ : (int)OutOrderStatusEnum.åºåºä¸; |
| | | int newStatus; |
| | | if (allCompleted) |
| | | { |
| | | newStatus = (int)OutOrderStatusEnum.åºåºå®æ; |
| | | } |
| | | else if (hasPartial) |
| | | { |
| | | newStatus = (int)OutOrderStatusEnum.åºåºä¸; |
| | | } |
| | | else |
| | | { |
| | | newStatus = (int)OutOrderStatusEnum.æªå¼å§; |
| | | } |
| | | |
| | | 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(); |
| | | |
| | | // åªææ£å¸¸åæ£å®ææ¶æåMESåé¦ |
| | | if (allCompleted && newStatus == (int)OutOrderStatusEnum.åºåºå®æ) |
| | | { |
| | | await HandleOrderCompletion(outboundOrder, orderNo); |
| | | } |
| | | _logger.LogInformation($"订åç¶ææ´æ° - OrderNo: {orderNo}, æ§ç¶æ: {outboundOrder.OrderStatus}, æ°ç¶æ: {newStatus}"); |
| | | |
| | | |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ´æ°è®¢åæç»ç¶æï¼åºäºå·²åºåºæ°éï¼ |
| | | /// </summary> |
| | | private async Task UpdateOrderDetailStatus(int orderDetailId) |
| | | { |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == orderDetailId); |
| | | |
| | | if (orderDetail == null) return; |
| | | |
| | | int newStatus = orderDetail.OrderDetailStatus; |
| | | |
| | | if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity) |
| | | { |
| | | // å·²åºåºæ°é >= éæ±æ°éï¼æ è®°ä¸ºå®æ |
| | | newStatus = OrderDetailStatusEnum.Over.ObjToInt(); |
| | | } |
| | | else if (orderDetail.OverOutQuantity > 0) |
| | | { |
| | | // æé¨ååºåºï¼ä½æªå®æ |
| | | newStatus = OrderDetailStatusEnum.Outbound.ObjToInt(); |
| | | } |
| | | else if (orderDetail.LockQuantity > 0) |
| | | { |
| | | // æé宿°éï¼ä½æªåºåº |
| | | //newStatus = OrderDetailStatusEnum.Locked.ObjToInt(); |
| | | } |
| | | else |
| | | { |
| | | // æ°å»ºç¶æ |
| | | newStatus = OrderDetailStatusEnum.New.ObjToInt(); |
| | | } |
| | | |
| | | // åªæç¶æåçååæ¶ææ´æ° |
| | | if (orderDetail.OrderDetailStatus != newStatus) |
| | | { |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | OrderDetailStatus = newStatus, |
| | | |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// æ´æ°è®¢åæç»é宿°é |
| | | /// </summary> |
| | | private async Task UpdateOrderDetailLockQuantity(int orderDetailId) |
| | | { |
| | | var totalLockedQty = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderDetailId == orderDetailId && |
| | | x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .SumAsync(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | LockQuantity = totalLockedQty |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | private async Task UpdateOrderStatusForReturn(string orderNo) |
| | | { |
| | | try |
| | |
| | | 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(); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | private async Task HandleOrderCompletion(Dt_OutboundOrder outboundOrder, string orderNo) |
| | | { |
| | | // è°æ¨åºåºå鿣åºåºä¸éè¦åé¦MES |
| | | if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt() || |
| | | outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt()) |
| | | { |
| | | return; |
| | | } |
| | | #endregion |
| | | |
| | | #region 空æç |
| | | |
| | | /// <summary> |
| | | /// æ¸
çé¶åºåæ°æ® |
| | | /// </summary> |
| | | private async Task CleanupZeroStockData(int stockId) |
| | | { |
| | | try |
| | | { |
| | | var feedmodel = new FeedbackOutboundRequestModel |
| | | { |
| | | reqCode = Guid.NewGuid().ToString(), |
| | | reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), |
| | | business_type = outboundOrder.BusinessType, |
| | | factoryArea = outboundOrder.FactoryArea, |
| | | operationType = 1, |
| | | Operator = App.User.UserName, |
| | | orderNo = outboundOrder.UpperOrderNo, |
| | | status = outboundOrder.OrderStatus, |
| | | details = new List<FeedbackOutboundDetailsModel>() |
| | | }; |
| | | // 1. å é¤åºåæ°é为0çæç»è®°å½ |
| | | var deleteDetailCount = await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(x => x.StockId == stockId && x.StockQuantity == 0) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // åªè·åå·²æ£é宿çéå®è®°å½ |
| | | var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | .ToListAsync(); |
| | | _stockInfoService.DeleteData(stockId); |
| | | |
| | | var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.lineNo, item.Unit, item.WarehouseCode }) |
| | | .Select(group => new FeedbackOutboundDetailsModel |
| | | { |
| | | materialCode = group.Key.MaterielCode, |
| | | lineNo = group.Key.lineNo, |
| | | warehouseCode = group.Key.WarehouseCode, |
| | | qty = group.Sum(x => x.PickedQty), |
| | | currentDeliveryQty = group.Sum(x => x.PickedQty), |
| | | unit = group.Key.Unit, |
| | | barcodes = group.Select(row => new WIDESEA_DTO.Outbound.BarcodesModel |
| | | { |
| | | barcode = row.CurrentBarcode, |
| | | supplyCode = row.SupplyCode, |
| | | batchNo = row.BatchNo, |
| | | unit = row.Unit, |
| | | qty = row.PickedQty |
| | | }).ToList() |
| | | }).ToList(); |
| | | _logger.LogInformation($"æ¸
çé¶åºåæç»è®°å½ - StockId: {stockId}, å é¤è®°å½æ°: {deleteDetailCount}"); |
| | | |
| | | feedmodel.details = groupedData; |
| | | |
| | | var result = await _invokeMESService.FeedbackOutbound(feedmodel); |
| | | if (result != null && result.code == 200) |
| | | { |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 1) |
| | | .Where(x => x.OrderId == outboundOrder.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 1) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"FeedbackOutbound失败 - OrderNo: {orderNo}, Error: {ex.Message}"); |
| | | _logger.LogWarning($"æ¸
çé¶åºåæ°æ®å¤±è´¥ - StockId: {stockId}, Error: {ex.Message}"); |
| | | // 注æï¼æ¸
ç失败ä¸åºè¯¥å½±å主æµç¨ |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// å¤ç任塿¸
çï¼æè®¢ååæçï¼ |
| | | /// </summary> |
| | | private async Task HandleTaskCleanup(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | // æ¥æ¾ææä¸è¯¥è®¢ååæçç¸å
³çä»»å¡ |
| | | var tasks = await _taskRepository.Db.Queryable<Dt_Task>().Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode).ToListAsync(); |
| | | |
| | | if (tasks.Any()) |
| | | { |
| | | foreach (var task in tasks) |
| | | { |
| | | task.TaskStatus = (int)TaskStatusEnum.Finish; |
| | | } |
| | | // await _taskRepository.Db.Updateable(tasks).ExecuteCommandAsync(); |
| | | |
| | | _taskRepository.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.èªå¨å®æ); |
| | | _logger.LogInformation($"宿{tasks.Count}个æçä»»å¡ - 订å: {orderNo}, æç: {palletCode}"); |
| | | } |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogWarning($"å¤ç任塿¸
ç失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | throw new Exception($"任塿¸
ç失败: {ex.Message}"); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// æ´æ°è®¢åç¸å
³æ°æ® |
| | | /// </summary> |
| | | private async Task UpdateOrderData(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | // æ£æ¥è®¢åæ¯å¦è¿æå
¶ä»æçå¨å¤çä¸ |
| | | var otherActivePallets = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode != palletCode && |
| | | (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || x.Status == (int)OutLockStockStatusEnum.ååºä¸)) |
| | | .AnyAsync(); |
| | | |
| | | var otherActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode != palletCode |
| | | // && x.TaskStatus.In((int)TaskStatusEnum.å¾
æ§è¡, (int)TaskStatusEnum.æ§è¡ä¸) |
| | | ) |
| | | .AnyAsync(); |
| | | |
| | | // å¦ææ²¡æå
¶ä»æçå¨å¤çï¼æ£æ¥è®¢åæ¯å¦åºè¯¥å®æ |
| | | if (!otherActivePallets && !otherActiveTasks) |
| | | { |
| | | await CheckAndUpdateOrderCompletion(orderNo); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation($"订å {orderNo} è¿æå
¶ä»æçå¨å¤çï¼ä¸æ´æ°è®¢åç¶æ"); |
| | | } |
| | | |
| | | // æ´æ°æ£éè®°å½ç¶æï¼å¯éï¼ |
| | | await UpdatePickingRecordsStatus(orderNo, palletCode); |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogWarning($"æ´æ°è®¢åæ°æ®å¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | throw new Exception($"æ´æ°è®¢åæ°æ®å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥å¹¶æ´æ°è®¢åå®æç¶æ |
| | | /// </summary> |
| | | private async Task CheckAndUpdateOrderCompletion(string orderNo) |
| | | { |
| | | var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id) |
| | | .Where((o, item) => item.OrderNo == orderNo) |
| | | .Select((o, item) => o) |
| | | .ToListAsync(); |
| | | |
| | | bool allCompleted = true; |
| | | foreach (var detail in orderDetails) |
| | | { |
| | | if (detail.OverOutQuantity < detail.NeedOutQuantity) |
| | | { |
| | | allCompleted = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .FirstAsync(x => x.OrderNo == orderNo); |
| | | |
| | | 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} å·²æ 记为åºåºå®æ"); |
| | | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ´æ°æ£éè®°å½ç¶æ |
| | | /// </summary> |
| | | private async Task UpdatePickingRecordsStatus(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | // å¯ä»¥å°ç¸å
³çæ£éè®°å½æ è®°ä¸ºå·²å®æ |
| | | var pickingRecords = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | // è¿éå¯ä»¥æ ¹æ®éè¦æ´æ°æ£éè®°å½çç¶æåæ®µ |
| | | // ä¾å¦ï¼pickingRecord.Status = (int)PickingStatusEnum.已宿; |
| | | _logger.LogInformation($"æ¾å°{pickingRecords.Count}æ¡æ£éè®°å½ - 订å: {orderNo}, æç: {palletCode}"); |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogWarning($"æ´æ°æ£éè®°å½ç¶æå¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | |
| | | |
| | | #region è¾
婿¹æ³ |
| | | /// <summary> |
| | | /// ç»ä¸åææçç¶æ - è¿åæçç宿´ç¶æä¿¡æ¯ |
| | | /// </summary> |
| | | private async Task<PalletStatusAnalysis> AnalyzePalletStatus(string orderNo, string palletCode, int stockId) |
| | | { |
| | | var result = new PalletStatusAnalysis |
| | | { |
| | | OrderNo = orderNo, |
| | | PalletCode = palletCode, |
| | | StockId = stockId |
| | | }; |
| | | |
| | | // åææªåæ£çåºåºéå®è®°å½ |
| | | var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | it.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .ToListAsync(); |
| | | |
| | | if (remainingLocks.Any()) |
| | | { |
| | | result.HasRemainingLocks = true; |
| | | result.RemainingLocks = remainingLocks; |
| | | result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | _logger.LogInformation($"åç°{remainingLocks.Count}æ¡æªåæ£éå®è®°å½ï¼æ»æ°é: {result.RemainingLocksReturnQty}"); |
| | | } |
| | | |
| | | // åææçä¸çåºåè´§ç© |
| | | var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.StockId == stockId && |
| | | (it.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt() || |
| | | it.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt() || |
| | | it.Status == StockStatusEmun.åºåºéå®.ObjToInt())) |
| | | .Where(it => it.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | if (palletStockGoods.Any()) |
| | | { |
| | | result.HasPalletStockGoods = true; |
| | | result.PalletStockGoods = palletStockGoods; |
| | | result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity); |
| | | _logger.LogInformation($"åç°{palletStockGoods.Count}个åºåè´§ç©ï¼æ»æ°é: {result.PalletStockReturnQty}"); |
| | | |
| | | // è®°å½è¯¦ç»ç¶æåå¸ |
| | | var statusGroups = palletStockGoods.GroupBy(x => x.Status); |
| | | foreach (var group in statusGroups) |
| | | { |
| | | _logger.LogInformation($"åºåç¶æ{group.Key}: {group.Count()}个货ç©ï¼æ°é: {group.Sum(x => x.StockQuantity)}"); |
| | | } |
| | | } |
| | | |
| | | //åææå
è®°å½ |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.å·²æ£é && |
| | | it.Status != (int)SplitPackageStatusEnum.å·²ååº) |
| | | .ToListAsync(); |
| | | |
| | | if (splitRecords.Any()) |
| | | { |
| | | result.HasSplitRecords = true; |
| | | result.SplitRecords = splitRecords; |
| | | result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId); |
| | | |
| | | _logger.LogInformation($"åç°{splitRecords.Count}æ¡æªæ£éæå
è®°å½ï¼æ»æ°é: {result.SplitReturnQty}"); |
| | | } |
| | | |
| | | // 4. è®¡ç®æ»ååºæ°éå空æçç¶æ |
| | | result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty; |
| | | result.HasItemsToReturn = result.TotalReturnQty > 0; |
| | | result.IsEmptyPallet = !result.HasItemsToReturn; |
| | | |
| | | // 5. æ£æ¥æ¯å¦æè¿è¡ä¸çä»»å¡ |
| | | result.HasActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>() |
| | | .Where(x => x.OrderNo == orderNo && x.TaskType == TaskTypeEnum.InPick.ObjToInt() && |
| | | x.PalletCode == palletCode && |
| | | x.TaskStatus == (int)TaskStatusEnum.New) |
| | | .AnyAsync(); |
| | | |
| | | _logger.LogInformation($"æçç¶æåæå®æ - 订å: {orderNo}, æç: {palletCode}, " + |
| | | $"æ»ååºæ°é: {result.TotalReturnQty}, æ¯å¦ç©ºæç: {result.IsEmptyPallet}, " + |
| | | $"æè¿è¡ä¸ä»»å¡: {result.HasActiveTasks}"); |
| | | |
| | | return result; |
| | | } |
| | | |
| | | |
| | | private async Task<string> GenerateNewBarcode() |
| | | { |
| | |
| | | OriginalLockQuantity = quantity, |
| | | IsSplitted = 1, |
| | | ParentLockId = originalLock.Id, |
| | | Operator= App.User.UserName, |
| | | FactoryArea=originalLock.FactoryArea, |
| | | lineNo=originalLock.lineNo, |
| | | WarehouseCode=originalLock.WarehouseCode, |
| | | Operator = App.User.UserName, |
| | | FactoryArea = originalLock.FactoryArea, |
| | | lineNo = originalLock.lineNo, |
| | | WarehouseCode = originalLock.WarehouseCode, |
| | | BarcodeQty = originalLock.BarcodeQty, |
| | | BarcodeUnit = originalLock.BarcodeUnit, |
| | | |
| | | }; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | private async Task<int> GenerateTaskNumber() |
| | | { |
| | | return await _dailySequenceService.GetNextSequenceAsync(); |
| | | } |
| | | |
| | | private WebResponseContent CreatePickingResponse(PickingResult result, string adjustedReason) |
| | | { |
| | | //if (result.SplitResults.Any()) |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | #region èæåºå
¥åº |
| | | public WebResponseContent GetAvailablePurchaseOrders() |
| | | { |
| | | List<Dt_InboundOrder> InOders = _inboundOrderRepository.QueryData().Where(x => x.OrderStatus != InOrderStatusEnum.å
¥åºå®æ.ObjToInt()).ToList(); |
| | | List<string> InOderCodes = InOders.Select(x => x.UpperOrderNo).ToList(); |
| | | return WebResponseContent.Instance.OK("æå",data: InOderCodes); |
| | | return WebResponseContent.Instance.OK("æå", data: InOderCodes); |
| | | } |
| | | |
| | | public WebResponseContent GetAvailablePickingOrders() |
| | |
| | | try |
| | | { |
| | | Dt_InboundOrder inboundOrder = Db.Queryable<Dt_InboundOrder>().Where(x => x.UpperOrderNo == noStockOut.inOder && x.OrderStatus != InOrderStatusEnum.å
¥åºå®æ.ObjToInt()).Includes(x => x.Details).First(); |
| | | if(inboundOrder == null) |
| | | if (inboundOrder == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°éè´åï¼{noStockOut.inOder}"); |
| | | } |
| | |
| | | |
| | | //å©ä½å
¥åºæ°éå³èæåºå
¥åºå©ä½å¯åºæ°é |
| | | decimal outQuantity = matchedDetail.OrderQuantity - matchedDetail.ReceiptQuantity; |
| | | if(outQuantity == 0) |
| | | if (outQuantity == 0) |
| | | { |
| | | return WebResponseContent.Instance.Error($"该éè´åä¸çæ¡ç 对åºçå¯åºæ°é为0"); |
| | | } |
| | |
| | | |
| | | if ((matchedCode.LockQuantity + matchedCode.NoStockOutQty) > matchedCode.OrderQuantity) |
| | | { |
| | | return WebResponseContent.Instance.Error($"åºåºåæç»æ°é溢åº{matchedCode.LockQuantity - matchedCode.OrderQuantity}"); |
| | | return WebResponseContent.Instance.Error($"åºåºåæç»æ°é溢åº{matchedCode.LockQuantity - matchedCode.OrderQuantity}"); |
| | | } |
| | | matchedDetail.OrderDetailStatus = OrderDetailStatusEnum.Inbounding.ObjToInt(); |
| | | matchedCode.OrderDetailStatus = OrderDetailStatusEnum.Outbound.ObjToInt(); |
| | | matchedCode.OrderDetailStatus = OrderDetailStatusEnum.AssignOver.ObjToInt(); |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | _inboundOrderDetailService.UpdateData(matchedDetail); |
| | |
| | | _unitOfWorkManage.CommitTran(); |
| | | return WebResponseContent.Instance.OK(); |
| | | } |
| | | catch(Exception ex) |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | |
| | | } |
| | | matchedDetail.NoStockOutQty = 0; |
| | | |
| | | if (matchedDetail.ReceiptQuantity == 0 && matchedDetail.OverInQuantity == 0) |
| | | { |
| | | matchedDetail.OrderDetailStatus = OrderDetailStatusEnum.New.ObjToInt(); |
| | | } |
| | | |
| | | Dt_OutboundOrder outboundOrder = Db.Queryable<Dt_OutboundOrder>().Where(x => x.UpperOrderNo == noStockOut.outOder && x.OrderStatus != OutOrderStatusEnum.åºåºå®æ.ObjToInt()).Includes(x => x.Details).First(); |
| | | if (outboundOrder == null) |
| | | { |
| | |
| | | return WebResponseContent.Instance.Error($"å¨åºåºåçç©æç¼ç 䏿ªæ¾å°ä¸éè´åä¸ç{matchedDetail.MaterielCode} 对åºçç©æã"); |
| | | } |
| | | matchedCode.NoStockOutQty = 0; |
| | | if (matchedCode.LockQuantity == 0 && matchedCode.OverOutQuantity == 0) |
| | | { |
| | | matchedCode.OrderDetailStatus = OrderDetailStatusEnum.New.ObjToInt(); |
| | | } |
| | | _unitOfWorkManage.BeginTran(); |
| | | _inboundOrderDetailService.UpdateData(matchedDetail); |
| | | _outboundOrderDetailService.UpdateData(matchedCode); |
| | |
| | | return WebResponseContent.Instance.OK(); |
| | | |
| | | } |
| | | catch(Exception ex) |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | } |
| | | |
| | | public WebResponseContent NoStockOutSubmit(NoStockOutSubmit noStockOutSubmit) |
| | | public async Task<WebResponseContent> NoStockOutSubmit(NoStockOutSubmit noStockOutSubmit) |
| | | { |
| | | try |
| | | { |
| | | Dt_InboundOrder inboundOrder = Db.Queryable<Dt_InboundOrder>().Where(x => x.UpperOrderNo == noStockOutSubmit.InOderSubmit && x.OrderStatus != InOrderStatusEnum.å
¥åºå®æ.ObjToInt()).Includes(x => x.Details).First(); |
| | | Dt_InboundOrder inboundOrder = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Where(x => x.UpperOrderNo == noStockOutSubmit.InOderSubmit && x.OrderStatus != InOrderStatusEnum.å
¥åºå®æ.ObjToInt()).Includes(x => x.Details).First(); |
| | | if (inboundOrder == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°éè´åï¼{noStockOutSubmit.InOderSubmit}"); |
| | | } |
| | | Dt_OutboundOrder outboundOrder = Db.Queryable<Dt_OutboundOrder>().Where(x => x.UpperOrderNo == noStockOutSubmit.OutOderSubmit && x.OrderStatus != OutOrderStatusEnum.åºåºå®æ.ObjToInt()).Includes(x => x.Details).First(); |
| | | Dt_OutboundOrder outboundOrder = _inboundOrderRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => x.UpperOrderNo == noStockOutSubmit.OutOderSubmit && x.OrderStatus != OutOrderStatusEnum.åºåºå®æ.ObjToInt()).Includes(x => x.Details).First(); |
| | | if (outboundOrder == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°åºåºåï¼{noStockOutSubmit.OutOderSubmit}"); |
| | |
| | | List<Dt_OutboundOrderDetail> outboundOrderDetails = new List<Dt_OutboundOrderDetail>(); |
| | | foreach (var BarCode in noStockOutSubmit.BarCodeSubmit) |
| | | { |
| | | var inboundOrderDetail = inboundOrder.Details.FirstOrDefault(detail => detail.Barcode == BarCode && detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()); |
| | | var inboundOrderDetail = inboundOrder.Details.FirstOrDefault(detail => detail.Barcode == BarCode && detail.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()); |
| | | |
| | | if(inboundOrderDetail == null) |
| | | if (inboundOrderDetail == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"å¨éè´å {noStockOutSubmit.InOderSubmit} 䏿ªæ¾å°æ¡ç 为 {BarCode} çæç»ã"); |
| | | } |
| | |
| | | |
| | | outboundOrderDetail.LockQuantity += outboundOrderDetail.NoStockOutQty; |
| | | outboundOrderDetail.OverOutQuantity = outboundOrderDetail.LockQuantity; |
| | | if(outboundOrderDetail.OrderQuantity == outboundOrderDetail.OverOutQuantity) |
| | | if (outboundOrderDetail.OrderQuantity == outboundOrderDetail.OverOutQuantity) |
| | | { |
| | | outboundOrderDetail.OrderDetailStatus = OrderDetailStatusEnum.Over.ObjToInt(); |
| | | } |
| | | outboundOrderDetails.Add(outboundOrderDetail); |
| | | |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | OrderNo = outboundOrder.UpperOrderNo, |
| | | OrderDetailId = outboundOrderDetail.Id, |
| | | OutboundBatchNo = outboundOrderDetail.BatchNo, |
| | | MaterielCode = outboundOrderDetail.MaterielCode, |
| | | MaterielName = outboundOrderDetail.MaterielName, |
| | | StockId = 0, |
| | | OrderQuantity = outboundOrderDetail.OrderQuantity, |
| | | AssignQuantity = outboundOrderDetail.OverOutQuantity, |
| | | PickedQty = outboundOrderDetail.NoStockOutQty, |
| | | LocationCode = "空", |
| | | PalletCode = "空", |
| | | TaskNum = 0, |
| | | Status = (int)OutLockStockStatusEnum.æ£é宿, |
| | | Unit = outboundOrderDetail.Unit, |
| | | SupplyCode = outboundOrderDetail.SupplyCode ?? "æ ", |
| | | OrderType = outboundOrder.OrderType, |
| | | CurrentBarcode = inboundOrderDetail.Barcode, |
| | | IsSplitted = 1, |
| | | Operator = App.User.UserName, |
| | | lineNo = outboundOrderDetail.lineNo, |
| | | WarehouseCode = outboundOrderDetail.WarehouseCode ?? "æ ", |
| | | BarcodeQty = outboundOrderDetail.NoStockOutQty, |
| | | BarcodeUnit = outboundOrderDetail.BarcodeUnit, |
| | | BatchNo = outboundOrderDetail.BatchNo |
| | | }; |
| | | _outStockLockInfoService.AddData(newLockInfo); |
| | | } |
| | | //夿å
¥åºåæ®æç»æ¯å¦å
¨é¨æ¯å®æç¶æ |
| | | bool inoderOver = inboundOrder.Details.Count() == inboundOrder.Details.Select(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); |
| | | int e = inboundOrder.Details.Count(); |
| | | int w = inboundOrder.Details.Where(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); |
| | | bool inoderOver = inboundOrder.Details.Count() == inboundOrder.Details.Where(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); |
| | | if (inoderOver) |
| | | { |
| | | inboundOrder.OrderStatus = InOrderStatusEnum.å
¥åºå®æ.ObjToInt(); |
| | | } |
| | | else |
| | | { |
| | | inboundOrder.OrderStatus = InOrderStatusEnum.å
¥åºä¸.ObjToInt(); |
| | | } |
| | | //夿åºåºåæ®æç»æ¯å¦å
¨é¨æ¯å®æç¶æ |
| | | bool outOderOver = outboundOrder.Details.Count() == outboundOrder.Details.Select(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); |
| | | bool outOderOver = outboundOrder.Details.Count() == outboundOrder.Details.Where(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); |
| | | if (outOderOver) |
| | | { |
| | | outboundOrder.OrderStatus = OutOrderStatusEnum.åºåºå®æ.ObjToInt(); |
| | | } |
| | | else |
| | | { |
| | | outboundOrder.OrderStatus = OutOrderStatusEnum.åºåºä¸.ObjToInt(); |
| | | } |
| | | //æ°æ®å¤ç |
| | | _unitOfWorkManage.BeginTran(); |
| | |
| | | _outboundOrderService.UpdateData(outboundOrder); |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | //å
¥åºåä¼ MES |
| | | var infeedmodel = new FeedbackInboundRequestModel |
| | | { |
| | | reqCode = Guid.NewGuid().ToString(), |
| | | reqTime = DateTime.Now.ToString(), |
| | | business_type = inboundOrder.BusinessType, |
| | | factoryArea = inboundOrder.FactoryArea, |
| | | operationType = 1, |
| | | Operator = App.User.UserName, |
| | | orderNo = inboundOrder.UpperOrderNo, |
| | | status = inboundOrder.OrderStatus, |
| | | details = new List<FeedbackInboundDetailsModel>() |
| | | |
| | | }; |
| | | |
| | | var groupedData = inboundOrderDetails.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.lineNo, item.BarcodeUnit, item.WarehouseCode }) |
| | | .Select(group => new FeedbackInboundDetailsModel |
| | | { |
| | | materialCode = group.Key.MaterielCode, |
| | | supplyCode = group.Key.SupplyCode, |
| | | batchNo = group.Key.BatchNo, |
| | | lineNo = group.Key.lineNo, |
| | | warehouseCode = group.Key.WarehouseCode, |
| | | qty = group.Sum(x => x.BarcodeQty), |
| | | // warehouseCode= "1072", |
| | | unit = group.Key.BarcodeUnit, |
| | | barcodes = group.Select(row => new FeedbackBarcodesModel |
| | | { |
| | | barcode = row.Barcode, |
| | | qty = row.BarcodeQty |
| | | }).ToList() |
| | | }).ToList(); |
| | | infeedmodel.details = groupedData; |
| | | |
| | | var result1 = await _invokeMESService.FeedbackInbound(infeedmodel); |
| | | if (result1 != null && result1.code == 200) |
| | | { |
| | | var orderIds = inboundOrderDetails.Select(x => x.Id).Distinct().ToList(); |
| | | if (inboundOrder.OrderStatus == InOrderStatusEnum.å
¥åºå®æ.ObjToInt()) |
| | | { |
| | | _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1, Remark = "" }) |
| | | .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); |
| | | } |
| | | _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 }) |
| | | .Where(it => orderIds.Contains(it.Id)).ExecuteCommand(); |
| | | } |
| | | else |
| | | { |
| | | _inboundOrderRepository.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 2, Remark = result1.message }) |
| | | .Where(it => it.Id == inboundOrder.Id).ExecuteCommand(); |
| | | _inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 2 }) |
| | | .Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand(); |
| | | } |
| | | //åºåºåä¼ MES |
| | | |
| | | var documentNo = UniqueValueGenerator.Generate(); |
| | | |
| | | var outfeedmodel = new FeedbackOutboundRequestModel |
| | | { |
| | | reqCode = Guid.NewGuid().ToString(), |
| | | reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), |
| | | business_type = outboundOrder.BusinessType, |
| | | factoryArea = outboundOrder.FactoryArea, |
| | | operationType = 1, |
| | | Operator = App.User.UserName, |
| | | orderNo = outboundOrder.UpperOrderNo, |
| | | documentsNO = documentNo, |
| | | status = outboundOrder.OrderStatus, |
| | | details = new List<FeedbackOutboundDetailsModel>() |
| | | }; |
| | | foreach (var detail in outboundOrderDetails) |
| | | { |
| | | // è·å该æç»å¯¹åºçæ¡ç ä¿¡æ¯ï¼ä»éå®è®°å½ï¼ |
| | | var detailLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == outboundOrder.UpperOrderNo && |
| | | x.OrderDetailId == detail.Id && |
| | | (x.Status == (int)OutLockStockStatusEnum.æ£é宿 || x.Status == (int)OutLockStockStatusEnum.å·²ååº)) |
| | | .ToListAsync(); |
| | | |
| | | var groupdata = detailLocks.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode }) |
| | | .Select(group => new FeedbackOutboundDetailsModel |
| | | { |
| | | |
| | | materialCode = group.Key.MaterielCode, |
| | | lineNo = group.Key.lineNo, |
| | | warehouseCode = group.Key.WarehouseCode, |
| | | qty = group.Sum(x => x.PickedQty), |
| | | currentDeliveryQty = group.Sum(x => x.PickedQty), |
| | | unit = group.Key.BarcodeUnit, |
| | | barcodes = group.Select(lockInfo => new WIDESEA_DTO.Outbound.BarcodesModel |
| | | { |
| | | barcode = lockInfo.CurrentBarcode, |
| | | supplyCode = lockInfo.SupplyCode, |
| | | batchNo = lockInfo.BatchNo, |
| | | unit = lockInfo.BarcodeUnit, |
| | | qty = lockInfo.PickedQty |
| | | }).ToList() |
| | | }).ToList(); |
| | | outfeedmodel.details.AddRange(groupdata); |
| | | } |
| | | //åå¨åä¼ åæ°ï¼ä¿è¯å¼å¸¸æå¨åä¼ |
| | | Dt_InterfaceLog interfaceLog = new Dt_InterfaceLog |
| | | { |
| | | OrderNo = outboundOrder.UpperOrderNo, |
| | | DocumentNo = documentNo, |
| | | OrderType = "èæåºå
¥åº", |
| | | Content = outfeedmodel.ToJson(), |
| | | ReturnToMESStatus = 0, |
| | | IsDeleted = false |
| | | }; |
| | | _interfaceLog.AddData(interfaceLog); |
| | | |
| | | var result = await _invokeMESService.FeedbackOutbound(outfeedmodel); |
| | | if (result != null && result.code == 200) |
| | | { |
| | | var orderIds = outboundOrderDetails.Select(x => x.Id).Distinct().ToList(); |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 1) |
| | | .Where(x => orderIds.Contains(x.Id)) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 1, Remark = "" }) |
| | | .Where(x => x.Id == outboundOrder.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await _interfaceLog.Db.Updateable<Dt_InterfaceLog>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 1) |
| | | .Where(x => x.DocumentNo == documentNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | else |
| | | { |
| | | var uporderIds = outboundOrderDetails.Select(x => x.Id).Distinct().ToList(); |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 2) |
| | | .Where(x => uporderIds.Contains(x.Id)) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = result.message }) |
| | | .Where(x => x.Id == outboundOrder.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await _interfaceLog.Db.Updateable<Dt_InterfaceLog>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 2) |
| | | .Where(x => x.DocumentNo == documentNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | return WebResponseContent.Instance.OK(); |
| | | } |
| | | catch(Exception ex) |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | } |
| | | |
| | | public WebResponseContent GetPurchaseOrderByBarcode(string barcode) |
| | | { |
| | | try |
| | | { |
| | | Dt_InboundOrderDetail inboundOrderDetail = _stockInfoDetailService.Db.Queryable<Dt_InboundOrderDetail>().Where(x => x.Barcode == barcode && x.OrderDetailStatus != OrderDetailStatusEnum.Over.ObjToInt()).First(); |
| | | if (inboundOrderDetail == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°è¯¥æ¡ç {barcode}çå
¥åºæç»æè
æç»ç¶æå·²å
¥æºä»å®æ"); |
| | | } |
| | | Dt_InboundOrder inboundOrder = _inboundOrderRepository.QueryFirst(x => x.Id == inboundOrderDetail.OrderId && x.OrderStatus != InOrderStatusEnum.å
¥åºå®æ.ObjToInt()); |
| | | if (inboundOrder == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"该å
¥åºå{inboundOrder}ç¶æå·²å
¥æºä»å®æ"); |
| | | } |
| | | var resultData = new { purchaseOrderNo = inboundOrder.UpperOrderNo }; |
| | | |
| | | return WebResponseContent.Instance.OK("æ¥è¯¢éè´åæå", data: resultData); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | public WebResponseContent UnPalletQuantity(string orderNo) |
| | | { |
| | | // åå§åè¿åDTOï¼é»è®¤å¼é½ä¸º0ï¼é¿å
nullï¼ |
| | | var resultDTO = new PalletSumQuantityDTO |
| | | { |
| | | StockSumQuantity = 0, |
| | | StockCount = 0, |
| | | UniqueUnit = "" |
| | | }; |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | if (string.IsNullOrWhiteSpace(orderNo)) |
| | | { |
| | | return content.Error("ä¼ å
¥ç订åå·orderNo为空æç©ºç½"); |
| | | } |
| | | var orderDetail = Db.Queryable<Dt_PickingRecord>().Where(s => s.OrderNo == orderNo).ToList(); |
| | | if (orderDetail == null) |
| | | { |
| | | return content.Error("æªæ¾å°åæ®"); |
| | | } |
| | | var unitGroups = orderDetail.GroupBy(d => d.BarcodeUnit).ToList(); |
| | | if (unitGroups.Count == 1) |
| | | { |
| | | resultDTO.UniqueUnit = unitGroups.First().Key; |
| | | } |
| | | else |
| | | { |
| | | resultDTO.UniqueUnit = ""; |
| | | } |
| | | var validDetails = _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>().Where(s => s.OrderNo == orderNo).ToList(); |
| | | resultDTO.StockSumQuantity = orderDetail.Sum(d => d.PickQuantity); |
| | | resultDTO.StockCount = orderDetail.Count; |
| | | if (validDetails.Any()) |
| | | { |
| | | resultDTO.StockSumQuantity -= validDetails.Sum(d => d.StockQuantity); |
| | | // æç»è®°å½æ°ï¼ç¬¦åæ¡ä»¶çææè®°å½æ¡æ° |
| | | resultDTO.StockCount -= validDetails.Count; |
| | | } |
| | | return content.OK("", resultDTO); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return content.Error("SumQuantity ç»è®¡åºåæ°é失败ï¼è®¢åå·ï¼{OrderNo}"); |
| | | } |
| | | } |
| | | |
| | | public WebResponseContent BarcodeMaterielGroup(BarcodeMaterielGroupDTO materielGroupDTO) |
| | | { |
| | | |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | (bool, string, object?) result2 = ModelValidate.ValidateModelData(materielGroupDTO); |
| | | if (!result2.Item1) return content = WebResponseContent.Instance.Error(result2.Item2); |
| | | |
| | | // materielGroupDTO.WarehouseCode |
| | | var code = _warehouseAreaRepository.Db.Queryable<Dt_WarehouseArea>().Where(x => x.Code == materielGroupDTO.WarehouseType).Select(x => x.Code).First(); |
| | | if (string.IsNullOrEmpty(code)) |
| | | { |
| | | return content = WebResponseContent.Instance.Error($"ä»åºä¸æ²¡æè¯¥{materielGroupDTO.WarehouseType}ç¼å·ã"); |
| | | } |
| | | |
| | | if (materielGroupDTO.orderTypes == InOrderTypeEnum.ReCheck.ObjToInt()) |
| | | { |
| | | var dborder = _reCheckOrderService.Db.Queryable<Dt_ReCheckOrder>().First(x => x.OrderNo == materielGroupDTO.OrderNo); |
| | | if (dborder != null && (dborder.SignSeq == 0 || dborder.SignSeq == 1)) |
| | | { |
| | | return content.Error("åªææ¿å°éæ£ç»ææè½å
¥åºï¼"); |
| | | } |
| | | |
| | | |
| | | } |
| | | // Dt_InboundOrder inboundOrder = GetInboundOrder(materielGroupDTO.OrderNo); |
| | | |
| | | var dbinboundOrderDetails = Db.Queryable<Dt_PickingRecord>().Where(x => x.OrderNo == materielGroupDTO.OrderNo && !x.IsCancelled && x.Barcode == materielGroupDTO.Barcodes).ToList(); |
| | | |
| | | if (dbinboundOrderDetails != null && !dbinboundOrderDetails.Any()) |
| | | { |
| | | return content = WebResponseContent.Instance.Error($"忮䏿²¡æè¯¥{materielGroupDTO.Barcodes}æ¡ç æ°æ®ã"); |
| | | } |
| | | |
| | | List<string?> materielCodes = dbinboundOrderDetails.GroupBy(x => x.Barcode).Select(x => x.Key).ToList(); |
| | | |
| | | Dt_StockInfo? stockInfo = _stockService.StockInfoService.GetStockByPalletCode(materielGroupDTO.PalletCode); |
| | | |
| | | |
| | | |
| | | (bool, string, object?) result = CheckMaterielGroupParam(materielGroupDTO, materielCodes, stockInfo); |
| | | if (!result.Item1) return content = WebResponseContent.Instance.Error(result.Item2); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | stockInfo = new Dt_StockInfo() { PalletType = (int)PalletTypeEnum.None, LocationType = materielGroupDTO.locationType.ObjToInt() }; |
| | | stockInfo.Details = new List<Dt_StockInfoDetail>(); |
| | | } |
| | | var inboindId = 0; Dt_InboundOrder dt_InboundOrder = null; |
| | | var orderno = dbinboundOrderDetails.First().OrderNo; |
| | | var dbinbound = _inboundOrderRepository.QueryData(x => x.InboundOrderNo == orderno).FirstOrDefault(); |
| | | if (dbinbound == null) |
| | | { |
| | | dt_InboundOrder = new Dt_InboundOrder |
| | | { |
| | | WarehouseId = 0, |
| | | InboundOrderNo = dbinboundOrderDetails.First()?.OrderNo, |
| | | UpperOrderNo = dbinboundOrderDetails.First()?.OrderNo, |
| | | SupplierId = dbinboundOrderDetails.First()?.SupplyCode, |
| | | OrderType = materielGroupDTO.orderTypes, |
| | | |
| | | BusinessType = materielGroupDTO.orderTypes.ToString(), |
| | | |
| | | FactoryArea = dbinboundOrderDetails.First()?.FactoryArea, |
| | | Remark = "", |
| | | Details = new List<Dt_InboundOrderDetail>() |
| | | }; |
| | | inboindId = _inboundOrderRepository.AddData(dt_InboundOrder); |
| | | } |
| | | else |
| | | { |
| | | dt_InboundOrder = new Dt_InboundOrder { Details = new List<Dt_InboundOrderDetail>() }; |
| | | inboindId = dbinbound.Id; |
| | | } |
| | | |
| | | foreach (var item in dbinboundOrderDetails) |
| | | { |
| | | stockInfo.Details.Add(new Dt_StockInfoDetail |
| | | { |
| | | StockId = stockInfo == null ? 0 : stockInfo.Id, |
| | | Barcode = item.Barcode, |
| | | MaterielCode = item.MaterielCode, |
| | | BatchNo = item.BatchNo, |
| | | Unit = item.BarcodeUnit, |
| | | InboundOrderRowNo = item.lineNo, |
| | | SupplyCode = item.SupplyCode, |
| | | WarehouseCode = materielGroupDTO.WarehouseType, |
| | | StockQuantity = item.PickQuantity, |
| | | BarcodeQty = item.BarcodeQty, |
| | | BarcodeUnit = item.BarcodeUnit, |
| | | FactoryArea = item.FactoryArea, |
| | | Status = 0, |
| | | OrderNo = item.OrderNo, |
| | | BusinessType = materielGroupDTO.orderTypes.ToString() |
| | | |
| | | }); |
| | | item.WarehouseCode = item.WarehouseCode; |
| | | |
| | | dt_InboundOrder.Details.Add(new Dt_InboundOrderDetail |
| | | { |
| | | OrderId = inboindId, |
| | | MaterielCode = item.MaterielCode, |
| | | MaterielName = "", |
| | | BatchNo = item.BatchNo, |
| | | OrderQuantity = item.PickQuantity, |
| | | ReceiptQuantity = 0, |
| | | OverInQuantity = 0, |
| | | Unit = item.BarcodeUnit, |
| | | RowNo = 0, |
| | | lineNo = item.lineNo, |
| | | SupplyCode = item.SupplyCode, |
| | | WarehouseCode = item.WarehouseCode, |
| | | Barcode = item.Barcode, |
| | | OutBoxbarcodes = "", |
| | | BarcodeQty = (decimal)item.BarcodeQty, |
| | | BarcodeUnit = item.BarcodeUnit |
| | | }); |
| | | } |
| | | |
| | | _inboundOrderDetailService.Db.Insertable<Dt_InboundOrderDetail>(dt_InboundOrder.Details); |
| | | if (stockInfo.Id == 0) |
| | | { |
| | | stockInfo.PalletCode = materielGroupDTO.PalletCode; |
| | | stockInfo.StockStatus = StockStatusEmun.ç»çæå.ObjToInt(); |
| | | } |
| | | stockInfo.PalletType = (int)PalletTypeEnum.None; |
| | | |
| | | List<int> updateDetailIds = dbinboundOrderDetails.Select(x => x.Id).ToList(); |
| | | |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | _stockService.StockInfoService.AddMaterielGroup(stockInfo); |
| | | _unitOfWorkManage.CommitTran(); |
| | | return WebResponseContent.Instance.OK(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | content = WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | finally |
| | | { |
| | | |
| | | } |
| | | return content; |
| | | |
| | | } |
| | | |
| | | |
| | | public (bool, string, object?) CheckMaterielGroupParam(BarcodeMaterielGroupDTO materielGroupDTO, List<string> barcodeCodes, Dt_StockInfo stockInfo) |
| | | { |
| | | (bool, string, object?) result = ModelValidate.ValidateModelData(materielGroupDTO); |
| | | if (!result.Item1) return result; |
| | | |
| | | if (_taskRepository.QueryFirst(x => x.PalletCode == materielGroupDTO.PalletCode) != null) |
| | | { |
| | | return (false, "该æçå·å·²æä»»å¡", materielGroupDTO); |
| | | } |
| | | |
| | | if (stockInfo != null && !string.IsNullOrEmpty(stockInfo.LocationCode) && stockInfo.StockStatus != StockStatusEmun.ç»çæå.ObjToInt()) |
| | | { |
| | | return (false, "已䏿¶çæçä¸è½å次ç»ç", materielGroupDTO); |
| | | } |
| | | |
| | | if (_stockService.StockInfoDetailService.ExistBarcodes(barcodeCodes)) |
| | | { |
| | | return (false, $"{barcodeCodes[0]} æ¡ç å¨åºåä¸å·²åå¨", materielGroupDTO); |
| | | } |
| | | |
| | | |
| | | |
| | | return (true, "æå", materielGroupDTO); |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | } |
| | | |
| | | |
| | | |
| | | #region æ¯æç±»å®ä¹ |
| | | |
| | |
| | | public List<SplitResult> SplitResults { get; set; } = new List<SplitResult>(); |
| | | } |
| | | |
| | | public class ReturnAnalysisResult |
| | | public class PalletStatusAnalysis |
| | | { |
| | | public string OrderNo { get; set; } |
| | | public string PalletCode { get; set; } |
| | | public int StockId { get; set; } |
| | | |
| | | // ååºç¸å
³å±æ§ |
| | | public bool HasItemsToReturn { get; set; } |
| | | public bool HasRemainingLocks { get; set; } |
| | | public bool HasPalletStockGoods { get; set; } |
| | | public bool HasSplitRecords { get; set; } |
| | | public decimal RemainingLocksReturnQty { get; set; } |
| | | public decimal PalletStockReturnQty { get; set; } |
| | | |
| | | public decimal SplitReturnQty { get; set; } |
| | | public decimal TotalReturnQty { get; set; } |
| | | |
| | | // æªåé
çéå®è®°å½ï¼å¦èªå¨æå
产ççï¼ |
| | | public bool HasUnallocatedLocks { get; set; } |
| | | public List<Dt_OutStockLockInfo> UnallocatedLocks { get; set; } = new List<Dt_OutStockLockInfo>(); |
| | | public decimal UnallocatedLocksReturnQty { get; set; } |
| | | |
| | | public List<Dt_OutStockLockInfo> RemainingLocks { get; set; } = new List<Dt_OutStockLockInfo>(); |
| | | public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>(); |
| | | public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>(); |
| | | |
| | | // å·²å¤ççæ¡ç éåï¼ç¨äºé¿å
éå¤ï¼ |
| | | public HashSet<string> ProcessedBarcodes { get; set; } = new HashSet<string>(); |
| | | public List<string> AllBarcodes { get; set; } = new List<string>(); |
| | | // 空æçç¸å
³å±æ§ |
| | | public bool IsEmptyPallet { get; set; } |
| | | public bool HasActiveTasks { get; set; } |
| | | |
| | | // ä¾¿å©æ¹æ³ |
| | | public bool CanReturn => HasItemsToReturn && !HasActiveTasks; |
| | | public bool CanRemove => IsEmptyPallet && !HasActiveTasks; |
| | | } |
| | | |
| | | 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 |
| | | } |