Skip to content

Extract NL customization to object extensions (TrMode)#8933

Open
Alexander-Ya wants to merge 31 commits into
mainfrom
bugs/Extract-NL-customization-to-object-extensions-v2
Open

Extract NL customization to object extensions (TrMode)#8933
Alexander-Ya wants to merge 31 commits into
mainfrom
bugs/Extract-NL-customization-to-object-extensions-v2

Conversation

@Alexander-Ya

@Alexander-Ya Alexander-Ya commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What & why

Linked work

Fixes AB#640601

How I validated this

  • I read the full diff and it contains only changes I intended.
  • I built the affected app(s) locally with no new analyzer warnings.
  • I ran the change in Business Central and confirmed it behaves as expected.
  • I added or updated tests for the new behavior, or explained below why none are needed.

What I tested and the outcome (required — be specific: scenarios, commands, screenshots for UI changes)

Risk & compatibility

@Alexander-Ya
Alexander-Ya requested review from a team June 30, 2026 13:39
@Alexander-Ya

Copy link
Copy Markdown
Contributor Author

Fixes AB#640601

Comment thread src/Layers/NL/BaseApp/Local/Purchases/Vendor/VendorNL.TableExt.al
Comment thread src/Layers/NL/BaseApp/Local/Purchases/Vendor/VendorNL.TableExt.al
Comment thread src/Layers/NL/BaseApp/Local/Sales/Customer/CustomerNL.TableExt.al
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Copilot PR Review

Iteration 17 · Outcome: completed

Knowledge source: https://github.com/microsoft/BCQuality@186d8a131465475c79244d994acb872cd5c0d4bf

Findings by domain

Findings split into Knowledge-backed (cite a BCQuality article) and Agent (the agent's own judgement, no matching BCQuality rule).

Domain Findings Knowledge-backed Agent Inline Fallback
Accessibility 1 1 0 0 0
Breaking Changes 2 2 0 2 0

Totals: 3 knowledge-backed · 0 agent findings.

Orchestrator pre-filter (2 file(s) excluded)

  • layer-disabled (knowledge) : 2 file(s)

Findings produced by the AL review agent v1.7.3. Reply 👎 on any inline comment to flag false positives.

JesperSchulz pushed a commit that referenced this pull request Jun 30, 2026
The model-reported anchor for a single-line suggestion can be off by more
than 8 lines (e.g. PR #8933 VendorNL Confirm() was off by 10, label rename
off by 9). Widen the search window to 40 lines either side so the correct
target within the same procedure is considered, while the 0.5 similarity
floor and 0.1 ambiguity margin keep an unrelated look-alike from winning.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
JesperSchulz pushed a commit that referenced this pull request Jun 30, 2026
Widening the search window exposed a precision problem: a label-rename
suggestion whose added Comment text echoes the field captions at the
Error()/Confirm() call site would re-anchor onto the call site (PR #8933
GenJournalLineNL/GeneralLedgerSetupNL 'Text1000000/1' findings), which is
worse than the original mis-anchor.

Raise the similarity floor to 0.6 and use a bounded window (20). Genuine
edit targets - an edited statement or a renamed declaration - score
~0.75-0.99 and re-anchor confidently (the PR #8933 Confirm() findings and
the PartnerTypeMismatchMsg->Qst rename now land on the right line). Lower-
confidence look-alikes stay below the floor and are suppressed, so the
caller posts a manual snippet instead of a wrong auto-applicable anchor.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment was marked as resolved.

Comment thread src/Layers/NL/BaseApp/Local/Sales/Customer/CustomerNL.TableExt.al
Comment thread src/Layers/NL/BaseApp/Local/Sales/Customer/CustomerNL.TableExt.al
@github-actions github-actions Bot added this to the Version 29.0 milestone Jul 1, 2026
Access = Internal;

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Sales-Post Prepayments", 'OnBeforePostCustomerEntry', '', false, false)]
local procedure OnBeforePostCustomerEntry(var GenJnlLine: Record "Gen. Journal Line"; SalesHeader: Record "Sales Header")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🔴\ Critical\ Severity\ —\ Style} \quad \color{gray}{\texttt{\small Iteration\ 16}}$

The new EventSubscriber OnBeforePostCustomerEntry on Codeunit::"Sales-Post Prepayments" is declared with only two parameters, `(var GenJnlLine: Record "Gen.

Journal Line"; SalesHeader: Record "Sales Header"), but the publisher (SalesPostPrepayments.Codeunit.al line 2431) declares six parameters: (var GenJnlLine: Record "Gen. Journal Line"; TotalPrepmtInvLineBuffer: Record "Prepayment Inv. Line Buffer"; TotalPrepmtInvLineBufferLCY: Record "Prepayment Inv. Line Buffer"; CommitIsSuppressed: Boolean; SalesHeader: Record "Sales Header"; DocumentType: Option Invoice,"Credit Memo")`. A subscriber cannot cherry-pick a subset of the publisher's parameters; the full parameter list, in order, must be reproduced. As written this subscriber will not bind to the publisher and the extracted NL Transaction Mode Code/Bank Account Code logic that used to run inline in the old NL override of Sales-Post Prepayments will silently stop firing.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

@@ -7581,7 +7582,7 @@ table 36 "Sales Header"
if ReplaceVATDate then
"VAT Reporting Date" := VATDateReq;

if ReplaceDocDate and ("Document Date" <> PostingDateReq) then begin
if ReplacePostingDate and ReplaceDocDate and ("Document Date" <> PostingDateReq) then begin

This comment was marked as off-topic.

…Extract-NL-customization-to-object-extensions-v2
}
}

procedure UpdateElecTaxDeclCategoryCode()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Breaking\ Changes} \quad \color{gray}{\texttt{\small Iteration\ 17}}$

VATStatementLineNL.TableExt widens UpdateElecTaxDeclCategoryCode from a local procedure in the original full-object NL override to a public tableextension procedure, but it is only invoked from the companion VATStatementLineNL.Codeunit.al within the same app.

Publishing it needlessly turns an internal helper into an external contract that must now be preserved across future refactors.

Suggested change
procedure UpdateElecTaxDeclCategoryCode()
internal procedure UpdateElecTaxDeclCategoryCode()

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

UpdateBankAccountsQst: Label 'Do you want to update the bank accounts for this customer to reflect the new value of %1?', Comment = '%1 = Field Caption';
PartnerTypeMismatchQst: Label 'The Partner Type does not match the Partner Type defined in Transaction Mode. Do you still want to change the Partner Type?';

[Scope('OnPrem')]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Breaking\ Changes} \quad \color{gray}{\texttt{\small Iteration\ 17}}$

CustomerNL.TableExt widens UpdateCustomerBankAccounts from a local procedure in the original full-object NL override to a published, non-local procedure marked only with [Scope('OnPrem')], even though every call site remains inside the same tableextension.

That turns an implementation detail into a supported API surface for no functional reason, freezing a contract that was never meant to be external.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

    [Scope('OnPrem')]
    local procedure UpdateCustomerBankAccounts(UseFieldCaption: Text[250])

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

{
addafter("Industrial Classification")
{
field("Fiscal Entity No."; Rec."Fiscal Entity No.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ AppSource}$

The new namespaced NL layer repeatedly adds unaffixed members to standard objects, for example field(11400; "Cash Journal"; ...) in src/Layers/NL/BaseApp/Local/Foundation/AuditCodes/SourceCodeSetupNL.TableExt.al:14, field("Fiscal Entity No."; ...) in src/Layers/NL/BaseApp/Local/Foundation/Company/CompanyInformationNL.PageExt.al:13, and action("Post Code Updates") in src/Layers/NL/BaseApp/Local/RoleCenters/AdministratorMainRCNL.PageExt.al:15. A two-level namespace only replaces the owned object affix; fields, controls, and actions added to base objects still need the registered member affix.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.12.4

@github-actions

Copy link
Copy Markdown
Contributor

$\textbf{🟡\ Medium\ Severity\ —\ Breaking\ Changes}$

The public IntegrationEvent OnBeforeUpdateVendorBankAccounts, moved from the base Vendor codeunit into the new VendorNL.TableExt.al, changed signature from (var IsHandled: Boolean; var VendorBankAccount: Record "Vendor Bank Account") to (var Vendor: Record Vendor; var IsHandled: Boolean; var VendorBankAccount: Record "Vendor Bank Account"). Any existing subscriber compiled against the old signature will fail to bind. Restore the original event signature and introduce a separate event if subscribers also need the Vendor record. Note: the underlying impact is a real breaking change to a public extensibility point, but this is emitted as an advisory agent finding capped at minor severity because no loaded knowledge file currently covers event-publisher signature changes directly — it should be promoted to a knowledge-backed rule.

Line mapping was unavailable, so this was posted as an issue comment.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.12.4

end;
}
field(11000002; "Currency Euro"; Code[10])
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ Error\ Handling}$

The Currency Euro OnValidate path dead-ends with a plain Error even though the code already knows the immediate

Recommendation:

  • when Local Currency is Euro, Currency Euro must be cleared. Raise an ErrorInfo with a Fix-it action so the user can apply the correction in one step instead of dismissing a blocking dialog.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.12.4

}

var
TransactionModeAccountTypeErrorQst: Label '%1 can only be filled in when %2 %3 is equal to Customer or Vendor.', Comment = '%1 - Field Caption of the field causing the error, %2 - Field Caption of the Account Type field, %3 - Field Caption of the Bal. Account Type field';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Error\ Handling}$

The validation error text on GenJournalLineNL.TableExt.al says Transaction Mode Code is allowed only for Customer or Vendor, but the surrounding TableRelation and lookup logic also accept Employee. Update the message so users who hit this error are told the real set of supported account types.

Suggested change
TransactionModeAccountTypeErrorQst: Label '%1 can only be filled in when %2 %3 is equal to Customer or Vendor.', Comment = '%1 - Field Caption of the field causing the error, %2 - Field Caption of the Account Type field, %3 - Field Caption of the Bal. Account Type field';
TransactionModeAccountTypeErrorQst: Label '%1 can only be filled in when %2 %3 is equal to Customer, Vendor, or Employee.', Comment = '%1 - Field Caption of the field causing the error, %2 - Field Caption of the Account Type field, %3 - Field Caption of the Bal. Account Type field';

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.12.4

@github-actions

Copy link
Copy Markdown
Contributor

$\textbf{🟠\ High\ Severity\ —\ Privacy}$

The touched G/L Account field Omit Default Descr. in Jnl. is a Normal stored field but still has no DataClassification property, both before and after this PR's relocation of the field within the object. AS0016 requires field-level classification on every Normal field; leaving this field unclassified keeps its privacy posture undefined.

Knowledge:

Line mapping was unavailable, so this was posted as an issue comment.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.12.4


tableextension 11382 "G/L Entry NL" extends "G/L Entry"
{
fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ Upgrade}$

src/Layers/NL/BaseApp/Local/Finance/GeneralLedger/Ledger/GLEntryNL.TableExt.al reintroduces field 11301 Open (moved verbatim, including its InitValue = true, from the base G/L Entry table which had the same field removed in this diff) as a new tableextension field, but the NL upgrade work added in this PR only registers upgrade tags for Local SEPA Instr. Priority and Elec. Tax Declaration Setup. Moving a field's ownership from a base table to a table extension does not automatically carry over existing row values; without a tagged upgrade step, pre-upgrade G/L Entry rows will read back the Boolean default false instead of their real historical Open value.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.12.4

@github-actions github-actions Bot added needs-approval Workflow runs require maintainer approval to start AL: Apps (W1) Add-on apps for W1 and removed needs-approval Workflow runs require maintainer approval to start labels Jul 21, 2026
UnapplyVendorLedgerEntryAmount(''); // Currency as blank.
end;

[Test]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you remove the test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All-E already reverted this change, so after sybc these tests and their earlier fix will dissappear anyway. I did it earlier myself to identify if this is the last issue with tests or I have smething else.

@github-actions github-actions Bot removed the AL: Apps (W1) Add-on apps for W1 label Jul 24, 2026
/// Defines country-specific VAT registration number formats for validation and duplicate checking.
/// Provides pattern matching capabilities and business rules enforcement for VAT numbers across different jurisdictions.
/// </summary>
codeunit 13381 "VAT Reg. No. Format NL"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Breaking\ Changes}$

Three new NL localization codeunits are declared without Access = Internal;, unlike every one of the other ~19 new NL event-subscriber codeunits added in this PR (e.g. "Employee NL", "Sales Header NL", "Customer NL"), which all consistently set it. "VAT Reg. No. Format NL" (codeunit 13381), "VAT Statement Line NL" (codeunit 11366), and "Company Information NL" (codeunit 11361) contain only local event-subscriber procedures with no intended external entry point, so leaving them without an access modifier makes them default-public and reachable from other extensions, turning implementation detail into an accidental contract.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

codeunit 13381 "VAT Reg. No. Format NL"
{
    Access = Internal;

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.15.4

// ------------------------------------------------------------------------------------------------
namespace Microsoft.Finance.VAT.Reporting;

codeunit 11366 "VAT Statement Line NL"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Breaking\ Changes}$

Same missing Access = Internal; inconsistency as codeunit 13381 "VAT Reg. No. Format NL": this codeunit contains only a local event-subscriber procedure and should be internal like its sibling NL codeunits.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

codeunit 11366 "VAT Statement Line NL"
{
    Access = Internal;

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.15.4


using Microsoft.Utilities;

codeunit 11361 "Company Information NL"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Breaking\ Changes}$

Same missing Access = Internal; inconsistency as codeunit 13381 "VAT Reg. No. Format NL": this codeunit contains only a local event-subscriber procedure and should be internal like its sibling NL codeunits.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

codeunit 11361 "Company Information NL"
{
    Access = Internal;

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.15.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Delocalization Extracting from country layers and converting local functionality to app Finance GitHub request for Finance area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants