Why do you need this change?
We need an event inside the trigger OnValidate of field "Pay-to Vendor No.", to be able to run the procedure RecreatePurchLines if a custom if statement is satisfied or, alternatively, run a custom procedure.
To manage an IsHandled variable is the only way to skip RecreatePurchLines (if a particular custom condition is satisfied) and run a custom procedure instead. At the moment there are no other ways to do that.
Describe the request
In trigger OnValidate of field(4; "Pay-to Vendor No."; Code[20]) of table 38 "Purchase Header" we need an event:
[IntegrationEvent(false, false)]
local procedure OnBeforeRecreatePurchLines(var Ishandled: Boolean; var Rec: record "Purchase Header"; xRec: record "Purchase Header")
begin
end;
Changes between **:
trigger OnValidate()
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeValidatePayToVendorNo(Rec, xRec, Confirmed, IsHandled);
if IsHandled then
exit;
TestStatusOpen();
if (xRec."Pay-to Vendor No." <> "Pay-to Vendor No.") and
(xRec."Pay-to Vendor No." <> '')
then
if ConfirmUpdateField(FieldNo("Pay-to Vendor No.")) then begin
OnValidatePayToVendorNoOnAfterConfirmed(Rec);
PurchLine.SetRange("Document Type", "Document Type");
PurchLine.SetRange("Document No.", "No.");
CheckReceiptInfo(PurchLine, true);
CheckPrepmtInfo(PurchLine);
CheckReturnInfo(PurchLine, true);
PurchLine.Reset();
end else
"Pay-to Vendor No." := xRec."Pay-to Vendor No.";
OnValidatePayToVendorNoOnBeforeGetPayToVend(Rec);
GetVend("Pay-to Vendor No.");
CheckBlockedVendOnDocs(Vend);
Vend.TestField("Vendor Posting Group");
PostingSetupMgt.CheckVendPostingGroupPayablesAccount("Vendor Posting Group");
OnAfterCheckPayToVendor(Rec, xRec, Vend);
"Pay-to Name" := Vend.Name;
"Pay-to Name 2" := Vend."Name 2";
CopyPayToVendorAddressFieldsFromVendor(Vend, false);
"Individual Person" := Vend."Individual Person";
Resident := Vend.Resident;
"First Name" := Vend."First Name";
"Last Name" := Vend."Last Name";
"Date of Birth" := Vend."Date of Birth";
"Birth City" := Vend."Birth City";
"Tax Representative Type" := Vend."Tax Representative Type";
"Tax Representative No." := Vend."Tax Representative No.";
"VAT Country/Region Code" := Vend."Country/Region Code";
if not SkipPayToContact then
"Pay-to Contact" := Vend.Contact;
"Payment Terms Code" := Vend."Payment Terms Code";
"Prepmt. Payment Terms Code" := Vend."Prepmt. Payment Terms Code";
"Payment Method Code" := Vend."Payment Method Code";
"Price Calculation Method" := Vend.GetPriceCalculationMethod();
if "Buy-from Vendor No." = Vend."No." then
Validate("Shipment Method Code", Vend."Shipment Method Code");
"Vendor Posting Group" := Vend."Vendor Posting Group";
OnAfterCopyPayToVendorFieldsFromVendor(Rec, Vend, xRec);
GLSetup.Get();
if GLSetup."Bill-to/Sell-to VAT Calc." = GLSetup."Bill-to/Sell-to VAT Calc."::"Bill-to/Pay-to No." then begin
"VAT Bus. Posting Group" := Vend."VAT Bus. Posting Group";
"VAT Country/Region Code" := Vend."Country/Region Code";
AssignVATRegistrationNo("Pay-to Vendor No.");
"Gen. Bus. Posting Group" := Vend."Gen. Bus. Posting Group";
end;
if not CheckVATExemption() then
FieldError("Pay-to Vendor No.");
"Prices Including VAT" := Vend."Prices Including VAT";
"Currency Code" := Vend."Currency Code";
"Invoice Disc. Code" := Vend."Invoice Disc. Code";
"Language Code" := Vend."Language Code";
"Format Region" := Vend."Format Region";
SetPurchaserCode(Vend."Purchaser Code", "Purchaser Code");
Validate("Payment Terms Code");
Validate("Payment Method Code");
Validate("Currency Code");
Validate("Creditor No.", Vend."Creditor No.");
OnValidatePurchaseHeaderPayToVendorNoOnBeforeCheckDocType(Vend, Rec, xRec, SkipPayToContact);
if "Document Type" = "Document Type"::Order then
Validate("Prepayment %", Vend."Prepayment %");
if "Pay-to Vendor No." = xRec."Pay-to Vendor No." then
if ReceivedPurchLinesExist() then
TestField("Currency Code", xRec."Currency Code");
CreateDimensionsFromValidatePayToVendorNo();
OnValidatePaytoVendorNoBeforeRecreateLines(Rec, CurrFieldNo);
if (xRec."Buy-from Vendor No." = "Buy-from Vendor No.") and
(xRec."Pay-to Vendor No." <> "Pay-to Vendor No.")
then begin
**ishandled := false;
OnBeforeRecreatePurchLines(Ishandled, Rec, xRec);
if not ishandled then**
RecreatePurchLines(PayToVendorTxt);
end;
if not SkipPayToContact then
UpdatePayToCont("Pay-to Vendor No.");
"Pay-to IC Partner Code" := Vend."IC Partner Code";
OnValidatePayToVendorNoOnBeforeRecallModifyAddressNotification(Rec, xRec, Vend);
if (xRec."Pay-to Vendor No." <> '') and (xRec."Pay-to Vendor No." <> "Pay-to Vendor No.") then
Rec.RecallModifyAddressNotification(GetModifyPayToVendorAddressNotificationId());
end;
Alternatives evaluated
The following existing extensibility points were evaluated:
OnBeforeValidatePayToVendorNo
OnValidatePayToVendorNoOnAfterConfirmed
OnAfterCopyPayToVendorFieldsFromVendor
OnValidatePurchaseHeaderPayToVendorNoOnBeforeCheckDocType
OnValidatePaytoVendorNoBeforeRecreateLines
OnValidatePayToVendorNoOnBeforeRecallModifyAddressNotification
None of these events allow partners to conditionally replace or bypass the call to:
RecreatePurchLines(PayToVendorTxt);
The existing OnValidatePaytoVendorNoBeforeRecreateLines event is raised immediately before the call, but it does not provide an IsHandled parameter and therefore cannot prevent the execution of RecreatePurchLines().
The only alternative would be duplicating the entire "Pay-to Vendor No." validation logic, which is difficult to maintain and introduces upgrade risks.
Justification for IsHandled
The business requirement is to execute a custom line recreation process only under specific conditions.
For example, some custom purchase lines contain additional information that must be preserved when the Pay-to Vendor changes. In these scenarios, executing the standard:
RecreatePurchLines(PayToVendorTxt);
would remove or recreate lines in a way that is not compatible with the custom business process.
The extension therefore needs to:
- Evaluate a custom condition.
- Skip the standard
RecreatePurchLines() call when that condition is satisfied.
- Execute an alternative recreation procedure that preserves the custom information.
A regular integration event is insufficient because the standard RecreatePurchLines() would still execute afterwards and overwrite the custom processing.
Therefore, an IsHandled event is required.
Performance considerations
The proposed event is executed only when:
- field
"Pay-to Vendor No." is validated;
- the Pay-to Vendor has changed;
- the Buy-from Vendor has not changed.
This is a relatively infrequent operation, typically performed by a user while editing purchase documents.
The proposed change introduces only:
OnBeforeRecreatePurchLines(IsHandled, Rec, xRec);
and a Boolean check. No additional database operations are introduced by the platform change itself.
Therefore, the performance impact is negligible.
Data sensitivity review
The event exposes only:
var Rec: Record "Purchase Header"
xRec: Record "Purchase Header"
var IsHandled: Boolean
These records are already available through other events in the purchase document process and do not expose any new categories of information.
No personally identifiable information, credentials, secrets, or sensitive business data are introduced by this change.
Therefore, the requested event does not introduce any security or data exposure concerns.
Multi-extension interaction
As with any IsHandled event, multiple extensions could subscribe and set IsHandled := true, causing the standard RecreatePurchLines() logic to be skipped.
Potential conflicts include:
- one extension replacing the recreation logic while another extension expects the standard behavior;
- multiple extensions implementing different recreation strategies.
This risk is considered acceptable because:
- the event is narrowly scoped and affects only the recreation of purchase lines after a Pay-to Vendor change;
- extensions should set
IsHandled := true only when intentionally replacing the standard recreation process;
- without this event, partners are forced to duplicate the entire
"Pay-to Vendor No." validation trigger, resulting in significantly higher maintenance and upgrade risks.
An extensibility point already exists at the required location, but it cannot influence the subsequent call to RecreatePurchLines(). Adding an IsHandled event is therefore a minimal and low-risk change that completes the existing extensibility model.
We evaluated the existing event:
OnBeforeRecreatePurchLinesHandler(
var PurchHeader;
xPurchHeader;
ChangedFieldName;
var IsHandled)
and the possibility of checking:
if ChangedFieldName = PayToVendorTxt then
IsHandled := true;
This approach is not sufficient for our scenario.
The existing event is raised at the beginning of RecreatePurchLines(), after the OnValidate trigger has already decided to invoke the recreation process. Our requirement is to make the decision in the context of the "Pay-to Vendor No." validation itself, based on information available during that specific validation flow and before entering RecreatePurchLines().
In our scenario, the custom logic is specific to a Pay-to Vendor change and needs to either:
- execute the standard RecreatePurchLines() call, or
- execute an alternative recreation process that is dedicated to the "Pay-to Vendor No." validation.
Using the generic OnBeforeRecreatePurchLinesHandler event would affect all callers of RecreatePurchLines() that pass ChangedFieldName = PayToVendorTxt and would move the customization into a generic recreation hook rather than the specific validation point where the business decision belongs.
The proposed event is therefore intended to provide an extensibility point at the caller level, inside the "Pay-to Vendor No." validation flow, instead of inside RecreatePurchLines() itself.
xRec justification
The subscriber requires access to xRec because the decision to replace the standard RecreatePurchLines() logic depends on comparing the document state before and after the validation of "Pay-to Vendor No.".
Rec alone contains only the current values after validation and is therefore insufficient to determine whether the custom recreation logic should be executed.
Typical custom scenarios require comparing previous and current values, for example:
detecting whether additional header fields changed together with the Pay-to Vendor;
executing the custom recreation logic only when the document transitions from one specific state to another;
preserving custom purchase line information only for particular changes between the previous and current document state.
Without xRec, subscribers would have to re-read the document from the database or maintain their own copy of the previous values, which is unnecessary because the original values are already available in the validation context.
Using both Rec and xRec is also consistent with the extensibility model used throughout Business Central validation events, where subscribers commonly receive both the current and previous record to make context-aware decisions.
Confirmation of full replacement for skipped standard logic
Yes. When our extension sets IsHandled := true, it intentionally takes full ownership of the purchase line recreation process for the specific custom scenario.
Our custom implementation does not simply skip RecreatePurchLines(). Instead, it executes an alternative recreation process that reproduces all the standard functional outcomes required for the affected document, while preserving additional custom information that would otherwise be lost by the standard implementation.
Specifically, our alternative process performs the equivalent document update activities normally carried out through RecreatePurchLines(), including:
updating the purchase document where required by the Pay-to Vendor change;
recreating the purchase lines according to the new header values;
preserving or restoring purchase comment lines as appropriate;
preserving or recreating item charge assignments when applicable;
maintaining any other standard business effects that are relevant for the customized scenario.
The only intentional difference from the standard implementation is that our recreation process also preserves custom data stored on purchase lines and applies additional business rules that cannot be implemented by extending the existing RecreatePurchLines() logic.
The event is therefore not intended to partially bypass the standard process. When IsHandled := true, the extension completely replaces the standard RecreatePurchLines() execution with an equivalent implementation that maintains the expected document consistency while introducing the required custom behavior.
This replacement occurs only under specific business conditions determined by the extension. In all other scenarios, the standard RecreatePurchLines() implementation continues to execute unchanged.
Internal work item: AB#641640
Why do you need this change?
We need an event inside the trigger OnValidate of field "Pay-to Vendor No.", to be able to run the procedure RecreatePurchLines if a custom if statement is satisfied or, alternatively, run a custom procedure.
To manage an IsHandled variable is the only way to skip RecreatePurchLines (if a particular custom condition is satisfied) and run a custom procedure instead. At the moment there are no other ways to do that.
Describe the request
In trigger OnValidate of field(4; "Pay-to Vendor No."; Code[20]) of table 38 "Purchase Header" we need an event:
Changes between **:
Alternatives evaluated
The following existing extensibility points were evaluated:
OnBeforeValidatePayToVendorNoOnValidatePayToVendorNoOnAfterConfirmedOnAfterCopyPayToVendorFieldsFromVendorOnValidatePurchaseHeaderPayToVendorNoOnBeforeCheckDocTypeOnValidatePaytoVendorNoBeforeRecreateLinesOnValidatePayToVendorNoOnBeforeRecallModifyAddressNotificationNone of these events allow partners to conditionally replace or bypass the call to:
The existing
OnValidatePaytoVendorNoBeforeRecreateLinesevent is raised immediately before the call, but it does not provide anIsHandledparameter and therefore cannot prevent the execution ofRecreatePurchLines().The only alternative would be duplicating the entire
"Pay-to Vendor No."validation logic, which is difficult to maintain and introduces upgrade risks.Justification for IsHandled
The business requirement is to execute a custom line recreation process only under specific conditions.
For example, some custom purchase lines contain additional information that must be preserved when the Pay-to Vendor changes. In these scenarios, executing the standard:
would remove or recreate lines in a way that is not compatible with the custom business process.
The extension therefore needs to:
RecreatePurchLines()call when that condition is satisfied.A regular integration event is insufficient because the standard
RecreatePurchLines()would still execute afterwards and overwrite the custom processing.Therefore, an
IsHandledevent is required.Performance considerations
The proposed event is executed only when:
"Pay-to Vendor No."is validated;This is a relatively infrequent operation, typically performed by a user while editing purchase documents.
The proposed change introduces only:
and a Boolean check. No additional database operations are introduced by the platform change itself.
Therefore, the performance impact is negligible.
Data sensitivity review
The event exposes only:
var Rec: Record "Purchase Header"xRec: Record "Purchase Header"var IsHandled: BooleanThese records are already available through other events in the purchase document process and do not expose any new categories of information.
No personally identifiable information, credentials, secrets, or sensitive business data are introduced by this change.
Therefore, the requested event does not introduce any security or data exposure concerns.
Multi-extension interaction
As with any
IsHandledevent, multiple extensions could subscribe and setIsHandled := true, causing the standardRecreatePurchLines()logic to be skipped.Potential conflicts include:
This risk is considered acceptable because:
IsHandled := trueonly when intentionally replacing the standard recreation process;"Pay-to Vendor No."validation trigger, resulting in significantly higher maintenance and upgrade risks.An extensibility point already exists at the required location, but it cannot influence the subsequent call to RecreatePurchLines(). Adding an IsHandled event is therefore a minimal and low-risk change that completes the existing extensibility model.
We evaluated the existing event:
OnBeforeRecreatePurchLinesHandler(
var PurchHeader;
xPurchHeader;
ChangedFieldName;
var IsHandled)
and the possibility of checking:
if ChangedFieldName = PayToVendorTxt then
IsHandled := true;
This approach is not sufficient for our scenario.
The existing event is raised at the beginning of RecreatePurchLines(), after the OnValidate trigger has already decided to invoke the recreation process. Our requirement is to make the decision in the context of the "Pay-to Vendor No." validation itself, based on information available during that specific validation flow and before entering RecreatePurchLines().
In our scenario, the custom logic is specific to a Pay-to Vendor change and needs to either:
Using the generic OnBeforeRecreatePurchLinesHandler event would affect all callers of RecreatePurchLines() that pass ChangedFieldName = PayToVendorTxt and would move the customization into a generic recreation hook rather than the specific validation point where the business decision belongs.
The proposed event is therefore intended to provide an extensibility point at the caller level, inside the "Pay-to Vendor No." validation flow, instead of inside RecreatePurchLines() itself.
xRec justification
The subscriber requires access to xRec because the decision to replace the standard RecreatePurchLines() logic depends on comparing the document state before and after the validation of "Pay-to Vendor No.".
Rec alone contains only the current values after validation and is therefore insufficient to determine whether the custom recreation logic should be executed.
Typical custom scenarios require comparing previous and current values, for example:
detecting whether additional header fields changed together with the Pay-to Vendor;
executing the custom recreation logic only when the document transitions from one specific state to another;
preserving custom purchase line information only for particular changes between the previous and current document state.
Without xRec, subscribers would have to re-read the document from the database or maintain their own copy of the previous values, which is unnecessary because the original values are already available in the validation context.
Using both Rec and xRec is also consistent with the extensibility model used throughout Business Central validation events, where subscribers commonly receive both the current and previous record to make context-aware decisions.
Confirmation of full replacement for skipped standard logic
Yes. When our extension sets IsHandled := true, it intentionally takes full ownership of the purchase line recreation process for the specific custom scenario.
Our custom implementation does not simply skip RecreatePurchLines(). Instead, it executes an alternative recreation process that reproduces all the standard functional outcomes required for the affected document, while preserving additional custom information that would otherwise be lost by the standard implementation.
Specifically, our alternative process performs the equivalent document update activities normally carried out through RecreatePurchLines(), including:
updating the purchase document where required by the Pay-to Vendor change;
recreating the purchase lines according to the new header values;
preserving or restoring purchase comment lines as appropriate;
preserving or recreating item charge assignments when applicable;
maintaining any other standard business effects that are relevant for the customized scenario.
The only intentional difference from the standard implementation is that our recreation process also preserves custom data stored on purchase lines and applies additional business rules that cannot be implemented by extending the existing RecreatePurchLines() logic.
The event is therefore not intended to partially bypass the standard process. When IsHandled := true, the extension completely replaces the standard RecreatePurchLines() execution with an equivalent implementation that maintains the expected document consistency while introducing the required custom behavior.
This replacement occurs only under specific business conditions determined by the extension. In all other scenarios, the standard RecreatePurchLines() implementation continues to execute unchanged.
Internal work item: AB#641640