Codeunit 1340 Undo Bank Statement (Yes/No)
- App
- Base Application
- Namespace
- Microsoft.Bank.Statement
- Versions
- 17-28
Versions171819202122232425262728
Source29
Source in 29
src/Layers/W1/BaseApp/Bank/Statement/UndoBankStatementYesNo.Codeunit.al282 lines, Copyright (c) Microsoft Corporation. MIT
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.Bank.Statement;
using Microsoft.Bank.BankAccount;
using Microsoft.Bank.Check;
using Microsoft.Bank.Ledger;
using Microsoft.Bank.Reconciliation;
/// <summary>
/// Handles the reversal of posted bank statements and restoration of ledger entries to open status.
/// Provides functionality to undo bank statement reconciliation and optionally create new reconciliation records.
/// </summary>
/// <remarks>
/// Reverses applied bank account and check ledger entries back to open status.
/// Optionally creates new bank reconciliation records with the original statement data.
/// Integrates with bank reconciliation workflow for error correction and reprocessing scenarios.
/// </remarks>
codeunit 1340 "Undo Bank Statement (Yes/No)"
{
Permissions = TableData "Bank Account Ledger Entry" = rm,
TableData "Check Ledger Entry" = rm,
TableData "Bank Acc. Reconciliation" = ri,
TableData "Bank Acc. Reconciliation Line" = ri,
TableData "Bank Account Statement" = rd,
TableData "Bank Account Statement Line" = rd;
TableNo = "Bank Account Statement";
trigger OnRun()
var
BankAccountStatement: Record "Bank Account Statement";
begin
BankAccountStatement.Copy(Rec);
Code(BankAccountStatement);
Rec := BankAccountStatement;
end;
var
UndoBankStatementQst: Label 'Do you want to reverse this bank statement and automatically create a new bank reconciliation with the same information?';
local procedure Code(var BankAccountStatement: Record "Bank Account Statement")
var
BankAccReconciliation: Record "Bank Acc. Reconciliation";
StatementNo: Code[20];
begin
if not Confirm(UndoBankStatementQst) then
exit;
StatementNo := UndoBankAccountStatement(BankAccountStatement);
BankAccReconciliation.Get(
BankAccReconciliation."Statement Type"::"Bank Reconciliation",
BankAccountStatement."Bank Account No.",
StatementNo);
Page.Run(Page::"Bank Acc. Reconciliation", BankAccReconciliation);
end;
/// <summary>
/// Undoes a bank account statement and creates a new bank reconciliation.
/// </summary>
/// <param name="BankAccountStatement">The bank account statement to undo.</param>
/// <returns>The statement number of the new bank reconciliation created.</returns>
procedure UndoBankAccountStatement(BankAccountStatement: Record "Bank Account Statement"): Code[20]
begin
exit(UndoBankAccountStatement(BankAccountStatement, true));
end;
/// <summary>
/// Undoes a bank account statement with the option to create a new bank reconciliation.
/// Reverses the applied entries and optionally creates a new reconciliation for the transactions.
/// </summary>
/// <param name="BankAccountStatement">The bank account statement to undo.</param>
/// <param name="CreateBankRec">Specifies whether to create a new bank reconciliation.</param>
/// <returns>The statement number of the new bank reconciliation if created, otherwise an empty string.</returns>
procedure UndoBankAccountStatement(BankAccountStatement: Record "Bank Account Statement"; CreateBankRec: Boolean): Code[20]
var
BankAccount: Record "Bank Account";
BankAccReconciliation: Record "Bank Acc. Reconciliation";
BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line";
BankAccountStatementLine: Record "Bank Account Statement Line";
begin
BankAccount.Get(BankAccountStatement."Bank Account No.");
BankAccount."Balance Last Statement" := BankAccountStatement."Balance Last Statement";
OnUndoBankAccountStatementOnBeforeBankAccountModify(BankAccount);
BankAccount.Modify();
if CreateBankRec then begin
BankAccReconciliation.Init();
BankAccReconciliation.TransferFields(BankAccountStatement);
BankAccReconciliation."Statement No." := '';
BankAccReconciliation.Validate("Bank Account No.");
BankAccReconciliation.Validate("Statement Type", BankAccReconciliation."Statement Type"::"Bank Reconciliation");
OnUndoBankAccountStatementOnBeforeBankAccReconciliationInsert(BankAccReconciliation);
BankAccReconciliation.Insert(true);
end;
BankAccountStatementLine.SetRange("Bank Account No.", BankAccountStatement."Bank Account No.");
BankAccountStatementLine.SetRange("Statement No.", BankAccountStatement."Statement No.");
if BankAccountStatementLine.FindSet() then
repeat
if CreateBankRec then begin
BankAccReconciliationLine.Init();
BankAccReconciliationLine.TransferFields(BankAccountStatementLine);
BankAccReconciliationLine."Statement No." := BankAccReconciliation."Statement No.";
BankAccReconciliationLine.Validate("Statement Type", BankAccReconciliationLine."Statement Type"::"Bank Reconciliation");
OnUndoBankAccountStatementOnBeforeBankAccReconciliationLineInsert(BankAccReconciliationLine);
BankAccReconciliationLine.Insert();
OnUndoBankAccountStatementOnAfterBankAccReconciliationLineInsert(BankAccountStatementLine, BankAccReconciliationLine);
end;
UndoBankAccountLedgerEntries(BankAccountStatementLine, BankAccReconciliation."Statement No.", CreateBankRec);
until BankAccountStatementLine.Next() = 0;
BankAccountStatementLine.DeleteAll();
BankAccountStatement.Delete();
exit(BankAccReconciliation."Statement No.");
end;
local procedure UndoBankAccountLedgerEntries(BankAccountStatementLine: Record "Bank Account Statement Line"; NewStatementNo: Code[20]; CreateBankRec: Boolean)
var
BankAccountLedgerEntry: Record "Bank Account Ledger Entry";
begin
// When posting a bank reconciliation, the related BLEs have the
// match stored in their Statement No., Statement Line No.
BankAccountLedgerEntry.SetRange("Bank Account No.", BankAccountStatementLine."Bank Account No.");
BankAccountLedgerEntry.SetRange("Statement No.", BankAccountStatementLine."Statement No.");
BankAccountLedgerEntry.SetRange("Statement Line No.", BankAccountStatementLine."Statement Line No.");
if BankAccountLedgerEntry.FindFirst() then
repeat
// This removes and sets the new status for these entries
UndoBankAccountLedgerEntry(BankAccountLedgerEntry, BankAccountStatementLine, NewStatementNo, CreateBankRec);
until BankAccountLedgerEntry.Next() = 0;
// When posting a bank reconciliation with ManyToOne matches, the
// BLEs have the right Statement No. but Statement Line No. set to -1
// Therefore the above filters won't properly revert them.
RestoreManyToOneMatchesForNewBankReconciliation(BankAccountStatementLine, NewStatementNo, CreateBankRec);
end;
local procedure RestoreManyToOneMatchesForNewBankReconciliation(var BankAccountStatementLine: Record "Bank Account Statement Line"; NewStatementNo: Code[20]; CreateBankRec: Boolean)
var
BankAccRecMatchBuffer: Record "Bank Acc. Rec. Match Buffer";
BankAccountLedgerEntry: Record "Bank Account Ledger Entry";
begin
// When undoing a bank statement posted from the page "Bank Acc. Reconciliation"
// the many to one matches are stored in "Bank Acc. Rec. Match Buffer" table,
// and they are kept even after posted.
// We update these buffer entries to point to the new Bank Reconciliation
BankAccountStatementLine.FilterManyToOneMatches(BankAccRecMatchBuffer);
if BankAccRecMatchBuffer.FindFirst() then begin
BankAccountLedgerEntry.Reset();
BankAccountLedgerEntry.SetRange("Entry No.", BankAccRecMatchBuffer."Ledger Entry No.");
if BankAccountLedgerEntry.FindFirst() then
UndoBankAccountLedgerEntry(BankAccountLedgerEntry, BankAccountStatementLine, NewStatementNo, CreateBankRec);
if CreateBankRec then begin
BankAccRecMatchBuffer.Rename(NewStatementNo,
BankAccRecMatchBuffer."Statement Line No.",
BankAccRecMatchBuffer."Bank Account No.",
BankAccRecMatchBuffer."Match ID");
BankAccRecMatchBuffer."Is Processed" := false;
BankAccRecMatchBuffer.Modify();
end;
end;
end;
local procedure UndoBankAccountLedgerEntry(var BankAccountLedgerEntry: Record "Bank Account Ledger Entry"; BankAccountStatementLine: Record "Bank Account Statement Line"; NewStatementNo: Code[20]; CreateBankRec: Boolean)
var
CheckLedgerEntry: Record "Check Ledger Entry";
begin
CheckLedgerEntry.SetCurrentKey("Bank Account Ledger Entry No.");
CheckLedgerEntry.SetRange("Bank Account Ledger Entry No.", BankAccountLedgerEntry."Entry No.");
if CheckLedgerEntry.FindSet(true) then begin
repeat
CheckLedgerEntry."Statement Status" := GetNewStatementStatus(BankAccountStatementLine);
if CheckLedgerEntry."Statement Status" = CheckLedgerEntry."Statement Status"::"Check Entry Applied" then
CheckLedgerEntry."Statement No." := NewStatementNo
else begin
CheckLedgerEntry."Statement No." := NewStatementNo;
CheckLedgerEntry."Statement Line No." := BankAccountStatementLine."Statement Line No.";
end;
if not CreateBankRec then begin
CheckLedgerEntry."Statement Status" := CheckLedgerEntry."Statement Status"::Open;
CheckLedgerEntry."Statement No." := '';
CheckLedgerEntry."Statement Line No." := 0;
end;
CheckLedgerEntry.Open := true;
OnUndoBankAccountLedgerEntryOnBeforeCheckLedgerEntryModify(CheckLedgerEntry);
CheckLedgerEntry.Modify();
until CheckLedgerEntry.Next() = 0;
BankAccountLedgerEntry."Statement Status" := GetNewStatementStatus(BankAccountStatementLine);
if BankAccountLedgerEntry."Statement Status" = BankAccountLedgerEntry."Statement Status"::"Bank Acc. Entry Applied" then
BankAccountLedgerEntry."Statement No." := NewStatementNo
else begin
BankAccountLedgerEntry."Statement No." := '';
BankAccountLedgerEntry."Statement Line No." := 0;
end;
end else begin
BankAccountLedgerEntry."Statement No." := NewStatementNo;
BankAccountLedgerEntry."Statement Status" := BankAccountLedgerEntry."Statement Status"::"Bank Acc. Entry Applied";
end;
if not CreateBankRec then begin
BankAccountLedgerEntry."Statement Status" := BankAccountLedgerEntry."Statement Status"::Open;
BankAccountLedgerEntry."Statement No." := '';
BankAccountLedgerEntry."Statement Line No." := 0;
end;
BankAccountLedgerEntry."Remaining Amount" := BankAccountLedgerEntry.Amount;
BankAccountLedgerEntry.Open := true;
OnUndoBankAccountLedgerEntryOnBeforeBankAccountLedgerEntryModify(BankAccountLedgerEntry);
BankAccountLedgerEntry.Modify();
end;
local procedure GetNewStatementStatus(BankAccountStatementLine: Record "Bank Account Statement Line") StatementStatus: Option Open,"Bank Acc. Entry Applied","Check Entry Applied",Closed
begin
case BankAccountStatementLine.Type of
BankAccountStatementLine.Type::"Bank Account Ledger Entry":
exit(StatementStatus::"Bank Acc. Entry Applied");
BankAccountStatementLine.Type::"Check Ledger Entry":
exit(StatementStatus::"Check Entry Applied");
end;
end;
/// <summary>
/// Integration event raised before modifying the bank account during undo operation.
/// </summary>
/// <param name="BankAccount">The bank account record being modified.</param>
[IntegrationEvent(false, false)]
local procedure OnUndoBankAccountStatementOnBeforeBankAccountModify(var BankAccount: Record "Bank Account")
begin
end;
/// <summary>
/// Integration event raised before inserting a new bank account reconciliation during undo operation.
/// </summary>
/// <param name="BankAccReconciliation">The bank account reconciliation record being inserted.</param>
[IntegrationEvent(false, false)]
local procedure OnUndoBankAccountStatementOnBeforeBankAccReconciliationInsert(var BankAccReconciliation: Record "Bank Acc. Reconciliation")
begin
end;
/// <summary>
/// Integration event raised before inserting a bank account reconciliation line during undo operation.
/// </summary>
/// <param name="BankAccReconciliationLine">The bank account reconciliation line record being inserted.</param>
[IntegrationEvent(false, false)]
local procedure OnUndoBankAccountStatementOnBeforeBankAccReconciliationLineInsert(var BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line")
begin
end;
/// <summary>
/// Integration event raised before modifying a bank account ledger entry during undo operation.
/// </summary>
/// <param name="BankAccountLedgerEntry">The bank account ledger entry record being modified.</param>
[IntegrationEvent(false, false)]
local procedure OnUndoBankAccountLedgerEntryOnBeforeBankAccountLedgerEntryModify(var BankAccountLedgerEntry: Record "Bank Account Ledger Entry")
begin
end;
/// <summary>
/// Integration event raised before modifying a check ledger entry during undo operation.
/// </summary>
/// <param name="CheckLedgerEntry">The check ledger entry record being modified.</param>
[IntegrationEvent(false, false)]
local procedure OnUndoBankAccountLedgerEntryOnBeforeCheckLedgerEntryModify(var CheckLedgerEntry: Record "Check Ledger Entry")
begin
end;
/// <summary>
/// Integration event raised after inserting a bank account reconciliation line during undo operation.
/// </summary>
/// <param name="BankAccountStatementLine">The original bank account statement line being processed.</param>
/// <param name="BankAccReconciliationLine">The bank account reconciliation line that was inserted.</param>
[IntegrationEvent(false, false)]
local procedure OnUndoBankAccountStatementOnAfterBankAccReconciliationLineInsert(var BankAccountStatementLine: Record "Bank Account Statement Line"; var BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line")
begin
end;
}