Repository navigation
Extract intercompany module into app - #13232
Alexander Yakunin (Alexander-Ya) wants to merge 45 commits into
Conversation
…res/Extract-Intercompany-module
….com/microsoft/BCApps into features/Extract-Intercompany-module
…res/Extract-Intercompany-module
….com/microsoft/BCApps into features/Extract-Intercompany-module
…xtract-Intercompany-module' of https://github.com/microsoft/BCApps into features/Extract-Intercompany-module
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…field Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…res/Extract-Intercompany-module
…res/Extract-Intercompany-module
…res/Extract-Intercompany-module
…res/Extract-Intercompany-module
…res/Extract-Intercompany-module
…res/Extract-Intercompany-module
….com/microsoft/BCApps into features/Extract-Intercompany-module
|
The source file name d365icsetup.permissionset.al does not follow the PascalCase ..al convention. Rename it to a PascalCase object name with the PermissionSet type segment, while preserving the declared permission-set object identity. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
|
The source file name d365icview.permissionset.al does not follow the PascalCase ..al convention. Rename it to a PascalCase object name with the PermissionSet type segment, while preserving the declared permission-set object identity. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
|
The ordinary procedure parameter ChildrenSetupDiagnostic is declared as a temporary record without the Temp prefix. Rename it to TempChildrenSetupDiagnostic and update its uses so the temporary nature is visible at call sites. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
| @@ -10704,7 +10578,7 @@ table 39 "Purchase Line" | |||
| end; | |||
|
|
|||
| [IntegrationEvent(false, false)] | |||
| local procedure OnAfterUpdateICPartner(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header") | |||
| local procedure OnAfterUpdateItemReference(var PurchaseLine: Record "Purchase Line") | |||
There was a problem hiding this comment.
The existing local Purchase Line events OnBeforeUpdateICPartner and OnAfterUpdateICPartner were removed from the base table and replaced by a different publisher, OnAfterUpdateItemReference, while the old publishers were recreated in a table extension. This removes the original base-table event contracts for dependent subscribers; preserve the original publishers and their parameters while moving the implementation.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| @@ -1032,22 +1058,18 @@ table 125 "Purch. Cr. Memo Line" | |||
| ItemLedgerEntry: Record "Item Ledger Entry"; | |||
| ValueEntry: Record "Value Entry"; | |||
| begin | |||
| if Rec.Type = Rec.Type::Item then begin | |||
| CheckApplFromItemLedgEntry(ItemLedgerEntry); | |||
| CheckApplFromItemLedgEntry(ItemLedgerEntry); | |||
There was a problem hiding this comment.
GetPurchaseInvoiceLine no longer guards its item-ledger and Value Entry lookups with Rec.Type = Rec.Type::Item and ItemLedgerEntry."Entry No." <> 0. Non-item lines and lines without an item ledger entry therefore execute an unnecessary database lookup; restore both guards before querying Value Entry. The same regression is present in the corresponding country-layer copies.
Suggested fix (apply manually — could not be anchored as a one-click suggestion):
if Rec.Type = Rec.Type::Item then begin
CheckApplFromItemLedgEntry(ItemLedgerEntry);
if ItemLedgerEntry."Entry No." = 0 then
FindItemLedgerEntryFromItemApplicationEntry(ItemLedgerEntry);
if ItemLedgerEntry."Entry No." <> 0 then begin
ValueEntry.SetLoadFields("Item Ledger Entry No.", "Item Ledger Entry Type", "Document Type", "Document No.", "Document Line No.");
ValueEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntry."Entry No.");
ValueEntry.SetRange("Item Ledger Entry Type", ItemLedgerEntry."Entry Type");
ValueEntry.SetRange("Document Type", ValueEntry."Document Type"::"Purchase Invoice");
if ValueEntry.FindFirst() then begin
PurchInvLine.Get(ValueEntry."Document No.", ValueEntry."Document Line No.");
exit;
end;
end;
end;👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
|
The cross-environment intercompany connector posts record JSON to an external Business Central API without checking approval for a dedicated privacy notice for this integration. Register a stable custom notice and require its approval before the request is issued. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
| InvoicePostingInterface, InvoicePostingParameters, SuppressCommit); | ||
| end; | ||
|
|
||
| local procedure PostGLAccICLine(PurchHeader: Record "Purchase Header"; PurchLine: Record "Purchase Line"; xPurchLine: Record "Purchase Line" temporary; PurchLineACY: Record "Purchase Line"; PurchInvHeader: Record "Purch. Inv. Header"; PurchCrMemoHeader: Record "Purch. Cr. Memo Hdr."; var InvoicePostingInterface: Interface "Invoice Posting"; InvoicePostingParameters: Record "Invoice Posting Parameters"; SuppressCommit: Boolean) |
There was a problem hiding this comment.
The ordinary procedure parameter xPurchLine is declared as a temporary Record but does not start with Temp, making it look like a database-backed record. Rename the parameter to a Temp-prefixed name and update its local call sites.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
|
The Intercompany app's assignable role permission sets add tabledata grants but do not grant execute permission for the app-owned codeunits used by setup and normal workflows. A user assigned only the app's Intercompany roles can therefore reach the app's pages but fail when those workflows invoke the moved codeunits; add the required codeunit execute grants to the assignable roles (or included focused permission sets) and validate representative setup and usage paths without SUPER. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
| } | ||
| } | ||
|
|
||
| procedure CheckICPartner(ICPartnerCode: Code[20]; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]) |
There was a problem hiding this comment.
The moved IC Gen. Journal Line table extension exposes implementation helpers such as CheckICPartner and GetDefaultICPartnerGLAccNo as public procedures, widening the former protected/local surface into a supported external API without an indicated API reason. Keep these helpers internal (or local where they are used by only one object) and reserve public access for deliberate extension points.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| procedure CheckICPartner(ICPartnerCode: Code[20]; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]) | ||
| var | ||
| ICPartner: Record "IC Partner"; | ||
| begin |
There was a problem hiding this comment.
The moved Standard General Journal Line table extension exposes implementation helpers such as CheckICPartner and GetDefaultICPartnerGLAccNo as public procedures, widening the former protected/local surface into a supported external API without an indicated API reason. Keep these helpers internal (or local where they are used by only one object) and reserve public access for deliberate extension points.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| #if not CLEAN30 | ||
| GenJnlPostLine.RunOnBeforePostICPartner(GenJnlLine, IsHandled); | ||
| #endif | ||
| if IsHandled then |
There was a problem hiding this comment.
The OnBeforePostICPartner IsHandled guard can exit before the intercompany partner posting routine creates the balancing G/L entry and performs its posting validations. Do not make this critical ledger operation suppressible; limit IsHandled to a safe calculation or run the ledger-entry creation unconditionally.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
|
OnUpdateICStatusOnAfterLoopIteration is raised inside the repeat/until loop, so every processed outbox transaction invokes all subscribers separately and scales event overhead with the number of rows. Move the extensibility point outside the loop or expose a set-level operation instead of publishing once per iteration. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
| #if not CLEAN30 | ||
| PurchPost.RunOnBeforePostGLAccICLine(PurchHeader, PurchLine, ICGenJnlLineNo, IsHandled); | ||
| #endif | ||
| if IsHandled then |
There was a problem hiding this comment.
The OnBeforePostGLAccICLine IsHandled guard can exit before an intercompany purchase posting line is validated and its intercompany journal line is created. Do not allow this OnBefore event to suppress the critical posting work; make only a safe calculation overridable or execute the posting unconditionally.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| #if not CLEAN30 | ||
| PurchPost.RunOnBeforeInsertICGenJnlLine(PurchHeader, PurchLine, ICGenJnlLineNo, IsHandled); | ||
| #endif | ||
| if IsHandled then |
There was a problem hiding this comment.
The OnBeforeInsertICGenJnlLine IsHandled guard can exit before intercompany purchase journal-line validation, account lookup, and journal-line creation. This lets a subscriber bypass critical posting work; restrict the override to a safe calculation and keep the posting operation unconditional.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| begin | ||
| IsHandled := false; | ||
| OnBeforePostGLAccICLine(SalesHeader, SalesLine, ICGenJnlLineNo, IsHandled); | ||
| if IsHandled then |
There was a problem hiding this comment.
The OnBeforePostGLAccICLine IsHandled guard can exit before an intercompany sales posting line is validated and its intercompany journal line is created. Do not allow this OnBefore event to suppress the critical posting work; make only a safe calculation overridable or execute the posting unconditionally.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| #if not CLEAN30 | ||
| SalesPost.RunOnBeforeInsertICGenJnlLine(TempICGenJnlLine, SalesHeader, SalesLine, IsHandled); | ||
| #endif | ||
| if IsHandled then |
There was a problem hiding this comment.
The OnBeforeInsertICGenJnlLine IsHandled guard can exit before intercompany sales journal-line validation, account lookup, and journal-line creation. This lets a subscriber bypass critical posting work; restrict the override to a safe calculation and keep the posting operation unconditional.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
|
The persistent buffer tables are checked with IsEmpty() and then read with FindSet(), causing an unnecessary existence-query round trip before each iteration. Replace each guard in AssignOperationIDToBufferObjects with FindSet() as the loop guard; the same redundant pattern is repeated for the buffer collections through this procedure. Suggested fix (apply manually — could not be anchored as a one-click suggestion): if BufferICInboxJnlLine.FindSet() then beginKnowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
| /// <summary> | ||
| /// Bank account number used for intercompany transactions and payment processing. | ||
| /// </summary> | ||
| field(4; "Bank Account No."; Text[30]) |
There was a problem hiding this comment.
The new IC Bank Account field "Bank Account No." stores a financial account identifier but inherits the table's broad CustomerContent classification. Add a field-level DataClassification = AccountData so the platform classifies the identifier according to its actual data.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| /// <summary> | ||
| /// International Bank Account Number for the intercompany bank account with automatic validation. | ||
| /// </summary> | ||
| field(7; IBAN; Code[50]) |
There was a problem hiding this comment.
The new IC Bank Account field "IBAN" stores a financial account identifier but inherits the table's broad CustomerContent classification. Add a field-level DataClassification = AccountData so the platform classifies the identifier according to its actual data.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
|
The permission check for changing sensitive IC Partner fields returns immediately when GuiAllowed() is false. Table event subscribers also run for API, background, and job-queue sessions, so those sessions can modify the sensitive endpoint, token, client-secret, and connection-key fields without the required D365 IC Partner Edit or SUPER permission. Remove the noninteractive bypass and enforce authorization for every session type, with an explicit separate policy only if a trusted automation path is intended. Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
|
|
||
| codeunit 8559 "IC Payment Journal Test NA" | ||
| { | ||
| Access = Internal; |
There was a problem hiding this comment.
The payment-journal test declares labels with one or more placeholders, but the comments only describe every value generically as a field, value, or account information. Replace those descriptions with the actual meaning of each argument so translators can distinguish the placeholders.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| #pragma warning disable AA0470 | ||
| Text009: Label '%1 %2 posted on %3 includes more than one customer or vendor. '; | ||
| #pragma warning restore AA0470 | ||
| Text010: Label 'In order for the program to calculate VAT, the entries must be separated by another document number or by an empty line.'; |
There was a problem hiding this comment.
The posting-batch labels Text012 through Text020 and Text026 through Text027 contain multiple placeholders without comments explaining what each argument represents. Add one translator-facing description for every placeholder.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| } | ||
| } | ||
|
|
||
| trigger OnInsert() |
There was a problem hiding this comment.
The custom master table "IC G/L Account" uses a Code[20] "No." as its primary key, but its OnInsert trigger does not assign a blank number from a configured number series or record the originating "No. Series". Inserts therefore depend on callers supplying every business identifier manually and cannot follow the standard master numbering and manual-entry flow. Add a setup-configured number series and assign it in OnInsert when "No." is blank.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
| Access = Internal; | ||
|
|
||
| var | ||
| MustBeSpecifiedErr: Label '%1 must be specified.', Comment = ' %1 = field, value, or account information'; |
There was a problem hiding this comment.
The payment-journal validation labels contain multiple placeholders, but their Comments only say 'field, value, or account information' and do not identify each argument. Replace those generic descriptions with the actual semantic meaning of every placeholder.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6
|
These labels use multiple placeholders without a Comment that identifies each placeholder's meaning. Add one semantic description per placeholder so translators can distinguish the transaction, document type, code, and table values. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
|
This four-placeholder label has no Comment describing the document type, document number, partner, and window placeholders. Add a Comment with one named description for each placeholder. Knowledge: Posting this finding as an issue comment because inline comment placement failed. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.51.6 |
Reconcile AppSourceCop object and member removals against isolated aggregate Application symbols before the new-warning gate. Keep schema checks and unverified removals enforced, and publish migration audit reports. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
What & why
Linked work
Fixes #
How I validated this
What I tested and the outcome (required — be specific: scenarios, commands, screenshots for UI changes)
Risk & compatibility