Skip to content

[Event Request] Page 35516 "Cash Receipt Journal FactBox" #30078

@meadowGarden

Description

@meadowGarden

Why do you need this change?

Target Layer: DACH ΓÇö Layers/DACH/BaseApp/Local/Finance/GeneralLedger/Journal/CashReceiptJournalFactBox.Page.al

1. event subscriber before Accepted Payment Tolerance
Event Placement in the procedure UpdateInfoBox:
Insert immediately after the payment discount deduction amount is calculated and rounded, within the repeat loop that processes customer ledger entries:

CurrPaymDiscDeductAmount := Round(CurrPaymDiscDeductAmount, Currency."Amount Rounding Precision");

// place of the new event
OnUpdateInfoBoxOnAfterCalcCurrPaymDiscDeductAmount(Rec, CustLedgEntry, PaymDiscDeductAmount, CurrPaymDiscDeductAmount);

// Accepted Payment Tolerance
CurrAcceptedPaymentTol := CustLedgEntry."Accepted Payment Tolerance";

Business Justification:
In scenarios where payment discounts are managed through external add-ons (e.g., extended application functionality), the calculated payment discount deduction may need to be overridden based on custom fields that track applied entries and pre-calculated discount amounts.

Our add-on stores the actual posting payment discount in one custom field and tracks the applied entry relationship via another. When an entry has been pre-applied with a specific discount amount, we need to override the standard calculation with this pre-determined value to ensure accurate payment processing and customer balance calculations.

Without this event, extensions cannot adjust the payment discount deduction amount after it's been calculated, leading to incorrect "Remaining after Payment" displays in the FactBox, which impacts user decision-making during payment entry.

The event must fire per-iteration because CurrPaymDiscDeductAmount is recalculated from the current CustLedgerEntry on each iteration. An extension override must happen after this per-entry calculation but before CurrRemainAfterPayment is derived from it on the same iteration:
CurrRemainAfterPayment := -CurrOeRemainAmountFC + CurrPaymDiscDeductAmount + CurrAcceptedPaymentTol;

A post-loop hook would only expose the final iteration's CurrPaymDiscDeductAmount - it could not correctly influence CurrRemainAfterPayment for each individual entry in multi-entry application scenarios (where "Applies-to ID" produces multiple entries). The per-iteration placement is therefore not a design choice - it is required by the data flow.

Alternatives Evaluated:
OnUpdateInfoBoxOnAfterSetCustLedgEntryFilters with IsHandled: This event exists and allows exiting the entire UpdateInfoBox procedure, but we need to process customer ledger entriesΓÇöwe only need to override one specific calculation. Setting IsHandled := true would prevent all FactBox calculations from running.

Custom FactBox page: Creating a separate custom FactBox would duplicate significant standard functionality and create maintenance burden. Users expect standard pages to work with extensions.

Performance Considerations:
The UpdateInfoBox procedure is triggered on OnAfterGetRecord for each journal line when the user navigates through the Cash Receipt Journal. This event fires within the repeat loop that processes applied customer ledger entries. The event itself performs no calculationsΓÇöit simply provides an extension point to override a decimal variable. Performance impact is negligible.

Data Sensitivity Review:
The event exposes:

  • Gen. Journal Line (already displayed on the page source)
  • Cust. Ledger Entry (already filtered and processed in the procedure)
  • Payment discount amounts (already displayed in FactBox fields)

All exposed data is already accessible within the page context and displayed to users with appropriate permissions. No additional sensitive information is exposed.

Multi-Extension Interaction:
This event does not use IsHandled. Multiple extensions can subscribe to modify the payment discount amounts. Extensions execute in dependency order. If multiple extensions modify CurrPaymDiscDeductAmount, the last extension in the execution order takes precedence. This is acceptable as extensions managing payment discounts would typically declare dependencies to ensure proper execution order, or coordinate via custom fields to avoid conflicts.


2. event subscriber before current remaining after payment assessment
Event Placement in the procedure UpdateInfoBox:
Insert immediately before the check that adjusts RemainAfterPayment when it's positive, within the REPEAT loop that processes customer ledger entries:

CurrRemainAfterPayment := -CurrOeRemainAmountFC + CurrPaymDiscDeductAmount + CurrAcceptedPaymentTol;

if (Rec."Currency Code" <> CustLedgEntry."Currency Code") and
   ((Rec."Currency Code" <> '') and (CustLedgEntry."Currency Code" <> ''))
then begin
    RemainAfterPaymentCaption := '';
    RemainAfterPaymentText := '';
    exit;
end;

// place of the new event
IsHandled := false;
OnUpdateInfoBoxOnBeforeCheckRemainAfterPayment(Rec, CustLedgEntry, CurrRemainAfterPayment, CurrPaymDiscDeductAmount, IsHandled);

if not IsHandled then begin
    // Pmt. Disc is not applied if entry is not closed
    if CurrRemainAfterPayment > 0 then begin
        CurrRemainAfterPayment := CurrRemainAfterPayment - CurrPaymDiscDeductAmount;
        RemainAfterPaymentText := Format(CurrRemainAfterPayment, 0, Text002);
        CurrPaymDiscDeductAmount := 0;
    end;
end;
OeRemainAmountFC += CurrOeRemainAmountFC;

Business Justification:
When payments are applied to multiple ledger entries simultaneously via "Applies-to ID", the loop processes each entry independently. The decision to skip the standard "Pmt. Disc is not applied if entry is not closed" block may differ per entry ΓÇö it can depend on the current CustLedgerEntry's state (remaining amount, discount date, tolerance flags) combined with the journal line context.

A pre-loop boolean flag (set once before the loop) would force the same decision for all entries, which is incorrect in partial application scenarios where some entries should follow standard logic and others should not. The IsHandled flag must therefore be evaluated per-iteration, with CustLedgerEntry passed as a parameter so extensions can make entry-specific decisions.

Without this event, there is no way for an extension to conditionally bypass this block per-entry without rewriting the entire loop via OnUpdateInfoBoxOnAfterSetCustLedgEntryFilters with IsHandled := true, which would require duplicating all standard customer loop logic.

Alternatives Evaluated:
OnUpdateInfoBoxOnAfterSetCustLedgEntryFilters with IsHandled: Would exit the entire procedure, preventing all FactBox calculations. We need all calculations except this one specific adjustment.

Modifying CurrPaymDiscDeductAmount to 0: Could theoretically prevent the addition by zeroing the discount amount, but this would corrupt the accumulated PaymDiscDeductAmount variable that displays in the FactBox "Deduction" field. The display would be incorrect.

Performance Considerations:
This event fires within the repeat loop that processes applied customer ledger entries, triggered on OnAfterGetRecord as users navigate journal lines. The event provides a simple boolean check extension point with no computational overhead. The standard check IF CurrRemainAfterPayment > 0 executes in nanoseconds. Performance impact is negligible.

Data Sensitivity Review:
The event exposes:

  • Gen. Journal Line (page source data)
  • Cust. Ledger Entry (already filtered and processed)
  • Calculated decimal values for remaining amounts and payment discounts

All data is already accessible in the page context and displayed to users with appropriate permissions. No sensitive information is additionally exposed.

Multi-Extension Interaction:
This event uses IsHandled, so coordination is required. Only one extension should set IsHandled := true for a given customer ledger entry to skip the standard logic. Extensions managing payment application workflows should declare dependencies to ensure proper execution order. If multiple extensions need to influence this logic, they must coordinate via custom field checks or dependency declarations. This follows standard Business Central patterns for IsHandled events.


3. event subscriber at the end of the procedure
Event Placement in the procedure UpdateInfoBox:
Insert at the end of the UpdateInfoBox procedure, after the repeat loop that processes customer ledger entries completes

        RemainAfterPayment += CurrRemainAfterPayment;
        RemainAfterPaymentText := Format(RemainAfterPayment, 0, Text002);
    until CustLedgEntry.Next() = 0;
    // place of the new event
    OnAfterUpdateInfoBox(
         Rec, 
         OeRemainAmountFC, 
         PMTDiscount, 
         PaymDiscDeductAmount, 
         AcceptedPaymentTol, 
         RemainAfterPayment, 
         RemainAfterPaymentText, 
         RemainAfterPaymentCaption, 
         PostingDate, 
         DueDate, 
         PmtDiscDate, 
         AgeDays, 
         PaymDiscDays, 
         DueDays);
end;

Business Justification:
Extensions that add custom account types beyond Customer need to perform equivalent payment information calculations for these additional account types and accumulate the results into the same FactBox display fields.
Our add-on extends the Cash Receipt Journal FactBox to support applying payments to Vendors through a custom field. When this field is set to Vendor, we need to:

  • Filter Vendor Ledger Entries based on "Applies-to ID" or "Applies-to Doc. No."
  • Calculate remaining amounts, payment discounts, age/due days for vendors
  • Accumulate these values into the same display variables used for customers
  • Display vendor payment terms and dates in the FactBox

The existing OnUpdateInfoBoxOnAfterSetCustLedgEntryFilters event allows exiting early when the account type is not Customer (via IsHandled := true), but there's no event that allows extensions to add processing after customer processing completes. We need an event after the standard customer logic executes where we can add our own vendor processing loop.

Without this event, extensions cannot display payment application information for custom account types in the standard FactBox, forcing either:

  • Duplication of the entire page as a custom FactBox (maintenance burden)
  • Loss of payment application visibility for extended scenarios (poor user experience)

Alternatives Evaluated:
OnUpdateInfoBoxOnAfterSetCustLedgEntryFilters with IsHandled: This event fires before customer processing. Setting IsHandled := true skips all standard logic, requiring complete duplication of both customer and custom account type processing. This is inefficient and error-prone.

Custom FactBox page: Creating a separate FactBox for extended account types would fragment the user experience and require maintaining duplicate code for all standard customer calculations. Users expect one cohesive FactBox.

Page extension with field modifications: Page extensions can add fields but cannot inject processing logic into the middle of existing procedures. We need a code injection point.

Separate "Vendor Receipt Journal FactBox": Would require users to use different pages/templates for different account types, which breaks the unified payment entry workflow our add-on provides.

Performance Considerations:
The UpdateInfoBox procedure executes on OnAfterGetRecord as users navigate through journal lines. This event fires once per line after all customer ledger processing completes. Extensions subscribing to this event would typically perform one additional loop through vendor ledger entries (if applicable), which involves:

  • Filtering vendor ledger entries (database read with filter)
  • Updating local decimal variables

This is equivalent in computational cost to the standard customer processing that just completed. Performance impact is proportional to the complexity of extension logic, but for typical payment application scenarios, the overhead is negligible and comparable to standard processing time.

Data Sensitivity Review:
The event exposes:

  • Gen. Journal Line (page source data, already visible)
  • Calculated aggregates: amounts, discounts, tolerances, dates, day counters
  • Display strings for the FactBox fields

All parameters represent calculated display values already shown in the FactBox fields. No raw ledger entry data or sensitive details are exposed beyond what users with Cash Receipt Journal permissions already access. The GenJournalLine record provides context for extensions to fetch related records (Vendor Ledger Entries, etc.) using the same security context as the standard page.

Multi-Extension Interaction:
This event does not use IsHandled. Multiple extensions can subscribe to perform additional calculations and modify the display variables. Extensions execute in dependency order. Since all parameters are passed as VAR, the last extension to modify a value takes precedence.

Extensions adding different account type support (e.g., one extension adds Vendor support, another adds Bank Account support) can coordinate by checking custom fields on GenJournalLine to ensure they only process their specific scenarios without conflicting.

Describe the request

OnUpdateInfoBoxOnAfterCalcCurrPaymDiscDeductAmount(
var GenJournalLine: Record "Gen. Journal Line";
var CustLedgerEntry: Record "Cust. Ledger Entry";
var PaymDiscDeductAmount: Decimal;
var CurrPaymDiscDeductAmount: Decimal)
OnUpdateInfoBoxOnBeforeCheckRemainAfterPayment(
var GenJournalLine: Record "Gen. Journal Line";
var CustLedgerEntry: Record "Cust. Ledger Entry";
var CurrRemainAfterPayment: Decimal;
var CurrPaymDiscDeductAmount: Decimal;
var IsHandled: Boolean)
OnAfterUpdateInfoBox(
var GenJournalLine: Record "Gen. Journal Line";
var OeRemainAmountFC: Decimal;
var PMTDiscount: Decimal;
var PaymDiscDeductAmount: Decimal;
var AcceptedPaymentTol: Decimal;
var RemainAfterPayment: Decimal;
var RemainAfterPaymentText: Text[30];
var RemainAfterPaymentCaption: Text[30];
var PostingDate: Date;
var DueDate: Date;
var PmtDiscDate: Date;
var AgeDays: Integer;
var PaymDiscDays: Integer;
var DueDays: Integer)

Internal work item: AB#635599

Metadata

Metadata

Assignees

No one assigned

    Labels

    FinanceGitHub request for Finance areaevent-requestRequest for adding an event

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions