Skip to content

Bug 642053: [master] [Sustainability] Preview Posting Creates Gaps in Sustainability Ledger Entry Numbers - #10051

Open
Aleksandr Gladkov (AleksanderGladkov) wants to merge 3 commits into
mainfrom
bugs/642053-master-Sustainability-Preview-Posting-Entry-No-Gaps
Open

Bug 642053: [master] [Sustainability] Preview Posting Creates Gaps in Sustainability Ledger Entry Numbers#10051
Aleksandr Gladkov (AleksanderGladkov) wants to merge 3 commits into
mainfrom
bugs/642053-master-Sustainability-Preview-Posting-Entry-No-Gaps

Conversation

@AleksanderGladkov

@AleksanderGladkov Aleksandr Gladkov (AleksanderGladkov) commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

ISSUE:
Running Preview Posting on a journal line that includes Sustainability emissions leaves gaps in the Sustainability Ledger Entry "Entry No." sequence (for example, 128 then 132). General Ledger Entries are not affected and stay sequential.

CAUSE:
Preview built the Sustainability Ledger Entries by physically inserting them, which consumed the AutoIncrement identity. The rollback that ends the preview did not return those numbers, so every preview permanently burned entry numbers.

SOLUTION:
Preview no longer inserts real Sustainability Ledger Entries. The shared insert is intercepted just before it reaches the database, and preview rows are collected in memory under temporary numbers, so no identity is used. Normal posting is untouched and keeps its sequential AutoIncrement numbering.

TESTS:
Added identity-continuity regressions for repeated general journal preview, purchase credit memo, native and recurring Sustainability journals, a custom generic preview path, and direct fixed asset journal preview. Each verifies that repeated preview consumes no number and the next real post continues the sequence.

Fixes AB#642053

… numbers

- intercept the ledger insert with an internal handled event before SQL allocation
- store preview rows under session-local negative keys; keep AutoIncrement for real posts
- add identity-continuity regressions for journal, purchase, and fixed-asset previews

🌱 - Generated by Copilot
if SustLedgEntry.IsTemporary() then
exit;

if NextSustLedgerPreviewEntryNo = 0 then

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}$

NextSustLedgerPreviewEntryNo uses 0 as its "not initialized" sentinel, but a counter that starts at -2000000000 can legitimately reach 0. On the next preview insert, this code resets the counter back to -2000000000 and reuses an existing temporary primary key, so a sufficiently large preview fails with a generic duplicate-key/runtime error instead of a controlled exhaustion check. Use a non-reachable sentinel or add an explicit guard when the negative preview range is exhausted.

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

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.

The counter only reaches 0 after about 2 billion previews in one session, so it is not reachable in practice.

@AleksanderGladkov Aleksandr Gladkov (AleksanderGladkov) changed the title [Sustainability] Fix preview posting consuming Sustainability Ledger Entry numbers Bug 642053: [master] [Sustainability] Preview Posting Creates Gaps in Sustainability Ledger Entry Numbers Aug 7, 2026
@github-actions github-actions Bot added this to the Version 29.0 milestone Aug 7, 2026
var
SustainabilityLedgerEntry: Record "Sustainability Ledger Entry";
FeatureTelemetry: Codeunit "Feature Telemetry";
IsHandled: Boolean;

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\ —\ Telemetry}$

FeatureTelemetry.LogUsage('0000PH5', ...) and LogUptake(..., "Used") are still called unconditionally near the top of InsertLedgerEntry, before the new OnInsertLedgerEntryOnBeforeInsert/IsHandled branch decides whether a real ledger entry is ever persisted. With the new preview-diversion path, a call that ends up fully handled (no physical Insert) still reports feature usage as if a real Sustainability Ledger Entry was created, inflating usage telemetry for preview-only invocations of this procedure and making usage counts unreliable for measuring real adoption.

Knowledge:

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

PostedCrMemoNo: Code[20];
BaselineEntryNo: Integer;
BaselineEmissionCO2: Decimal;
begin

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\ —\ Testing}$

The new preview-mode tests in SustGeneralJournalTest.Codeunit.al, SustValueChainFixedAsset.Codeunit.al, and SustainabilityPostingTest.Codeunit.al all follow asserterror with Assert.ExpectedError(''). An empty expected-error string matches any error text, so each of these tests will pass even if the failure is an unrelated setup or posting error rather than the intended preview-mode 'stop the transaction' error, silently defeating the purpose of the assertion.

Knowledge:

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

Comment on lines +1318 to +1321
[PageHandler]
procedure GLPostingPreviewPageHandler(var GLPostingPreview: TestPage "G/L Posting Preview")
begin
end;

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\ —\ Testing}$

GLPostingPreviewPageHandler in SustValueChainFixedAsset.Codeunit.al is an empty handler body wired to the new FA-journal preview test. It proves only that some preview page opened, without asserting the Sustainability Ledger Entry row count or count shown on the preview page, so a regression that drops or duplicates preview rows would not be caught.

Suggested change
[PageHandler]
procedure GLPostingPreviewPageHandler(var GLPostingPreview: TestPage "G/L Posting Preview")
begin
end;
[PageHandler]
procedure GLPostingPreviewPageHandler(var GLPostingPreview: TestPage "G/L Posting Preview")
begin
GLPostingPreview.Filter.SetFilter("Table ID", Format(Database::"Sustainability Ledger Entry"));
GLPostingPreview."No. of Records".AssertEquals(1);
GLPostingPreview.OK().Invoke();
end;

Knowledge:

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

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Agentic PR Review - Round 1

Recommendation: Accept with Suggestions

What this PR does

This PR fixes a gap in Sustainability Ledger Entry numbers that appeared after running Preview Posting. Before the fix, the preview called SustainabilityLedgerEntry.Insert(true) through InsertLedgerEntry, which consumed the SQL AutoIncrement counter even though the database transaction was rolled back at the end of the preview. After the fix, a new internal event OnInsertLedgerEntryOnBeforeInsert with an IsHandled guard is raised inside InsertLedgerEntry just before the real insert. The preview handler subscribes to this event, redirects the entry into the in-memory temporary table with a negative counter-based key (starting at -2,000,000,000, reset on each Initialize()), and sets IsHandled := true so the real Insert(true) is never reached. Normal posting is not affected: nothing binds the subscriber outside of preview mode.

The design is correct. The OnBeforeInsertSustainabilityLedgerEntry event that was already present fires first and can still modify fields; then the new OnInsertLedgerEntryOnBeforeInsert intercepts the insert for preview. The SingleInstance scope of Sust. Preview Post Instance means the counter is shared for the life of the preview session and resets cleanly via Initialize(). The existing OnAfterInsertEvent subscriber in Sust. Preview Posting Handler is preserved as a safety net for any direct Insert(true) call that bypasses InsertLedgerEntry.

Suggestions

S1 - Sustainability Value Entry preview path still uses the old after-insert interception

InsertValueEntry in Sustainability Post Mgt still calls SustainabilityValueEntry.Insert(true) directly, and the preview handler only captures it via OnAfterInsertEvent. This means a preview that produces value entries (for example, item-ledger-linked sustainability costs) still consumes AutoIncrement identity and can cause the same kind of gap in Sustainability Value Entry numbers. Add a matching OnInsertValueEntryOnBeforeInsert event and a corresponding handler to cover this path, or confirm in a comment that value entries are never produced during preview.

Risk assessment and necessity

Risk: Low. The change is additive — it introduces a new internal event and one new subscriber; it does not modify any existing event or posting logic. Normal posting (not in preview mode) is fully unchanged because the new subscriber is only bound during preview. The negative temporary keys (-2,000,000,000 and up) are well outside the range of real AutoIncrement values and cannot collide with committed entries. The IsHandled guard follows the standard BC pattern and prevents double-handling if a second subscriber were ever added.

Necessity: Clear. Entry-number gaps in a financial ledger are a data-quality issue that can confuse auditors and break sequence-dependent queries. The fix is scoped precisely to the root cause and does not touch any other posting path.


[AI-PR-REVIEW] version=1 promptVersion=1 system=github pr=10051 round=1 by=alexei-dobriansky at=2026-08-10T08:22:25Z lastSha=e185970b77ddc930120ad9b38adfc7e7003ba106 reviewKey=a2bc3e9db214da7d938282ead98ee0682b04c287c842cf5e5c083ef5ee04a531 suggestions=S1@2f56307e

…G/L account

- CreateBankAccount overload creates a posting group that has a G/L account, so the journal line can post

🧪 - Generated by Copilot
@github-actions

Copy link
Copy Markdown
Contributor

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

InsertLedgerEntry still calls FeatureTelemetry.LogUsage('0000PH5', ...) before the new OnInsertLedgerEntryOnBeforeInsert/IsHandled branch decides whether a real ledger-entry insert will happen. Sust. Preview Posting Handler handles that event by copying the record into a temporary preview buffer and setting IsHandled := true, so preview runs now emit a successful "Sustainability Ledger Entry Added" usage event even though no committed ledger entry was created. Keep LogUptake(...Used) if attempt telemetry is desired, but move LogUsage to the path that runs only after a real insert succeeds.

Knowledge:

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

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

end;

[Test]
[HandlerFunctions('ConfirmHandler,MessageHandler')]

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\ —\ Testing}$

The newly added journal-posting tests opt into ConfirmHandler and MessageHandler, but those shared handlers always reply true / ignore the message and the tests do not enqueue expected interactions or prove the queue is empty. That means the tests never verify which confirm/message was raised or how many times, so a wrong dialog contract can still leave them green.

Knowledge:

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

// [WHEN] Preview the second FA Journal Line through FA Jnl.-Post.Preview.
FAJournalLine.SetRange("Journal Template Name", FAJournalLine."Journal Template Name");
FAJournalLine.SetRange("Journal Batch Name", FAJournalLine."Journal Batch Name");
asserterror FAJnlPost.Preview(FAJournalLine);

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\ —\ Testing}$

The new FA preview test follows asserterror with Assert.ExpectedError(''), so it still accepts any error instead of proving that the expected preview-mode failure occurred. That leaves the test green on unrelated posting or fixture defects.

Knowledge:

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

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

Labels

AL: Apps (W1) Add-on apps for W1 Finance GitHub request for Finance area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants