Table 1250 Bank Statement Matching Buffer

App
Base Application
Namespace
Microsoft.Bank.Reconciliation
Versions
17-28

Fields, 18Keys, 2Procedures, 2Events, 2

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/Bank/Reconciliation/BankStatementMatchingBuffer.Table.al274 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.Finance.GeneralLedger.Journal;

/// <summary>
/// Temporary buffer table for storing and ranking potential matches during automatic bank reconciliation.
/// This table accumulates candidate ledger entries that could potentially match with bank statement lines,
/// along with scoring information, quality metrics, and matching criteria details. Used internally by
/// matching algorithms to evaluate, rank, and select the best matches based on configurable rules and
/// thresholds before applying final matching decisions.
/// </summary>
/// <remarks>
/// Key features include match quality scoring, detailed criteria tracking (amounts, dates, document numbers),
/// one-to-many relationship handling, related party matching status, and comprehensive match details for
/// audit and review purposes. The buffer enables sophisticated ranking algorithms that consider multiple
/// matching factors simultaneously, supporting both exact and fuzzy matching scenarios with weighted scoring.
/// Used exclusively during matching processes and cleared after each matching operation completion.
/// </remarks>
table 1250 "Bank Statement Matching Buffer"
{
    Caption = 'Bank Statement Matching Buffer';
    ReplicateData = false;
    TableType = Temporary;
    DataClassification = CustomerContent;

    fields
    {
        /// <summary>
        /// Bank statement line number being evaluated for matching.
        /// References the source statement line for which potential matches are being identified.
        /// </summary>
        field(1; "Line No."; Integer)
        {
            Caption = 'Line No.';
        }
        /// <summary>
        /// Ledger entry number of the potential match candidate.
        /// References the bank account, customer, vendor, or GL entry that could match the statement line.
        /// </summary>
        field(2; "Entry No."; Integer)
        {
            Caption = 'Entry No.';
        }
        /// <summary>
        /// Match quality score indicating the strength of the potential match.
        /// Higher scores represent better matches based on multiple matching criteria and algorithms.
        /// </summary>
        field(3; Quality; Integer)
        {
            Caption = 'Quality';
        }
        /// <summary>
        /// Type of account for the potential match candidate.
        /// Determines whether the match is against a customer, vendor, bank account, or GL account entry.
        /// </summary>
        field(4; "Account Type"; Enum "Gen. Journal Account Type")
        {
            Caption = 'Account Type';
        }
        /// <summary>
        /// Account number of the potential match candidate.
        /// Identifies the specific customer, vendor, bank account, or GL account for the match.
        /// </summary>
        field(5; "Account No."; Code[20])
        {
            Caption = 'Account No.';
        }
        /// <summary>
        /// Indicates if this match represents a one-to-many relationship scenario.
        /// True when one statement line could potentially match multiple ledger entries.
        /// </summary>
        field(10; "One to Many Match"; Boolean)
        {
            Caption = 'One to Many Match';
        }
        /// <summary>
        /// Number of related entries in a one-to-many or many-to-one matching scenario.
        /// Used for aggregating multiple entries that collectively match a single statement line.
        /// </summary>
        field(11; "No. of Entries"; Integer)
        {
            Caption = 'No. of Entries';
        }
        /// <summary>
        /// Total remaining amount across multiple entries in complex matching scenarios.
        /// Calculated sum for one-to-many matches to compare against statement line amount.
        /// </summary>
        field(12; "Total Remaining Amount"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Total Remaining Amount';
        }
        /// <summary>
        /// Status of related party matching for the potential match candidate.
        /// Indicates whether customer/vendor information matches the statement line party details.
        /// </summary>
        field(13; "Related Party Matched"; Option)
        {
            Caption = 'Related Party Matched';
            OptionCaption = 'Not Considered,Fully,Partially,No';
            OptionMembers = "Not Considered",Fully,Partially,No;
        }
        /// <summary>
        /// Detailed description of matching criteria that contributed to the match score.
        /// Provides audit trail and explanation of why this candidate was identified as a potential match.
        /// </summary>
        field(14; "Match Details"; Text[250])
        {
            Caption = 'Match Details';
        }
        /// <summary>
        /// Score contribution from document number matching algorithms.
        /// Measures how well the statement line document reference matches the ledger entry document number.
        /// </summary>
        field(15; "Doc. No. Score"; Integer)
        {
            Caption = 'Document No. Score';
        }
        /// <summary>
        /// Score contribution from external document number matching algorithms.
        /// Measures how well the statement line reference matches the ledger entry external document number.
        /// </summary>
        field(16; "Ext. Doc. No. Score"; Integer)
        {
            Caption = 'External Document No. Score';
        }
        /// <summary>
        /// Score contribution from description and narrative text matching algorithms.
        /// Measures similarity between statement line description and ledger entry description.
        /// </summary>
        field(17; "Description Score"; Integer)
        {
            Caption = 'Description Score';
        }
        /// <summary>
        /// Amount difference between statement line and potential match candidate.
        /// Used to evaluate amount-based matching tolerance and precision.
        /// </summary>
        field(18; "Amount Difference"; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Amount Matches';
        }
        /// <summary>
        /// Date difference in days between statement line and potential match candidate.
        /// Used to evaluate date-based matching tolerance and temporal proximity.
        /// </summary>
        field(19; "Date Difference"; Integer)
        {
            Caption = 'Date Matches';
        }
        /// <summary>
        /// Score for exact document number matches without fuzzy logic.
        /// Higher weight given to precise document number correspondences.
        /// </summary>
        field(20; "Doc. No. Exact Score"; Integer)
        {
            Caption = 'Doc. No. Exact Score';
        }
        /// <summary>
        /// Score for exact external document number matches without fuzzy logic.
        /// Higher weight given to precise external document number correspondences.
        /// </summary>
        field(21; "Ext. Doc. No. Exact Score"; Integer)
        {
            Caption = 'Ext. Doc. No. Exact Score';
        }
        /// <summary>
        /// Score for exact description matches without fuzzy logic.
        /// Higher weight given to precise description text correspondences.
        /// </summary>
        field(22; "Description Exact Score"; Integer)
        {
            Caption = 'Description Exact Score';
        }
    }

    keys
    {
        key(Key1; "Line No.", "Entry No.", "Account Type", "Account No.")
        {
            Clustered = true;
        }
        key(Key2; Quality, "No. of Entries")
        {
        }
    }

    fieldgroups
    {
    }

    /// <summary>
    /// Adds or updates a match candidate entry in the temporary buffer for ranking and evaluation.
    /// Creates new buffer entries for potential matches or updates existing entries with improved quality scores.
    /// Used during the matching process to accumulate and rank all possible match candidates.
    /// </summary>
    /// <param name="LineNo">Bank statement line number being matched.</param>
    /// <param name="EntryNo">Ledger entry number of the potential match candidate.</param>
    /// <param name="NewQuality">Quality score for this match candidate based on matching algorithms.</param>
    /// <param name="AccountType">Type of account for the match candidate (Customer, Vendor, Bank Account, etc.).</param>
    /// <param name="AccountNo">Account number of the match candidate.</param>
    procedure AddMatchCandidate(LineNo: Integer; EntryNo: Integer; NewQuality: Integer; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20])
    var
        BankStatementMatchingBuffer: Record "Bank Statement Matching Buffer";
    begin
        BankStatementMatchingBuffer.Init();
        BankStatementMatchingBuffer."Line No." := LineNo;
        BankStatementMatchingBuffer."Entry No." := EntryNo;
        BankStatementMatchingBuffer."Account No." := AccountNo;
        BankStatementMatchingBuffer."Account Type" := AccountType;
        BankStatementMatchingBuffer.Quality := NewQuality;
        OnAddMatchCandidateOnAfterAssignBankStatementMatchingBufferValues(Rec, BankStatementMatchingBuffer);
        if Get(LineNo, EntryNo, AccountType, AccountNo) then begin
            Rec := BankStatementMatchingBuffer;
            Modify();
        end else begin
            Rec := BankStatementMatchingBuffer;
            Insert();
        end;
    end;

    /// <summary>
    /// Inserts or updates a one-to-many matching rule for scenarios where multiple ledger entries match a single statement line.
    /// Manages complex matching relationships by aggregating multiple entries under a common account and calculating
    /// collective remaining amounts and quality scores for the one-to-many matching evaluation.
    /// </summary>
    /// <param name="TempLedgerEntryMatchingBuffer">Source ledger entry data for the one-to-many relationship.</param>
    /// <param name="LineNo">Bank statement line number participating in the one-to-many match.</param>
    /// <param name="RelatedPartyMatched">Status of related party matching for this relationship.</param>
    /// <param name="AccountType">Type of account involved in the one-to-many relationship.</param>
    /// <param name="RemainingAmount">Remaining amount contribution from this entry to the total match amount.</param>
    procedure InsertOrUpdateOneToManyRule(TempLedgerEntryMatchingBuffer: Record "Ledger Entry Matching Buffer" temporary; LineNo: Integer; RelatedPartyMatched: Option; AccountType: Enum "Gen. Journal Account Type"; RemainingAmount: Decimal)
    begin
        Init();
        SetRange("Line No.", LineNo);
        SetRange("Account Type", AccountType);
        SetRange("Account No.", TempLedgerEntryMatchingBuffer."Account No.");
        SetRange("Entry No.", -1);
        SetRange("One to Many Match", true);

        if not FindFirst() then begin
            "Line No." := LineNo;
            "Account Type" := AccountType;
            "Account No." := TempLedgerEntryMatchingBuffer."Account No.";
            "Entry No." := -1;
            "One to Many Match" := true;
            "No. of Entries" := 1;
            "Related Party Matched" := RelatedPartyMatched;
            OnInsertOrUpdateOneToManyRuleOnBeforeInsert(Rec, TempLedgerEntryMatchingBuffer);
            Insert();
        end else
            "No. of Entries" += 1;

        "Total Remaining Amount" += RemainingAmount;
        Modify(true);
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAddMatchCandidateOnAfterAssignBankStatementMatchingBufferValues(var BankStatementMatchingBuffer: Record "Bank Statement Matching Buffer"; var BankStatementMatchingBuffer2: Record "Bank Statement Matching Buffer")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnInsertOrUpdateOneToManyRuleOnBeforeInsert(var BankStatementMatchingBuffer: Record "Bank Statement Matching Buffer"; TempLedgerEntryMatchingBuffer: Record "Ledger Entry Matching Buffer" temporary)
    begin
    end;
}