How to Use the Match and Reconcile Feature for ERPNext Bank Reconciliation

The Match and Reconcile feature in ERPNext automates bank reconciliation by matching imported bank statement lines against existing vouchers or new payment entries, updating the Bank Transaction document status to "Reconciled" upon confirmation.

The ERPNext Match and Reconcile functionality provides a centralized interface within the Frappe framework for aligning bank transactions with accounting vouchers. This feature combines a React-based split-pane UI with Python server-side logic to handle everything from transaction filtering to ledger updates.

Understanding the Match and Reconcile Architecture

The reconciliation workflow operates through a coordinated system of client-side state management and server-side document processing. The interface uses Jotai atoms to track selection states. When you interact with the BankPicker component in BankReconciliation.tsx (lines 44-48), it updates the selectedBankAccountAtom, which triggers the useGetUnreconciledTransactions hook to fetch data via the Frappe RPC endpoint erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions.

Step-by-Step Bank Reconciliation Process

1. Select a Bank Account and Load Transactions

Begin by selecting a bank account from the dropdown picker. The system immediately queries the server using get_bank_transactions to pull all unreconciled items for that account. The UnreconciledTransactions component (starting at line 73 of MatchAndReconcile.tsx) renders these results in the left pane, invoking useGetUnreconciledTransactions (line 84) which ultimately calls erpnext.accounts.doctype.bank_transaction.bank_transaction.get_unreconciled_transactions on the backend.

2. Filter and Search Transaction Lists

Narrow down large transaction lists using the search interface defined around lines 45-110 of MatchAndReconcile.tsx. The implementation uses Fuse.js (lines 97-101) for fuzzy searching against transaction descriptions and references, while the getSearchResults helper (imported from utils) applies client-side filtering. Filter states are stored in dedicated atoms: bankRecTransactionTypeFilter for debit/credit filtering and bankRecAmountFilter for amount ranges.

3. Select Transactions for Matching

Click any row in the unreconciled list to select it. The click handler resides in UnreconciledTransactionItem (lines 84-92) and updates the bankRecSelectedTransactionAtom (line 76). For bulk operations, Shift-click enables multi-selection across the transaction list, storing multiple selections in the atom keyed by bank account name.

4. View Matching Vouchers

Once you select a transaction, the right pane populated by VouchersForTransaction (starting at line 220) displays potential matches. The component calls useGetVouchersForTransaction, which executes the server method get_linked_payments. This function runs check_matching (around line 1110 in bank_reconciliation_tool.py), which builds ranked queries using specific builders like get_pe_matching_query (line 1319) for Payment Entries, get_je_matching_query for Journal Entries, and get_bt_matching_query for opposite bank transactions. The results render via VoucherItem (lines 71-82), with the highest-ranked matches displaying a green "Suggested" badge.

5. Execute Reconciliation or Create Entries

You have two resolution paths:

  • Reconcile against existing voucher: Click the Reconcile button on any listed voucher. This invokes useReconcileTransaction (line 99), which POSTs to the reconcile_vouchers method (line 610 in bank_reconciliation_tool.py). The server loads the Bank Transaction document, calls add_payment_entries (lines 65-72) to link the voucher, runs validation and allocation logic, and sets the status to "Reconciled".

  • Create new voucher: If no match exists, use the action buttons in OptionsForSingleTransaction or OptionsForMultipleTransactions (lines 456-527) to create a Payment Entry, Bank Entry, or Internal Transfer. These call APIs like create_payment_entry_bts (line 308), which builds and submits the document before automatically calling reconcile_vouchers with is_new_voucher=True.

6. Handle Date Range Gaps

If unreconciled transactions exist before your selected date range, the OlderUnreconciledTransactionsBanner (lines 997-1045) appears. This component queries get_older_unreconciled_transactions (defined at line 889 in bank_reconciliation_tool.py) to count items before the from_date and retrieve the oldest date, allowing you to expand the filter range to include historical items.

Core Server-Side Implementation

The reconciliation engine resides in erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py.

Fetching Unreconciled Bank Transactions


# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

@frappe.whitelist()
def get_bank_transactions(
    bank_account: str,
    from_date: str | date | None = None,
    to_date: str | date | None = None,
    all_transactions: bool = False,
):
    # Filters and retrieves Bank Transaction documents

    # Implementation at lines 49-88

Matching Logic and Query Builders


# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

def get_linked_payments(
    bank_transaction_name: str,
    document_types: str | list[str] | None = None,
):
    transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
    # Retrieves GL account and company, then executes matching

    matching = check_matching(gl_account, company, transaction, document_types)
    return subtract_allocations(gl_account, matching)

The check_matching function orchestrates ranked queries for each document type, utilizing specific query builders such as get_pe_matching_query (line 1319) for Payment Entries.

Reconciliation API


# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

@frappe.whitelist()
def reconcile_vouchers(
    bank_transaction_name: str | int,
    vouchers: str,
    is_new_voucher: bool = False
):
    vouchers = json.loads(vouchers)
    transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
    transaction.add_payment_entries(vouchers, is_new_voucher)
    transaction.validate_duplicate_references()
    transaction.allocate_payment_entries()
    transaction.update_allocated_amount()
    transaction.set_status()
    transaction.save()
    return transaction  # Status now "Reconciled"

Creating Payment Entries


# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

def create_payment_entry_bts(
    bank_transaction_name: str,
    reference_number: str | None = None,
    # ... additional parameters

):
    # Constructs Payment Entry document (lines 308-374)

    pe.insert()
    pe.submit()
    # Links and reconciles automatically

    return reconcile_vouchers(
        bank_transaction_name,
        json.dumps([{"payment_entry": pe.name}]),
        is_new_voucher=True
    )

Summary

  • The Match and Reconcile interface in ERPNext provides a split-pane workflow for matching bank transactions to vouchers.
  • Selection logic utilizes Jotai atoms (selectedBankAccountAtom, bankRecSelectedTransactionAtom) to manage UI state.
  • Server-side logic in bank_reconciliation_tool.py handles transaction retrieval, fuzzy matching via check_matching, and final reconciliation through reconcile_vouchers.
  • The system supports both matching against existing documents and creating new Payment Entries, Journal Entries, or Bank Entries on the fly.
  • Date range management includes warnings for older unreconciled items via get_older_unreconciled_transactions.

Frequently Asked Questions

What document types does the Match and Reconcile feature support?

According to the ERPNext source code, the matching engine queries Payment Entry, Journal Entry, Sales Invoice, Purchase Invoice, and opposite Bank Transaction documents. The check_matching function in bank_reconciliation_tool.py builds specific SQL queries for each type, such as get_pe_matching_query for payments and get_je_matching_query for journal entries.

How does ERPNext determine which vouchers match a bank transaction?

The system retrieves the bank account's GL account and company, then passes these to check_matching (around line 1110). This function executes ranked queries comparing amounts, dates, and references. Results are scored and returned to the UI, where the top match receives a "Suggested" indicator.

Can I reconcile multiple bank transactions simultaneously?

Yes. The UI supports Shift-click multi-selection in the UnreconciledTransactionItem component (lines 84-92), storing multiple selections in bankRecSelectedTransactionAtom. When multiple transactions are selected, the OptionsForMultipleTransactions component (lines 456-527) provides actions to create consolidated entries or reconcile against matching vouchers.

What happens to the Bank Transaction document after reconciliation?

When you confirm reconciliation, the reconcile_vouchers method (line 610) loads the Bank Transaction document, invokes add_payment_entries (lines 65-72) to link the voucher allocations, validates for duplicates, updates the allocated amount, and calls set_status(). The document status changes to "Reconciled", the unallocated amount drops to zero, and the ledger reflects the matched entries.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →