| | |
| | | _dailySequenceService = dailySequenceService; |
| | | } |
| | | |
| | | |
| | | #region æ¥è¯¢åºåºè¯¦æ
å表 |
| | | public async Task<List<OutStockLockListResp>> GetOutStockLockListAsync(string orderNo) |
| | | // è·åæªæ£éå表 |
| | | public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode) |
| | | { |
| | | var locks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(t => t.OrderNo == orderNo) |
| | | var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Status == 1) |
| | | .ToListAsync(); |
| | | |
| | | return locks.Select(t => new OutStockLockListResp |
| | | { |
| | | Id = t.Id, |
| | | // TaskNum = t.TaskNum, |
| | | PalletCode = t.PalletCode, |
| | | CurrentBarcode = t.CurrentBarcode, |
| | | AssignQuantity = t.AssignQuantity, |
| | | PickedQty = t.PickedQty, |
| | | Status = t.Status, |
| | | // IsSplitted = t.IsSplitted |
| | | }).ToList(); |
| | | return list.Where(x => x.RemainQuantity > 0).ToList(); |
| | | } |
| | | #endregion |
| | | public async Task<WebResponseContent> ValidateBarcode(string barcode) |
| | | |
| | | // è·åå·²æ£éå表 |
| | | public async Task<List<Dt_OutStockLockInfo>> GetPickedList(string orderNo, string palletCode) |
| | | { |
| | | try |
| | | { |
| | | if (string.IsNullOrEmpty(barcode)) |
| | | { |
| | | return WebResponseContent.Instance.Error("æ¡ç ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // æ ¹æ®æ¡ç æ¥è¯¢åºåæç» |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Includes(x => x.StockInfo) |
| | | .Where(x => x.Barcode == barcode) |
| | | .FirstAsync(); |
| | | |
| | | if (stockDetail == null) |
| | | { |
| | | return WebResponseContent.Instance.Error("æ¡ç ä¸åå¨"); |
| | | } |
| | | |
| | | |
| | | |
| | | var result = new |
| | | { |
| | | Barcode = barcode, |
| | | MaterielCode = stockDetail.MaterielCode, |
| | | |
| | | BatchNo = stockDetail.BatchNo, |
| | | AvailableQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity, |
| | | LocationCode = stockDetail.StockInfo?.LocationCode, |
| | | PalletCode = stockDetail.StockInfo?.PalletCode |
| | | }; |
| | | |
| | | return WebResponseContent.Instance.OK(null, result); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æ¡ç éªè¯å¤±è´¥: {ex.Message}"); |
| | | } |
| | | var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Status == 6) |
| | | .ToListAsync(); |
| | | return list; |
| | | } |
| | | |
| | | // æ£æ¥å¹¶æ´æ°è®¢åç¶æ |
| | | private async Task CheckAndUpdateOrderStatus(string orderNo) |
| | | // è·åæ£éæ±æ» |
| | | public async Task<object> GetPickingSummary(ConfirmPickingDto dto) |
| | | { |
| | | |
| | | var orderDetails = _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id) // å
³èæ¡ä»¶ï¼ç¶è¡¨ Id = å表 OrderId |
| | | .Where((o, item) => item.OrderNo == orderNo) // è¿æ»¤ç¶è¡¨ OrderNo |
| | | .Select((o, item) => o) // åªè¿ååè¡¨æ°æ® |
| | | .ToList(); |
| | | |
| | | //var orderDetails = await _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | // .Where(x => x.OrderId == orderNo.ObjToInt()) |
| | | // .ToListAsync(); |
| | | |
| | | bool allCompleted = true; |
| | | foreach (var detail in orderDetails) |
| | | var picked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), x => x.OrderNo == dto.OrderNo) |
| | | .WhereIF(!string.IsNullOrEmpty(dto.PalletCode), x => x.PalletCode == dto.PalletCode) |
| | | .Where(x => x.Status == 6) |
| | | .GroupBy(x => new { x.PalletCode, x.MaterielCode }) |
| | | .Select(x => new SummaryPickingDto |
| | | { |
| | | PalletCode = x.PalletCode, |
| | | MaterielCode = x.MaterielCode, |
| | | pickedCount = SqlFunc.AggregateCount(x.Id) |
| | | }).FirstAsync(); |
| | | if (picked == null) |
| | | { |
| | | if (detail.OverOutQuantity < detail.NeedOutQuantity) |
| | | { |
| | | allCompleted = false; |
| | | break; |
| | | } |
| | | picked = new SummaryPickingDto { pickedCount = 0 }; |
| | | } |
| | | |
| | | if (allCompleted) |
| | | var summary = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), x => x.OrderNo == dto.OrderNo) |
| | | .WhereIF(!string.IsNullOrEmpty(dto.PalletCode), x => x.PalletCode == dto.PalletCode) |
| | | .Where(x => x.Status == 1) |
| | | .GroupBy(x => new { x.PalletCode, x.MaterielCode }) |
| | | .Select(x => new SummaryPickingDto |
| | | { |
| | | PalletCode = x.PalletCode, |
| | | MaterielCode = x.MaterielCode, |
| | | UnpickedCount = SqlFunc.AggregateCount(x.Id), |
| | | UnpickedQuantity = SqlFunc.AggregateSum(x.AssignQuantity) - SqlFunc.AggregateSum(x.PickedQty), |
| | | |
| | | }).FirstAsync(); |
| | | if (summary == null) |
| | | { |
| | | try |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == 2) // 已宿 |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | var outboundOrder = _stockInfoService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == orderNo); |
| | | |
| | | |
| | | if (outboundOrder != null && outboundOrder.OrderStatus == OutOrderStatusEnum.åºåºå®æ.ObjToInt()) |
| | | { |
| | | |
| | | if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt().ObjToInt())//è°æ¨åºåº |
| | | { |
| | | |
| | | } |
| | | else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt()) //鿣åºåº |
| | | { |
| | | |
| | | } |
| | | else |
| | | { |
| | | var feedmodel = new FeedbackOutboundRequestModel |
| | | { |
| | | reqCode = Guid.NewGuid().ToString(), |
| | | reqTime = DateTime.Now.ToString(), |
| | | business_type = outboundOrder.BusinessType, |
| | | factoryArea = outboundOrder.FactoryArea, |
| | | operationType = 1, |
| | | Operator = outboundOrder.Operator, |
| | | orderNo = outboundOrder.UpperOrderNo, |
| | | status = outboundOrder.OrderStatus, |
| | | details = new List<FeedbackOutboundDetailsModel>() |
| | | |
| | | }; |
| | | var lists = _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>().Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.æ£é宿).ToList(); |
| | | |
| | | 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, |
| | | currentDeliveryQty = group.Sum(x => x.OrderQuantity), |
| | | // warehouseCode= "1072", |
| | | 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(); |
| | | 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(" OutboundPickingService FeedbackOutbound : " + ex.Message); |
| | | } |
| | | |
| | | summary = new SummaryPickingDto { pickedCount = 0 }; |
| | | } |
| | | summary.pickedCount = picked.pickedCount; |
| | | |
| | | return summary; |
| | | } |
| | | |
| | | #region æ ¸å¿ä¸å¡æµç¨ |
| | | |
| | | public async Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode) |
| | | { |
| | |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. éªè¯è¾å
¥åæ° |
| | | if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode) || string.IsNullOrEmpty(barcode)) |
| | | { |
| | | throw new Exception("订åå·ãæçç åæ¡ç ä¸è½ä¸ºç©º"); |
| | | } |
| | | // 1. åç½®éªè¯åä¸å¡æ£æ¥ |
| | | var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | // 2. æ¥æ¾åºåºéå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.Status == (int)OutLockStockStatusEnum.åºåºä¸ && |
| | | it.PalletCode == palletCode && |
| | | it.CurrentBarcode == barcode && |
| | | it.AssignQuantity > it.PickedQty) |
| | | .FirstAsync(); |
| | | var (lockInfo, orderDetail, stockDetail) = validationResult.Data; |
| | | |
| | | if (lockInfo == null) |
| | | { |
| | | lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.CurrentBarcode == barcode && |
| | | it.Status == (int)OutLockStockStatusEnum.åºåºä¸ && |
| | | it.AssignQuantity > it.PickedQty) |
| | | .FirstAsync(); |
| | | // 2. 计ç®å®é
æ£éæ°é |
| | | var quantityResult = await CalculateActualPickingQuantity(lockInfo, orderDetail, stockDetail); |
| | | if (!quantityResult.IsValid) |
| | | return WebResponseContent.Instance.Error(quantityResult.ErrorMessage); |
| | | |
| | | if (lockInfo == null) |
| | | { |
| | | var completedLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.CurrentBarcode == barcode && |
| | | (it.Status == (int)OutLockStockStatusEnum.æ£é宿 || |
| | | it.PickedQty >= it.AssignQuantity)) |
| | | .FirstAsync(); |
| | | var (actualQty, adjustedReason) = quantityResult.Data; |
| | | |
| | | if (completedLockInfo != null) |
| | | throw new Exception($"æ¡ç {barcode}å·²ç»å®æåæ£ï¼ä¸è½éå¤åæ£"); |
| | | else |
| | | throw new Exception($"æ¡ç {barcode}ä¸å±äºæç{palletCode}æä¸åå¨å¾
åæ£è®°å½"); |
| | | } |
| | | } |
| | | // 3. æ§è¡åæ£é»è¾ |
| | | var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, orderNo, palletCode, barcode, actualQty); |
| | | |
| | | if (lockInfo.PalletCode != palletCode) |
| | | throw new Exception($"æ¡ç {barcode}ä¸å±äºæç{palletCode}"); |
| | | // 4. æ´æ°ç¸å
³æ°æ® |
| | | await UpdateOrderRelatedData(orderDetail.Id, pickingResult.ActualPickedQty, orderNo); |
| | | |
| | | // æ£æ¥æ£éåå²ï¼é²æ¢éå¤åæ£ |
| | | var existingPicking = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(x => x.Barcode == barcode && |
| | | x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.OutStockLockId == lockInfo.Id) |
| | | .FirstAsync(); |
| | | |
| | | if (existingPicking != null) |
| | | { |
| | | throw new Exception($"æ¡ç {barcode}å·²ç»åæ£è¿ï¼ä¸è½éå¤åæ£"); |
| | | } |
| | | |
| | | // è·å订åæç»å¹¶æ£æ¥æ°ééå¶ |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == lockInfo.OrderDetailId); |
| | | |
| | | if (orderDetail == null) |
| | | throw new Exception($"æªæ¾å°è®¢åæç»ï¼ID: {lockInfo.OrderDetailId}"); |
| | | |
| | | // å
³é®ä¿®å¤ï¼æ£æ¥ç´¯è®¡æ£éæ°éæ¯å¦ä¼è¶
è¿è®¢åæ°é |
| | | decimal actualQty = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | decimal remainingOrderQty = orderDetail.NeedOutQuantity - orderDetail.OverOutQuantity; |
| | | |
| | | if (actualQty > remainingOrderQty) |
| | | { |
| | | // 妿åé
æ°é大äºå©ä½è®¢åæ°éï¼è°æ´å®é
æ£éæ°é |
| | | actualQty = remainingOrderQty; |
| | | |
| | | if (actualQty <= 0) |
| | | { |
| | | throw new Exception($"订å{orderNo}çéæ±æ°éå·²æ»¡è¶³ï¼æ æ³ç»§ç»åæ£"); |
| | | } |
| | | |
| | | _logger.LogWarning($"è°æ´åæ£æ°éï¼ååé
{lockInfo.AssignQuantity - lockInfo.PickedQty}ï¼è°æ´ä¸º{actualQty}ï¼è®¢åéæ±{orderDetail.NeedOutQuantity}ï¼å·²åºåº{orderDetail.OverOutQuantity}"); |
| | | } |
| | | |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(x => x.Barcode == barcode && x.StockId == lockInfo.StockId) |
| | | .FirstAsync(); |
| | | |
| | | if (stockDetail == null) |
| | | return WebResponseContent.Instance.Error("æ æçæ¡ç æç©æç¼ç "); |
| | | |
| | | decimal stockQuantity = stockDetail.StockQuantity; |
| | | |
| | | List<SplitResult> splitResults = new List<SplitResult>(); |
| | | Dt_OutStockLockInfo finalLockInfo = lockInfo; |
| | | var finalBarcode = barcode; |
| | | var finalStockId = stockDetail.Id; |
| | | decimal actualPickedQty = actualQty; |
| | | |
| | | if (actualQty < stockQuantity) |
| | | { |
| | | // æ
åµ1: åé
æ°éå°äºåºåæ°éï¼éè¦èªå¨æå
|
| | | decimal remainingStockQty = stockQuantity - actualQty; |
| | | |
| | | // æ´æ°åæ¡ç åºå为å©ä½æ°é |
| | | stockDetail.StockQuantity = remainingStockQty; |
| | | stockDetail.OutboundQuantity = remainingStockQty; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | // çææ°æ¡ç ç¨äºè®°å½æ£éæ°é |
| | | var seq = await _dailySequenceService.GetNextSequenceAsync(); |
| | | string newBarcode = "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0'); |
| | | |
| | | // ä¸ºæ°æ¡ç å建åºåºéå®ä¿¡æ¯ |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | OrderNo = lockInfo.OrderNo, |
| | | OrderDetailId = lockInfo.OrderDetailId, |
| | | BatchNo = lockInfo.BatchNo, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | MaterielName = lockInfo.MaterielName, |
| | | StockId = lockInfo.StockId, |
| | | OrderQuantity = actualQty, |
| | | OriginalQuantity = actualQty, |
| | | AssignQuantity = actualQty, |
| | | PickedQty = actualQty, |
| | | LocationCode = lockInfo.LocationCode, |
| | | PalletCode = lockInfo.PalletCode, |
| | | TaskNum = lockInfo.TaskNum, |
| | | Status = (int)OutLockStockStatusEnum.æ£é宿, |
| | | Unit = lockInfo.Unit, |
| | | SupplyCode = lockInfo.SupplyCode, |
| | | OrderType = lockInfo.OrderType, |
| | | CurrentBarcode = newBarcode, |
| | | OriginalLockQuantity = actualQty, |
| | | IsSplitted = 1, |
| | | ParentLockId = lockInfo.Id |
| | | }; |
| | | |
| | | var newLockId = await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteReturnIdentityAsync(); |
| | | newLockInfo.Id = newLockId; |
| | | |
| | | // è®°å½æå
åå² |
| | | var splitHistory = new Dt_SplitPackageRecord |
| | | { |
| | | FactoryArea = lockInfo.FactoryArea, |
| | | TaskNum = lockInfo.TaskNum, |
| | | OutStockLockInfoId = lockInfo.Id, |
| | | StockId = stockDetail.StockId, |
| | | Operator = App.User.UserName, |
| | | IsReverted = false, |
| | | OriginalBarcode = barcode, |
| | | NewBarcode = newBarcode, |
| | | SplitQty = actualQty, |
| | | RemainQuantity = remainingStockQty, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | SplitTime = DateTime.Now, |
| | | OrderNo = lockInfo.OrderNo, |
| | | PalletCode = lockInfo.PalletCode, |
| | | Status = (int)SplitPackageStatusEnum.å·²æ£é |
| | | }; |
| | | await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync(); |
| | | |
| | | // æ´æ°åéå®ä¿¡æ¯ä¸ºå©ä½åºåæ°é |
| | | lockInfo.AssignQuantity = remainingStockQty; |
| | | lockInfo.PickedQty = 0; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | splitResults.Add(new SplitResult |
| | | { |
| | | materialCode = lockInfo.MaterielCode, |
| | | supplierCode = lockInfo.SupplyCode, |
| | | quantityTotal = actualQty.ToString("F2"), |
| | | batchNumber = newBarcode, |
| | | batch = lockInfo.BatchNo, |
| | | factory = lockInfo.FactoryArea, |
| | | date = DateTime.Now.ToString("yyyy-MM-dd"), |
| | | }); |
| | | |
| | | splitResults.Add(new SplitResult |
| | | { |
| | | materialCode = lockInfo.MaterielCode, |
| | | supplierCode = lockInfo.SupplyCode, |
| | | quantityTotal = remainingStockQty.ToString("F2"), |
| | | batchNumber = barcode, |
| | | batch = lockInfo.BatchNo, |
| | | factory = lockInfo.FactoryArea, |
| | | date = DateTime.Now.ToString("yyyy-MM-dd"), |
| | | }); |
| | | |
| | | finalLockInfo = newLockInfo; |
| | | finalBarcode = newBarcode; |
| | | } |
| | | else if (actualQty == stockQuantity) |
| | | { |
| | | // æ
åµ2: åé
æ°éçäºåºåæ°éï¼æ´å
åºåº |
| | | stockDetail.StockQuantity = 0; |
| | | stockDetail.OutboundQuantity = 0; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | lockInfo.PickedQty += actualQty; |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.æ£é宿; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | } |
| | | else |
| | | { |
| | | // æ
åµ3: åé
æ°é大äºåºåæ°éï¼åºåæ´å
åºåº |
| | | decimal stockOutQty = stockQuantity; |
| | | stockDetail.StockQuantity = 0; |
| | | stockDetail.OutboundQuantity = 0; |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | |
| | | decimal remainingAssignQty = actualQty - stockQuantity; |
| | | lockInfo.PickedQty += stockOutQty; |
| | | lockInfo.AssignQuantity = remainingAssignQty; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | var relatedSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(it => it.OriginalBarcode == barcode || it.NewBarcode == barcode) |
| | | .Where(it => !it.IsReverted) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var record in relatedSplitRecords) |
| | | { |
| | | record.Status = (int)SplitPackageStatusEnum.å·²æ£é; |
| | | await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | actualPickedQty = stockOutQty; |
| | | } |
| | | |
| | | // å
³é®ä¿®å¤ï¼åæ¬¡æ£æ¥è®¢åæ°ééå¶ |
| | | decimal newOverOutQuantity = orderDetail.OverOutQuantity + actualPickedQty; |
| | | decimal newPickedQty = orderDetail.PickedQty + actualPickedQty; |
| | | |
| | | if (newOverOutQuantity > orderDetail.NeedOutQuantity) |
| | | { |
| | | throw new Exception($"忣åå°å¯¼è´å·²åºåºæ°é({newOverOutQuantity})è¶
è¿è®¢åéæ±æ°é({orderDetail.NeedOutQuantity})"); |
| | | } |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity |
| | | }) |
| | | .Where(it => it.Id == lockInfo.OrderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await CheckAndUpdateOrderStatus(orderNo); |
| | | |
| | | // æ¥è¯¢ä»»å¡è¡¨ |
| | | var task = _taskRepository.QueryData(x => x.OrderNo == orderNo && x.PalletCode == palletCode).FirstOrDefault(); |
| | | |
| | | if (finalLockInfo.Id <= 0) |
| | | { |
| | | throw new Exception($"éå®ä¿¡æ¯IDæ æ: {finalLockInfo.Id}ï¼æ æ³è®°å½æ£éåå²"); |
| | | } |
| | | |
| | | // è®°å½æ£éåå² |
| | | var pickingHistory = new Dt_PickingRecord |
| | | { |
| | | FactoryArea = finalLockInfo.FactoryArea, |
| | | TaskNo = task?.TaskNum ?? 0, |
| | | LocationCode = task?.SourceAddress ?? "", |
| | | StockId = finalStockId, |
| | | OrderNo = orderNo, |
| | | OrderDetailId = finalLockInfo.OrderDetailId, |
| | | PalletCode = palletCode, |
| | | Barcode = finalBarcode, |
| | | MaterielCode = finalLockInfo.MaterielCode, |
| | | PickQuantity = actualPickedQty, |
| | | PickTime = DateTime.Now, |
| | | Operator = App.User.UserName, |
| | | OutStockLockId = finalLockInfo.Id |
| | | }; |
| | | await Db.Insertable(pickingHistory).ExecuteCommandAsync(); |
| | | // 5. è®°å½æä½åå² |
| | | await RecordPickingHistory(pickingResult, orderNo, palletCode); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | if (splitResults.Any()) |
| | | { |
| | | return WebResponseContent.Instance.OK("æ£é确认æåï¼å·²èªå¨æå
", new { SplitResults = splitResults }); |
| | | } |
| | | |
| | | return WebResponseContent.Instance.OK("æ£é确认æå", new { SplitResults = new List<SplitResult>() }); |
| | | |
| | | return CreatePickingResponse(pickingResult, adjustedReason); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // æ¥æ¾æ£éè®°å½ |
| | | var pickingRecord = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | it.Barcode == barcode) |
| | | .OrderByDescending(it => it.PickTime) |
| | | .FirstAsync(); |
| | | // 1. åç½®éªè¯ |
| | | var validationResult = await ValidateCancelRequest(orderNo, palletCode, barcode); |
| | | if (!validationResult.IsValid) |
| | | return WebResponseContent.Instance.Error(validationResult.ErrorMessage); |
| | | |
| | | if (pickingRecord == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçæ£éè®°å½"); |
| | | var (pickingRecord, lockInfo, orderDetail) = validationResult.Data; |
| | | |
| | | // æ¥æ¾åºåºéå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.Id == pickingRecord.OutStockLockId) |
| | | .FirstAsync(); |
| | | |
| | | if (lockInfo == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯"); |
| | | |
| | | // æ£æ¥æ¯å¦å¯ä»¥åæ¶ |
| | | if (lockInfo.Status != (int)OutLockStockStatusEnum.æ£é宿) |
| | | return WebResponseContent.Instance.Error("å½åç¶æä¸å
è®¸åæ¶åæ£"); |
| | | |
| | | decimal cancelQty = pickingRecord.PickQuantity; |
| | | |
| | | // è·å订åæç» |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == pickingRecord.OrderDetailId); |
| | | |
| | | if (orderDetail == null) |
| | | throw new Exception($"æªæ¾å°è®¢åæç»ï¼ID: {pickingRecord.OrderDetailId}"); |
| | | |
| | | // å
³é®ä¿®å¤ï¼æ£æ¥åæ¶åæ°éä¸ä¼ä¸ºè´æ° |
| | | decimal newOverOutQuantity = orderDetail.OverOutQuantity - cancelQty; |
| | | decimal newPickedQty = orderDetail.PickedQty - cancelQty; |
| | | |
| | | if (newOverOutQuantity < 0 || newPickedQty < 0) |
| | | { |
| | | throw new Exception($"忶忣å°å¯¼è´å·²åºåºæ°éæå·²æ£éæ°éä¸ºè´æ°"); |
| | | } |
| | | |
| | | // å¤çåæ¶é»è¾ |
| | | if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue) |
| | | { |
| | | await HandleSplitBarcodeCancel(lockInfo, pickingRecord, cancelQty); |
| | | } |
| | | else |
| | | { |
| | | await HandleNormalBarcodeCancel(lockInfo, pickingRecord, cancelQty); |
| | | } |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity |
| | | }) |
| | | .Where(it => it.Id == pickingRecord.OrderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // å 餿£éè®°å½ |
| | | await Db.Deleteable<Dt_PickingRecord>() |
| | | .Where(x => x.Id == pickingRecord.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // éæ°æ£æ¥è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(orderNo); |
| | | // 2. æ§è¡åæ¶é»è¾ |
| | | await ExecuteCancelLogic(lockInfo, pickingRecord, orderDetail, orderNo); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | return WebResponseContent.Instance.OK($"忶忣æåï¼æ¢å¤æ°éï¼{cancelQty}"); |
| | | |
| | | return WebResponseContent.Instance.OK($"忶忣æåï¼æ¢å¤æ°éï¼{pickingRecord.PickQuantity}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | _logger.LogError($"CancelPicking失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Barcode: {barcode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"åæ¶åæ£å¤±è´¥ï¼{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | // 1. åºç¡éªè¯ |
| | | if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) |
| | | return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); |
| | | |
| | | // 2. è·ååºååä»»å¡ä¿¡æ¯ |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); |
| | | |
| | | var task = await GetCurrentTask(orderNo, palletCode); |
| | | if (task == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡ä¿¡æ¯"); |
| | | |
| | | // 3. åæéè¦ååºçè´§ç© |
| | | var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id); |
| | | if (!returnAnalysis.HasItemsToReturn) |
| | | return await HandleNoReturnItems(orderNo, palletCode); |
| | | |
| | | // 4. æ§è¡ååºæä½ |
| | | await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, returnAnalysis); |
| | | |
| | | // 5. å建ååºä»»å¡ |
| | | await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, returnAnalysis); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | // 6. æ´æ°è®¢åç¶æï¼ä¸è§¦åMESåä¼ ï¼ |
| | | await UpdateOrderStatusForReturn(orderNo); |
| | | |
| | | return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{returnAnalysis.TotalReturnQty}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"ReturnRemaining失败 - 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) |
| | | .FirstAsync(); |
| | | |
| | | 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(); |
| | | |
| | | if (existingPicking != null) |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Error($"æ¡ç {barcode}å·²ç»åæ£è¿"); |
| | | |
| | | return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail)>.Success((lockInfo, orderDetail, stockDetail)); |
| | | } |
| | | |
| | | private async Task<Dt_OutStockLockInfo> FindValidLockInfo(string orderNo, string palletCode, string barcode) |
| | | { |
| | | // ä¼å
æ¥æ¾ç²¾ç¡®å¹é
çè®°å½ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.Status == (int)OutLockStockStatusEnum.åºåºä¸ && |
| | | it.PalletCode == palletCode && |
| | | it.CurrentBarcode == barcode && |
| | | it.AssignQuantity > it.PickedQty) |
| | | .FirstAsync(); |
| | | |
| | | if (lockInfo == null) |
| | | { |
| | | // æ¥æ¾åä¸è®¢åä¸çè®°å½ |
| | | lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .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.PickedQty >= it.AssignQuantity)) |
| | | .FirstAsync(); |
| | | |
| | | if (completedLockInfo != null) |
| | | throw new Exception($"æ¡ç {barcode}å·²ç»å®æåæ£ï¼ä¸è½éå¤åæ£"); |
| | | else |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | return lockInfo; |
| | | } |
| | | |
| | | private async Task<ValidationResult<(decimal, string)>> CalculateActualPickingQuantity( |
| | | Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail) |
| | | { |
| | | decimal plannedQty = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | decimal remainingOrderQty = orderDetail.NeedOutQuantity - orderDetail.OverOutQuantity; |
| | | decimal stockQuantity = stockDetail.StockQuantity; |
| | | |
| | | // ä¸éæ£æ¥ï¼åæå°å¼ |
| | | decimal actualQty = plannedQty; |
| | | string adjustedReason = null; |
| | | |
| | | // æ£æ¥1ï¼è®¢åæ°ééå¶ |
| | | if (plannedQty > remainingOrderQty && remainingOrderQty > 0) |
| | | { |
| | | actualQty = remainingOrderQty; |
| | | adjustedReason = $"è®¢åæ°ééå¶ï¼ä»{plannedQty}è°æ´ä¸º{actualQty}"; |
| | | } |
| | | |
| | | // æ£æ¥2ï¼åºåæ°ééå¶ |
| | | if (actualQty > stockQuantity) |
| | | { |
| | | actualQty = stockQuantity; |
| | | adjustedReason = adjustedReason != null |
| | | ? $"{adjustedReason}ï¼åºåæ°ééå¶ï¼è¿ä¸æ¥è°æ´ä¸º{actualQty}" |
| | | : $"åºåæ°ééå¶ï¼ä»{plannedQty}è°æ´ä¸º{actualQty}"; |
| | | } |
| | | |
| | | // æ£æ¥3ï¼å®é
坿£éæ°éå¿
须大äº0 |
| | | if (actualQty <= 0) |
| | | { |
| | | return ValidationResult<(decimal, string)>.Error($"æ æ³åæ£ï¼è®¡åæ°é{plannedQty}ï¼å©ä½è®¢å{remainingOrderQty}ï¼åºå{stockQuantity}"); |
| | | } |
| | | |
| | | if (adjustedReason != null) |
| | | { |
| | | _logger.LogWarning($"忣æ°éè°æ´ï¼{adjustedReason}ï¼è®¢å{orderDetail.NeedOutQuantity}ï¼å·²åºåº{orderDetail.OverOutQuantity}ï¼åºå{stockQuantity}"); |
| | | } |
| | | |
| | | return ValidationResult<(decimal, string)>.Success((actualQty, adjustedReason)); |
| | | } |
| | | |
| | | private async Task<PickingResult> ExecutePickingLogic( |
| | | 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 |
| | | { |
| | | FinalLockInfo = lockInfo, |
| | | FinalBarcode = barcode, |
| | | FinalStockId = stockDetail.Id, |
| | | ActualPickedQty = actualQty |
| | | }; |
| | | |
| | | if (actualQty < stockQuantity) |
| | | { |
| | | await HandleSplitPacking(lockInfo, stockDetail, actualQty, stockQuantity, result); |
| | | } |
| | | else if (actualQty == stockQuantity) |
| | | { |
| | | await HandleFullPicking(lockInfo, stockDetail, actualQty, result); |
| | | } |
| | | else |
| | | { |
| | | await HandlePartialPicking(lockInfo, stockDetail, actualQty, stockQuantity, result); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | private async Task HandleSplitPacking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | 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; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // 6. è®¾ç½®ç»æ |
| | | result.FinalLockInfo = newLockInfo; |
| | | result.FinalBarcode = newBarcode; |
| | | result.SplitResults.AddRange(CreateSplitResults(lockInfo, actualQty, remainingStockQty, newBarcode, stockDetail.Barcode)); |
| | | } |
| | | |
| | | 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.æ£é宿; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | private async Task HandlePartialPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal actualQty, decimal stockQuantity, PickingResult result) |
| | | { |
| | | 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; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | // 3. æ´æ°æå
è®°å½ç¶æ |
| | | await UpdateSplitRecordsStatus(stockDetail.Barcode); |
| | | |
| | | result.ActualPickedQty = stockOutQty; |
| | | } |
| | | |
| | | private async Task UpdateOrderRelatedData(int orderDetailId, decimal pickedQty, string orderNo) |
| | | { |
| | | // è·åææ°ç订åæç»æ°æ® |
| | | var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == orderDetailId); |
| | | |
| | | decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity + pickedQty; |
| | | decimal newPickedQty = currentOrderDetail.PickedQty + pickedQty; |
| | | |
| | | // æç»æ£æ¥ï¼ç¡®ä¿ä¸ä¼è¶
è¿è®¢åéæ±æ°é |
| | | if (newOverOutQuantity > currentOrderDetail.NeedOutQuantity) |
| | | { |
| | | throw new Exception($"忣åå°å¯¼è´å·²åºåºæ°é({newOverOutQuantity})è¶
è¿è®¢åéæ±æ°é({currentOrderDetail.NeedOutQuantity})"); |
| | | } |
| | | |
| | | // æ´æ°è®¢åæç» |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity, |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ£æ¥å¹¶æ´æ°è®¢åç¶æ |
| | | await CheckAndUpdateOrderStatus(orderNo); |
| | | } |
| | | |
| | | private async Task RecordPickingHistory(PickingResult result, string orderNo, string palletCode) |
| | | { |
| | | var task = await _taskRepository.Db.Queryable<Dt_Task>() |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | |
| | | if (result.FinalLockInfo.Id <= 0) |
| | | { |
| | | throw new Exception($"éå®ä¿¡æ¯IDæ æ: {result.FinalLockInfo.Id}ï¼æ æ³è®°å½æ£éåå²"); |
| | | } |
| | | |
| | | var pickingHistory = new Dt_PickingRecord |
| | | { |
| | | FactoryArea = result.FinalLockInfo.FactoryArea, |
| | | TaskNo = task?.TaskNum ?? 0, |
| | | LocationCode = task?.SourceAddress ?? "", |
| | | StockId = result.FinalStockId, |
| | | OrderNo = orderNo, |
| | | OrderDetailId = result.FinalLockInfo.OrderDetailId, |
| | | PalletCode = palletCode, |
| | | Barcode = result.FinalBarcode, |
| | | MaterielCode = result.FinalLockInfo.MaterielCode, |
| | | PickQuantity = result.ActualPickedQty, |
| | | PickTime = DateTime.Now, |
| | | Operator = App.User.UserName, |
| | | OutStockLockId = result.FinalLockInfo.Id |
| | | }; |
| | | |
| | | await Db.Insertable(pickingHistory).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region åæ¶åæ£ç§ææ¹æ³ |
| | | |
| | | private async Task<ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>> ValidateCancelRequest(string orderNo, string palletCode, string barcode) |
| | | { |
| | | // åºç¡åæ°éªè¯ |
| | | if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode) || string.IsNullOrEmpty(barcode)) |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("订åå·ãæçç åæ¡ç ä¸è½ä¸ºç©º"); |
| | | |
| | | // æ¥æ¾æ£éè®°å½ |
| | | var pickingRecord = await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | | it.Barcode == barcode) |
| | | .OrderByDescending(it => it.PickTime) |
| | | .FirstAsync(); |
| | | |
| | | if (pickingRecord == null) |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("æªæ¾å°å¯¹åºçæ£éè®°å½"); |
| | | |
| | | // æ¥æ¾éå®ä¿¡æ¯ |
| | | var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.Id == pickingRecord.OutStockLockId) |
| | | .FirstAsync(); |
| | | |
| | | if (lockInfo == null) |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("æªæ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯"); |
| | | |
| | | // æ£æ¥ç¶ææ¯å¦å
è®¸åæ¶ |
| | | if (lockInfo.Status != (int)OutLockStockStatusEnum.æ£é宿) |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("å½åç¶æä¸å
è®¸åæ¶åæ£"); |
| | | |
| | | // æ£æ¥è®¢åç¶æ |
| | | var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .FirstAsync(); |
| | | |
| | | if (order?.OrderStatus == (int)OutOrderStatusEnum.åºåºå®æ) |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("订åå·²åºåºå®æï¼ä¸å
è®¸åæ¶åæ£"); |
| | | |
| | | // è·å订åæç» |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == pickingRecord.OrderDetailId); |
| | | |
| | | if (orderDetail == null) |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"æªæ¾å°è®¢åæç»ï¼ID: {pickingRecord.OrderDetailId}"); |
| | | |
| | | return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail)); |
| | | } |
| | | |
| | | private async Task ExecuteCancelLogic(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, |
| | | Dt_OutboundOrderDetail orderDetail, string orderNo) |
| | | { |
| | | decimal cancelQty = pickingRecord.PickQuantity; |
| | | |
| | | // 1. æ£æ¥åæ¶åæ°éä¸ä¼ä¸ºè´æ° |
| | | decimal newOverOutQuantity = orderDetail.OverOutQuantity - cancelQty; |
| | | decimal newPickedQty = orderDetail.PickedQty - cancelQty; |
| | | |
| | | if (newOverOutQuantity < 0 || newPickedQty < 0) |
| | | { |
| | | throw new Exception($"忶忣å°å¯¼è´æ°æ®å¼å¸¸ï¼å·²åºåº{newOverOutQuantity}ï¼å·²æ£é{newPickedQty}"); |
| | | } |
| | | |
| | | // 2. å¤çä¸åç±»åçåæ¶ |
| | | if (lockInfo.IsSplitted == 1 && lockInfo.ParentLockId.HasValue) |
| | | { |
| | | await HandleSplitBarcodeCancel(lockInfo, pickingRecord, cancelQty); |
| | | } |
| | | else |
| | | { |
| | | await HandleNormalBarcodeCancel(lockInfo, pickingRecord, cancelQty); |
| | | } |
| | | |
| | | // 3. æ´æ°è®¢åæç» |
| | | await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty); |
| | | |
| | | // 4. å 餿£éè®°å½ |
| | | await Db.Deleteable<Dt_PickingRecord>() |
| | | .Where(x => x.Id == pickingRecord.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // 5. éæ°æ£æ¥è®¢åç¶æ |
| | | await UpdateOrderStatusForReturn(orderNo); |
| | | } |
| | | |
| | | private async Task HandleSplitBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty) |
| | |
| | | .FirstAsync(); |
| | | |
| | | if (parentLockInfo == null) |
| | | { |
| | | throw new Exception("æªæ¾å°ç¶éå®ä¿¡æ¯ï¼æ æ³åæ¶æå
忣"); |
| | | } |
| | | |
| | | // æ¢å¤ç¶éå®ä¿¡æ¯çåé
æ°é |
| | | parentLockInfo.AssignQuantity += cancelQty; |
| | |
| | | if (stockDetail != null) |
| | | { |
| | | stockDetail.StockQuantity += cancelQty; |
| | | stockDetail.OutboundQuantity += cancelQty; |
| | | stockDetail.OutboundQuantity = stockDetail.StockQuantity; |
| | | stockDetail.Status = StockStatusEmun.åºåºéå®.ObjToInt(); |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | } |
| | | |
| | |
| | | .SetColumns(x => new Dt_SplitPackageRecord |
| | | { |
| | | Status = (int)SplitPackageStatusEnum.å·²æ¤é, |
| | | IsReverted = true |
| | | IsReverted = true, |
| | | }) |
| | | .Where(x => x.NewBarcode == lockInfo.CurrentBarcode && !x.IsReverted) |
| | | .ExecuteCommandAsync(); |
| | |
| | | if (stockDetail != null) |
| | | { |
| | | stockDetail.StockQuantity += cancelQty; |
| | | stockDetail.OutboundQuantity += cancelQty; |
| | | stockDetail.OutboundQuantity = stockDetail.StockQuantity; |
| | | stockDetail.Status = StockStatusEmun.åºåºéå®.ObjToInt(); |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | |
| | | public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason) |
| | | private async Task UpdateOrderDetailOnCancel(int orderDetailId, decimal cancelQty) |
| | | { |
| | | try |
| | | // è·åææ°ç订åæç»æ°æ® |
| | | var currentOrderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .FirstAsync(x => x.Id == orderDetailId); |
| | | |
| | | decimal newOverOutQuantity = currentOrderDetail.OverOutQuantity - cancelQty; |
| | | decimal newPickedQty = currentOrderDetail.PickedQty - cancelQty; |
| | | |
| | | // æ£æ¥åæ¶åæ°éä¸ä¼ä¸ºè´æ° |
| | | if (newOverOutQuantity < 0 || newPickedQty < 0) |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) |
| | | { |
| | | return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); |
| | | } |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); |
| | | } |
| | | var task = await GetCurrentTask(orderNo, palletCode); |
| | | if (task == null) |
| | | { |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡ä¿¡æ¯"); |
| | | } |
| | | |
| | | // åæéè¦ååºçè´§ç© |
| | | var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id); |
| | | |
| | | if (!returnAnalysis.HasItemsToReturn) |
| | | { |
| | | return await HandleNoReturnItems(orderNo, palletCode); |
| | | } |
| | | |
| | | // æ§è¡ååºæä½ |
| | | await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, returnAnalysis); |
| | | |
| | | //å建ååºä»»å¡å¹¶å¤çESS |
| | | await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, returnAnalysis); |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | // æ´æ°è®¢åç¶æ |
| | | await UpdateOrderStatusForReturn(orderNo); |
| | | |
| | | return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{returnAnalysis.TotalReturnQty}"); |
| | | |
| | | throw new Exception($"忶忣å°å¯¼è´å·²åºåºæ°é({newOverOutQuantity})æå·²æ£éæ°é({newPickedQty})ä¸ºè´æ°"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | _logger.LogError($"ReturnRemaining失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); |
| | | return WebResponseContent.Instance.Error($"ååºæä½å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #region 订åç¶æ |
| | | |
| | | private async Task UpdateOrderStatusForReturn(string orderNo) |
| | | { |
| | | try |
| | | { |
| | | 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) |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | if (detail.OverOutQuantity < detail.NeedOutQuantity) |
| | | { |
| | | allCompleted = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .FirstAsync(x => x.OrderNo == orderNo); |
| | | |
| | | if (outboundOrder == null) return; |
| | | |
| | | // åªæå½ç¶æç¡®å®åçååæ¶ææ´æ° |
| | | int newStatus = allCompleted ? (int)OutOrderStatusEnum.åºåºå®æ : (int)OutOrderStatusEnum.åºåºä¸; |
| | | |
| | | if (outboundOrder.OrderStatus != newStatus) |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == newStatus) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"ååºæä½æ´æ°è®¢åç¶æ - OrderNo: {orderNo}, æ°ç¶æ: {newStatus}"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"UpdateOrderStatusForReturn失败 - OrderNo: {orderNo}, Error: {ex.Message}"); |
| | | |
| | | } |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity, |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region Private Methods |
| | | #region ååºæä½ç§ææ¹æ³ |
| | | |
| | | private async Task<Dt_StockInfo> GetStockInfo(string palletCode) |
| | | { |
| | | return await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .FirstAsync(x => x.PalletCode == palletCode); |
| | | } |
| | | |
| | | private async Task<Dt_Task> GetCurrentTask(string orderNo, string palletCode) |
| | | { |
| | |
| | | { |
| | | var result = new ReturnAnalysisResult(); |
| | | |
| | | // è·åæªåæ£çåºåºéå®è®°å½ |
| | | // æ
åµ1ï¼è·åæªåæ£çåºåºéå®è®°å½ |
| | | var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && |
| | | it.PalletCode == palletCode && |
| | |
| | | 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) // æåºåç |
| | | .Where(it => it.StockQuantity > 0) |
| | | .ToListAsync(); |
| | | |
| | | |
| | | if (palletStockGoods.Any()) |
| | | { |
| | |
| | | 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) |
| | | .ToListAsync(); |
| | |
| | | await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>() |
| | | .SetColumns(it => new Dt_OutStockLockInfo |
| | | { |
| | | Status = (int)OutLockStockStatusEnum.ååºä¸ |
| | | Status = (int)OutLockStockStatusEnum.ååºä¸, |
| | | }) |
| | | .Where(it => lockIds.Contains(it.Id)) |
| | | .ExecuteCommandAsync(); |
| | |
| | | } |
| | | else |
| | | { |
| | | // å建æ°çåºåè®°å½ï¼æå
产ççæ°æ¡ç ï¼ |
| | | // å建æ°çåºåè®°å½ |
| | | var newStockDetail = new Dt_StockInfoDetail |
| | | { |
| | | StockId = lockInfo.StockId, |
| | |
| | | Status = StockStatusEmun.å
¥åºå®æ.ObjToInt(), |
| | | SupplyCode = lockInfo.SupplyCode, |
| | | WarehouseCode = lockInfo.WarehouseCode, |
| | | Unit = lockInfo.Unit |
| | | Unit = lockInfo.Unit, |
| | | }; |
| | | await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); |
| | | } |
| | |
| | | .SetColumns(it => new Dt_OutboundOrderDetail |
| | | { |
| | | PickedQty = newPickedQty, |
| | | OverOutQuantity = newOverOutQuantity |
| | | OverOutQuantity = newOverOutQuantity, |
| | | }) |
| | | .Where(it => it.Id == orderDetailId) |
| | | .ExecuteCommandAsync(); |
| | |
| | | { |
| | | // æ¢å¤åºåç¶æ |
| | | stockGood.OutboundQuantity = 0; |
| | | stockGood.Status = StockStatusEmun.å
¥åºå®æ.ObjToInt(); |
| | | stockGood.Status = StockStatusEmun.å
¥åºå®æ.ObjToInt(); |
| | | |
| | | await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | |
| | | await _splitPackageService.Db.Updateable<Dt_SplitPackageRecord>() |
| | | .SetColumns(x => new Dt_SplitPackageRecord |
| | | { |
| | | Status = (int)SplitPackageStatusEnum.å·²ååº |
| | | Status = (int)SplitPackageStatusEnum.å·²ååº, |
| | | }) |
| | | .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && !x.IsReverted) |
| | | .ExecuteCommandAsync(); |
| | |
| | | private async Task UpdateStockInfoStatus(Dt_StockInfo stockInfo) |
| | | { |
| | | // æ´æ°åºåä¸»è¡¨ç¶æ |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.ObjToInt(); |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.ObjToInt(); |
| | | await _stockInfoService.Db.Updateable(stockInfo).ExecuteCommandAsync(); |
| | | } |
| | | |
| | |
| | | var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>() |
| | | .FirstAsync(x => x.LocationCode == originalTask.SourceAddress); |
| | | |
| | | // åé
æ°è´§ä½ï¼ååºå°åå¨ä½ï¼ |
| | | // åé
æ°è´§ä½ |
| | | var newLocation = _locationInfoService.AssignLocation(firstLocation.LocationType); |
| | | |
| | | Dt_Task returnTask = new() |
| | |
| | | TaskStatus = TaskStatusEnum.New.ObjToInt(), |
| | | TaskType = TaskTypeEnum.InPick.ObjToInt(), |
| | | PalletType = originalTask.PalletType, |
| | | WarehouseId = originalTask.WarehouseId, |
| | | WarehouseId = originalTask.WarehouseId |
| | | |
| | | }; |
| | | |
| | | }; |
| | | // ä¿åååºä»»å¡ |
| | | await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync(); |
| | | |
| | | var targetAddress = originalTask.TargetAddress; |
| | | |
| | | // å é¤åå§åºåºä»»å¡ |
| | | _taskRepository.Db.Deleteable(originalTask); |
| | | await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); |
| | | |
| | | // ç» ESS åéæµå¨ä¿¡å·ååå»ºä»»å¡ |
| | | await SendESSCommands(palletCode, originalTask, returnTask); |
| | | await SendESSCommands(palletCode, targetAddress, returnTask); |
| | | } |
| | | private async Task SendESSCommands(string palletCode, Dt_Task originalTask, Dt_Task returnTask) |
| | | |
| | | private async Task SendESSCommands(string palletCode, string targetAddress, Dt_Task returnTask) |
| | | { |
| | | try |
| | | { |
| | | // 1. åéæµå¨ä¿¡å· |
| | | var moveResult = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest |
| | | { |
| | | slotCode = movestations[originalTask.TargetAddress], |
| | | slotCode = movestations[targetAddress], |
| | | containerCode = palletCode |
| | | }); |
| | | |
| | |
| | | taskGroupCode = "", |
| | | groupPriority = 0, |
| | | tasks = new List<TasksType> |
| | | { |
| | | new() |
| | | { |
| | | taskCode = returnTask.TaskNum.ToString(), |
| | | taskPriority = 0, |
| | | taskDescribe = new TaskDescribeType |
| | | new() |
| | | { |
| | | containerCode = palletCode, |
| | | containerType = "CT_KUBOT_STANDARD", |
| | | fromLocationCode = stations.GetValueOrDefault(originalTask.TargetAddress) ?? "", |
| | | toStationCode = "", |
| | | toLocationCode = returnTask.TargetAddress, |
| | | deadline = 0, |
| | | storageTag = "" |
| | | taskCode = returnTask.TaskNum.ToString(), |
| | | taskPriority = 0, |
| | | taskDescribe = new TaskDescribeType |
| | | { |
| | | containerCode = palletCode, |
| | | containerType = "CT_KUBOT_STANDARD", |
| | | fromLocationCode = stations.GetValueOrDefault(targetAddress) ?? "", |
| | | toStationCode = "", |
| | | toLocationCode = returnTask.TargetAddress, |
| | | deadline = 0, |
| | | storageTag = "" |
| | | } |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | var resultTask = await _eSSApiService.CreateTaskAsync(essTask); |
| | |
| | | |
| | | #endregion |
| | | |
| | | |
| | | #region 订åç¶æç®¡ç |
| | | |
| | | /// <summary> |
| | | /// ååºæä½ |
| | | /// </summary> |
| | | |
| | | //public async Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason) |
| | | //{ |
| | | // try |
| | | // { |
| | | // _unitOfWorkManage.BeginTran(); |
| | | |
| | | // // è·åæææªåæ£çåºåºéå®è®°å½ï¼å
æ¬æå
产ççè®°å½ |
| | | // var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | // .Where(it => it.OrderNo == orderNo && it.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | // .ToListAsync(); |
| | | |
| | | // var stockinfo = _stockInfoService.Db.Queryable<Dt_StockInfo>().First(x => x.PalletCode == palletCode); |
| | | |
| | | // var tasks = new List<Dt_Task>(); |
| | | |
| | | // // æ¥è¯¢ä»»å¡è¡¨ |
| | | // var task = remainingLocks.Any() |
| | | // ? _taskRepository.QueryData(x => x.TaskNum == remainingLocks.First().TaskNum).FirstOrDefault() |
| | | // : _taskRepository.QueryData(x => x.PalletCode == palletCode).FirstOrDefault(); |
| | | |
| | | // if (task == null) |
| | | // { |
| | | // return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡ä¿¡æ¯"); |
| | | // } |
| | | |
| | | // // æ£æ¥æç䏿¯å¦æå
¶ä»éåºåºè´§ç©ï¼åºåè´§ç©ï¼ |
| | | // var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | // .Where(it => it.StockId == stockinfo.Id && |
| | | // (it.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt() || |
| | | // it.Status == StockStatusEmun.å
¥åºå®æ.ObjToInt() || |
| | | // it.Status == StockStatusEmun.åºåºéå®.ObjToInt())) |
| | | // .Where(it => it.OutboundQuantity == 0 || it.OutboundQuantity < it.StockQuantity) // æªå®å
¨åºåºç |
| | | // .ToListAsync(); |
| | | |
| | | // // æ£æ¥æå
è®°å½ï¼æ¾åºéè¦ååºçæ¡ç |
| | | // var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | // .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted) |
| | | // .ToListAsync(); |
| | | |
| | | // // 计ç®éè¦ååºçæå
æ¡ç |
| | | // var splitBarcodesToReturn = new List<string>(); |
| | | // foreach (var splitRecord in splitRecords) |
| | | // { |
| | | // // æ£æ¥åæ¡ç æ¯å¦è¿æåºåéè¦ååº |
| | | // var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | // .Where(it => it.Barcode == splitRecord.OriginalBarcode && it.StockId == stockinfo.Id) |
| | | // .FirstAsync(); |
| | | |
| | | // if (originalStock != null && originalStock.StockQuantity > 0) |
| | | // { |
| | | // splitBarcodesToReturn.Add(splitRecord.OriginalBarcode); |
| | | // } |
| | | |
| | | // // æ£æ¥æ°æ¡ç æ¯å¦è¿æåºåéè¦ååº |
| | | // var newStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | // .Where(it => it.Barcode == splitRecord.NewBarcode && it.StockId == stockinfo.Id) |
| | | // .FirstAsync(); |
| | | |
| | | // if (newStock != null && newStock.StockQuantity > 0) |
| | | // { |
| | | // splitBarcodesToReturn.Add(splitRecord.NewBarcode); |
| | | // } |
| | | // } |
| | | |
| | | // // å¦ææ²¡æéè¦ååºçè´§ç©ï¼æ¢æ æªåæ£åºåºè´§ç©ï¼ä¹æ å
¶ä»åºåè´§ç©ï¼ä¹æ æå
å©ä½è´§ç©ï¼ |
| | | // if (!remainingLocks.Any() && !palletStockGoods.Any() && !splitBarcodesToReturn.Any()) |
| | | // { |
| | | // // æ£æ¥æ¯å¦ææè´§ç©é½å·²æ£é宿 |
| | | // var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | // .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode) |
| | | // .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.æ£é宿); |
| | | |
| | | // if (allPicked) |
| | | // { |
| | | // return WebResponseContent.Instance.OK("ææè´§ç©å·²æ£éå®æï¼æç为空"); |
| | | // } |
| | | // else |
| | | // { |
| | | // return WebResponseContent.Instance.Error("没æéè¦ååºçå©ä½è´§ç©"); |
| | | // } |
| | | // } |
| | | |
| | | // var firstlocation = _locationInfoService.Db.Queryable<Dt_LocationInfo>().First(x => x.LocationCode == task.SourceAddress); |
| | | // decimal totalReturnQty = 0; |
| | | |
| | | // // æ
åµ1ï¼å¤çæªåæ£çåºåºéå®è®°å½ |
| | | // if (remainingLocks.Any(x => x.PalletCode == palletCode)) |
| | | // { |
| | | // var palletLocks = remainingLocks.Where(x => x.PalletCode == palletCode).ToList(); |
| | | // totalReturnQty = palletLocks.Sum(x => x.AssignQuantity - x.PickedQty); |
| | | |
| | | // if (totalReturnQty > 0) |
| | | // { |
| | | // // åé
æ°è´§ä½ |
| | | // var newLocation = _locationInfoService.AssignLocation(firstlocation.LocationType); |
| | | |
| | | // // æ´æ°åºåºéå®è®°å½ç¶æ |
| | | // var lockIds = palletLocks.Select(x => x.Id).ToList(); |
| | | // await _outStockLockInfoService.Db.Updateable<Dt_OutStockLockInfo>() |
| | | // .SetColumns(it => new Dt_OutStockLockInfo { Status = (int)OutLockStockStatusEnum.ååºä¸ }) |
| | | // .Where(it => lockIds.Contains(it.Id)) |
| | | // .ExecuteCommandAsync(); |
| | | |
| | | |
| | | |
| | | // // å¤çåºåè®°å½ |
| | | // foreach (var lockInfo in palletLocks) |
| | | // { |
| | | // decimal returnQty = lockInfo.AssignQuantity - lockInfo.PickedQty; |
| | | |
| | | // // æ£æ¥åºåè®°å½æ¯å¦åå¨ |
| | | // var existingStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | // .Where(it => it.Barcode == lockInfo.CurrentBarcode && it.StockId == lockInfo.StockId) |
| | | // .FirstAsync(); |
| | | |
| | | // if (existingStock != null) |
| | | // { |
| | | // // åºåè®°å½åå¨ï¼æ¢å¤é宿°é |
| | | // existingStock.OutboundQuantity = 0; |
| | | |
| | | // await _stockInfoDetailService.Db.Updateable(existingStock).ExecuteCommandAsync(); |
| | | // } |
| | | // else |
| | | // { |
| | | // // åºåè®°å½ä¸åå¨ï¼å¯è½æ¯æå
产ççæ°æ¡ç ï¼ï¼å建æ°çåºåè®°å½ |
| | | // 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(); |
| | | // } |
| | | // } |
| | | |
| | | // // å建ååºä»»å¡ |
| | | // CreateReturnTask(tasks, task, palletCode, newLocation); |
| | | // } |
| | | // } |
| | | |
| | | // // æ
åµ2ï¼å¤çæå
å©ä½çåºåè´§ç© |
| | | // if (splitBarcodesToReturn.Any()) |
| | | // { |
| | | // decimal splitReturnQty = 0; |
| | | |
| | | // foreach (var barcode in splitBarcodesToReturn) |
| | | // { |
| | | // var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | // .Where(it => it.Barcode == barcode && it.StockId == stockinfo.Id) |
| | | // .FirstAsync(); |
| | | |
| | | // if (stockDetail != null && stockDetail.StockQuantity > 0) |
| | | // { |
| | | // splitReturnQty += stockDetail.StockQuantity; |
| | | |
| | | // // æ¢å¤åºåç¶æä¸ºå
¥åºå®æ |
| | | // stockDetail.OutboundQuantity = 0; |
| | | |
| | | // await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | // } |
| | | // } |
| | | |
| | | // totalReturnQty += splitReturnQty; |
| | | |
| | | // // å¦ææ²¡æå建任å¡ï¼å建ååºä»»å¡ |
| | | // if (!tasks.Any()) |
| | | // { |
| | | // var newLocation = _locationInfoService.AssignLocation(firstlocation.LocationType); |
| | | // CreateReturnTask(tasks, task, palletCode, newLocation); |
| | | // } |
| | | // } |
| | | |
| | | // // æ
åµ3ï¼åºåºè´§ç©å·²åæ£å®ï¼ä½æçä¸è¿æå
¶ä»åºåè´§ç©éè¦ååº |
| | | // if (palletStockGoods.Any() && !remainingLocks.Any(x => x.PalletCode == palletCode)) |
| | | // { |
| | | // decimal otherReturnQty = palletStockGoods.Sum(x => x.StockQuantity - x.OutboundQuantity); |
| | | // totalReturnQty += otherReturnQty; |
| | | // // æ´æ°è¿äºåºåè´§ç©çç¶æ |
| | | // foreach (var stockGood in palletStockGoods) |
| | | // { |
| | | // stockGood.OutboundQuantity = 0; |
| | | |
| | | // await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync(); |
| | | // } |
| | | // // å¦ææ²¡æå建任å¡ï¼å建ååºä»»å¡ |
| | | // if (!tasks.Any()) |
| | | // { |
| | | // var newLocation = _locationInfoService.AssignLocation(firstlocation.LocationType); |
| | | // CreateReturnTask(tasks, task, palletCode, newLocation); |
| | | // } |
| | | |
| | | |
| | | // } |
| | | |
| | | // var allSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | // .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted) |
| | | // .ToListAsync(); |
| | | |
| | | // foreach (var record in allSplitRecords) |
| | | // { |
| | | // record.Status = (int)SplitPackageStatusEnum.å·²ååº; |
| | | // await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync(); |
| | | // } |
| | | // // ä¿åä»»å¡ ç»ESSä¸åä»»å¡ |
| | | // if (tasks.Any()) |
| | | // { |
| | | // try |
| | | // { |
| | | // await _taskRepository.Db.Insertable(tasks).ExecuteCommandAsync(); |
| | | // var targetAddress = task.TargetAddress; |
| | | // _taskRepository.DeleteData(task); |
| | | |
| | | // // ç» ESS æµå¨ä¿¡å·ååå»ºä»»å¡ |
| | | // try |
| | | // { |
| | | // var result = await _eSSApiService.MoveContainerAsync(new WIDESEA_DTO.Basic.MoveContainerRequest |
| | | // { |
| | | // slotCode = movestations[targetAddress], |
| | | // containerCode = palletCode |
| | | // }); |
| | | |
| | | // if (result) |
| | | // { |
| | | // TaskModel esstask = new TaskModel() |
| | | // { |
| | | // taskType = "putaway", |
| | | // taskGroupCode = "", |
| | | // groupPriority = 0, |
| | | // tasks = new List<TasksType> |
| | | // { |
| | | // new() |
| | | // { |
| | | // taskCode = tasks.First().TaskNum.ToString(), |
| | | // taskPriority = 0, |
| | | // taskDescribe = new TaskDescribeType { |
| | | // containerCode = palletCode, |
| | | // containerType = "CT_KUBOT_STANDARD", |
| | | // fromLocationCode = stations.GetValueOrDefault(targetAddress) ?? "", |
| | | // toStationCode = "", |
| | | // toLocationCode = tasks.First().TargetAddress, |
| | | // deadline = 0, storageTag = "" |
| | | // } |
| | | // } |
| | | // } |
| | | // }; |
| | | |
| | | // var resulttask = await _eSSApiService.CreateTaskAsync(esstask); |
| | | // _logger.LogInformation("ReturnRemaining å建任å¡è¿å: " + resulttask); |
| | | // } |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // _logger.LogInformation("ReturnRemaining å建任å¡è¿å catch err: " + ex.Message); |
| | | // } |
| | | |
| | | // _unitOfWorkManage.CommitTran(); |
| | | // return WebResponseContent.Instance.OK($"ååºæä½æåï¼å
±ååºæ°éï¼{totalReturnQty}"); |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // _unitOfWorkManage.RollbackTran(); |
| | | // return WebResponseContent.Instance.Error($"å建ååºä»»å¡å¤±è´¥: {ex.Message}"); |
| | | // } |
| | | // } |
| | | |
| | | // _unitOfWorkManage.RollbackTran(); |
| | | // return WebResponseContent.Instance.Error("æªå建任ä½ååºä»»å¡"); |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // _unitOfWorkManage.RollbackTran(); |
| | | // return WebResponseContent.Instance.Error($"ååºæä½å¤±è´¥: {ex.Message}"); |
| | | // } |
| | | //} |
| | | |
| | | |
| | | /// <summary> |
| | | /// å建ååºä»»å¡ |
| | | /// </summary> |
| | | private void CreateReturnTask(List<Dt_Task> tasks, Dt_Task originalTask, string palletCode, Dt_LocationInfo newLocation) |
| | | private async Task CheckAndUpdateOrderStatus(string orderNo) |
| | | { |
| | | Dt_Task newTask = new() |
| | | try |
| | | { |
| | | CurrentAddress = stations[originalTask.TargetAddress], |
| | | Grade = 0, |
| | | PalletCode = palletCode, |
| | | NextAddress = "", |
| | | OrderNo = originalTask.OrderNo, |
| | | Roadway = newLocation.RoadwayNo, |
| | | SourceAddress = stations[originalTask.TargetAddress], |
| | | TargetAddress = newLocation.LocationCode, |
| | | TaskStatus = TaskStatusEnum.New.ObjToInt(), |
| | | TaskType = TaskTypeEnum.InPick.ObjToInt(), |
| | | PalletType = originalTask.PalletType, |
| | | WarehouseId = originalTask.WarehouseId, |
| | | 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(); |
| | | |
| | | }; |
| | | tasks.Add(newTask); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥æçæ¯å¦éè¦ååºçè¾
婿¹æ³ |
| | | /// </summary> |
| | | public async Task<bool> CheckPalletNeedReturn(string orderNo, string palletCode) |
| | | { |
| | | // 1. æ£æ¥æ¯å¦ææªåæ£çåºåºè®°å½ |
| | | var hasUnpickedLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && it.Status == 1) |
| | | .AnyAsync(); |
| | | |
| | | if (hasUnpickedLocks) |
| | | return true; |
| | | |
| | | // 2. æ£æ¥åºåºæ¯å¦å·²å®æä½æçè¿æåºåè´§ç© |
| | | var outboundFinished = !await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.PalletCode == palletCode && it.Status == 1) |
| | | .AnyAsync(); |
| | | |
| | | var stockinfo = _stockInfoService.Db.Queryable<Dt_StockInfo>().First(x => x.PalletCode == palletCode); |
| | | |
| | | |
| | | var hasRemainingGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.StockId == stockinfo.Id && it.Status == StockStatusEmun.å
¥åºç¡®è®¤.ObjToInt()) |
| | | .Where(it => it.OutboundQuantity == 0 || it.OutboundQuantity < it.StockQuantity) |
| | | .AnyAsync(); |
| | | |
| | | return outboundFinished && hasRemainingGoods; |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// è·åæå
é¾ï¼ä»å½åæ¡ç 追溯å°åå§æ¡ç ï¼ |
| | | /// </summary> |
| | | // å¨ GetSplitChain æ¹æ³ä¸æ·»å æ´ä¸¥æ ¼çéªè¯ |
| | | private async Task<List<SplitChainItem>> GetSplitChain(string currentBarcode) |
| | | { |
| | | var chain = new List<SplitChainItem>(); |
| | | var visited = new HashSet<string>(); |
| | | |
| | | string current = currentBarcode; |
| | | int maxDepth = 10; // 鲿¢æ éå¾ªç¯ |
| | | |
| | | while (!string.IsNullOrEmpty(current) && maxDepth > 0) |
| | | { |
| | | maxDepth--; |
| | | |
| | | if (visited.Contains(current)) |
| | | bool allCompleted = true; |
| | | foreach (var detail in orderDetails) |
| | | { |
| | | _logger.LogWarning($"æ£æµå°å¾ªç¯å¼ç¨å¨æå
é¾ä¸: {current}"); |
| | | break; |
| | | if (detail.OverOutQuantity < detail.NeedOutQuantity) |
| | | { |
| | | allCompleted = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | visited.Add(current); |
| | | var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .FirstAsync(x => x.OrderNo == orderNo); |
| | | |
| | | var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(it => it.NewBarcode == current && !it.IsReverted) |
| | | .FirstAsync(); |
| | | if (outboundOrder == null) return; |
| | | |
| | | if (splitRecord == null) |
| | | break; |
| | | int newStatus = allCompleted ? (int)OutOrderStatusEnum.åºåºå®æ : (int)OutOrderStatusEnum.åºåºä¸; |
| | | |
| | | // éªè¯æå
è®°å½ç宿´æ§ |
| | | if (string.IsNullOrEmpty(splitRecord.OriginalBarcode)) |
| | | if (outboundOrder.OrderStatus != newStatus) |
| | | { |
| | | _logger.LogError($"æå
è®°å½ {splitRecord.Id} 缺å°åå§æ¡ç "); |
| | | break; |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == newStatus) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // åªææ£å¸¸åæ£å®ææ¶æåMESåé¦ |
| | | if (allCompleted && newStatus == (int)OutOrderStatusEnum.åºåºå®æ) |
| | | { |
| | | await HandleOrderCompletion(outboundOrder, orderNo); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"CheckAndUpdateOrderStatus失败 - OrderNo: {orderNo}, Error: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | private async Task UpdateOrderStatusForReturn(string orderNo) |
| | | { |
| | | try |
| | | { |
| | | 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 item = new SplitChainItem |
| | | var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .FirstAsync(x => x.OrderNo == orderNo); |
| | | |
| | | if (outboundOrder == null) return; |
| | | |
| | | int newStatus = allCompleted ? (int)OutOrderStatusEnum.åºåºå®æ : (int)OutOrderStatusEnum.åºåºä¸; |
| | | |
| | | if (outboundOrder.OrderStatus != newStatus) |
| | | { |
| | | SplitRecord = splitRecord, |
| | | OriginalBarcode = splitRecord.OriginalBarcode, |
| | | NewBarcode = splitRecord.NewBarcode, |
| | | SplitQuantity = splitRecord.SplitQty |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == newStatus) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | _logger.LogInformation($"ååºæä½æ´æ°è®¢åç¶æ - OrderNo: {orderNo}, æ°ç¶æ: {newStatus}"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError($"UpdateOrderStatusForReturn失败 - OrderNo: {orderNo}, Error: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | private async Task HandleOrderCompletion(Dt_OutboundOrder outboundOrder, string orderNo) |
| | | { |
| | | // è°æ¨åºåºå鿣åºåºä¸éè¦åé¦MES |
| | | if (outboundOrder.OrderType == OutOrderTypeEnum.Allocate.ObjToInt() || |
| | | outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt()) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | 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 = outboundOrder.Operator, |
| | | orderNo = outboundOrder.UpperOrderNo, |
| | | status = outboundOrder.OrderStatus, |
| | | details = new List<FeedbackOutboundDetailsModel>() |
| | | }; |
| | | |
| | | chain.Add(item); |
| | | // åªè·åå·²æ£é宿çéå®è®°å½ |
| | | var lists = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && x.Status == (int)OutLockStockStatusEnum.æ£é宿) |
| | | .ToListAsync(); |
| | | |
| | | current = splitRecord.OriginalBarcode; |
| | | 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, |
| | | 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(); |
| | | |
| | | 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(); |
| | | } |
| | | } |
| | | |
| | | if (maxDepth <= 0) |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogWarning($"æå
é¾è¿½æº¯è¾¾å°æå¤§æ·±åº¦: {currentBarcode}"); |
| | | _logger.LogError($"FeedbackOutbound失败 - OrderNo: {orderNo}, Error: {ex.Message}"); |
| | | } |
| | | |
| | | chain.Reverse(); |
| | | return chain; |
| | | } |
| | | /// <summary> |
| | | /// å¤çæå
é¾ç忶忣 |
| | | /// </summary> |
| | | private async Task HandleSplitChainCancel(string orderNo, string palletCode, string barcode, |
| | | decimal cancelQty, Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, List<SplitChainItem> splitChain) |
| | | { |
| | | if (!splitChain.Any()) |
| | | return; |
| | | |
| | | // æ¾å°åå§æ¡ç ï¼é¾ç第ä¸ä¸ªï¼ |
| | | var originalSplitItem = splitChain.First(); |
| | | var originalBarcode = originalSplitItem.OriginalBarcode; |
| | | |
| | | // æ¥æ¾åå§æ¡ç çéå®ä¿¡æ¯ååºå |
| | | var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(it => it.CurrentBarcode == originalBarcode && it.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .FirstAsync(); |
| | | |
| | | var originalStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == originalBarcode && it.StockId == originalLockInfo.StockId) |
| | | .FirstAsync(); |
| | | |
| | | if (originalLockInfo == null || originalStockDetail == null) |
| | | throw new Exception("æªæ¾å°åå§æ¡ç çéå®ä¿¡æ¯æåºåä¿¡æ¯"); |
| | | |
| | | // æ¢å¤åå§æ¡ç åºåï¼å°åæ¶çæ°éå åå»ï¼ |
| | | originalStockDetail.StockQuantity += cancelQty; |
| | | originalStockDetail.OutboundQuantity += cancelQty; |
| | | await _stockInfoDetailService.Db.Updateable(originalStockDetail).ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤åå§æ¡ç éå®ä¿¡æ¯ |
| | | originalLockInfo.AssignQuantity += cancelQty; |
| | | await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); |
| | | |
| | | // å 餿å
é¾ä¸æææ°æ¡ç çéå®ä¿¡æ¯ååºåè®°å½ |
| | | var allNewBarcodes = splitChain.Select(x => x.NewBarcode).ToList(); |
| | | |
| | | // å é¤éå®ä¿¡æ¯ |
| | | await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() |
| | | .Where(it => allNewBarcodes.Contains(it.CurrentBarcode)) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // å é¤åºåè®°å½ï¼åªå 餿å
产ççæ°æ¡ç åºåï¼ä¿çåå§æ¡ç ï¼ |
| | | await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() |
| | | .Where(it => allNewBarcodes.Contains(it.Barcode) && it.Barcode != originalBarcode) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ´æ°æå
é¾ä¸æææå
è®°å½ç¶æä¸ºå·²æå
|
| | | foreach (var chainItem in splitChain) |
| | | { |
| | | chainItem.SplitRecord.Status = (int)SplitPackageStatusEnum.å·²æå
; |
| | | await _splitPackageService.Db.Updateable(chainItem.SplitRecord).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // æ¢å¤è®¢åæç»æ£éæ°éï¼ä½¿ç¨åå§éå®ä¿¡æ¯ç订åæç»IDï¼ |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => it.PickedQty == it.PickedQty - cancelQty) |
| | | .Where(it => it.Id == originalLockInfo.OrderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // æ¢å¤è®¢åç¶æ |
| | | await CheckAndRevertOrderStatus(orderNo); |
| | | |
| | | // å 餿£éè®°å½ |
| | | await Db.Deleteable<Dt_PickingRecord>() |
| | | .Where(it => it.Id == pickingRecord.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | //// è®°å½åæ¶æä½åå² |
| | | //await RecordCancelHistory(orderNo, palletCode, barcode, cancelQty, pickingRecord.Id, |
| | | // lockInfo.MaterielCode, "åæ¶æå
é¾åæ£"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæ®éæ¡ç ç忶忣 |
| | | /// </summary> |
| | | private async Task HandleNormalBarcodeCancel(string orderNo, string palletCode, string barcode, |
| | | decimal cancelQty, Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord) |
| | | #endregion |
| | | |
| | | #region è¾
婿¹æ³ |
| | | |
| | | private async Task<string> GenerateNewBarcode() |
| | | { |
| | | // 1. æ¥æ¾åºåä¿¡æ¯ |
| | | var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(it => it.Barcode == barcode && it.StockId == lockInfo.StockId) |
| | | .FirstAsync(); |
| | | var seq = await _dailySequenceService.GetNextSequenceAsync(); |
| | | return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString()?.PadLeft(5, '0'); |
| | | } |
| | | |
| | | if (stockDetail == null) |
| | | throw new Exception("æªæ¾å°å¯¹åºçåºåä¿¡æ¯"); |
| | | |
| | | // 2. æ¢å¤åºåæ°é |
| | | if (stockDetail.StockQuantity == 0) |
| | | private async Task<Dt_OutStockLockInfo> CreateSplitLockInfo(Dt_OutStockLockInfo originalLock, decimal quantity, string newBarcode) |
| | | { |
| | | var newLockInfo = new Dt_OutStockLockInfo |
| | | { |
| | | // æ´å
åºåºçæ
åµ |
| | | stockDetail.StockQuantity = cancelQty; |
| | | stockDetail.OutboundQuantity = cancelQty; |
| | | } |
| | | else |
| | | OrderNo = originalLock.OrderNo, |
| | | OrderDetailId = originalLock.OrderDetailId, |
| | | BatchNo = originalLock.BatchNo, |
| | | MaterielCode = originalLock.MaterielCode, |
| | | MaterielName = originalLock.MaterielName, |
| | | StockId = originalLock.StockId, |
| | | OrderQuantity = quantity, |
| | | OriginalQuantity = quantity, |
| | | AssignQuantity = quantity, |
| | | PickedQty = quantity, |
| | | LocationCode = originalLock.LocationCode, |
| | | PalletCode = originalLock.PalletCode, |
| | | TaskNum = originalLock.TaskNum, |
| | | Status = (int)OutLockStockStatusEnum.æ£é宿, |
| | | Unit = originalLock.Unit, |
| | | SupplyCode = originalLock.SupplyCode, |
| | | OrderType = originalLock.OrderType, |
| | | CurrentBarcode = newBarcode, |
| | | OriginalLockQuantity = quantity, |
| | | IsSplitted = 1, |
| | | ParentLockId = originalLock.Id |
| | | }; |
| | | |
| | | var newLockId = await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteReturnIdentityAsync(); |
| | | newLockInfo.Id = newLockId; |
| | | return newLockInfo; |
| | | } |
| | | |
| | | private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, |
| | | decimal splitQty, decimal remainQty, string newBarcode) |
| | | { |
| | | var splitHistory = new Dt_SplitPackageRecord |
| | | { |
| | | // é¨ååºåºçæ
åµ |
| | | stockDetail.StockQuantity += cancelQty; |
| | | stockDetail.OutboundQuantity += cancelQty; |
| | | } |
| | | await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); |
| | | FactoryArea = lockInfo.FactoryArea, |
| | | TaskNum = lockInfo.TaskNum, |
| | | OutStockLockInfoId = lockInfo.Id, |
| | | StockId = stockDetail.StockId, |
| | | Operator = App.User.UserName, |
| | | IsReverted = false, |
| | | OriginalBarcode = stockDetail.Barcode, |
| | | NewBarcode = newBarcode, |
| | | SplitQty = splitQty, |
| | | RemainQuantity = remainQty, |
| | | MaterielCode = lockInfo.MaterielCode, |
| | | SplitTime = DateTime.Now, |
| | | OrderNo = lockInfo.OrderNo, |
| | | PalletCode = lockInfo.PalletCode, |
| | | Status = (int)SplitPackageStatusEnum.å·²æ£é |
| | | }; |
| | | |
| | | // 3. æ¢å¤éå®ä¿¡æ¯ç¶æ |
| | | lockInfo.AssignQuantity += cancelQty; |
| | | lockInfo.PickedQty -= cancelQty; |
| | | await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | if (lockInfo.PickedQty == 0) |
| | | private List<SplitResult> CreateSplitResults(Dt_OutStockLockInfo lockInfo, decimal splitQty, decimal remainQty, string newBarcode, string originalBarcode) |
| | | { |
| | | return new List<SplitResult> |
| | | { |
| | | new SplitResult |
| | | { |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; |
| | | materialCode = lockInfo.MaterielCode, |
| | | supplierCode = lockInfo.SupplyCode, |
| | | quantityTotal = splitQty.ToString("F2"), |
| | | batchNumber = newBarcode, |
| | | batch = lockInfo.BatchNo, |
| | | factory = lockInfo.FactoryArea, |
| | | date = DateTime.Now.ToString("yyyy-MM-dd"), |
| | | }, |
| | | new SplitResult |
| | | { |
| | | materialCode = lockInfo.MaterielCode, |
| | | supplierCode = lockInfo.SupplyCode, |
| | | quantityTotal = remainQty.ToString("F2"), |
| | | batchNumber = originalBarcode, |
| | | batch = lockInfo.BatchNo, |
| | | factory = lockInfo.FactoryArea, |
| | | date = DateTime.Now.ToString("yyyy-MM-dd"), |
| | | } |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | }; |
| | | } |
| | | |
| | | // 4. å¤çç¸å
³çæå
è®°å½ç¶ææ¢å¤ |
| | | private async Task UpdateSplitRecordsStatus(string barcode) |
| | | { |
| | | var relatedSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(it => it.OriginalBarcode == barcode && |
| | | it.Status == (int)SplitPackageStatusEnum.å·²æ£é) |
| | | .Where(it => it.OriginalBarcode == barcode || it.NewBarcode == barcode) |
| | | .Where(it => !it.IsReverted) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var record in relatedSplitRecords) |
| | | { |
| | | record.Status = (int)SplitPackageStatusEnum.å·²æå
; |
| | | record.Status = (int)SplitPackageStatusEnum.å·²æ£é; |
| | | await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | // 5. æ¢å¤è®¢åæç»çæ£éæ°é |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(it => it.PickedQty == it.PickedQty - cancelQty) |
| | | .Where(it => it.Id == lockInfo.OrderDetailId) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | // 6. æ¢å¤è®¢åç¶æ |
| | | await CheckAndRevertOrderStatus(orderNo); |
| | | |
| | | // 7. å 餿£éè®°å½ |
| | | await Db.Deleteable<Dt_PickingRecord>().Where(it => it.Id == pickingRecord.Id).ExecuteCommandAsync(); |
| | | |
| | | //// 8. è®°å½åæ¶æä½åå² |
| | | //await RecordCancelHistory(orderNo, palletCode, barcode, cancelQty, pickingRecord.Id, |
| | | // lockInfo.MaterielCode, "忶忣"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥å¹¶æ¢å¤è®¢åç¶æ |
| | | /// </summary> |
| | | private async Task CheckAndRevertOrderStatus(string orderNo) |
| | | private async Task<int> GenerateTaskNumber() |
| | | { |
| | | var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .FirstAsync(); |
| | | return await _dailySequenceService.GetNextSequenceAsync(); |
| | | } |
| | | |
| | | if (order != null && order.OrderStatus == OutOrderStatusEnum.åºåºå®æ.ObjToInt()) |
| | | private WebResponseContent CreatePickingResponse(PickingResult result, string adjustedReason) |
| | | { |
| | | if (result.SplitResults.Any()) |
| | | { |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(x => x.OrderStatus == OutOrderStatusEnum.åºåºä¸.ObjToInt()) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | // è·åæªæ£éå表 |
| | | public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode) |
| | | { |
| | | var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Status == 1) |
| | | .ToListAsync(); |
| | | return list.Where(x => x.RemainQuantity > 0).ToList(); |
| | | } |
| | | |
| | | // è·åå·²æ£éå表 |
| | | public async Task<List<Dt_OutStockLockInfo>> GetPickedList(string orderNo, string palletCode) |
| | | { |
| | | var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == orderNo && |
| | | x.PalletCode == palletCode && |
| | | x.Status == 6) |
| | | .ToListAsync(); |
| | | return list; |
| | | } |
| | | // è·åæ£éæ±æ» |
| | | public async Task<object> GetPickingSummary(ConfirmPickingDto dto) |
| | | { |
| | | var picked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), x => x.OrderNo == dto.OrderNo) |
| | | .WhereIF(!string.IsNullOrEmpty(dto.PalletCode), x => x.PalletCode == dto.PalletCode) |
| | | .Where(x => x.Status == 6) |
| | | .GroupBy(x => new { x.PalletCode, x.MaterielCode }) |
| | | .Select(x => new SummaryPickingDto |
| | | { |
| | | PalletCode = x.PalletCode, |
| | | MaterielCode = x.MaterielCode, |
| | | pickedCount = SqlFunc.AggregateCount(x.Id) |
| | | }).FirstAsync(); |
| | | if (picked == null) |
| | | { |
| | | picked = new SummaryPickingDto { pickedCount = 0 }; |
| | | return WebResponseContent.Instance.OK("æ£é确认æåï¼å·²èªå¨æå
", new { SplitResults = result.SplitResults }); |
| | | } |
| | | |
| | | var summary = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), x => x.OrderNo == dto.OrderNo) |
| | | .WhereIF(!string.IsNullOrEmpty(dto.PalletCode), x => x.PalletCode == dto.PalletCode) |
| | | .Where(x => x.Status == 1) |
| | | .GroupBy(x => new { x.PalletCode, x.MaterielCode }) |
| | | .Select(x => new SummaryPickingDto |
| | | { |
| | | PalletCode = x.PalletCode, |
| | | MaterielCode = x.MaterielCode, |
| | | UnpickedCount = SqlFunc.AggregateCount(x.Id), |
| | | UnpickedQuantity = SqlFunc.AggregateSum(x.AssignQuantity) - SqlFunc.AggregateSum(x.PickedQty), |
| | | |
| | | }).FirstAsync(); |
| | | if (summary == null) |
| | | { |
| | | summary = new SummaryPickingDto { pickedCount = 0 }; |
| | | } |
| | | summary.pickedCount = picked.pickedCount; |
| | | |
| | | return summary; |
| | | } |
| | | /// <summary> |
| | | /// è·åæ£éåå² |
| | | /// </summary> |
| | | public async Task<List<Dt_PickingRecord>> GetPickingHistory(int orderId) |
| | | { |
| | | // éè¿åºåºåIDæ¥è¯¢ç¸å
³çæ£éåå² |
| | | // 注æï¼Dt_PickingRecord 䏿²¡æç´æ¥åå¨OrderIdï¼éè¦éè¿åºåºåæç»å
³è |
| | | var detailIds = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .Where(d => d.OrderId == orderId) |
| | | .Select(d => d.Id) |
| | | .ToListAsync(); |
| | | |
| | | return await Db.Queryable<Dt_PickingRecord>() |
| | | .Where(p => detailIds.Contains(p.OrderDetailId)) |
| | | .OrderByDescending(p => p.PickTime) |
| | | .ToListAsync(); |
| | | return WebResponseContent.Instance.OK("æ£é确认æå", new { SplitResults = new List<SplitResult>() }); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// è·åæççåºåºç¶æä¿¡æ¯ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> GetPalletOutboundStatus(string palletCode) |
| | | { |
| | | // è·åæççéå®ä¿¡æ¯ |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.PalletCode == palletCode) |
| | | .ToListAsync(); |
| | | |
| | | // è·åæçåºåä¿¡æ¯ |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .Includes(x => x.Details) |
| | | .Where(x => x.PalletCode == palletCode) |
| | | .FirstAsync(); |
| | | |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°æçä¿¡æ¯"); |
| | | |
| | | // 计ç®åç§æ°é |
| | | var totalStockQuantity = stockInfo.Details.Sum(x => x.StockQuantity); |
| | | var totalOutboundQuantity = stockInfo.Details.Sum(x => x.OutboundQuantity); |
| | | var totalLockedQuantity = lockInfos.Where(x => x.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | .Sum(x => x.AssignQuantity - x.PickedQty); |
| | | var totalPickedQuantity = lockInfos.Sum(x => x.PickedQty); |
| | | |
| | | var result = new |
| | | { |
| | | PalletCode = palletCode, |
| | | LocationCode = stockInfo.LocationCode, |
| | | StockStatus = stockInfo.StockStatus, |
| | | TotalStockQuantity = totalStockQuantity, |
| | | TotalOutboundQuantity = totalOutboundQuantity, |
| | | TotalLockedQuantity = totalLockedQuantity, |
| | | TotalPickedQuantity = totalPickedQuantity, |
| | | AvailableQuantity = totalStockQuantity - totalOutboundQuantity, |
| | | LockInfos = lockInfos.Select(x => new |
| | | { |
| | | x.Id, |
| | | x.MaterielCode, |
| | | x.OrderDetailId, |
| | | x.AssignQuantity, |
| | | x.PickedQty, |
| | | x.Status, |
| | | x.CurrentBarcode, |
| | | x.IsSplitted |
| | | }).ToList(), |
| | | StockDetails = stockInfo.Details.Select(x => new |
| | | { |
| | | x.Barcode, |
| | | x.MaterielCode, |
| | | StockQuantity = x.StockQuantity, |
| | | OutboundQuantity = x.OutboundQuantity, |
| | | AvailableQuantity = x.StockQuantity - x.OutboundQuantity |
| | | }).ToList() |
| | | }; |
| | | |
| | | return WebResponseContent.Instance.OK(null, result); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç´æ¥åºåº - æ´ä¸ªæçåºåºï¼æ¸
空åºå |
| | | /// </summary> |
| | | public async Task<WebResponseContent> DirectOutbound(DirectOutboundRequest request) |
| | | { |
| | | try |
| | | { |
| | | _unitOfWorkManage.BeginTran(); |
| | | |
| | | var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() |
| | | .Includes(x => x.Details) |
| | | .Where(x => x.PalletCode == request.PalletCode).FirstAsync(); |
| | | |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°æçåºåä¿¡æ¯"); |
| | | |
| | | |
| | | var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() |
| | | .Where(x => x.OrderNo == request.OrderNo && x.PalletCode == request.PalletCode) |
| | | .ToListAsync(); |
| | | |
| | | |
| | | foreach (var lockInfo in lockInfos) |
| | | { |
| | | if (lockInfo.Status == (int)OutLockStockStatusEnum.åºåºä¸) |
| | | { |
| | | lockInfo.PickedQty = lockInfo.AssignQuantity; |
| | | } |
| | | lockInfo.Status = (int)OutLockStockStatusEnum.å·²åºåº; |
| | | await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); |
| | | |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() |
| | | .Where(x => x.Id == lockInfo.OrderDetailId) |
| | | .FirstAsync(); |
| | | if (orderDetail != null) |
| | | { |
| | | orderDetail.OverOutQuantity += lockInfo.PickedQty; |
| | | orderDetail.LockQuantity -= lockInfo.PickedQty; |
| | | orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.Over; |
| | | orderDetail.LockQuantity = 0; |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | var groupDetails = lockInfos.GroupBy(x => x.OrderDetailId).Select(x => new |
| | | { |
| | | OrderDetailId = x.Key, |
| | | TotalQuantity = x.Sum(o => o.PickedQty) |
| | | }).ToList(); |
| | | foreach (var item in groupDetails) |
| | | { |
| | | var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>().Where(x => x.Id == item.OrderDetailId).FirstAsync(); |
| | | if (orderDetail != null) |
| | | { |
| | | orderDetail.OverOutQuantity = item.TotalQuantity; |
| | | orderDetail.LockQuantity = 0; |
| | | orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.Over; |
| | | await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | |
| | | await CheckAndUpdateOrderStatus(request.OrderNo); |
| | | |
| | | var lockInfoIds = lockInfos.Select(x => x.Id).ToList(); |
| | | var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() |
| | | .Where(x => lockInfoIds.Contains(x.OutStockLockInfoId) && |
| | | x.Status == (int)SplitPackageStatusEnum.å·²æå
) |
| | | .ToListAsync(); |
| | | |
| | | foreach (var record in splitRecords) |
| | | { |
| | | record.Status = (int)SplitPackageStatusEnum.å·²æ£é; |
| | | await _splitPackageService.Db.Updateable(record).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | |
| | | var location = await _locationInfoService.Db.Queryable<Dt_LocationInfo>() |
| | | .Where(x => x.LocationCode == stockInfo.LocationCode) |
| | | .FirstAsync(); |
| | | if (location != null) |
| | | { |
| | | location.LocationStatus = (int)LocationStatusEnum.Free; |
| | | await _locationInfoService.Db.Updateable(location).ExecuteCommandAsync(); |
| | | } |
| | | |
| | | foreach (var detail in stockInfo.Details) |
| | | { |
| | | await _stockInfoDetailService.Db.Deleteable(detail).ExecuteCommandAsync(); |
| | | } |
| | | await _stockInfoService.Db.Deleteable(stockInfo).ExecuteCommandAsync(); |
| | | |
| | | |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | return WebResponseContent.Instance.OK("ç´æ¥åºåºæå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error($"ç´æ¥åºåºå¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | #endregion |
| | | } |
| | | |
| | | #region æ¯æç±»å®ä¹ |
| | | |
| | | #region è¿å |
| | | /// <summary> |
| | | /// æå
é¾é¡¹ |
| | | /// </summary> |
| | | public class SplitChainItem |
| | | public class ValidationResult<T> |
| | | { |
| | | public Dt_SplitPackageRecord SplitRecord { get; set; } |
| | | public string OriginalBarcode { get; set; } |
| | | public string NewBarcode { get; set; } |
| | | public decimal SplitQuantity { get; set; } |
| | | public bool IsValid { get; set; } |
| | | public T Data { get; set; } |
| | | public string ErrorMessage { get; set; } |
| | | |
| | | public static ValidationResult<T> Success(T data) |
| | | { |
| | | return new ValidationResult<T> |
| | | { |
| | | IsValid = true, |
| | | Data = data |
| | | }; |
| | | } |
| | | |
| | | public static ValidationResult<T> Error(string message) |
| | | { |
| | | return new ValidationResult<T> |
| | | { |
| | | IsValid = false, |
| | | ErrorMessage = message |
| | | }; |
| | | } |
| | | } |
| | | public class ReturnAnalysisResult |
| | | |
| | | public class PickingResult |
| | | { |
| | | public Dt_OutStockLockInfo FinalLockInfo { get; set; } |
| | | public string FinalBarcode { get; set; } |
| | | public int FinalStockId { get; set; } |
| | | public decimal ActualPickedQty { get; set; } |
| | | public List<SplitResult> SplitResults { get; set; } = new List<SplitResult>(); |
| | | } |
| | | |
| | | public class ReturnAnalysisResult |
| | | { |
| | | public bool HasItemsToReturn { get; set; } |
| | | public bool HasRemainingLocks { get; set; } |
| | |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | } |