diff --git a/src/Layers/APAC/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/APAC/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index 2b7a225aea..d72f90f326 100644
--- a/src/Layers/APAC/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/APAC/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -236,7 +236,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -259,13 +259,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -13545,4 +13583,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/BE/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/BE/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index fc01e1d44d..d3d3a564c0 100644
--- a/src/Layers/BE/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/BE/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -218,7 +218,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -241,13 +241,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -11146,4 +11184,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/CH/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/CH/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index 20826749d9..fd9fa6801b 100644
--- a/src/Layers/CH/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/CH/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -219,7 +219,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -242,13 +242,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -11168,4 +11206,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/ES/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/ES/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index befcec4b41..92f6dc5da0 100644
--- a/src/Layers/ES/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/ES/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -258,7 +258,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -281,13 +281,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
Balancing: Boolean;
IsTransactionConsistent: Boolean;
@@ -12859,4 +12897,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/ES/Tests/General Journal/ERMJournalPosting.Codeunit.al b/src/Layers/ES/Tests/General Journal/ERMJournalPosting.Codeunit.al
index c98a6ba6bf..cba05f1e0c 100644
--- a/src/Layers/ES/Tests/General Journal/ERMJournalPosting.Codeunit.al
+++ b/src/Layers/ES/Tests/General Journal/ERMJournalPosting.Codeunit.al
@@ -24,6 +24,10 @@ codeunit 134420 "ERM Journal Posting"
MinRange: Decimal;
MiddleRange: Decimal;
MaxRange: Decimal;
+ SetIgnoreCommitToFalse: Boolean;
+ RaiseErrorAfterCommit: Boolean;
+ CommitTestMarkerID: Guid;
+ TestRollbackAfterCommitErr: Label 'Test error to trigger rollback after Commit() call.';
[Test]
[Scope('OnPrem')]
@@ -465,11 +469,88 @@ codeunit 134420 "ERM Journal Posting"
LibraryAssert.AreEqual('', NoSeriesLine."Last No. Used", 'Last No. Used must be empty.');
end;
+ [Test]
+ [Scope('OnPrem')]
+ procedure PostGenJnlLineCommitBySubscriberIsSuppressed()
+ var
+ GenJnlBatch: Record "Gen. Journal Batch";
+ GenJnlLine: Record "Gen. Journal Line";
+ ActivityLog: Record "Activity Log";
+ begin
+ // [FEATURE] [General Journal] [Posting] [CommitBehavior]
+ // [SCENARIO 637261] A Commit() called by a posting subscriber is suppressed during Gen. Jnl.-Post Line.
+ Initialize();
+
+ // [GIVEN] General journal line.
+ LibraryJournals.CreateGenJournalBatch(GenJnlBatch);
+ LibraryERM.CreateGeneralJnlLineWithBalAcc(
+ GenJnlLine, GenJnlBatch."Journal Template Name", GenJnlBatch.Name, GenJnlLine."Document Type"::" ",
+ GenJnlLine."Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(),
+ GenJnlLine."Bal. Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(), LibraryRandom.RandDec(1000, 2));
+ Commit();
+
+ // [GIVEN] Subscriber inserts a marker record, calls Commit(), and raises an error inside the posting scope.
+ CommitTestMarkerID := CreateGuid();
+ RaiseErrorAfterCommit := true;
+ BindSubscription(this);
+
+ // [WHEN] Post the journal line (posting fails because subscriber raises an error).
+ asserterror LibraryERM.PostGeneralJnlLine(GenJnlLine);
+ UnbindSubscription(this);
+
+ // [THEN] The marker record does not exist because Commit() was suppressed and the error rolled back all changes.
+ ActivityLog.SetRange("Activity Message", Format(CommitTestMarkerID));
+ Assert.RecordIsEmpty(ActivityLog);
+ end;
+
+ [Test]
+ [Scope('OnPrem')]
+ procedure PostGenJnlLineCommitBehaviorOptOutRestoresCommit()
+ var
+ GenJnlBatch: Record "Gen. Journal Batch";
+ GenJnlLine: Record "Gen. Journal Line";
+ ActivityLog: Record "Activity Log";
+ begin
+ // [FEATURE] [General Journal] [Posting] [CommitBehavior]
+ // [SCENARIO 637261] Setting IgnoreCommit := false via OnSetCommitBehavior restores old commit behavior.
+ Initialize();
+
+ // [GIVEN] General journal line.
+ LibraryJournals.CreateGenJournalBatch(GenJnlBatch);
+ LibraryERM.CreateGeneralJnlLineWithBalAcc(
+ GenJnlLine, GenJnlBatch."Journal Template Name", GenJnlBatch.Name, GenJnlLine."Document Type"::" ",
+ GenJnlLine."Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(),
+ GenJnlLine."Bal. Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(), LibraryRandom.RandDec(1000, 2));
+ Commit();
+
+ // [GIVEN] Subscriber sets IgnoreCommit := false to opt out of commit suppression.
+ SetIgnoreCommitToFalse := true;
+
+ // [GIVEN] Subscriber inserts a marker record, calls Commit(), and raises an error inside the posting scope.
+ CommitTestMarkerID := CreateGuid();
+ RaiseErrorAfterCommit := true;
+ BindSubscription(this);
+
+ // [WHEN] Post the journal line (posting fails because subscriber raises an error).
+ asserterror LibraryERM.PostGeneralJnlLine(GenJnlLine);
+ UnbindSubscription(this);
+
+ // [THEN] The marker record exists because Commit() was not suppressed and persisted before the error.
+ ActivityLog.SetRange("Activity Message", Format(CommitTestMarkerID));
+ Assert.RecordIsNotEmpty(ActivityLog);
+
+ // Cleanup: Remove test marker.
+ ActivityLog.DeleteAll();
+ end;
+
local procedure Initialize()
var
LibraryERMCountryData: Codeunit "Library - ERM Country Data";
begin
LibraryTestInitialize.OnTestInitialize(CODEUNIT::"ERM Journal Posting");
+ SetIgnoreCommitToFalse := false;
+ RaiseErrorAfterCommit := false;
+ Clear(CommitTestMarkerID);
if isInitialized then
exit;
LibraryTestInitialize.OnBeforeTestSuiteInitialize(CODEUNIT::"ERM Journal Posting");
@@ -598,4 +679,36 @@ codeunit 134420 "ERM Journal Posting"
GenJournalBatch.Validate("Posting No. Series", '');
GenJournalBatch.Modify(true);
end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", OnSetCommitBehavior, '', false, false)]
+ local procedure OnSetCommitBehaviorHandler(var IgnoreCommit: Boolean)
+ begin
+ if SetIgnoreCommitToFalse then
+ IgnoreCommit := false;
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", OnAfterGLFinishPosting, '', false, false)]
+ local procedure OnAfterGLFinishPostingHandler(GLEntry: Record "G/L Entry"; var GenJnlLine: Record "Gen. Journal Line")
+ var
+ ActivityLog: Record "Activity Log";
+ begin
+ if not RaiseErrorAfterCommit then
+ exit;
+ if IsNullGuid(CommitTestMarkerID) then
+ exit;
+
+ // Insert a marker record
+ ActivityLog.Init();
+ ActivityLog."Activity Date" := CurrentDateTime();
+ ActivityLog."User ID" := CopyStr(UserId(), 1, MaxStrLen(ActivityLog."User ID"));
+ ActivityLog."Activity Message" := Format(CommitTestMarkerID);
+ ActivityLog.Status := ActivityLog.Status::Success;
+ ActivityLog.Insert(true);
+
+ // Call Commit() - this should be suppressed by CommitBehavior::Ignore
+ Commit();
+
+ // Raise an error to abort the transaction
+ Error(TestRollbackAfterCommitErr);
+ end;
}
diff --git a/src/Layers/FI/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/FI/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index fbe8c6eda3..fc590b3645 100644
--- a/src/Layers/FI/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/FI/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -220,7 +220,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -243,13 +243,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -11169,4 +11207,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/FR/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/FR/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index b666e639cb..d6ac0212b8 100644
--- a/src/Layers/FR/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/FR/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -228,7 +228,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -251,13 +251,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -11472,4 +11510,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/IT/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/IT/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index 4ae77b19be..73955c5b76 100644
--- a/src/Layers/IT/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/IT/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -260,7 +260,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -283,13 +283,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -12224,4 +12262,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/NA/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/NA/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index 4c5356aa7a..232d8833a6 100644
--- a/src/Layers/NA/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/NA/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -221,7 +221,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -244,13 +244,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -11595,4 +11633,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/NO/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/NO/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index 67a1b6f901..fd2be544f3 100644
--- a/src/Layers/NO/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/NO/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -222,7 +222,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -245,13 +245,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -11206,4 +11244,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/RU/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/RU/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index 16a6c109a1..8894ea1a66 100644
--- a/src/Layers/RU/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/RU/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -255,7 +255,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -278,13 +278,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -13637,4 +13675,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/src/Layers/W1/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al b/src/Layers/W1/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
index 85589d60ea..98e2d96d7f 100644
--- a/src/Layers/W1/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
+++ b/src/Layers/W1/BaseApp/Finance/GeneralLedger/Posting/GenJnlPostLine.Codeunit.al
@@ -218,7 +218,7 @@ codeunit 12 "Gen. Jnl.-Post Line"
SequenceNoMgt.ClearSequenceNoCheck();
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, true);
+ Post(GenJnlLine, true);
OnAfterRunWithCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
@@ -241,13 +241,51 @@ codeunit 12 "Gen. Jnl.-Post Line"
exit(GLEntryNo);
GenJnlLine.Copy(GenJnlLine2);
- Code(GenJnlLine, false);
+ Post(GenJnlLine, false);
OnAfterRunWithoutCheck(GenJnlLine);
GenJnlLine2 := GenJnlLine;
exit(GLEntryNo);
end;
- local procedure "Code"(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ ///
+ /// A wrapper procedure to delegate to either a procedure that allows commit or a procedure that ignores commit.
+ /// By default, commits are suppressed during the critical posting window to prevent duplicate-key races
+ /// on G/L Entry (table 17). Subscribers can opt out by setting IgnoreCommit to false via OnSetCommitBehavior.
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the lines before posting.
+ local procedure Post(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ var
+ IgnoreCommit: Boolean;
+ begin
+ IgnoreCommit := true;
+ OnSetCommitBehavior(IgnoreCommit);
+
+ if IgnoreCommit then
+ PostLineCommitBehaviorIgnore(GenJnlLine, CheckLine)
+ else
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// A wrapper procedure to delegate to PostLine in order to ignore commits.
+ /// While this procedure is on the call stack, the platform turns every Commit() into a no-op,
+ /// preventing intermittent duplicate-key errors on G/L Entry (table 17).
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ [CommitBehavior(CommitBehavior::Ignore)]
+ local procedure PostLineCommitBehaviorIgnore(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
+ begin
+ PostLine(GenJnlLine, CheckLine);
+ end;
+
+ ///
+ /// Posting procedure for general journal lines
+ ///
+ /// The general journal line that is being posted.
+ /// Indicates whether to check the line before posting.
+ local procedure PostLine(var GenJnlLine: Record "Gen. Journal Line"; CheckLine: Boolean)
var
xGLEntryNo: Integer;
Balancing: Boolean;
@@ -11103,4 +11141,9 @@ codeunit 12 "Gen. Jnl.-Post Line"
local procedure OnPostUnapplyOnBeforeInsertTempVATEntry(var VATEntry: Record "VAT Entry"; var UnapplyVATEntries: Boolean)
begin
end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnSetCommitBehavior(var IgnoreCommit: Boolean)
+ begin
+ end;
}
diff --git a/src/Layers/W1/Tests/General Journal/ERMJournalPosting.Codeunit.al b/src/Layers/W1/Tests/General Journal/ERMJournalPosting.Codeunit.al
index 633eb8931f..c0d798ed4c 100644
--- a/src/Layers/W1/Tests/General Journal/ERMJournalPosting.Codeunit.al
+++ b/src/Layers/W1/Tests/General Journal/ERMJournalPosting.Codeunit.al
@@ -24,6 +24,10 @@ codeunit 134420 "ERM Journal Posting"
MinRange: Decimal;
MiddleRange: Decimal;
MaxRange: Decimal;
+ SetIgnoreCommitToFalse: Boolean;
+ RaiseErrorAfterCommit: Boolean;
+ CommitTestMarkerID: Guid;
+ TestRollbackAfterCommitErr: Label 'Test error to trigger rollback after Commit() call.';
[Test]
[Scope('OnPrem')]
@@ -464,11 +468,88 @@ codeunit 134420 "ERM Journal Posting"
LibraryAssert.AreEqual('', NoSeriesLine."Last No. Used", 'Last No. Used must be empty.');
end;
+ [Test]
+ [Scope('OnPrem')]
+ procedure PostGenJnlLineCommitBySubscriberIsSuppressed()
+ var
+ GenJnlBatch: Record "Gen. Journal Batch";
+ GenJnlLine: Record "Gen. Journal Line";
+ ActivityLog: Record "Activity Log";
+ begin
+ // [FEATURE] [General Journal] [Posting] [CommitBehavior]
+ // [SCENARIO 637261] A Commit() called by a posting subscriber is suppressed during Gen. Jnl.-Post Line.
+ Initialize();
+
+ // [GIVEN] General journal line.
+ LibraryJournals.CreateGenJournalBatch(GenJnlBatch);
+ LibraryERM.CreateGeneralJnlLineWithBalAcc(
+ GenJnlLine, GenJnlBatch."Journal Template Name", GenJnlBatch.Name, GenJnlLine."Document Type"::" ",
+ GenJnlLine."Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(),
+ GenJnlLine."Bal. Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(), LibraryRandom.RandDec(1000, 2));
+ Commit();
+
+ // [GIVEN] Subscriber inserts a marker record, calls Commit(), and raises an error inside the posting scope.
+ CommitTestMarkerID := CreateGuid();
+ RaiseErrorAfterCommit := true;
+ BindSubscription(this);
+
+ // [WHEN] Post the journal line (posting fails because subscriber raises an error).
+ asserterror LibraryERM.PostGeneralJnlLine(GenJnlLine);
+ UnbindSubscription(this);
+
+ // [THEN] The marker record does not exist because Commit() was suppressed and the error rolled back all changes.
+ ActivityLog.SetRange("Activity Message", Format(CommitTestMarkerID));
+ Assert.RecordIsEmpty(ActivityLog);
+ end;
+
+ [Test]
+ [Scope('OnPrem')]
+ procedure PostGenJnlLineCommitBehaviorOptOutRestoresCommit()
+ var
+ GenJnlBatch: Record "Gen. Journal Batch";
+ GenJnlLine: Record "Gen. Journal Line";
+ ActivityLog: Record "Activity Log";
+ begin
+ // [FEATURE] [General Journal] [Posting] [CommitBehavior]
+ // [SCENARIO 637261] Setting IgnoreCommit := false via OnSetCommitBehavior restores old commit behavior.
+ Initialize();
+
+ // [GIVEN] General journal line.
+ LibraryJournals.CreateGenJournalBatch(GenJnlBatch);
+ LibraryERM.CreateGeneralJnlLineWithBalAcc(
+ GenJnlLine, GenJnlBatch."Journal Template Name", GenJnlBatch.Name, GenJnlLine."Document Type"::" ",
+ GenJnlLine."Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(),
+ GenJnlLine."Bal. Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(), LibraryRandom.RandDec(1000, 2));
+ Commit();
+
+ // [GIVEN] Subscriber sets IgnoreCommit := false to opt out of commit suppression.
+ SetIgnoreCommitToFalse := true;
+
+ // [GIVEN] Subscriber inserts a marker record, calls Commit(), and raises an error inside the posting scope.
+ CommitTestMarkerID := CreateGuid();
+ RaiseErrorAfterCommit := true;
+ BindSubscription(this);
+
+ // [WHEN] Post the journal line (posting fails because subscriber raises an error).
+ asserterror LibraryERM.PostGeneralJnlLine(GenJnlLine);
+ UnbindSubscription(this);
+
+ // [THEN] The marker record exists because Commit() was not suppressed and persisted before the error.
+ ActivityLog.SetRange("Activity Message", Format(CommitTestMarkerID));
+ Assert.RecordIsNotEmpty(ActivityLog);
+
+ // Cleanup: Remove test marker.
+ ActivityLog.DeleteAll();
+ end;
+
local procedure Initialize()
var
LibraryERMCountryData: Codeunit "Library - ERM Country Data";
begin
LibraryTestInitialize.OnTestInitialize(CODEUNIT::"ERM Journal Posting");
+ SetIgnoreCommitToFalse := false;
+ RaiseErrorAfterCommit := false;
+ Clear(CommitTestMarkerID);
if isInitialized then
exit;
LibraryTestInitialize.OnBeforeTestSuiteInitialize(CODEUNIT::"ERM Journal Posting");
@@ -597,4 +678,36 @@ codeunit 134420 "ERM Journal Posting"
GenJournalBatch.Validate("Posting No. Series", '');
GenJournalBatch.Modify(true);
end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", OnSetCommitBehavior, '', false, false)]
+ local procedure OnSetCommitBehaviorHandler(var IgnoreCommit: Boolean)
+ begin
+ if SetIgnoreCommitToFalse then
+ IgnoreCommit := false;
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", OnAfterGLFinishPosting, '', false, false)]
+ local procedure OnAfterGLFinishPostingHandler(GLEntry: Record "G/L Entry"; var GenJnlLine: Record "Gen. Journal Line")
+ var
+ ActivityLog: Record "Activity Log";
+ begin
+ if not RaiseErrorAfterCommit then
+ exit;
+ if IsNullGuid(CommitTestMarkerID) then
+ exit;
+
+ // Insert a marker record
+ ActivityLog.Init();
+ ActivityLog."Activity Date" := CurrentDateTime();
+ ActivityLog."User ID" := CopyStr(UserId(), 1, MaxStrLen(ActivityLog."User ID"));
+ ActivityLog."Activity Message" := Format(CommitTestMarkerID);
+ ActivityLog.Status := ActivityLog.Status::Success;
+ ActivityLog.Insert(true);
+
+ // Call Commit() - this should be suppressed by CommitBehavior::Ignore
+ Commit();
+
+ // Raise an error to abort the transaction
+ Error(TestRollbackAfterCommitErr);
+ end;
}