Codeunit 386 Reverse Payment Rec. Journal
- App
- Base Application
- Namespace
- Microsoft.Bank.Reconciliation
- Versions
- 21-28
Versions171819202122232425262728
Source29
Source in 29
src/Layers/W1/BaseApp/Bank/Reconciliation/ReversePaymentRecJournal.Codeunit.al1000 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.Reconciliation;
using Microsoft.Bank.BankAccount;
using Microsoft.Bank.Ledger;
using Microsoft.Bank.Statement;
using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Ledger;
using Microsoft.Finance.GeneralLedger.Posting;
using Microsoft.Finance.GeneralLedger.Reversal;
using Microsoft.Finance.ReceivablesPayables;
using Microsoft.Foundation.AuditCodes;
using Microsoft.HumanResources.Payables;
using Microsoft.Purchases.Payables;
using Microsoft.Sales.Receivables;
/// <summary>
/// Provides comprehensive reversal functionality for posted payment reconciliation journals.
/// This codeunit handles the complex process of unapplying payment applications, reversing
/// general ledger entries, and restoring customer and vendor ledger entry statuses to their
/// pre-application state. Supports both partial and complete journal reversals with full
/// audit trail maintenance and proper handling of cross-ledger entry relationships.
/// </summary>
/// <remarks>
/// Key capabilities include automatic detection of related entries across multiple ledgers, validation
/// of reversal eligibility based on transaction dependencies, preservation of original posting dates
/// and references, and comprehensive error handling for complex reversal scenarios. Integrates with
/// the standard AL reversal framework while providing specialized logic for payment application reversals.
/// Maintains data integrity through transaction control and provides detailed logging for audit purposes.
/// </remarks>
codeunit 386 "Reverse Payment Rec. Journal"
{
EventSubscriberInstance = Manual;
var
EmptyTransactionNoErr: Label 'Entry %1 cannot be reversed because its "Transaction No." is not defined.', Comment = '%1 - The Entry No. of the transaction that cannot be reversed';
PostedPaymentReconciliationNotSelectedErr: Label 'You must select a journal to reverse.';
CantFindRelatedEntriesErr: Label 'Related entries not found. To unapply and reverse payments you must do it manually.';
PaymentRecJournalAlreadyReversedErr: Label 'This payment reconciliation journal has already been reversed.';
GLRegisterNo: Integer;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnAfterInitGLRegister', '', false, false)]
local procedure SetGLRegisterNoInPostedPaymentRecHeader(var GLRegister: Record "G/L Register"; var GenJournalLine: Record "Gen. Journal Line")
begin
GLRegisterNo := GLRegister."No.";
end;
[InherentPermissions(PermissionObjectType::TableData, Database::"Posted Payment Recon. Hdr", 'M', InherentPermissionsScope::Both)]
procedure SetGLRegisterNo(BankAccReconciliation: Record "Bank Acc. Reconciliation")
var
PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr";
begin
if GLRegisterNo = 0 then
exit;
if not PostedPaymentReconHdr.Get(BankAccReconciliation."Bank Account No.", BankAccReconciliation."Statement No.") then
exit;
PostedPaymentReconHdr."G/L Register No." := GLRegisterNo;
PostedPaymentReconHdr.Modify();
end;
procedure RunReversalWizard(var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr")
var
BankAccountStatement: Record "Bank Account Statement";
BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line";
PmtRecUndoStatement: Page "Pmt. Rec. Undo Statement";
PaymentRecRelatedEntries: Page "Payment Rec. Related Entries";
PmtRecReversalFinalize: Page "Pmt. Rec. Reversal Finalize";
WizardState: Option UndoStatement,RelatedEntries,Finalize,Done;
NewStatementNo: Code[20];
BankAccountNo: Code[20];
StatementNo: Code[20];
HasBankStatement: Boolean;
begin
if PostedPaymentReconHdr."Is Reversed" then
Error(PaymentRecJournalAlreadyReversedErr);
BankAccountNo := PostedPaymentReconHdr."Bank Account No.";
StatementNo := PostedPaymentReconHdr."Statement No.";
BankAccountStatement.SetRange("Bank Account No.", BankAccountNo);
BankAccountStatement.SetRange("Statement No.", StatementNo);
PostedPaymentReconHdr.CalcFields("Is Reconciled");
// Misconfigured page caller
if PostedPaymentReconHdr.IsEmpty() then
Error(PostedPaymentReconciliationNotSelectedErr);
InsertPaymentRecRelatedAndAppliedEntries(PostedPaymentReconHdr);
RefreshRelatedEntriesReversalStatus(PostedPaymentReconHdr."Bank Account No.", PostedPaymentReconHdr."Statement No.", true);
Commit();
WizardState := WizardState::UndoStatement;
repeat
HasBankStatement := not BankAccountStatement.IsEmpty();
Clear(PmtRecUndoStatement);
Clear(PaymentRecRelatedEntries);
Clear(PmtRecReversalFinalize);
case WizardState of
WizardState::UndoStatement:
begin
PmtRecUndoStatement.SetBankAccountStatement(BankAccountNo, StatementNo);
if TryOpenPmtRecUndoStatement(PmtRecUndoStatement) then begin
if PmtRecUndoStatement.NextSelected() then
WizardState := WizardState::RelatedEntries
else
exit;
end else
WizardState := WizardState::RelatedEntries;
end;
WizardState::RelatedEntries:
begin
PaymentRecRelatedEntries.SetPaymentRecRelatedEntries(BankAccountNo, StatementNo);
if not HasBankStatement then
PaymentRecRelatedEntries.HideBackAction();
PaymentRecRelatedEntries.RunModal();
if PaymentRecRelatedEntries.NextSelected() then
WizardState := WizardState::Finalize
else
if PaymentRecRelatedEntries.BackSelected() then
WizardState := WizardState::UndoStatement
else
exit;
end;
WizardState::Finalize:
begin
PmtRecReversalFinalize.SetPaymentRecRelatedEntries(BankAccountNo, StatementNo);
if not HasBankStatement then
PmtRecReversalFinalize.SetNoStatementMsg();
PmtRecReversalFinalize.RunModal();
if PmtRecReversalFinalize.FinalizeSelected() then begin
FinalizeReversal(BankAccountNo, StatementNo);
Commit();
if PmtRecReversalFinalize.CreatePaymentRecJournalSelected() then
NewStatementNo := CreateCopyPaymentRecJournal(PostedPaymentReconHdr);
CleanUpReversal(PostedPaymentReconHdr);
WizardState := WizardState::Done;
end
else
if PmtRecReversalFinalize.BackSelected() then
WizardState := WizardState::RelatedEntries
else
exit;
end;
end;
until WizardState = WizardState::Done;
if NewStatementNo <> '' then begin
BankAccReconciliationLine.FilterGroup(2);
BankAccReconciliationLine.SetRange("Statement Type", BankAccReconciliationLine."Statement Type"::"Payment Application");
BankAccReconciliationLine.SetRange("Bank Account No.", BankAccountNo);
BankAccReconciliationLine.SetRange("Statement No.", NewStatementNo);
BankAccReconciliationLine.FilterGroup(0);
Page.Run(Page::"Payment Reconciliation Journal", BankAccReconciliationLine);
end;
end;
[TryFunction]
local procedure TryOpenPmtRecUndoStatement(var PmtRecUndoStatement: Page "Pmt. Rec. Undo Statement")
begin
PmtRecUndoStatement.RunModal();
end;
local procedure InsertPaymentRecRelatedAndAppliedEntries(var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr")
var
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry";
BankAccountStatement: Record "Bank Account Statement";
GLRegister: Record "G/L Register";
begin
// Entries PaymentRecRelatedEntry, PmtRecAppliedToEntry are only inserted if not previously inserted
PaymentRecRelatedEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PaymentRecRelatedEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
if not PaymentRecRelatedEntry.IsEmpty() then
exit;
PmtRecAppliedToEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PmtRecAppliedToEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
if not PmtRecAppliedToEntry.IsEmpty() then
exit;
if PostedPaymentReconHdr."Is Reconciled" then
if BankAccountStatement.Get(PostedPaymentReconHdr."Bank Account No.", PostedPaymentReconHdr."Statement No.") then begin
InsertRelatedAndAppliedEntries(PostedPaymentReconHdr."Bank Account No.", PostedPaymentReconHdr."Statement No.");
PostedPaymentReconHdr."Entries found with G/L Reg." := false;
PostedPaymentReconHdr.Modify();
exit;
end;
if PostedPaymentReconHdr."G/L Register No." <> 0 then
if GLRegister.Get(PostedPaymentReconHdr."G/L Register No.") then begin
InsertRelatedAndAppliedEntriesOfGLRegister(GLRegister, PostedPaymentReconHdr);
PostedPaymentReconHdr."Entries found with G/L Reg." := true;
PostedPaymentReconHdr.Modify();
exit;
end;
Error(CantFindRelatedEntriesErr);
end;
local procedure CreateCopyPaymentRecJournal(var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr"): Code[20]
var
BankAccReconciliation: Record "Bank Acc. Reconciliation";
begin
BankAccReconciliation.Init();
BankAccReconciliation.TransferFields(PostedPaymentReconHdr);
BankAccReconciliation."Statement No." := '';
BankAccReconciliation.Validate("Statement Type", BankAccReconciliation."Statement Type"::"Payment Application");
BankAccReconciliation.Validate("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
BankAccReconciliation.Insert(true);
if not PostedPaymentReconHdr."Entries found with G/L Reg." then
CopyPaymentRecJournalFromPostedPaymentReconLines(PostedPaymentReconHdr, BankAccReconciliation)
else
CopyPaymentRecJournalFromPaymentRecRelatedEntries(PostedPaymentReconHdr, BankAccReconciliation);
OnAfterCreateCopyPaymentRecJournal(PostedPaymentReconHdr, BankAccReconciliation);
exit(BankAccReconciliation."Statement No.");
end;
local procedure CopyPaymentRecJournalFromPaymentRecRelatedEntries(var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr"; var BankAccReconciliation: Record "Bank Acc. Reconciliation")
var
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line";
PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry";
begin
PaymentRecRelatedEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PaymentRecRelatedEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
PaymentRecRelatedEntry.SetFilter("Entry Type", '<>%1', PaymentRecRelatedEntry."Entry Type"::"Bank Account");
if not PaymentRecRelatedEntry.FindSet() then
exit;
repeat
BankAccReconciliationLine.Init();
BankAccReconciliationLine."Statement No." := BankAccReconciliation."Statement No.";
BankAccReconciliationLine."Statement Line No." := PaymentRecRelatedEntry."Statement Line No.";
BankAccReconciliationLine."Bank Account No." := PaymentRecRelatedEntry."Bank Account No.";
BankAccReconciliationLine."Statement Type" := BankAccReconciliationLine."Statement Type"::"Payment Application";
SetBankRecLineDetailsFromPaymentRecRelatedEntry(BankAccReconciliationLine, PaymentRecRelatedEntry);
BankAccReconciliationLine.Insert(true);
PmtRecAppliedToEntry.Reset();
PmtRecAppliedToEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PmtRecAppliedToEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
PmtRecAppliedToEntry.SetRange("Statement Line No.", BankAccReconciliationLine."Statement Line No.");
if PaymentRecRelatedEntry.Reversed then
if PmtRecAppliedToEntry.FindSet() then
repeat
CreateApplicationEntryForBankAccReconciliationLine(BankAccReconciliationLine, PmtRecAppliedToEntry);
until PmtRecAppliedToEntry.Next() = 0;
until PaymentRecRelatedEntry.Next() = 0;
end;
local procedure SetBankRecLineDetailsFromPaymentRecRelatedEntry(var BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry")
var
CustLedgerEntry: Record "Cust. Ledger Entry";
VendorLedgerEntry: Record "Vendor Ledger Entry";
EmployeeLedgerEntry: Record "Employee Ledger Entry";
begin
BankAccReconciliationLine."Applied Amount" := 0;
case PaymentRecRelatedEntry."Entry Type" of
PaymentRecRelatedEntry."Entry Type"::Customer:
if CustLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.") then begin
BankAccReconciliationLine."Account Type" := BankAccReconciliationLine."Account Type"::Customer;
BankAccReconciliationLine."Account No." := CustLedgerEntry."Customer No.";
BankAccReconciliationLine.Description := CustLedgerEntry.Description;
BankAccReconciliationLine."Transaction Text" := CustLedgerEntry.Description;
BankAccReconciliationLine."Transaction Date" := CustLedgerEntry."Posting Date";
BankAccReconciliationLine.Validate("Statement Amount", -CustLedgerEntry."Closed by Amount");
end;
PaymentRecRelatedEntry."Entry Type"::Vendor:
if VendorLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.") then begin
BankAccReconciliationLine."Account Type" := BankAccReconciliationLine."Account Type"::Vendor;
BankAccReconciliationLine."Account No." := VendorLedgerEntry."Vendor No.";
BankAccReconciliationLine.Description := VendorLedgerEntry.Description;
BankAccReconciliationLine."Transaction Text" := VendorLedgerEntry.Description;
BankAccReconciliationLine."Transaction Date" := VendorLedgerEntry."Posting Date";
BankAccReconciliationLine.Validate("Statement Amount", -VendorLedgerEntry."Closed by Amount");
end;
PaymentRecRelatedEntry."Entry Type"::Employee:
if EmployeeLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.") then begin
BankAccReconciliationLine."Account Type" := BankAccReconciliationLine."Account Type"::Employee;
BankAccReconciliationLine."Account No." := EmployeeLedgerEntry."Employee No.";
BankAccReconciliationLine.Description := EmployeeLedgerEntry.Description;
BankAccReconciliationLine."Transaction Text" := EmployeeLedgerEntry.Description;
BankAccReconciliationLine."Transaction Date" := EmployeeLedgerEntry."Posting Date";
BankAccReconciliationLine.Validate("Statement Amount", -EmployeeLedgerEntry."Closed by Amount");
end;
end;
end;
local procedure CopyPaymentRecJournalFromPostedPaymentReconLines(var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr"; var BankAccReconciliation: Record "Bank Acc. Reconciliation")
var
PostedPaymentReconLine: Record "Posted Payment Recon. Line";
BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line";
PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry";
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
begin
PostedPaymentReconLine.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PostedPaymentReconLine.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
if not PostedPaymentReconLine.FindSet() then
exit;
repeat
BankAccReconciliationLine.Init();
BankAccReconciliationLine.TransferFromPostedPaymentReconLine(PostedPaymentReconLine);
BankAccReconciliationLine."Statement No." := BankAccReconciliation."Statement No.";
BankAccReconciliationLine.Insert(true);
OnCopyPaymentRecJournalFromPostedPaymentReconLinesOnAfterInsertBankAccReconciliationLine(PostedPaymentReconLine, BankAccReconciliationLine);
// if unapplied create application entry for the new BankAccReconciliationLine
PmtRecAppliedToEntry.Reset();
PmtRecAppliedToEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PmtRecAppliedToEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
PmtRecAppliedToEntry.SetRange("Statement Line No.", PostedPaymentReconLine."Statement Line No.");
PaymentRecRelatedEntry.Reset();
PaymentRecRelatedEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PaymentRecRelatedEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
PaymentRecRelatedEntry.SetRange("Statement Line No.", PostedPaymentReconLine."Statement Line No.");
PaymentRecRelatedEntry.SetFilter("Entry Type", '<>%1', PaymentRecRelatedEntry."Entry Type"::"Bank Account");
if PaymentRecRelatedEntry.FindFirst() then
if PaymentRecRelatedEntry.Reversed then
if PmtRecAppliedToEntry.FindSet() then
repeat
CreateApplicationEntryForBankAccReconciliationLine(BankAccReconciliationLine, PmtRecAppliedToEntry);
until PmtRecAppliedToEntry.Next() = 0;
until PostedPaymentReconLine.Next() = 0;
end;
local procedure CleanUpReversal(var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr")
var
PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry";
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
begin
// We set "Is Reversed" to true, to avoid reversing multiple times
PostedPaymentReconHdr."Is Reversed" := true;
PostedPaymentReconHdr.Modify();
// We also remove the entries created for the reversal: PmtRecRelatedEntry and PaymentRecRelatedEntry
PmtRecAppliedToEntry.Reset();
PmtRecAppliedToEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PmtRecAppliedToEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
PmtRecAppliedToEntry.DeleteAll();
PaymentRecRelatedEntry.Reset();
PaymentRecRelatedEntry.SetRange("Bank Account No.", PostedPaymentReconHdr."Bank Account No.");
PaymentRecRelatedEntry.SetRange("Statement No.", PostedPaymentReconHdr."Statement No.");
PaymentRecRelatedEntry.DeleteAll();
end;
procedure UnapplyEntry(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry"; ShowEntriesToPost: Boolean)
begin
case PaymentRecRelatedEntry."Entry Type" of
PaymentRecRelatedEntry."Entry Type"::Customer:
UnapplyCustomerEntry(PaymentRecRelatedEntry, ShowEntriesToPost);
PaymentRecRelatedEntry."Entry Type"::Vendor:
UnapplyVendorEntry(PaymentRecRelatedEntry, ShowEntriesToPost);
PaymentRecRelatedEntry."Entry Type"::Employee:
UnapplyEmployeeEntry(PaymentRecRelatedEntry, ShowEntriesToPost);
end;
end;
procedure ReverseEntry(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry"; ShowEntriesToPost: Boolean)
var
BankAccountStatement: Record "Bank Account Statement";
CustLedgerEntry: Record "Cust. Ledger Entry";
VendorLedgerEntry: Record "Vendor Ledger Entry";
EmployeeLedgerEntry: Record "Employee Ledger Entry";
ReversalEntry: Record "Reversal Entry";
begin
OnBeforeReverseEntry(PaymentRecRelatedEntry);
if not ShowEntriesToPost then
ReversalEntry.SetHideWarningDialogs()
else
if BankAccountStatement.Get(PaymentRecRelatedEntry."Bank Account No.", PaymentRecRelatedEntry."Statement No.") then
ReversalEntry.SetBankAccountStatement(PaymentRecRelatedEntry."Bank Account No.", PaymentRecRelatedEntry."Statement No.");
case PaymentRecRelatedEntry."Entry Type" of
PaymentRecRelatedEntry."Entry Type"::Customer:
begin
CustLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.");
ErrorIfEntryIsNotReversable(CustLedgerEntry);
ReversalEntry.ReverseTransaction(CustLedgerEntry."Transaction No.");
end;
PaymentRecRelatedEntry."Entry Type"::Vendor:
begin
VendorLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.");
ErrorIfEntryIsNotReversable(VendorLedgerEntry);
ReversalEntry.ReverseTransaction(VendorLedgerEntry."Transaction No.");
end;
PaymentRecRelatedEntry."Entry Type"::Employee:
begin
EmployeeLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.");
ErrorIfEntryIsNotReversable(EmployeeLedgerEntry);
ReversalEntry.ReverseTransaction(EmployeeLedgerEntry."Transaction No.");
end;
end;
RefreshRelatedEntryReversalStatus(PaymentRecRelatedEntry);
OnAfterReverseEntry();
end;
[CommitBehavior(CommitBehavior::Ignore)]
local procedure FinalizeReversal(BankAccountNo: Code[20]; StatementNo: Code[20])
var
BankAccountStatement: Record "Bank Account Statement";
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
UndoBankStatementYesNo: Codeunit "Undo Bank Statement (Yes/No)";
begin
RefreshRelatedEntriesReversalStatus(BankAccountNo, StatementNo);
// Undoing bank statement
if BankAccountStatement.Get(BankAccountNo, StatementNo) then
UndoBankStatementYesNo.UndoBankAccountStatement(BankAccountStatement, false);
// Unapplying entries
PaymentRecRelatedEntry.SetRange("Bank Account No.", BankAccountNo);
PaymentRecRelatedEntry.SetRange("Statement No.", StatementNo);
PaymentRecRelatedEntry.SetFilter("Entry Type", '<>%1', PaymentRecRelatedEntry."Entry Type"::"Bank Account");
PaymentRecRelatedEntry.SetRange(Unapplied, false);
PaymentRecRelatedEntry.SetRange(ToUnapply, true);
if PaymentRecRelatedEntry.FindSet() then
repeat
PaymentRecRelatedEntry.Unapplied := true;
UnapplyEntry(PaymentRecRelatedEntry, false);
PaymentRecRelatedEntry.Modify();
until PaymentRecRelatedEntry.Next() = 0;
// Reversing entries
PaymentRecRelatedEntry.Reset();
PaymentRecRelatedEntry.SetRange("Bank Account No.", BankAccountNo);
PaymentRecRelatedEntry.SetRange("Statement No.", StatementNo);
PaymentRecRelatedEntry.SetFilter("Entry Type", '<>%1', PaymentRecRelatedEntry."Entry Type"::"Bank Account");
PaymentRecRelatedEntry.SetRange(Unapplied, true);
PaymentRecRelatedEntry.SetRange(Reversed, false);
PaymentRecRelatedEntry.SetRange(ToReverse, true);
if PaymentRecRelatedEntry.FindSet() then
repeat
PaymentRecRelatedEntry.Reversed := true;
ReverseEntry(PaymentRecRelatedEntry, false);
PaymentRecRelatedEntry.Modify();
until PaymentRecRelatedEntry.Next() = 0;
end;
local procedure InsertRelatedAndAppliedEntries(BankAccountNo: Code[20]; StatementNo: Code[20])
var
BankAccountStatementLine: Record "Bank Account Statement Line";
PostedPaymentReconLine: Record "Posted Payment Recon. Line";
begin
BankAccountStatementLine.SetRange("Bank Account No.", BankAccountNo);
BankAccountStatementLine.SetRange("Statement No.", StatementNo);
if not BankAccountStatementLine.FindSet() then
exit;
repeat
if PostedPaymentReconLine.Get(BankAccountNo, StatementNo, BankAccountStatementLine."Statement Line No.") then
InsertRelatedAndAppliedEntries(BankAccountNo, StatementNo, BankAccountStatementLine."Statement Line No.", PostedPaymentReconLine."Account Type");
until BankAccountStatementLine.Next() = 0;
end;
local procedure InsertRelatedAndAppliedEntriesOfGLRegister(var GLRegister: Record "G/L Register"; var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr")
var
BankAccountLedgerEntry: Record "Bank Account Ledger Entry";
CustLedgerEntry: Record "Cust. Ledger Entry";
VendorLedgerEntry: Record "Vendor Ledger Entry";
EmployeeLedgerEntry: Record "Employee Ledger Entry";
StatementLineNo: Integer;
begin
BankAccountLedgerEntry.SetRange("Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
if BankAccountLedgerEntry.FindSet() then
repeat
InsertBankPaymentRecRelatedEntry(BankAccountLedgerEntry, PostedPaymentReconHdr."Statement No.", -1);
until BankAccountLedgerEntry.Next() = 0;
CustLedgerEntry.SetRange("Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
if CustLedgerEntry.FindSet() then
repeat
StatementLineNo += 10000;
InsertRelatedAndAppliedEntries(PostedPaymentReconHdr."Bank Account No.", PostedPaymentReconHdr."Statement No.", StatementLineNo, CustLedgerEntry);
until CustLedgerEntry.Next() = 0;
VendorLedgerEntry.SetRange("Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
if VendorLedgerEntry.FindSet() then
repeat
StatementLineNo += 10000;
InsertRelatedAndAppliedEntries(PostedPaymentReconHdr."Bank Account No.", PostedPaymentReconHdr."Statement No.", StatementLineNo, VendorLedgerEntry);
until VendorLedgerEntry.Next() = 0;
EmployeeLedgerEntry.SetRange("Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
if EmployeeLedgerEntry.FindSet() then
repeat
StatementLineNo += 10000;
InsertRelatedAndAppliedEntries(PostedPaymentReconHdr."Bank Account No.", PostedPaymentReconHdr."Statement No.", StatementLineNo, EmployeeLedgerEntry);
until EmployeeLedgerEntry.Next() = 0;
OnAfterInsertRelatedAndAppliedEntriesOfGLRegister(GLRegister, PostedPaymentReconHdr, StatementLineNo);
end;
local procedure RefreshRelatedEntryReversalStatus(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry")
begin
RefreshRelatedEntryReversalStatus(PaymentRecRelatedEntry, false);
end;
local procedure RefreshRelatedEntryReversalStatus(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry"; SetDefaultValues: Boolean)
var
CustLedgerEntry: Record "Cust. Ledger Entry";
VendorLedgerEntry: Record "Vendor Ledger Entry";
EmployeeLedgerEntry: Record "Employee Ledger Entry";
CustEntryApplyPostedEntries: Codeunit "CustEntry-Apply Posted Entries";
VendEntryApplyPostedEntries: Codeunit "VendEntry-Apply Posted Entries";
EmplEntryApplyPostedEntries: Codeunit "EmplEntry-Apply Posted Entries";
begin
case PaymentRecRelatedEntry."Entry Type" of
PaymentRecRelatedEntry."Entry Type"::Customer:
begin
CustLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.");
PaymentRecRelatedEntry.Reversed := CustLedgerEntry.Reversed;
if PaymentRecRelatedEntry.Reversed then
PaymentRecRelatedEntry.Unapplied := true
else
PaymentRecRelatedEntry.Unapplied := CustEntryApplyPostedEntries.FindLastApplEntry(CustLedgerEntry."Entry No.") = 0;
end;
PaymentRecRelatedEntry."Entry Type"::Vendor:
begin
VendorLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.");
PaymentRecRelatedEntry.Reversed := VendorLedgerEntry.Reversed;
if PaymentRecRelatedEntry.Reversed then
PaymentRecRelatedEntry.Unapplied := true
else
PaymentRecRelatedEntry.Unapplied := VendEntryApplyPostedEntries.FindLastApplEntry(VendorLedgerEntry."Entry No.") = 0;
end;
PaymentRecRelatedEntry."Entry Type"::Employee:
begin
EmployeeLedgerEntry.Get(PaymentRecRelatedEntry."Entry No.");
PaymentRecRelatedEntry.Reversed := EmployeeLedgerEntry.Reversed;
if PaymentRecRelatedEntry.Reversed then
PaymentRecRelatedEntry.Unapplied := true
else
PaymentRecRelatedEntry.Unapplied := EmplEntryApplyPostedEntries.FindLastApplEntry(EmployeeLedgerEntry."Entry No.") = 0;
end;
end;
if PaymentRecRelatedEntry.Unapplied then
PaymentRecRelatedEntry.ToUnapply := false;
if PaymentRecRelatedEntry.Reversed then
PaymentRecRelatedEntry.ToReverse := false;
if SetDefaultValues then begin
PaymentRecRelatedEntry.ToUnapply := not PaymentRecRelatedEntry.Unapplied;
PaymentRecRelatedEntry.ToReverse := not PaymentRecRelatedEntry.Reversed;
end;
end;
local procedure RefreshRelatedEntriesReversalStatus(BankAccountNo: Code[20]; StatementNo: Code[20])
begin
RefreshRelatedEntriesReversalStatus(BankAccountNo, StatementNo, false)
end;
local procedure RefreshRelatedEntriesReversalStatus(BankAccountNo: Code[20]; StatementNo: Code[20]; SetDefaultValues: Boolean)
var
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
begin
PaymentRecRelatedEntry.SetRange("Bank Account No.", BankAccountNo);
PaymentRecRelatedEntry.SetRange("Statement No.", StatementNo);
if not PaymentRecRelatedEntry.FindSet() then
exit;
repeat
RefreshRelatedEntryReversalStatus(PaymentRecRelatedEntry, SetDefaultValues);
PaymentRecRelatedEntry.Modify();
until PaymentRecRelatedEntry.Next() = 0;
end;
procedure ErrorIfEntryIsNotReversable(CustLedgerEntry: Record "Cust. Ledger Entry")
begin
ErrorIfEntryIsNotReversable(CustLedgerEntry.Reversed, CustLedgerEntry.TableCaption, CustLedgerEntry."Entry No.", CustLedgerEntry."Transaction No.", CustLedgerEntry."Journal Batch Name", CustLedgerEntry."Document Type", CustLedgerEntry."Amount to Apply", CustLedgerEntry."Applies-to Doc. No.", CustLedgerEntry."Applies-to ID", CustLedgerEntry."Source Code");
end;
procedure ErrorIfEntryIsNotReversable(VendorLedgerEntry: Record "Vendor Ledger Entry")
begin
ErrorIfEntryIsNotReversable(VendorLedgerEntry.Reversed, VendorLedgerEntry.TableCaption, VendorLedgerEntry."Entry No.", VendorLedgerEntry."Transaction No.", VendorLedgerEntry."Journal Batch Name", VendorLedgerEntry."Document Type", VendorLedgerEntry."Amount to Apply", VendorLedgerEntry."Applies-to Doc. No.", VendorLedgerEntry."Applies-to ID", VendorLedgerEntry."Source Code");
end;
procedure ErrorIfEntryIsNotReversable(EmployeeLedgerEntry: Record "Employee Ledger Entry")
begin
ErrorIfEntryIsNotReversable(EmployeeLedgerEntry.Reversed, EmployeeLedgerEntry.TableCaption, EmployeeLedgerEntry."Entry No.", EmployeeLedgerEntry."Transaction No.", EmployeeLedgerEntry."Journal Batch Name", EmployeeLedgerEntry."Document Type", EmployeeLedgerEntry."Amount to Apply", EmployeeLedgerEntry."Applies-to Doc. No.", EmployeeLedgerEntry."Applies-to ID", EmployeeLedgerEntry."Source Code");
end;
local procedure InsertRelatedAndAppliedEntries(BankAccountNo: Code[20]; StatementNo: Code[20]; StatementLineNo: Integer; var EmployeeLedgerEntry: Record "Employee Ledger Entry")
var
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry";
DetailedEmployeeLedgerEntry1: Record "Detailed Employee Ledger Entry";
DetailedEmployeeLedgerEntry2: Record "Detailed Employee Ledger Entry";
begin
// Insert the CustomerLedgerEntry to the related entries
PaymentRecRelatedEntry."Entry No." := EmployeeLedgerEntry."Entry No.";
PaymentRecRelatedEntry."Entry Type" := PaymentRecRelatedEntry."Entry Type"::Employee;
PaymentRecRelatedEntry."Bank Account No." := BankAccountNo;
PaymentRecRelatedEntry."Statement No." := StatementNo;
PaymentRecRelatedEntry."Statement Line No." := StatementLineNo;
PaymentRecRelatedEntry.Insert();
// Find entries that this entry was applied to. Insert this entries into PmtRecAppliedToEntry
// we follow the same approach as AppliedVendorEntries.Page.al
DetailedEmployeeLedgerEntry1.SetCurrentKey("Employee Ledger Entry No.");
DetailedEmployeeLedgerEntry1.SetRange("Employee Ledger Entry No.", EmployeeLedgerEntry."Entry No.");
DetailedEmployeeLedgerEntry1.SetRange(Unapplied, false);
if not DetailedEmployeeLedgerEntry1.FindSet() then
exit;
repeat
DetailedEmployeeLedgerEntry2.Reset();
DetailedEmployeeLedgerEntry2.SetCurrentKey("Applied Empl. Ledger Entry No.");
DetailedEmployeeLedgerEntry2.SetRange("Applied Empl. Ledger Entry No.", DetailedEmployeeLedgerEntry1."Applied Empl. Ledger Entry No.");
DetailedEmployeeLedgerEntry2.SetRange("Entry Type", DetailedEmployeeLedgerEntry2."Entry Type"::Application);
DetailedEmployeeLedgerEntry2.SetRange(Unapplied, false);
if DetailedEmployeeLedgerEntry2.FindSet() then
repeat
if DetailedEmployeeLedgerEntry2."Employee Ledger Entry No." <> DetailedEmployeeLedgerEntry2."Applied Empl. Ledger Entry No." then begin
PmtRecAppliedToEntry.Init();
PmtRecAppliedToEntry."Entry No." := DetailedEmployeeLedgerEntry2."Employee Ledger Entry No.";
PmtRecAppliedToEntry.Amount := DetailedEmployeeLedgerEntry2.Amount;
PmtRecAppliedToEntry."Entry Type" := PmtRecAppliedToEntry."Entry Type"::Employee;
PmtRecAppliedToEntry."Bank Account No." := BankAccountNo;
PmtRecAppliedToEntry."Statement No." := StatementNo;
PmtRecAppliedToEntry."Statement Line No." := StatementLineNo;
PmtRecAppliedToEntry."Applied by Entry No." := EmployeeLedgerEntry."Entry No.";
PmtRecAppliedToEntry.Insert();
end;
until DetailedEmployeeLedgerEntry2.Next() = 0;
until DetailedEmployeeLedgerEntry1.Next() = 0;
end;
local procedure InsertRelatedAndAppliedEntries(BankAccountNo: Code[20]; StatementNo: Code[20]; StatementLineNo: Integer; var VendorLedgerEntry: Record "Vendor Ledger Entry")
var
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry";
DetailedVendorLedgEntry1: Record "Detailed Vendor Ledg. Entry";
DetailedVendorLedgEntry2: Record "Detailed Vendor Ledg. Entry";
begin
// Insert the CustomerLedgerEntry to the related entries
PaymentRecRelatedEntry."Entry No." := VendorLedgerEntry."Entry No.";
PaymentRecRelatedEntry."Entry Type" := PaymentRecRelatedEntry."Entry Type"::Vendor;
PaymentRecRelatedEntry."Bank Account No." := BankAccountNo;
PaymentRecRelatedEntry."Statement No." := StatementNo;
PaymentRecRelatedEntry."Statement Line No." := StatementLineNo;
PaymentRecRelatedEntry.Insert();
// Find entries that this entry was applied to. Insert this entries into PmtRecAppliedToEntry
// we follow the same approach as AppliedVendorEntries.Page.al
DetailedVendorLedgEntry1.SetCurrentKey("Vendor Ledger Entry No.");
DetailedVendorLedgEntry1.SetRange("Vendor Ledger Entry No.", VendorLedgerEntry."Entry No.");
DetailedVendorLedgEntry1.SetRange(Unapplied, false);
if not DetailedVendorLedgEntry1.FindSet() then
exit;
repeat
DetailedVendorLedgEntry2.Reset();
DetailedVendorLedgEntry2.SetCurrentKey("Applied Vend. Ledger Entry No.");
DetailedVendorLedgEntry2.SetRange("Applied Vend. Ledger Entry No.", DetailedVendorLedgEntry1."Applied Vend. Ledger Entry No.");
DetailedVendorLedgEntry2.SetRange("Entry Type", DetailedVendorLedgEntry2."Entry Type"::Application);
DetailedVendorLedgEntry2.SetRange(Unapplied, false);
if DetailedVendorLedgEntry2.FindSet() then
repeat
if DetailedVendorLedgEntry2."Vendor Ledger Entry No." <> DetailedVendorLedgEntry2."Applied Vend. Ledger Entry No." then begin
PmtRecAppliedToEntry.Init();
PmtRecAppliedToEntry."Entry No." := DetailedVendorLedgEntry2."Vendor Ledger Entry No.";
PmtRecAppliedToEntry.Amount := DetailedVendorLedgEntry2.Amount;
PmtRecAppliedToEntry."Entry Type" := PmtRecAppliedToEntry."Entry Type"::Vendor;
PmtRecAppliedToEntry."Bank Account No." := BankAccountNo;
PmtRecAppliedToEntry."Statement No." := StatementNo;
PmtRecAppliedToEntry."Statement Line No." := StatementLineNo;
PmtRecAppliedToEntry."Applied by Entry No." := VendorLedgerEntry."Entry No.";
PmtRecAppliedToEntry.Insert();
end;
until DetailedVendorLedgEntry2.Next() = 0;
until DetailedVendorLedgEntry1.Next() = 0;
end;
local procedure InsertRelatedAndAppliedEntries(BankAccountNo: Code[20]; StatementNo: Code[20]; StatementLineNo: Integer; var CustLedgerEntry: Record "Cust. Ledger Entry")
var
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry";
DetailedCustLedgEntry1: Record "Detailed Cust. Ledg. Entry";
DetailedCustLedgEntry2: Record "Detailed Cust. Ledg. Entry";
begin
// Insert the CustomerLedgerEntry to the related entries
PaymentRecRelatedEntry."Entry No." := CustLedgerEntry."Entry No.";
PaymentRecRelatedEntry."Entry Type" := PaymentRecRelatedEntry."Entry Type"::Customer;
PaymentRecRelatedEntry."Bank Account No." := BankAccountNo;
PaymentRecRelatedEntry."Statement No." := StatementNo;
PaymentRecRelatedEntry."Statement Line No." := StatementLineNo;
PaymentRecRelatedEntry.Insert();
// Find entries that this entry was applied to. Insert this entries into PmtRecAppliedToEntry
// we follow the same approach as AppliedCustomerEntries.Page.al
DetailedCustLedgEntry1.SetCurrentKey("Cust. Ledger Entry No.");
DetailedCustLedgEntry1.SetRange("Cust. Ledger Entry No.", CustLedgerEntry."Entry No.");
DetailedCustLedgEntry1.SetRange(Unapplied, false);
if not DetailedCustLedgEntry1.FindSet() then
exit;
repeat
DetailedCustLedgEntry2.Reset();
DetailedCustLedgEntry2.SetCurrentKey("Applied Cust. Ledger Entry No.");
DetailedCustLedgEntry2.SetRange("Applied Cust. Ledger Entry No.", DetailedCustLedgEntry1."Applied Cust. Ledger Entry No.");
DetailedCustLedgEntry2.SetRange("Entry Type", DetailedCustLedgEntry2."Entry Type"::Application);
DetailedCustLedgEntry2.SetRange(Unapplied, false);
if DetailedCustLedgEntry2.FindSet() then
repeat
if DetailedCustLedgEntry2."Cust. Ledger Entry No." <> DetailedCustLedgEntry2."Applied Cust. Ledger Entry No." then begin
PmtRecAppliedToEntry.Init();
PmtRecAppliedToEntry."Entry No." := DetailedCustLedgEntry2."Cust. Ledger Entry No.";
PmtRecAppliedToEntry.Amount := DetailedCustLedgEntry2.Amount;
PmtRecAppliedToEntry."Entry Type" := PmtRecAppliedToEntry."Entry Type"::Customer;
PmtRecAppliedToEntry."Bank Account No." := BankAccountNo;
PmtRecAppliedToEntry."Statement No." := StatementNo;
PmtRecAppliedToEntry."Statement Line No." := StatementLineNo;
PmtRecAppliedToEntry."Applied by Entry No." := CustLedgerEntry."Entry No.";
PmtRecAppliedToEntry.Insert();
end;
until DetailedCustLedgEntry2.Next() = 0;
until DetailedCustLedgEntry1.Next() = 0;
end;
local procedure InsertBankPaymentRecRelatedEntry(var BankAccountLedgerEntry: Record "Bank Account Ledger Entry"; StatementNo: Code[20]; StatementLineNo: Integer)
var
PaymentRecRelatedEntry: Record "Payment Rec. Related Entry";
begin
PaymentRecRelatedEntry."Entry No." := BankAccountLedgerEntry."Entry No.";
PaymentRecRelatedEntry."Entry Type" := PaymentRecRelatedEntry."Entry Type"::"Bank Account";
PaymentRecRelatedEntry."Bank Account No." := BankAccountLedgerEntry."Bank Account No.";
PaymentRecRelatedEntry."Statement No." := StatementNo;
PaymentRecRelatedEntry."Statement Line No." := StatementLineNo;
PaymentRecRelatedEntry.Insert();
end;
local procedure InsertRelatedAndAppliedEntries(BankAccountNo: Code[20]; StatementNo: Code[20]; StatementLineNo: Integer; AccountType: Enum "Gen. Journal Account Type"; var BankAccountLedgerEntry: Record "Bank Account Ledger Entry")
var
CustLedgerEntry: Record "Cust. Ledger Entry";
VendorLedgerEntry: Record "Vendor Ledger Entry";
EmployeeLedgerEntry: Record "Employee Ledger Entry";
begin
InsertBankPaymentRecRelatedEntry(BankAccountLedgerEntry, StatementNo, StatementLineNo);
// Find if there's any Customer, Vendor or Employee related entries for this Bank Account Ledger Entry
case AccountType of
AccountType::Customer:
begin
CustLedgerEntry.SetRange("Document No.", BankAccountLedgerEntry."Document No.");
CustLedgerEntry.SetRange("Posting Date", BankAccountLedgerEntry."Posting Date");
CustLedgerEntry.SetRange(Reversed, false);
CustLedgerEntry.SetRange("Transaction No.", BankAccountLedgerEntry."Transaction No.");
CustLedgerEntry.SetRange("Customer No.", BankAccountLedgerEntry."Bal. Account No.");
OnInsertRelatedAndAppliedEntriesOnAfterFilterCustLedgerEntry(CustLedgerEntry, BankAccountLedgerEntry);
if CustLedgerEntry.FindSet() then
repeat
InsertRelatedAndAppliedEntries(BankAccountNo, StatementNo, StatementLineNo, CustLedgerEntry);
until CustLedgerEntry.Next() = 0;
end;
AccountType::Vendor:
begin
VendorLedgerEntry.SetRange("Document No.", BankAccountLedgerEntry."Document No.");
VendorLedgerEntry.SetRange("Posting Date", BankAccountLedgerEntry."Posting Date");
VendorLedgerEntry.SetRange(Reversed, false);
VendorLedgerEntry.SetRange("Transaction No.", BankAccountLedgerEntry."Transaction No.");
VendorLedgerEntry.SetRange("Vendor No.", BankAccountLedgerEntry."Bal. Account No.");
OnInsertRelatedAndAppliedEntriesOnAfterFilterVendorLedgerEntry(VendorLedgerEntry, BankAccountLedgerEntry);
if VendorLedgerEntry.FindSet() then
repeat
InsertRelatedAndAppliedEntries(BankAccountNo, StatementNo, StatementLineNo, VendorLedgerEntry);
until VendorLedgerEntry.Next() = 0;
end;
AccountType::Employee:
begin
EmployeeLedgerEntry.SetRange("Document No.", BankAccountLedgerEntry."Document No.");
EmployeeLedgerEntry.SetRange("Posting Date", BankAccountLedgerEntry."Posting Date");
EmployeeLedgerEntry.SetRange(Reversed, false);
EmployeeLedgerEntry.SetRange("Transaction No.", BankAccountLedgerEntry."Transaction No.");
EmployeeLedgerEntry.SetRange("Employee No.", BankAccountLedgerEntry."Bal. Account No.");
OnInsertRelatedAndAppliedEntriesOnAfterFilterEmployeeLedgerEntry(EmployeeLedgerEntry, BankAccountLedgerEntry);
if EmployeeLedgerEntry.FindSet() then
repeat
InsertRelatedAndAppliedEntries(BankAccountNo, StatementNo, StatementLineNo, EmployeeLedgerEntry);
until EmployeeLedgerEntry.Next() = 0;
end;
end;
OnAfterInsertRelatedAndAppliedEntries(BankAccountNo, StatementNo, StatementLineNo, AccountType, BankAccountLedgerEntry);
end;
local procedure InsertRelatedAndAppliedEntries(BankAccountNo: Code[20]; StatementNo: Code[20]; StatementLineNo: Integer; AccountType: Enum "Gen. Journal Account Type")
var
BankAccountLedgerEntry: Record "Bank Account Ledger Entry";
begin
BankAccountLedgerEntry.SetRange("Bank Account No.", BankAccountNo);
BankAccountLedgerEntry.SetRange("Statement No.", StatementNo);
BankAccountLedgerEntry.SetRange("Statement Line No.", StatementLineNo);
if not BankAccountLedgerEntry.FindSet() then
exit;
repeat
InsertRelatedAndAppliedEntries(BankAccountNo, StatementNo, StatementLineNo, AccountType, BankAccountLedgerEntry);
until BankAccountLedgerEntry.Next() = 0;
end;
local procedure CreateApplicationEntryForBankAccReconciliationLine(var BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; var PmtRecAppliedToEntry: Record "Pmt. Rec. Applied-to Entry")
var
CustLedgerEntry: Record "Cust. Ledger Entry";
VendorLedgerEntry: Record "Vendor Ledger Entry";
EmployeeLedgerEntry: Record "Employee Ledger Entry";
BankAccount: Record "Bank Account";
TempPaymentApplicationProposal: Record "Payment Application Proposal" temporary;
begin
// To apply the newly created entry Bank Acc. Reconciliation Line to the one it was previously applied,
// we create a temporary "Payment Application Proposal" to trigger it's "Applied" OnValidate
// which will trigger all the required side-effects.
TempPaymentApplicationProposal.Init();
TempPaymentApplicationProposal."Bank Account No." := BankAccReconciliationLine."Bank Account No.";
TempPaymentApplicationProposal."Statement No." := BankAccReconciliationLine."Statement No.";
TempPaymentApplicationProposal."Statement Line No." := BankAccReconciliationLine."Statement Line No.";
TempPaymentApplicationProposal."Statement Type" := BankAccReconciliationLine."Statement Type";
TempPaymentApplicationProposal."Account Type" := BankAccReconciliationLine."Account Type";
TempPaymentApplicationProposal."Account No." := BankAccReconciliationLine."Account No.";
TempPaymentApplicationProposal."Applies-to Entry No." := PmtRecAppliedToEntry."Entry No.";
TempPaymentApplicationProposal."Applied Amount" := PmtRecAppliedToEntry.Amount;
if not BankAccount.Get(BankAccReconciliationLine."Bank Account No.") then;
case PmtRecAppliedToEntry."Entry Type" of
PmtRecAppliedToEntry."Entry Type"::Customer:
begin
if not CustLedgerEntry.Get(PmtRecAppliedToEntry."Entry No.") then;
TempPaymentApplicationProposal.Description := CustLedgerEntry.Description;
TempPaymentApplicationProposal."Posting Date" := CustLedgerEntry."Posting Date";
TempPaymentApplicationProposal."Due Date" := CustLedgerEntry."Due Date";
TempPaymentApplicationProposal."Document Type" := CustLedgerEntry."Document Type";
TempPaymentApplicationProposal."Document No." := CustLedgerEntry."Document No.";
TempPaymentApplicationProposal."External Document No." := CustLedgerEntry."External Document No.";
TempPaymentApplicationProposal."Currency Code" := CustLedgerEntry."Currency Code"
end;
PmtRecAppliedToEntry."Entry Type"::Vendor:
begin
if not VendorLedgerEntry.Get(PmtRecAppliedToEntry."Entry No.") then;
TempPaymentApplicationProposal.Description := VendorLedgerEntry.Description;
TempPaymentApplicationProposal."Posting Date" := VendorLedgerEntry."Posting Date";
TempPaymentApplicationProposal."Due Date" := VendorLedgerEntry."Due Date";
TempPaymentApplicationProposal."Document Type" := VendorLedgerEntry."Document Type";
TempPaymentApplicationProposal."Document No." := VendorLedgerEntry."Document No.";
TempPaymentApplicationProposal."External Document No." := VendorLedgerEntry."External Document No.";
TempPaymentApplicationProposal."Currency Code" := VendorLedgerEntry."Currency Code"
end;
PmtRecAppliedToEntry."Entry Type"::Employee:
begin
if not EmployeeLedgerEntry.Get(PmtRecAppliedToEntry."Entry No.") then;
TempPaymentApplicationProposal.Description := EmployeeLedgerEntry.Description;
TempPaymentApplicationProposal."Posting Date" := EmployeeLedgerEntry."Posting Date";
TempPaymentApplicationProposal."Document Type" := EmployeeLedgerEntry."Document Type";
TempPaymentApplicationProposal."Document No." := EmployeeLedgerEntry."Document No.";
TempPaymentApplicationProposal."Currency Code" := EmployeeLedgerEntry."Currency Code"
end;
end;
TempPaymentApplicationProposal.Quality := 100;
TempPaymentApplicationProposal."Match Confidence" := TempPaymentApplicationProposal."Match Confidence"::High;
TempPaymentApplicationProposal.UpdateDefaultCalculatedFields(BankAccount, TempPaymentApplicationProposal."Applies-to Entry No.");
TempPaymentApplicationProposal.Insert();
TempPaymentApplicationProposal.Validate(Applied, true);
end;
local procedure UnapplyCustomerEntry(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry"; ShowEntriesToPost: Boolean)
var
DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry";
ApplyUnapplyParameters: Record "Apply Unapply Parameters";
CustEntryApplyPostedEntries: Codeunit "CustEntry-Apply Posted Entries";
begin
if ShowEntriesToPost then begin
CustEntryApplyPostedEntries.UnApplyCustLedgEntry(PaymentRecRelatedEntry."Entry No.");
RefreshRelatedEntryReversalStatus(PaymentRecRelatedEntry);
exit;
end;
CustEntryApplyPostedEntries.CheckCustLedgEntryToUnapply(PaymentRecRelatedEntry."Entry No.", DetailedCustLedgEntry);
ApplyUnapplyParameters.Init();
ApplyUnapplyParameters."Document No." := DetailedCustLedgEntry."Document No.";
ApplyUnapplyParameters."Posting Date" := DetailedCustLedgEntry."Posting Date";
CustEntryApplyPostedEntries.PostUnApplyCustomer(DetailedCustLedgEntry, ApplyUnapplyParameters);
end;
local procedure UnapplyVendorEntry(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry"; ShowEntriesToPost: Boolean)
var
DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry";
ApplyUnapplyParameters: Record "Apply Unapply Parameters";
VendEntryApplyPostedEntries: Codeunit "VendEntry-Apply Posted Entries";
begin
if ShowEntriesToPost then begin
VendEntryApplyPostedEntries.UnApplyVendLedgEntry(PaymentRecRelatedEntry."Entry No.");
RefreshRelatedEntryReversalStatus(PaymentRecRelatedEntry);
exit;
end;
VendEntryApplyPostedEntries.CheckVendorLedgerEntryToUnapply(PaymentRecRelatedEntry."Entry No.", DetailedVendorLedgEntry);
ApplyUnapplyParameters.Init();
ApplyUnapplyParameters."Document No." := DetailedVendorLedgEntry."Document No.";
ApplyUnapplyParameters."Posting Date" := DetailedVendorLedgEntry."Posting Date";
VendEntryApplyPostedEntries.PostUnApplyVendor(DetailedVendorLedgEntry, ApplyUnapplyParameters);
end;
local procedure UnapplyEmployeeEntry(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry"; ShowEntriesToPost: Boolean)
var
DetailedEmployeeLedgerEntry: Record "Detailed Employee Ledger Entry";
ApplyUnapplyParameters: Record "Apply Unapply Parameters";
EmplEntryApplyPostedEntries: Codeunit "EmplEntry-Apply Posted Entries";
begin
if ShowEntriesToPost then begin
EmplEntryApplyPostedEntries.UnApplyEmplLedgEntry(PaymentRecRelatedEntry."Entry No.");
RefreshRelatedEntryReversalStatus(PaymentRecRelatedEntry);
exit;
end;
EmplEntryApplyPostedEntries.CheckEmployeeLedgerEntryToUnapply(PaymentRecRelatedEntry."Entry No.", DetailedEmployeeLedgerEntry);
ApplyUnapplyParameters.Init();
ApplyUnapplyParameters."Document No." := DetailedEmployeeLedgerEntry."Document No.";
ApplyUnapplyParameters."Posting Date" := DetailedEmployeeLedgerEntry."Posting Date";
EmplEntryApplyPostedEntries.PostUnApplyEmployee(DetailedEmployeeLedgerEntry, ApplyUnapplyParameters);
end;
local procedure EntryIsReversable(JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AmountToApply: Decimal; AppliesToDocNo: Code[20]; AppliesToID: Code[50]; SourceCode: Code[10]): Boolean
var
SourceCodeSetup: Record "Source Code Setup";
Result: Boolean;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeEntryIsReversable(JournalBatchName, DocumentType, AmountToApply, AppliesToDocNo, AppliesToID, SourceCode, Result, IsHandled);
if IsHandled then
exit(Result);
if SourceCodeSetup.Get() then;
// We allow reversing entries created from normal journals, e.g.: Payment Journal, Cash Receipt, ...
// These entries have by default a "Journal Batch Name" associated.
// This can be used to determine whether the entry is reversible.
exit(
(JournalBatchName <> '') or (
// However, we also want to allow reversal
// of entries created by posting Payment Reconciliation Journals, which don't
// necesarily have a "Journal Batch Name" .
// Entries created from Paym. Rec. Journals, are created by GenJnlPostLine.Codeunit,
// and set the following values for those:
(DocumentType in [DocumentType::" ", DocumentType::Payment, DocumentType::Refund]) and
(AmountToApply = 0) and
(AppliesToDocNo = '') and
(AppliesToID = '') and
// As an extra condition, we also look at the SourceCode value
(SourceCode = SourceCodeSetup."Payment Reconciliation Journal")
)
);
end;
procedure ErrorIfEntryIsNotReversable(Reversed: Boolean; TableCaption: Text; EntryNo: Integer; TransactionNo: Integer; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AmountToApply: Decimal; AppliesToDocNo: Code[20]; AppliesToID: Code[50]; SourceCode: Code[10])
var
ReversalEntry: Record "Reversal Entry";
IsHandled: Boolean;
begin
if Reversed then
ReversalEntry.AlreadyReversedEntry(TableCaption, EntryNo);
IsHandled := false;
OnErrorIfEntryIsNotReversableOnBeforeEntryIsReversable(IsHandled);
if not IsHandled then
if not EntryIsReversable(JournalBatchName, DocumentType, AmountToApply, AppliesToDocNo, AppliesToID, SourceCode) then
ReversalEntry.TestFieldError();
if TransactionNo = 0 then
Error(EmptyTransactionNoErr, EntryNo);
end;
[IntegrationEvent(false, false)]
local procedure OnAfterReverseEntry()
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeReverseEntry(var PaymentRecRelatedEntry: Record "Payment Rec. Related Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnErrorIfEntryIsNotReversableOnBeforeEntryIsReversable(var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCopyPaymentRecJournalFromPostedPaymentReconLinesOnAfterInsertBankAccReconciliationLine(var PostedPaymentReconLine: Record "Posted Payment Recon. Line"; var BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCreateCopyPaymentRecJournal(var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr"; var BankAccReconciliation: Record "Bank Acc. Reconciliation")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeEntryIsReversable(JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AmountToApply: Decimal; AppliesToDocNo: Code[20]; AppliesToID: Code[50]; SourceCode: Code[10]; var Result: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnInsertRelatedAndAppliedEntriesOnAfterFilterCustLedgerEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var BankAccountLedgerEntry: Record "Bank Account Ledger Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnInsertRelatedAndAppliedEntriesOnAfterFilterVendorLedgerEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var BankAccountLedgerEntry: Record "Bank Account Ledger Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnInsertRelatedAndAppliedEntriesOnAfterFilterEmployeeLedgerEntry(var EmployeeLedgerEntry: Record "Employee Ledger Entry"; var BankAccountLedgerEntry: Record "Bank Account Ledger Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterInsertRelatedAndAppliedEntriesOfGLRegister(var GLRegister: Record "G/L Register"; var PostedPaymentReconHdr: Record "Posted Payment Recon. Hdr"; var StatementLineNo: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterInsertRelatedAndAppliedEntries(BankAccountNo: Code[20]; StatementNo: Code[20]; StatementLineNo: Integer; AccountType: Enum "Gen. Journal Account Type"; var BankAccountLedgerEntry: Record "Bank Account Ledger Entry")
begin
end;
}