Bank reconciliation in Odoo matches imported bank statement lines to existing journal entries (outstanding invoices, payments, refunds) and creates entries for transactions that have no existing match (bank fees, interest). Understanding how matching rules score candidates and when reconciliation models apply determines whether reconciliation takes minutes or hours.
Statement import#
Bank statements import via:
- Manual CSV/OFX/QIF: Accounting → Bank → Import Statement.
- Bank sync (Ponto, Yodlee): Accounting → Configuration → Settings → Bank Feeds → Connect a Bank.
- Manual entry: type statement lines directly in the reconciliation widget.
Odoo accepts OFX (Microsoft Money format), QIF, and CSV. For CSV, map columns: Date, Label (narration), Amount, Ref.
CAMT.053: For European banks using ISO 20022, install the account_bank_statement_import_camt module. CAMT.053 carries richer data (creditor/debtor IBANs, structured references) that improves auto-matching accuracy.
How reconciliation works#
The reconciliation widget (Accounting → Bank → [Bank Account] → Reconcile) presents each unreconciled statement line. For each line, Odoo:
- Runs matching rules against outstanding journal items.
- Presents candidates ranked by match score.
- If a candidate score exceeds the auto-validation threshold, validates automatically.
- If no candidate matches, offers reconciliation models.
Match score components:
- Amount match (exact or within tolerance): high score.
- Date proximity: closer dates score higher.
- Partner match: statement line partner name matches partner on the journal item.
- Reference match: statement reference matches invoice number or payment reference.
Configuring matching rules#
Accounting → Configuration → Reconciliation Models → Matching Rules tab:
| Rule field | Purpose |
|---|---|
| Rule Type | Invoice matching or Write-off |
| Auto-validate | Validate automatically when score exceeds threshold |
| Payment Tolerance | ±N EUR/% difference allowed for amount match |
| Match by Reference | Check if statement ref contains invoice number |
| Match by Partner | Match partner name from statement narration |
| Past Days Limit | Only consider journal items from last N days |
Tuning for automatic matching:
Set Auto-validate with a threshold of 80% and Payment Tolerance of 0.02 EUR (for rounding differences). This catches 95%+ of regular customer payments automatically.
For companies receiving payments with no structured reference (wire transfers with only partner name), enable "Match by Partner" and set a string distance tolerance. This fuzzy-matches "APPLE INC PAYMENT MARCH" to the partner "Apple Inc."
Reconciliation models for unmatched transactions#
When no existing journal item matches, a reconciliation model creates a new journal entry on the fly. Common use cases:
- Bank fees (debit from bank, no existing payable).
- Interest income (credit from bank, no existing receivable).
- Payment returned (credit, linked to a previously validated payment).
Create a reconciliation model: Accounting → Configuration → Reconciliation Models → New:
Name: Bank Fees
Type: Write-off Only
Applied on: Expense
Account: 6520 (Bank Charges)
Journal: Bank Journal
Tax: NoneWith this model active, when you encounter a statement line labeled "Monthly Fee - $25.00" with no match, click the "Bank Fees" model button. Odoo creates a journal entry:
Bank Charges (6520) DR 25.00
Bank Account CR 25.00And validates the statement line.
Reconciliation workflow in practice#
High-volume operations (100+ statement lines/day):
- Import statement at day start.
- Run auto-reconciliation: Accounting → Bank → [Account] → Auto-Reconcile. This processes all lines where a rule exceeds the auto-validate threshold.
- Review remaining unmatched lines in the reconciliation widget.
- Apply reconciliation models for fees and unidentifiable credits.
- Manually match ambiguous lines (multiple partial payments against one invoice).
Month-end procedure:
- Reconcile all statement lines to zero outstanding.
- Accounting → Reporting → Bank Reconciliation Report → verify the reconciled balance matches the bank statement closing balance.
- Post an exchange adjustment entry if foreign-currency bank accounts have unrealized rate differences.
Partial payments and payment groups#
For invoices paid across multiple payments (installment plans, partial payments):
Statement line: $500 payment received.
Outstanding invoice: $1,200.
Odoo's reconciliation widget allows matching the $500 to the $1,200 invoice as a partial payment. The invoice status becomes "In Payment" for the $500 and shows $700 remaining.
When the second payment of $700 arrives, reconcile it against the same invoice. Invoice closes.
Payment groups (multiple invoices, one payment): A customer pays three invoices with one bank transfer. In the reconciliation widget, select all three outstanding items. Odoo splits the statement amount across them and validates all three.
Common reconciliation problems#
"Outstanding credit" items accumulating: Payments posted but not linked to invoices appear as outstanding credits. These come from payments made before the invoice was created, or from miscoded manual entries. Fix by opening the payment and linking it to the corresponding invoice.
Duplicate payments posted: If a payment appears twice (once from the bank sync and once manually entered), the reconciliation widget shows the statement line matching two candidates. Do not validate both - delete the duplicate payment.
Bank statement balance does not match Odoo: Run the bank reconciliation report and compare line by line. Common causes: statement import skipped a line, a manual journal entry debited/credited the bank account without going through the bank statement reconciliation process.

