|
|
@@ -160,9 +160,16 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
|
|
|
LEFT JOIN PurOrdRctDetail d
|
|
|
ON p.RctType = d.RctType AND p.Receiver = d.Receiver
|
|
|
LEFT JOIN ItemMaster i ON d.ItemNum = i.ItemNum AND (p.tenant_id = i.tenant_id OR p.tenant_id IS NULL)
|
|
|
- WHERE p.RctType = 'rc' AND p.Supp = @Supp AND d.RecID > 0 AND IFNULL(p.TermsofTrade,'') <> ''
|
|
|
+ WHERE p.RctType = 'rc' AND p.Supp = @Supp AND d.RecID > 0
|
|
|
AND p.tenant_id = @TenantId
|
|
|
GROUP BY p.Receiver, d.LotSerial, d.ItemNum, i.Descr, p.Domain
|
|
|
+ HAVING SUM(d.QtyReceived) > IFNULL((
|
|
|
+ SELECT SUM(rd.QtyReceived) FROM PurOrdRctDetail rd
|
|
|
+ JOIN PurOrdRctMaster rm ON rd.PurOrdRctRecID = rm.RecID AND rd.RctType = rm.RctType
|
|
|
+ WHERE rm.RctType = 'pt' AND rm.OrdNbr = p.Receiver AND rd.IsActive = 1
|
|
|
+ AND rd.ItemNum = d.ItemNum AND IFNULL(rd.LotSerial,'') = IFNULL(d.LotSerial,'')
|
|
|
+ AND rm.tenant_id = p.tenant_id
|
|
|
+ ), 0)
|
|
|
ORDER BY p.Receiver DESC
|
|
|
""",
|
|
|
new SugarParameter("@Supp", supp.Trim()),
|
|
|
@@ -404,6 +411,9 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
|
|
|
if (string.IsNullOrWhiteSpace(domain))
|
|
|
domain = "100";
|
|
|
|
|
|
+ // 校验退货数量不超过收货单可退余量
|
|
|
+ await ValidateReturnQuantities(input.OrdNbr.Trim(), input.Id, input.Details, tenantId);
|
|
|
+
|
|
|
if (input.Id is null or 0)
|
|
|
{
|
|
|
try
|
|
|
@@ -626,4 +636,80 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
|
|
|
if (string.IsNullOrWhiteSpace(raw)) return null;
|
|
|
return DateTime.TryParse(raw.Trim(), out var d) ? d.Date : null;
|
|
|
}
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 校验退货数量不超过收货单可退余量。
|
|
|
+ /// 对每行按 ItemNum + LotSerial 分组,比较:已有退货总量 + 本次退货量 ≤ 收货量。
|
|
|
+ /// 编辑时排除当前退货单自身数量。
|
|
|
+ /// </summary>
|
|
|
+ private async Task ValidateReturnQuantities(
|
|
|
+ string rcReceiver, int? editingId, List<PurchaseReturnDetailInput> details, long tenantId)
|
|
|
+ {
|
|
|
+ // 1. 取收货单明细:按 (ItemNum, LotSerial) 汇总收货数量
|
|
|
+ var rcLines = await _db.Ado.SqlQueryAsync<dynamic>(
|
|
|
+ """
|
|
|
+ SELECT ItemNum, IFNULL(LotSerial,'') AS LotSerial, SUM(QtyReceived) AS QtyReceived
|
|
|
+ FROM PurOrdRctDetail
|
|
|
+ WHERE RctType='rc' AND Receiver=@Receiver AND tenant_id=@TenantId
|
|
|
+ GROUP BY ItemNum, IFNULL(LotSerial,'')
|
|
|
+ """,
|
|
|
+ new SugarParameter("@Receiver", rcReceiver),
|
|
|
+ new SugarParameter("@TenantId", tenantId));
|
|
|
+
|
|
|
+ if (!rcLines.Any()) return; // 收货单无明细则跳过校验
|
|
|
+
|
|
|
+ var received = new Dictionary<string, decimal>();
|
|
|
+ foreach (var rc in rcLines)
|
|
|
+ {
|
|
|
+ var key = $"{(string)rc.ItemNum}|{(string)rc.LotSerial}";
|
|
|
+ received[key] = (decimal)rc.QtyReceived;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 取已有退货总量(排除编辑中的当前退货单)
|
|
|
+ var excludeSql = editingId.HasValue ? " AND rm.RecID <> @ExcludeId" : "";
|
|
|
+ var existingReturns = await _db.Ado.SqlQueryAsync<dynamic>(
|
|
|
+ $"""
|
|
|
+ SELECT rd.ItemNum, IFNULL(rd.LotSerial,'') AS LotSerial, SUM(rd.QtyReceived) AS ReturnedQty
|
|
|
+ FROM PurOrdRctDetail rd
|
|
|
+ JOIN PurOrdRctMaster rm ON rd.PurOrdRctRecID = rm.RecID AND rd.RctType = rm.RctType
|
|
|
+ WHERE rm.RctType='pt' AND rm.OrdNbr=@Receiver AND rd.IsActive=1{excludeSql}
|
|
|
+ AND rm.tenant_id=@TenantId
|
|
|
+ GROUP BY rd.ItemNum, IFNULL(rd.LotSerial,'')
|
|
|
+ """,
|
|
|
+ editingId.HasValue
|
|
|
+ ? new List<SugarParameter>
|
|
|
+ {
|
|
|
+ new("@Receiver", rcReceiver),
|
|
|
+ new("@ExcludeId", editingId.Value),
|
|
|
+ new("@TenantId", tenantId)
|
|
|
+ }
|
|
|
+ : new List<SugarParameter>
|
|
|
+ {
|
|
|
+ new("@Receiver", rcReceiver),
|
|
|
+ new("@TenantId", tenantId)
|
|
|
+ });
|
|
|
+
|
|
|
+ var returned = new Dictionary<string, decimal>();
|
|
|
+ foreach (var rt in existingReturns)
|
|
|
+ {
|
|
|
+ var key = $"{(string)rt.ItemNum}|{(string)rt.LotSerial}";
|
|
|
+ returned[key] = (decimal)rt.ReturnedQty;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 逐行校验
|
|
|
+ for (var i = 0; i < details.Count; i++)
|
|
|
+ {
|
|
|
+ var d = details[i];
|
|
|
+ var key = $"{d.ItemNum?.Trim()}|{d.LotSerial?.Trim() ?? ""}";
|
|
|
+ if (!received.TryGetValue(key, out var rcQty)) continue;
|
|
|
+
|
|
|
+ var alreadyReturned = returned.GetValueOrDefault(key, 0m);
|
|
|
+ var thisQty = d.QtyReceived;
|
|
|
+ if (alreadyReturned + thisQty > rcQty)
|
|
|
+ {
|
|
|
+ var available = rcQty - alreadyReturned;
|
|
|
+ throw Oops.Oh($"第 {i + 1} 行退货数量({thisQty})超过可退余量({available}),收货数量={rcQty},已退数量={alreadyReturned}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|