The BPM is working as expected when the user add the receipt line by line.
However, the user will hit the exception “The table ds.RcvDtl has more than one record” when they are doing mass receipt and trying to change the receiving qty to more or less than the PO qty.
If you have multiple records then in my experience you have to use a custom code block to iterate over each record and apply your business logic to each.
foreach (var RcvDtlRecord in ds.RcvDtl)
{
// Apply business logic to check for over receipt here
// if (inputOurQty > RcvDtlRecord.OurQty)
// throw new ArgumentOutOfRangeException(RcvDtlRecord.PackSlip + " " + RcvDtlRecord.PackLine + " had qty of " + RcvDtlRecord.OurQty + " which user entry exceeded");
}
Though as mentioned in the other post - it’s probably better to leave this as a warning to prevent issues further downstream.
I’ve placed my custom code at the following methods’ Pre-Processing
Erp.BO.Receipt.CommitRcvDtl
Erp.BO.Receipt.OnChangeDtlReceived
Erp.BO.Receipt.OnChangeHdrReceived
Erp.BO.Receipt.UpdateMaster
The code is working as expected when the user is receiving the packline 1 by 1.
But it’s not working when the user entered a batch of receiving lines and received all.
// Initialize a variable to store the previous receipts quantity.
decimal prevrcpts = 0;
// Iterate over each receiving detail that meets PO conditions.
foreach (var rdtl in (from rdtlrow in ds.RcvDtl
where (string.Equals(rdtlrow.RowMod, IceRow.ROWSTATE_UPDATED, StringComparison.OrdinalIgnoreCase)
|| string.Equals(rdtlrow.RowMod, IceRow.ROWSTATE_ADDED, StringComparison.OrdinalIgnoreCase))
&& rdtlrow.PONum != 0
&& rdtlrow.POLine != 0
select rdtlrow))
{
// Retrieve the purchase order release related to the current receiving detail.
var prel = Db.PORel.FirstOrDefault(p => p.Company == rdtl.Company && p.PONum == rdtl.PONum && p.POLine == rdtl.POLine && p.PORelNum == rdtl.PORelNum);
if (prel != null)
{
// Determine the previous receipts quantity based on the RowMod of the receiving detail.
if (rdtl.RowMod == "A")
prevrcpts = prel.ReceivedQty;
if (rdtl.RowMod == "U")
prevrcpts = prel.ReceivedQty - rdtl.OurQty;
// Check if the sum of the current and previous receipts quantity exceeds the PO release quantity.
if ((rdtl.InputOurQty + prevrcpts) > (prel.XRelQty * 1))
{
// Throw an exception if over receiving is detected.
if (prevrcpts > 0)
throw new Ice.BLException("Over receiving detected at Line [" + rdtl.PackLine + "] ! Entered quantity of " + rdtl.InputOurQty + " plus previous receipts of " + Math.Round(prevrcpts, 2) + " is more than the PO release quantity of " + Math.Round(prel.XRelQty, 2) + " [BPM]");
else
throw new Ice.BLException("Over receiving detected at Line [" + rdtl.PackLine + "] ! Entered quantity of " + rdtl.InputOurQty + " is more than the PO release quantity of " + Math.Round(prel.XRelQty, 2) + " [BPM]");
}
}
}
Managed to solve my issue with the help of ChatGPT
Below is my code.
// Initialize variable to store previously received quantity for the current PO release.
decimal prevReceipts = 0;
// Loop through each receiving detail where records are either updated or newly added, and PO details are valid.
foreach (var receivingDetail in from detail in ds.RcvDtl
where (string.Equals(detail.RowMod, IceRow.ROWSTATE_UPDATED, StringComparison.OrdinalIgnoreCase) ||
string.Equals(detail.RowMod, IceRow.ROWSTATE_ADDED, StringComparison.OrdinalIgnoreCase)) &&
detail.PONum != 0 &&
detail.POLine != 0
select detail)
{
// Fetch the matching PO release for the current receiving detail.
var purchaseOrderRelease = Db.PORel.FirstOrDefault(p => p.Company == receivingDetail.Company &&
p.PONum == receivingDetail.PONum &&
p.POLine == receivingDetail.POLine &&
p.PORelNum == receivingDetail.PORelNum);
if (purchaseOrderRelease != null)
{
// Calculate the total previously received quantity for this PO release, excluding the current receipt to avoid double-counting.
var totalReceivedQuantity = Db.RcvDtl
.Where(p => p.Company == receivingDetail.Company &&
p.PONum == receivingDetail.PONum &&
p.POLine == receivingDetail.POLine &&
p.PORelNum == receivingDetail.PORelNum &&
p.SysRowID != receivingDetail.SysRowID) // Exclude current receipt row
.Sum(x => (decimal?)x.OurQty) ?? 0;
// Set prevReceipts to the already received quantity for this PO release.
prevReceipts = purchaseOrderRelease.ReceivedQty;
// Round quantities to two decimal places for consistency and to prevent precision issues.
var enteredQuantity = Math.Round(receivingDetail.InputOurQty, 2);
var totalQuantityIncludingCurrent = Math.Round(enteredQuantity + totalReceivedQuantity, 2);
var roundedXRelQty = Math.Round(purchaseOrderRelease.XRelQty, 2);
// Check if the total quantity (including the current entry) exceeds the allowed release quantity.
if (totalQuantityIncludingCurrent > roundedXRelQty)
{
// If over-receiving is detected, throw an exception with details for handling.
var exceptionMessage = prevReceipts > 0
? $"Over receiving detected at Line [{receivingDetail.POLine}]! Entered quantity of {enteredQuantity} plus previous receipts of {Math.Round(prevReceipts, 2)} exceeds PO release quantity of {roundedXRelQty} "
: $"Over receiving detected at Line [{receivingDetail.POLine}]! Entered quantity of {enteredQuantity} exceeds PO release quantity of {roundedXRelQty}";
throw new Ice.BLException(exceptionMessage);
}
}
}