Skip to content

About

Automated multi-tier financial reconciliation engine matching bank statement transactions against open receivables

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

recon-engine

CI Python Dependencies License

Deterministic and heuristic financial reconciliation engine matching bank statement transactions against open receivables (invoices).

Designed to automate accounting close cycles, accounts receivable (AR) settlement, and ERP invoice-clearing workflows.

The Problem

In enterprise finance operations, matching bank deposits (EFT, Havale, wire transfers) against issued e-invoices is labor-intensive and error-prone:

  • Customers often omit invoice numbers or make typos in transfer descriptions.
  • Partial payments and combined payments create discrepancies.
  • Double-allocations lead to accounting ledger corruption.

recon-engine implements a tiered, confidence-scored matching pipeline that guarantees zero double-allocation and surfaces exact reconciliation decisions.

Matching Pipeline

flowchart TD
    TX[Bank Credit Transaction] --> T1{Tier 1: Invoice Number & Exact Amount}
    T1 -- Yes --> C1[CONFIRMED 1.0<br/>Auto-reconcile]
    T1 -- No --> T2{Tier 2: Tax ID VKN/TCKN & Exact Amount}
    T2 -- Yes --> C2[CONFIRMED 0.95<br/>Auto-reconcile]
    T2 -- No --> T3{Tier 3: Invoice Number Found<br/>Different Amount}
    T3 -- Less --> P1[PARTIAL 0.95<br/>Allocate partial]
    T3 -- More --> O1[OVERPAID 0.90<br/>Flag surplus]
    T3 -- No --> T4{Tier 4: Customer Name Tokens & Exact Amount}
    T4 -- Yes --> M1[PROPOSED 0.85<br/>Manual sign-off]
    T4 -- No --> T5{Tier 5: Unique Amount Match}
    T5 -- Yes --> M2[PROPOSED 0.70<br/>Manual sign-off]
    T5 -- No --> U[UNMATCHED 0.0<br/>Investigation queue]
Loading

Matching Strategy Matrix

Tier Rule Status Confidence Action
1 Invoice Number found + Exact Amount CONFIRMED 1.00 Immediate auto-clear in ERP
2 Customer Tax ID (VKN/TCKN) + Exact Amount CONFIRMED 0.95 Auto-clear in ERP
3a Invoice Number found + Amount < Invoice PARTIAL 0.95 Allocate partial, keep invoice open
3b Invoice Number found + Amount > Invoice OVERPAID 0.90 Clear invoice, credit balance forward
4 Customer Name Tokens + Exact Amount PROPOSED 0.85 Suggested match for accountant
5 Single Unique Invoice with Matching Amount PROPOSED 0.70 Suggested match for accountant
6 No rule satisfied UNMATCHED 0.00 Queue for manual review

Features

  • Double-Allocation Guard: Once an invoice is matched or allocated, it is isolated from candidate pools for subsequent transactions in the run.
  • Turkish Character Normalization: Robust normalization of Turkish characters (İ, ı, Ğ, ğ, Ü, ü, Ş, ş, Ö, ö, Ç, ç) and punctuation in bank transaction descriptions.
  • Exact Decimal Math: Eliminates float rounding bugs by enforcing decimal.Decimal throughout.
  • Zero Runtime Dependencies: Built purely with Python standard library.

Installation

pip install recon-engine

Usage

from decimal import Decimal
from recon_engine import InvoiceRecord, TransactionRecord, ReconciliationEngine, MatchStatus

# 1. Define open invoices
invoices = [
    InvoiceRecord(
        invoice_id="INV-001",
        number="EDM2026000000042",
        customer_tax_id="1234567890",
        customer_name="Acme Teknoloji A.Ş.",
        amount=Decimal("15000.00"),
    ),
    InvoiceRecord(
        invoice_id="INV-002",
        number="EDM2026000000043",
        customer_tax_id="9876543210",
        customer_name="Beta Lojistik Ltd.",
        amount=Decimal("4500.50"),
    ),
]

# 2. Define bank transactions (from mt940-camt-parser)
transactions = [
    TransactionRecord(
        transaction_id="TX-101",
        amount=Decimal("15000.00"),
        description="HAVALE EDM2026000000042 FATURA BEDELI",
    ),
    TransactionRecord(
        transaction_id="TX-102",
        amount=Decimal("4500.50"),
        description="GELEN HAVALE VKN 9876543210",
    ),
]

# 3. Run reconciliation
engine = ReconciliationEngine(invoices)
summary = engine.reconcile(transactions)

print(f"Total Transactions: {summary.total_transactions}")
print(f"Confirmed Matches:  {summary.confirmed_matches}")
print(f"Unmatched:          {summary.unmatched_transactions}")

for r in summary.results:
    print(f"TX {r.transaction_id} -> INV {r.invoice_id} [{r.status.value}] ({r.confidence * 100:.0f}%) via {r.rule_applied}")

Running Tests

python -m unittest discover tests

License

MIT © Yasin BALÇIK

About

Automated multi-tier financial reconciliation engine matching bank statement transactions against open receivables

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages