Sales Order API: restore Completely Shipped after redistributing invoice discounts#29954
Conversation
… Sales Order API pages RedistributeInvoiceDiscounts called in OnAfterGetRecord triggers an OnAfterModifySalesLine event handler (UpdateCompletelyShipped) that copies spurious filters from the SalesLine record and incorrectly evaluates IsEmpty() as true, causing Completely Shipped to be set to true regardless of actual shipment status. Save and restore Rec.'Completely Shipped' around the call in both APIV1 - Sales Orders and APIV2 - Sales Orders pages so that the value returned by the API reflects the actual state of sales lines. Fixes microsoft#29071
Replace the IsCompletelyShipped save/restore pattern with Rec.Find() after RedistributeInvoiceDiscounts. This re-reads the entire Sales Header record from the database, ensuring all fields including Completely Shipped reflect the true persisted state regardless of any in-memory side effects from the invoice discount redistribution call chain.
jeffreybulanadi
left a comment
There was a problem hiding this comment.
Updated the fix to use Rec.Find() after RedistributeInvoiceDiscounts, as suggested. This re-reads the entire Sales Header from the database, which addresses both concerns raised:
- No risk of overwriting legitimate future updates - the database is the source of truth, and Rec.Find() always reflects the actual persisted state.
- All fields are restored, not just Completely Shipped - any other header field that may have been corrupted in-memory by the call chain is also corrected.
SetCalculatedFields() sets only page-level Text variables (BillingPostalAddressJSONText, ShippingPostalAddressJSONText, CurrencyCodeTxt, PartialOrderShipping) - not Rec fields - so Rec.Find() does not undo that work.
|
Thank you for your contribution and for taking the time to submit this pull request. At this stage, we’re not able to accept the change. We’d like to revisit this proposal once the migration to BCApps is complete though. At that point, we’ll be in a better position to properly evaluate and validate changes like this. We appreciate your contribution and encourage you to resubmit or revisit this after the transition has been finalized. |
|
Please open a BC idea for this and lets get votes. One of the issues here is that we are re-reading the record from the OnAfterGetRecord trigger which is not something we do and can lead to the issues down the line. If we are refactoring this code, it would be better to introduce a more stabile solution. The best would be if we could redistribute discounts always, or maybe from a different trigger/background job or a different system. Patching from the OnAfterGetRecord is a workaround. |
Summary
Fixes #29071
Root Cause
In OnAfterGetRecord of both APIV1 - Sales Orders (page 20000) and APIV2 - Sales Orders (page 30028), calling GraphMgtSalesOrderBuffer.RedistributeInvoiceDiscounts(Rec) has an unintended side effect on Rec.\Completely Shipped\`.
The call chain is:
Fix
Save the value of Rec.\Completely Shipped\` from the database before invoking RedistributeInvoiceDiscounts and restore it afterward. The invoice discount redistribution function has no business modifying shipping status; this ensures the API returns the actual shipment state of the sales lines.
Files Changed
How to Test
Fixes AB#632884