From 1a1bc81ac1d9ad656e15b409122e23f7f3763293 Mon Sep 17 00:00:00 2001
From: pan <antony1029@163.com>
Date: 星期四, 27 十一月 2025 08:27:41 +0800
Subject: [PATCH] 提交
---
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs | 248 ++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 204 insertions(+), 44 deletions(-)
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs"
index 4459d4c..121a74e 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs"
@@ -336,71 +336,231 @@
}
- public (List<Dt_StockInfo>, Dt_OutboundOrderDetail, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>) AssignStockOutbound(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
+ public (List<Dt_StockInfo>, Dt_OutboundOrderDetail, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>)
+ AssignStockOutbound(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
{
+ // 楠岃瘉鐢ㄦ埛閫夋嫨
(bool, string) checkResult = CheckSelectStockDeital(outboundOrderDetail, stockSelectViews);
if (!checkResult.Item1) throw new Exception(checkResult.Item2);
Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetail.OrderId);
var originalNeedQuantity = outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity - outboundOrderDetail.MoveQty;
- var needQuantity = originalNeedQuantity;
+ List<Dt_StockInfo> outStocks = new List<Dt_StockInfo>();
+ List<Dt_OutStockLockInfo> outStockLockInfos = new List<Dt_OutStockLockInfo>();
- List<Dt_StockInfo> outStocks = _stockService.StockInfoService.GetStockInfosByPalletCodes(stockSelectViews.Select(x => x.PalletCode).ToList());
- var assignQuantity = 0m;
- outStocks.ForEach(x =>
- {
- x.Details.ForEach(v =>
- {
- assignQuantity += v.StockQuantity - v.OutboundQuantity;
- });
- });
+ decimal remainingNeedQuantity = originalNeedQuantity;
+ decimal totalAssignedFromUserSelection = 0;
- outboundOrderDetail.LockQuantity += assignQuantity;
- outStocks.ForEach(x =>
+ // 鎸夊厛杩涘厛鍑烘帓搴忕敤鎴烽�夋嫨鐨勫簱瀛�
+ var userSelectedStocks = _stockService.StockInfoService.GetStockInfosByPalletCodes(
+ stockSelectViews.Select(x => x.PalletCode).ToList());
+
+ var sortedUserSelectedStocks = userSelectedStocks
+ .OrderBy(x => x.CreateDate)
+ .ToList();
+
+ // 鍒嗛厤鐢ㄦ埛閫夋嫨鐨勫簱瀛�
+ foreach (var stock in sortedUserSelectedStocks)
{
- x.Details.ForEach(v =>
+ if (remainingNeedQuantity <= 0) break;
+
+ // 鑾峰彇鐢ㄦ埛瀵硅鎵樼洏鐨勯�夋嫨鏁伴噺
+ var userSelection = stockSelectViews.FirstOrDefault(x => x.PalletCode == stock.PalletCode);
+ if (userSelection == null) continue;
+
+ // 璁$畻璇ユ墭鐩樺疄闄呭彲鐢ㄦ暟閲�
+ var availableQuantity = CalculateAvailableQuantity(stock, outboundOrderDetail.MaterielCode,
+ outboundOrderDetail.BatchNo, outboundOrderDetail.SupplyCode);
+
+ // 纭畾鍒嗛厤鏁伴噺锛氬彇鐢ㄦ埛閫夋嫨鏁伴噺銆佸彲鐢ㄦ暟閲忓拰鍓╀綑闇�姹傜殑鏈�灏忓��
+ var assignQuantity = Math.Min(
+ Math.Min(userSelection.UseableQuantity, availableQuantity),
+ remainingNeedQuantity);
+
+ if (assignQuantity <= 0) continue;
+
+ // 鎵ц鍒嗛厤
+ var actualAssigned = AssignStockQuantity(stock, outboundOrderDetail, assignQuantity);
+ if (actualAssigned > 0)
{
- v.OutboundQuantity = v.StockQuantity;
- });
- });
- needQuantity -= assignQuantity;
- if (outboundOrderDetail.OrderQuantity > outboundOrderDetail.LockQuantity)
- {
- List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(outboundOrderDetail.MaterielCode, outboundOrderDetail.BatchNo, "");
- stockInfos = stockInfos.Where(x => !stockSelectViews.Select(v => v.PalletCode).Contains(x.PalletCode)).ToList();
- var (autoAssignStocks, stockAllocations) = _stockService.StockInfoService.GetOutboundStocks(stockInfos, outboundOrderDetail.MaterielCode, needQuantity, out decimal residueQuantity);
- outboundOrderDetail.LockQuantity += needQuantity - residueQuantity;
- outStocks.AddRange(autoAssignStocks);
- outboundOrderDetail.OrderDetailStatus = OrderDetailStatusEnum.AssignOver.ObjToInt();
- if (residueQuantity > 0)
- {
- outboundOrderDetail.OrderDetailStatus = OrderDetailStatusEnum.AssignOverPartial.ObjToInt();
+ outStocks.Add(stock);
+ totalAssignedFromUserSelection += actualAssigned;
+ remainingNeedQuantity -= actualAssigned;
+
+ // 鍒涘缓閿佸畾璁板綍
+ var lockInfo = CreateOutStockLockInfo(outboundOrder, outboundOrderDetail, stock, actualAssigned);
+ outStockLockInfos.Add(lockInfo);
}
}
- List<Dt_OutStockLockInfo> outStockLockInfos = _outStockLockInfoService.GetOutStockLockInfos(outboundOrder, outboundOrderDetail, outStocks);
+ // 妫�鏌ョ敤鎴烽�夋嫨鏄惁鑷冲皯鍒嗛厤浜嗕竴閮ㄥ垎
+ if (totalAssignedFromUserSelection <= 0)
+ {
+ throw new Exception("鐢ㄦ埛閫夋嫨鐨勫簱瀛樻棤娉曞垎閰嶄换浣曟暟閲�");
+ }
+
+ // 濡傛灉鐢ㄦ埛閫夋嫨鐨勫簱瀛樹笉澶燂紝鑷姩鍒嗛厤鍓╀綑閮ㄥ垎
+ decimal autoAssignedQuantity = 0;
+ if (remainingNeedQuantity > 0)
+ {
+ List<Dt_StockInfo> autoStocks = _stockService.StockInfoService.GetUseableStocks(
+ outboundOrderDetail.MaterielCode, outboundOrderDetail.BatchNo, "");
+
+ // 鎺掗櫎鐢ㄦ埛宸查�夋嫨鐨勬墭鐩�
+ autoStocks = autoStocks
+ .Where(x => !stockSelectViews.Select(v => v.PalletCode).Contains(x.PalletCode))
+ .ToList();
+
+ var (autoAssignStocks, stockAllocations) = _stockService.StockInfoService.GetOutboundStocks(
+ autoStocks, outboundOrderDetail.MaterielCode, remainingNeedQuantity, out decimal residueQuantity);
+
+ // 妫�鏌ヨ嚜鍔ㄥ垎閰嶇粨鏋�
+ autoAssignedQuantity = remainingNeedQuantity - residueQuantity;
+ if (autoAssignedQuantity <= 0 && remainingNeedQuantity > 0)
+ {
+ // 閮ㄥ垎鍒嗛厤鏄彲浠ユ帴鍙楃殑锛岃褰曡鍛婁絾涓嶆姤閿�
+ _logger.LogWarning($"鑷姩鍒嗛厤澶辫触锛屽墿浣欓渶姹倇remainingNeedQuantity}鏃犳硶婊¤冻");
+ }
+ else if (autoAssignedQuantity > 0)
+ {
+ outStocks.AddRange(autoAssignStocks);
+
+ // 涓鸿嚜鍔ㄥ垎閰嶇殑搴撳瓨鍒涘缓閿佸畾璁板綍
+ var autoLockInfos = CreateLockInfosForAutoAssign(outboundOrder, outboundOrderDetail, autoAssignStocks, stockAllocations);
+ outStockLockInfos.AddRange(autoLockInfos);
+ }
+ }
+
+ // 鏇存柊閿佸畾鏁伴噺
+ outboundOrderDetail.LockQuantity += totalAssignedFromUserSelection + autoAssignedQuantity;
+
+ // 鏇存柊鐘舵��
+ UpdateOrderDetailStatus(outboundOrderDetail, remainingNeedQuantity - autoAssignedQuantity);
List<Dt_LocationInfo> locationInfos = _locationInfoService.GetLocationInfos(outStocks.Select(x => x.LocationCode).ToList());
return (outStocks, outboundOrderDetail, outStockLockInfos, locationInfos);
}
- private (bool, string) CheckSelectStockDeital(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
+
+ // 杈呭姪鏂规硶
+ private decimal CalculateAvailableQuantity(Dt_StockInfo stock, string materielCode, string batchNo, string supplyCode)
{
- if (outboundOrderDetail == null)
- {
- return (false, "鏈壘鍒板嚭搴撳崟鏄庣粏淇℃伅");
- }
- if (outboundOrderDetail.OrderDetailStatus != OrderDetailStatusEnum.New.ObjToInt() && outboundOrderDetail.OrderDetailStatus != OrderDetailStatusEnum.AssignOverPartial.ObjToInt())
- {
- return (false, "璇ユ槑缁嗕笉鍙搷浣�");
- }
- //if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity - outboundOrderDetail.MoveQty)
- //{
- // return (false, "閫夋嫨鏁伴噺瓒呭嚭鍗曟嵁鏁伴噺");
- //}
- return (true, "鎴愬姛");
+ var relevantDetails = stock.Details
+ .Where(d => d.MaterielCode == materielCode &&
+ (string.IsNullOrEmpty(batchNo) || d.BatchNo == batchNo) &&
+ (string.IsNullOrEmpty(supplyCode) || d.SupplyCode == supplyCode))
+ .ToList();
+
+ return relevantDetails.Sum(d => d.StockQuantity - d.OutboundQuantity);
}
+ private decimal AssignStockQuantity(Dt_StockInfo stock, Dt_OutboundOrderDetail detail, decimal assignQuantity)
+ {
+ decimal remainingAssign = assignQuantity;
+
+ // 鎸夊厛杩涘厛鍑哄垎閰嶅簱瀛樻槑缁�
+ var sortedDetails = stock.Details
+ .Where(d => d.MaterielCode == detail.MaterielCode &&
+ d.BatchNo == detail.BatchNo &&
+ (d.StockQuantity - d.OutboundQuantity) > 0)
+ .OrderBy(d => d.CreateDate)
+ .ToList();
+
+ foreach (var stockDetail in sortedDetails)
+ {
+ if (remainingAssign <= 0) break;
+
+ var available = stockDetail.StockQuantity - stockDetail.OutboundQuantity;
+ var assign = Math.Min(available, remainingAssign);
+
+ stockDetail.OutboundQuantity += assign;
+ remainingAssign -= assign;
+ }
+
+ return assignQuantity - remainingAssign; // 杩斿洖瀹為檯鍒嗛厤鏁伴噺
+ }
+
+ private Dt_OutStockLockInfo CreateOutStockLockInfo(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail detail,
+ Dt_StockInfo stock, decimal quantity)
+ {
+ var barcode = stock.Details
+ .Where(d => !string.IsNullOrEmpty(d.Barcode))
+ .Select(d => d.Barcode)
+ .FirstOrDefault();
+
+ return _outStockLockInfoService.GetOutStockLockInfo(outboundOrder, detail, stock, quantity, barcode);
+ }
+
+ private List<Dt_OutStockLockInfo> CreateLockInfosForAutoAssign(Dt_OutboundOrder outboundOrder,
+ Dt_OutboundOrderDetail detail, List<Dt_StockInfo> stocks, Dictionary<int, decimal> allocations)
+ {
+ var lockInfos = new List<Dt_OutStockLockInfo>();
+
+ foreach (var stock in stocks.OrderBy(x => x.CreateDate))
+ {
+ if (allocations.TryGetValue(stock.Id, out decimal quantity) && quantity > 0)
+ {
+ var lockInfo = CreateOutStockLockInfo(outboundOrder, detail, stock, quantity);
+ lockInfos.Add(lockInfo);
+ }
+ }
+
+ return lockInfos;
+ }
+
+ private void UpdateOrderDetailStatus(Dt_OutboundOrderDetail detail, decimal remainingQuantity)
+ {
+ if (remainingQuantity <= 0)
+ {
+ detail.OrderDetailStatus = OrderDetailStatusEnum.AssignOver.ObjToInt();
+ }
+ else
+ {
+ detail.OrderDetailStatus = OrderDetailStatusEnum.AssignOverPartial.ObjToInt();
+ }
+ }
+
+ private (bool, string) CheckSelectStockDeital(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
+ {
+ var needQuantity = outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity - outboundOrderDetail.MoveQty;
+
+ if (needQuantity <= 0)
+ {
+ return (false, "鍑哄簱鍗曟槑缁嗘棤闇�鍒嗛厤搴撳瓨");
+ }
+
+ // 妫�鏌ユ�婚�夋嫨鏁伴噺鏄惁澶т簬0
+ var totalSelected = stockSelectViews.Sum(x => x.UseableQuantity);
+ if (totalSelected <= 0)
+ {
+ return (false, "鐢ㄦ埛閫夋嫨鐨勫簱瀛樻暟閲忓繀椤诲ぇ浜�0");
+ }
+
+ // 妫�鏌ユ瘡涓墭鐩樼殑鍙敤鏁伴噺
+ foreach (var selection in stockSelectViews)
+ {
+ if (selection.UseableQuantity <= 0)
+ {
+ return (false, $"鎵樼洏[{selection.PalletCode}]鐨勯�夋嫨鏁伴噺蹇呴』澶т簬0");
+ }
+
+ var stock = _stockService.StockInfoService.GetStockInfoByPalletCode(selection.PalletCode);
+ if (stock == null)
+ {
+ return (false, $"鎵樼洏[{selection.PalletCode}]涓嶅瓨鍦�");
+ }
+
+ var available = CalculateAvailableQuantity(stock, outboundOrderDetail.MaterielCode,
+ outboundOrderDetail.BatchNo, outboundOrderDetail.SupplyCode);
+
+ if (available <= 0)
+ {
+ return (false, $"鎵樼洏[{selection.PalletCode}]娌℃湁鍙敤搴撳瓨");
+ }
+ }
+
+ return (true, "楠岃瘉閫氳繃");
+ }
}
}
--
Gitblit v1.9.3