Bugs/concurrent posting for general ledger gl entry#9587
Conversation
…https://github.com/microsoft/BCApps into bugs/Concurrent-Posting-for-General-Ledger-GL-Entry
| GeneralLedgerSetup.Validate("Currency Symbol Position", GeneralLedgerSetup."Currency Symbol Position"::"Before Amount"); | ||
| GeneralLedgerSetup.Validate("Enable Data Check", DataCheck); | ||
| GeneralLedgerSetup.Validate("Acc. Receivables Category", AccReceivablesCategory); | ||
| GeneralledgerSetup."Use Concurrent Posting" := true; // to test concurrent posting for all countries |
There was a problem hiding this comment.
CreateGeneralLedgerSetup.Codeunit.al unconditionally forces "Use Concurrent Posting" := true for every country's demo-data company, with a comment reading "to test concurrent posting for all countries".
This reads as leftover diagnostic/test code rather than an intentional demo-data default: it silently changes the posting behavior of the standard Contoso demo company for every locale, with no gating on a test/debug context, and the comment itself signals it was added for local verification. (Separately, the statement references the variable via inconsistent casing, "GeneralledgerSetup" instead of "GeneralLedgerSetup" — this compiles because AL identifiers are case-insensitive, but it is inconsistent with the casing used on every other line in the same procedure.) If enabling concurrent posting in the demo dataset is intentional, the hardcoded value should be reviewed and the debug-style comment removed; if it was left in from local testing, it should be reverted before merge.
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
| field(21; "SIFT Bucket No."; Integer) | ||
| { | ||
| Caption = 'SIFT Bucket No.'; | ||
| ToolTip = 'Specifies an automatically generated number that is used by the system to enable better concurrency.'; | ||
| Editable = false; | ||
| } |
There was a problem hiding this comment.
New field 21 "SIFT Bucket No." on table 17 "G/L Entry" has no DataClassification property.
Its immediate neighbor, field 20 "Source Currency Code", explicitly sets DataClassification = SystemMetadata, but the new field omits the property entirely, so the AL compiler applies the ToBeClassified sentinel. This field is a purely system-generated technical value (the OnInsert trigger sets it to "G/L Register No." mod 5) and should be classified the same way as other technical fields on this table.
| field(21; "SIFT Bucket No."; Integer) | |
| { | |
| Caption = 'SIFT Bucket No.'; | |
| ToolTip = 'Specifies an automatically generated number that is used by the system to enable better concurrency.'; | |
| Editable = false; | |
| } | |
| field(21; "SIFT Bucket No."; Integer) | |
| { | |
| Caption = 'SIFT Bucket No.'; | |
| ToolTip = 'Specifies an automatically generated number that is used by the system to enable better concurrency.'; | |
| Editable = false; | |
| DataClassification = SystemMetadata; | |
| } |
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
Copilot PR ReviewIteration 2 · Outcome: completed Knowledge source: https://github.com/microsoft/BCQuality@186d8a131465475c79244d994acb872cd5c0d4bf Findings by domainFindings split into Knowledge-backed (cite a BCQuality article) and Agent (the agent's own judgement, no matching BCQuality rule).
Totals: 1 knowledge-backed · 3 agent findings. Orchestrator pre-filter (2 file(s) excluded)
Findings produced by the AL review agent v1.7.3. Reply 👎 on any inline comment to flag false positives. |
|
|
||
| trigger OnInsert() | ||
| begin | ||
| Rec."SIFT Bucket No." := Rec."G/L Register No." mod 5; |
There was a problem hiding this comment.
The new "SIFT Bucket No." field is computed as 'Rec."G/L Register No." mod 5' in OnInsert and is appended to Key2 (the SumIndexFields key used for G/L account/posting-date aggregation) specifically to reduce SIFT-index write contention.
Every G/L entry created within the same posting run shares the same G/L Register No., so every entry from a single large batch (mass recurring-journal posting, a big sales/purchase batch, etc.) lands in exactly the same bucket — the scenario most likely to generate heavy SIFT-index write contention in the first place gets no distribution benefit at all; only different, non-overlapping posting runs land in different buckets. The bucket key would more directly serve the stated 'better concurrency' goal if it were derived from something that varies within a single run (e.g. the G/L Entry's own Entry No.) rather than from the Register No. that is constant for the whole run. The underlying impact could be more than cosmetic for high-volume batch posting, but this is capped at minor since no BCQuality knowledge file specifically addresses SIFT bucket-key selection strategy today.
| Rec."SIFT Bucket No." := Rec."G/L Register No." mod 5; | |
| Rec."SIFT Bucket No." := Rec."Entry No." mod 5; |
Agent judgement — not directly backed by a BCQuality knowledge article.
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
This PR replaces the LockTable()+GetLastEntry()/FindLast() pattern for G/L Entry and VAT Entry numbering with sequence-based GetNextEntryNo() calls whenever GeneralLedgerSetup.UseConcurrentPosting() is true, specifically to remove the serialization point that LockTable causes under concurrent posting.However, StartPosting still unconditionally does 'GLReg.LockTable(); if GLReg.FindLast() then GLReg."No." := GLReg."No." + 1 else GLReg."No." := 1;' to assign the next G/L Register number, in the very same procedure that was edited to branch on UseConcurrentPosting for VAT Entry numbering a few lines above. Because every posting run must go through this table lock to obtain its register number, all concurrent postings still serialize on the G/L Register table regardless of the new setting, which defeats the concurrency goal the rest of the change is trying to achieve for G/L Entry and VAT Entry. The real impact here would normally be major (it undermines the feature's stated purpose), but per agent-finding rules this is capped at minor since no BCQuality knowledge file backs it yet; the concern should be promoted to a knowledge-backed rule (or the register numbering path should be given the same sequence-based treatment) rather than accepted at this severity long-term. Agent judgement — not directly backed by a BCQuality knowledge article. Line mapping was unavailable, so this was posted as an issue comment. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why |
| "VAT Reporting Date" := GenJnlLine."VAT Reporting Date"; | ||
| end; | ||
|
|
||
| [InherentPermissions(PermissionObjectType::TableData, Database::"VAT Entry", 'r')] |
There was a problem hiding this comment.
The new VAT Entry.GetNextEntryNo() procedure is decorated with [InherentPermissions(PermissionObjectType::TableData, Database::"VAT Entry", 'r')], copied from the pre-existing GetLastEntryNo() immediately below it.
GetLastEntryNo() actually reads the VAT Entry table (via FindRecordManagement.GetLastEntryIntFieldValue) so the grant matches its body, but GetNextEntryNo() only calls SequenceNoMgt.GetNextSeqNo(DATABASE::"VAT Entry") — it never Gets, Finds, or otherwise reads a VAT Entry row. The inherent-permissions grant should match the procedure's actual work; here it grants table-data read access on VAT Entry that the procedure's body never exercises.
Knowledge:
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
This PR adds several new conditional code paths gated on GeneralLedgerSetup.UseConcurrentPosting() — sequence-based G/L Entry/VAT Entry numbering in InitNextEntryNo/StartPosting/ContinuePosting, the new GetNextGLEntryNoForPosting/GetNextVATEntryNoForPosting helpers, the PreviousEntryNo rollback path in UpdateGLEntryNo, and the new ValidateSequenceNo call for VAT Entry — none of which are exercised by any test file in this diff (no *.Test.al / *.Codeunit.al test file appears in the changed-file list).Given the change affects core posting entry-numbering logic across every localization layer, the absence of any accompanying automated test for the new UseConcurrentPosting = true branch is a real coverage gap for a change this central to posting correctness. Impact would ordinarily warrant more than a minor flag, but this is capped per agent-finding rules since no BCQuality knowledge file backs the specific gap. Agent judgement — not directly backed by a BCQuality knowledge article. Line mapping was unavailable, so this was posted as an issue comment. 👍 useful · ❤️ especially valuable · 👎 wrong - reply with why |
What & why
Linked work
Fixes AB#624164
How I validated this
What I tested and the outcome (required — be specific: scenarios, commands, screenshots for UI changes)
Risk & compatibility