Enterprise-grade financial reconciliation engine — deterministic, auditable, and modular.
ReconSmart reconciles ledger and bank statement data by modeling financial events, not merely matching rows. Every match decision is explainable, every run is auditable, and the engine produces identical output given identical inputs.
- Python ≥ 3.13
- uv package manager (install guide)
git clone https://github.com/Blu-Chips/ReconSmart.git
cd ReconSmart
uv syncuv run python -m backend.app.main reconcile \
--ledger sample_data/ledger/USD_LEDGER\ I\&M_Jan\ 2026.xlsx \
--bank sample_data/bank/USD_BANK\ TRN\ I\&M_Jan\ 2026_v2.xlsxOutput is written to output/ by default:
reconciliation_<run_id>.xlsx— multi-sheet Excel reportaudit_<run_id>.jsonl— immutable audit trail
uv run python -m backend.app.main import \
--file sample_data/ledger/USD_LEDGER\ I\&M_Jan\ 2026.xlsx \
--profile ledger| Command | Flag | Description |
|---|---|---|
reconcile |
--ledger, -l |
Path to ledger .xlsx file |
--bank, -b |
Path to bank statement .xlsx file | |
--output, -o |
Output directory (default: output/) |
|
--threshold, -t |
Minimum score for MATCHED (default: 70) | |
--max-date-delta |
Max calendar-day gap for date matching (default: 2) | |
--verbose, -v |
Enable DEBUG logging | |
import |
--file, -f |
Path to Excel file |
--profile, -p |
Import profile: ledger or bank |
|
version |
Print version |
backend/app/
├── main.py # Typer CLI entry point
├── core/
│ └── logging.py # Loguru configuration
└── engine/
├── config.py # ReconciliationConfig (externalized rules)
├── reconciliation_engine.py # Central orchestrator
├── run.py # ReconciliationRun result container
├── importer/ # Excel → Transaction pipeline
│ ├── excel_reader.py # pandas/openpyxl reader
│ ├── profiles.py # Column-mapping profiles
│ └── transaction_importer.py # Profile-driven importer
├── matcher/ # Matching algorithms
│ ├── candidate_generator.py # Deterministic candidate scoring
│ ├── exact_matcher.py # Greedy 1-to-1 assignment
│ ├── match.py # MatchResult dataclass
│ └── scorer.py # Transaction pair scorer
├── models/
│ └── transaction.py # Frozen Pydantic Transaction model
├── normalizer/
│ └── normalizer.py # Text/reference normalization
├── audit/
│ └── audit_logger.py # Immutable audit trail (JSON Lines)
└── reporting/
└── excel_report.py # Brown-style Excel report generator
Excel Files → TransactionImporter → Transaction[]
↓
ReconciliationEngine
┌────────────┼────────────┐
↓ ↓ ↓
MATCHED REVIEW UNMATCHED
↓ ↓ ↓
ExcelReport (flagged) (listed)
↓
AuditLogger → .jsonl
| Evidence | Points | Condition |
|---|---|---|
| Amount exact | 60 | Ledger amount == Bank amount (hard gate) |
| Reference exact | 25 | Normalized references match |
| Date exact | 15 | Same transaction date |
| Date window | 10 | Dates within ±N days (default 2) |
| Description exact | 5 | Normalized descriptions match |
Max score: 105 · Match threshold: 70 (configurable) · Scores below threshold → REVIEW
uv run pytest -vuv run ruff check .
uv run mypy backend tests
uv run black --check .- Strict mypy — no untyped definitions
- Ruff — linting with 100-char line length
- Black — formatting with 100-char line length
- Frozen models — Pydantic
ConfigDict(frozen=True)anddataclass(frozen=True) - No global state — all dependencies injected
| File | Source | Dimensions |
|---|---|---|
sample_data/ledger/USD_LEDGER I&M_Jan 2026.xlsx |
Sage 300 GL export | 927 rows × 42 cols |
sample_data/bank/USD_BANK TRN I&M_Jan 2026_v2.xlsx |
I&M Bank (Kenya) | 1,028 rows × 7 cols |
sample_data/expected/SAGE300_BROWN_I&M USD_DEC 2025.xlsx |
Brown reconciliation | 756 + 732 rows |
| Version | Scope | Status |
|---|---|---|
| v0.1.0 | Deterministic exact matching, Excel report, audit trail | ✅ Current |
| v0.2.0 | Fuzzy description matching, confidence engine | Planned |
| v0.3.0 | One-to-many / many-to-one, duplicate & reversal detection | Planned |
| v1.0.0 | Multi-company, user accounts, rule profiles, web UI | Planned |
MIT — © 2026 Blu-Chips