From 44adf59eea9284b5baaedf2b9d7edc3536db7cf4 Mon Sep 17 00:00:00 2001 From: Jesper Schulz-Wedde Date: Tue, 30 Jun 2026 14:59:05 +0200 Subject: [PATCH] Match Bank Payments: pass Payment Reference to DocumentMatching DocumentMatching in codeunit 1255 "Match Bank Payments" already accepts a PaymentReference parameter, but the W1 call site hardcoded '' so the bank rec line's Payment Reference No. was never matched against an open ledger entry's payment reference (typical SEPA flow). Pass TempLedgerEntryMatchingBuffer."Payment Reference" instead. Behavior is unchanged for empty references since DocumentMatching early-exits when PaymentReference = ''. Ported from internal NAV PR 249652 (originally microsoft/BusinessCentralApps#1912). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MatchBankPayments.Codeunit.al | 3 +- .../Bank/BankPmtApplAlgorithm.Codeunit.al | 50 +++++++++++++++++++ .../Bank/BankPmtApplAlgorithm.Codeunit.al | 50 +++++++++++++++++++ .../Bank/BankPmtApplAlgorithm.Codeunit.al | 50 +++++++++++++++++++ .../MatchBankPayments.Codeunit.al | 3 +- .../Bank/BankPmtApplAlgorithm.Codeunit.al | 50 +++++++++++++++++++ 6 files changed, 204 insertions(+), 2 deletions(-) diff --git a/src/Layers/CH/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al b/src/Layers/CH/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al index 3de2e06726..69d4a4b6a8 100644 --- a/src/Layers/CH/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al +++ b/src/Layers/CH/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al @@ -1081,7 +1081,8 @@ codeunit 1255 "Match Bank Payments" DocumentMatching( BankPmtApplRule, BankAccReconciliationLine, TempLedgerEntryMatchingBuffer."Document No.", - TempLedgerEntryMatchingBuffer."External Document No.", TempLedgerEntryMatchingBuffer."Payment Reference"); + TempLedgerEntryMatchingBuffer."External Document No.", + TempLedgerEntryMatchingBuffer."Payment Reference"); TotalTimeDocumentNoMatching += CurrentDateTime() - StartTime; end else begin StartTime := CurrentDateTime(); diff --git a/src/Layers/CH/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al b/src/Layers/CH/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al index a58ba81575..af706f1824 100644 --- a/src/Layers/CH/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al +++ b/src/Layers/CH/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al @@ -429,6 +429,56 @@ BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); end; + [Test] + [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] + [Scope('OnPrem')] + procedure TestCustPaymentReferenceMatch() + var + BankAccReconciliation: Record "Bank Acc. Reconciliation"; + BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; + Customer: Record Customer; + CustLedgerEntry: Record "Cust. Ledger Entry"; + BankPmtApplRule: Record "Bank Pmt. Appl. Rule"; + Amount: Decimal; + DocumentNo: Code[20]; + ExtDocNo: Code[20]; + PaymentReference: Code[50]; + begin + Initialize(); + + // Setup + CreateCustomer(Customer); + Amount := LibraryRandom.RandDecInRange(1, 1000, 2); + ExtDocNo := ''; + PaymentReference := 'PMTREF0001'; + DocumentNo := CreateAndPostSalesInvoiceWithOneLine(Customer."No.", ExtDocNo, Amount); + + // The W1 Sales Header has no Payment Reference field, so set the reference on the open ledger entry + CustLedgerEntry.SetRange("Document Type", CustLedgerEntry."Document Type"::Invoice); + CustLedgerEntry.SetRange("Customer No.", Customer."No."); + CustLedgerEntry.SetRange("Document No.", DocumentNo); + CustLedgerEntry.FindFirst(); + CustLedgerEntry."Payment Reference" := PaymentReference; + CustLedgerEntry.Modify(); + + CreateBankReconciliationAmountTolerance(BankAccReconciliation, 0); + // No document number in the transaction text, so the payment reference is the only possible match + CreateBankReconciliationLine(BankAccReconciliation, BankAccReconciliationLine, Amount / 2, '', ''); + BankAccReconciliationLine.Validate("Payment Reference No.", PaymentReference); + BankAccReconciliationLine.Modify(true); + + // Exercise + RunMatch(BankAccReconciliation, true); + + // Verify + SetRule(BankPmtApplRule, BankPmtApplRule."Related Party Matched"::No, + BankPmtApplRule."Doc. No./Ext. Doc. No. Matched"::Yes, BankPmtApplRule."Amount Incl. Tolerance Matched"::"No Matches"); + VerifyReconciliation(BankPmtApplRule, BankAccReconciliationLine."Statement Line No."); + VerifyEntryApplied(BankAccReconciliationLine, false); + VerifyMatchDetailsData(BankAccReconciliation, BankPmtApplRule, + BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); + end; + [Test] [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] [Scope('OnPrem')] diff --git a/src/Layers/DK/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al b/src/Layers/DK/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al index 156ac67890..d3d264c8d1 100644 --- a/src/Layers/DK/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al +++ b/src/Layers/DK/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al @@ -429,6 +429,56 @@ BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); end; + [Test] + [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] + [Scope('OnPrem')] + procedure TestCustPaymentReferenceMatch() + var + BankAccReconciliation: Record "Bank Acc. Reconciliation"; + BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; + Customer: Record Customer; + CustLedgerEntry: Record "Cust. Ledger Entry"; + BankPmtApplRule: Record "Bank Pmt. Appl. Rule"; + Amount: Decimal; + DocumentNo: Code[20]; + ExtDocNo: Code[20]; + PaymentReference: Code[50]; + begin + Initialize(); + + // Setup + CreateCustomer(Customer); + Amount := LibraryRandom.RandDecInRange(1, 1000, 2); + ExtDocNo := ''; + PaymentReference := 'PMTREF0001'; + DocumentNo := CreateAndPostSalesInvoiceWithOneLine(Customer."No.", ExtDocNo, Amount); + + // The W1 Sales Header has no Payment Reference field, so set the reference on the open ledger entry + CustLedgerEntry.SetRange("Document Type", CustLedgerEntry."Document Type"::Invoice); + CustLedgerEntry.SetRange("Customer No.", Customer."No."); + CustLedgerEntry.SetRange("Document No.", DocumentNo); + CustLedgerEntry.FindFirst(); + CustLedgerEntry."Payment Reference" := PaymentReference; + CustLedgerEntry.Modify(); + + CreateBankReconciliationAmountTolerance(BankAccReconciliation, 0); + // No document number in the transaction text, so the payment reference is the only possible match + CreateBankReconciliationLine(BankAccReconciliation, BankAccReconciliationLine, Amount / 2, '', ''); + BankAccReconciliationLine.Validate("Payment Reference No.", PaymentReference); + BankAccReconciliationLine.Modify(true); + + // Exercise + RunMatch(BankAccReconciliation, true); + + // Verify + SetRule(BankPmtApplRule, BankPmtApplRule."Related Party Matched"::No, + BankPmtApplRule."Doc. No./Ext. Doc. No. Matched"::Yes, BankPmtApplRule."Amount Incl. Tolerance Matched"::"No Matches"); + VerifyReconciliation(BankPmtApplRule, BankAccReconciliationLine."Statement Line No."); + VerifyEntryApplied(BankAccReconciliationLine, false); + VerifyMatchDetailsData(BankAccReconciliation, BankPmtApplRule, + BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); + end; + [Test] [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] [Scope('OnPrem')] diff --git a/src/Layers/IT/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al b/src/Layers/IT/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al index 4f425cb23a..77da9f4be5 100644 --- a/src/Layers/IT/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al +++ b/src/Layers/IT/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al @@ -430,6 +430,56 @@ BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); end; + [Test] + [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] + [Scope('OnPrem')] + procedure TestCustPaymentReferenceMatch() + var + BankAccReconciliation: Record "Bank Acc. Reconciliation"; + BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; + Customer: Record Customer; + CustLedgerEntry: Record "Cust. Ledger Entry"; + BankPmtApplRule: Record "Bank Pmt. Appl. Rule"; + Amount: Decimal; + DocumentNo: Code[20]; + ExtDocNo: Code[20]; + PaymentReference: Code[50]; + begin + Initialize(); + + // Setup + CreateCustomer(Customer); + Amount := LibraryRandom.RandDecInRange(1, 1000, 2); + ExtDocNo := ''; + PaymentReference := 'PMTREF0001'; + DocumentNo := CreateAndPostSalesInvoiceWithOneLine(Customer."No.", ExtDocNo, Amount); + + // The W1 Sales Header has no Payment Reference field, so set the reference on the open ledger entry + CustLedgerEntry.SetRange("Document Type", CustLedgerEntry."Document Type"::Invoice); + CustLedgerEntry.SetRange("Customer No.", Customer."No."); + CustLedgerEntry.SetRange("Document No.", DocumentNo); + CustLedgerEntry.FindFirst(); + CustLedgerEntry."Payment Reference" := PaymentReference; + CustLedgerEntry.Modify(); + + CreateBankReconciliationAmountTolerance(BankAccReconciliation, 0); + // No document number in the transaction text, so the payment reference is the only possible match + CreateBankReconciliationLine(BankAccReconciliation, BankAccReconciliationLine, Amount / 2, '', ''); + BankAccReconciliationLine.Validate("Payment Reference No.", PaymentReference); + BankAccReconciliationLine.Modify(true); + + // Exercise + RunMatch(BankAccReconciliation, true); + + // Verify + SetRule(BankPmtApplRule, BankPmtApplRule."Related Party Matched"::No, + BankPmtApplRule."Doc. No./Ext. Doc. No. Matched"::Yes, BankPmtApplRule."Amount Incl. Tolerance Matched"::"No Matches"); + VerifyReconciliation(BankPmtApplRule, BankAccReconciliationLine."Statement Line No."); + VerifyEntryApplied(BankAccReconciliationLine, false); + VerifyMatchDetailsData(BankAccReconciliation, BankPmtApplRule, + BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); + end; + [Test] [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] [Scope('OnPrem')] diff --git a/src/Layers/W1/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al b/src/Layers/W1/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al index 7019afd334..88597bc3ba 100644 --- a/src/Layers/W1/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al +++ b/src/Layers/W1/BaseApp/Bank/Reconciliation/MatchBankPayments.Codeunit.al @@ -1078,7 +1078,8 @@ codeunit 1255 "Match Bank Payments" DocumentMatching( BankPmtApplRule, BankAccReconciliationLine, TempLedgerEntryMatchingBuffer."Document No.", - TempLedgerEntryMatchingBuffer."External Document No.", ''); + TempLedgerEntryMatchingBuffer."External Document No.", + TempLedgerEntryMatchingBuffer."Payment Reference"); TotalTimeDocumentNoMatching += CurrentDateTime() - StartTime; end else begin StartTime := CurrentDateTime(); diff --git a/src/Layers/W1/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al b/src/Layers/W1/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al index 8009d65c56..64830b8f60 100644 --- a/src/Layers/W1/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al +++ b/src/Layers/W1/Tests/Bank/BankPmtApplAlgorithm.Codeunit.al @@ -429,6 +429,56 @@ BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); end; + [Test] + [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] + [Scope('OnPrem')] + procedure TestCustPaymentReferenceMatch() + var + BankAccReconciliation: Record "Bank Acc. Reconciliation"; + BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; + Customer: Record Customer; + CustLedgerEntry: Record "Cust. Ledger Entry"; + BankPmtApplRule: Record "Bank Pmt. Appl. Rule"; + Amount: Decimal; + DocumentNo: Code[20]; + ExtDocNo: Code[20]; + PaymentReference: Code[50]; + begin + Initialize(); + + // Setup + CreateCustomer(Customer); + Amount := LibraryRandom.RandDecInRange(1, 1000, 2); + ExtDocNo := ''; + PaymentReference := 'PMTREF0001'; + DocumentNo := CreateAndPostSalesInvoiceWithOneLine(Customer."No.", ExtDocNo, Amount); + + // The W1 Sales Header has no Payment Reference field, so set the reference on the open ledger entry + CustLedgerEntry.SetRange("Document Type", CustLedgerEntry."Document Type"::Invoice); + CustLedgerEntry.SetRange("Customer No.", Customer."No."); + CustLedgerEntry.SetRange("Document No.", DocumentNo); + CustLedgerEntry.FindFirst(); + CustLedgerEntry."Payment Reference" := PaymentReference; + CustLedgerEntry.Modify(); + + CreateBankReconciliationAmountTolerance(BankAccReconciliation, 0); + // No document number in the transaction text, so the payment reference is the only possible match + CreateBankReconciliationLine(BankAccReconciliation, BankAccReconciliationLine, Amount / 2, '', ''); + BankAccReconciliationLine.Validate("Payment Reference No.", PaymentReference); + BankAccReconciliationLine.Modify(true); + + // Exercise + RunMatch(BankAccReconciliation, true); + + // Verify + SetRule(BankPmtApplRule, BankPmtApplRule."Related Party Matched"::No, + BankPmtApplRule."Doc. No./Ext. Doc. No. Matched"::Yes, BankPmtApplRule."Amount Incl. Tolerance Matched"::"No Matches"); + VerifyReconciliation(BankPmtApplRule, BankAccReconciliationLine."Statement Line No."); + VerifyEntryApplied(BankAccReconciliationLine, false); + VerifyMatchDetailsData(BankAccReconciliation, BankPmtApplRule, + BankAccReconciliationLine."Account Type"::Customer, Amount / 2, 0, 0, 1); + end; + [Test] [HandlerFunctions('MessageHandler,VerifyMatchDetailsOnPaymentApplicationsPage')] [Scope('OnPrem')]