CASE FILE 01/13CLASS: SAMPLE BUILDDATA: REALISTIC, NOT CLIENTTYPE: Bookkeeping & reconciliation

Sample build: realistic data, built to show how I'd handle this work. Not client work.

Sample buildBookkeeping & reconciliation

Odoo bank reconciliation for a quarter: four accounts, every line matched or explained

1,636 bank lines across four accounts reconciled to Odoo for a quarter, with 0.00 left unexplained on every statement

Sample build · realistic data, built to show how I'd handle this work · not client work · every figure is computed from the files in the appendix

  • 1,636bank lines across 4 accounts
  • 99.7%matched by a rule
  • 0.00unexplained on all 12 statements
  • 28/28controls pass

01Summary

  1. In this scenario, 1,636 statement lines across four bank accounts are reconciled against 4,327 Odoo journal items for July to September.
  2. 1,618 of 1,623 lines (99.7%) match by a rule, and the unexplained difference is 0.00 on all 12 account-month statements.
  3. 204 exceptions each get a reason code, an owner and a proposed journal; 28 of 28 formula controls pass.

1,618 of 1,623 lines (99.7%) match by a rule, and the unexplained difference is 0.00 on all 12 account-month statements.

Key point, computed from the sample files

02The scenario

In this scenario an allied health group with four clinics banks with three AUD accounts and one USD account. Plan managers pay up to 12 invoices in one transfer, Stripe and the card terminals settle net of fees, some invoices are short-paid, one day's statement is imported twice, and cheques and deposits straddle month end. Matching that by eye in Odoo would take days, and errors would roll into the next month.

Exhibit 1: Current-state process map: 6 manual steps across 3 roles
Current-state swimlaneBankBookkeeperOdooStatementsimported1Searches eachline by amount2One-to-onematches only3Splitsremittances byhand4Differencecarried forward5Period left open6

Source: sample files

03Issues in the data

Exhibit 2: Issues in the scenario, counted from the sample data
426bank lines that each pay several Odoo items (3,555 in total)
200payee spellings on the statement for 66 partners with more than one
13statement lines imported twice from one day's file
111bank items with nothing in Odoo: fees, interest, receipts never registered

Source: sample files

04How I approached it

  • A matching engine (match.py) with 14 rules in priority order: duplicates, Stripe payouts, remittances, batches, pay runs, cheques, terminals, references, fuzzy payee names and amounts.
  • A workbook with 12 standard bank reconciliation statements (account by month) and a dashboard with sign-off, all formulas.
  • An exceptions register of 204 items with reason code, owner and action, and 189 proposed journals (450 lines) linked to it.
  • A 28-control tab and a test log, plus a 19-page report and a one-page executive summary.
Exhibit 3: Target design for the scenario
Future-state architectureINPUTS4 bank statementsOdoo items, openitems, TBRemittances, StripereportMATCHING14 rules, strongestfirstFuzzy payee scoreReason code per groupOUTPUTS12 rec statementsExceptions with ownersProposed journalsSIGN-OFF28 controlsDashboard per monthPeriod locked in Odoo

Source: my design and the sample files

05How this applies to your business

  1. Week 1: exports and opening positionRead-only Odoo access, the four statement exports, and an agreed 30 June reconciliation.
  2. Week 2: catch-up and rulesRun the engine on the quarter, clear routine items, set up fee models in Odoo.
  3. Week 3: decisions and lockOwners answer decisions and escalations, journals are posted and the period is locked.
  4. Week 4: first live monthYour team runs the month from the SOP while I watch, then the handover.
Exhibit 4: Responsibilities (R responsible, A accountable, C consulted, I informed)
ActivityBusiness ownerSpecialist (me)Your team
Export statements and Odoo dataICR
Run the engine and rebuild the workbookIRC
Decide short payments and double entriesACR
Answer escalated itemsRCI
Post journals and lock the periodACR
Change a matching ruleIRC

Source: sample plan

06Controls and checks

Exhibit 5: Control framework: 28 checks, status read from the files
CheckWhat it catchesStatus
Statement lines roll forward to the bank's closing balance (12 account-months)Proves the import is complete and the duplicates are excludedPASS
Odoo journal items roll forward to the trial balance (12 account-months)Proves the Odoo export is completePASS
Unexplained difference on all 12 reconciliation statementsAdjusted bank equals adjusted Odoo to the centPASS
Unclassified items on the statement side, all 12 statementsEvery reconciling item has a reason codePASS
Bank lines without a match groupEvery line is accounted forPASS
Odoo items without a match groupEvery Odoo item is accounted forPASS
Bank lines in groups = bank lines importedNo line counted twice or droppedPASS
Odoo items in groups = Odoo items exportedNo item counted twice or droppedPASS
Groups with a repeated group numberGroup numbers are uniquePASS
Clean matches (reason MATCH) that do not tie to the centA match only counts if it ties exactlyPASS
Matched groups that straddle a month end on one side onlyMonth-end positions are complete on both sidesPASS
Duplicate import lines detected (R01) and excluded from balancesThe 14 Aug file was imported twicePASS
Stripe report: gross - fee = net on every linePayout report is internally consistentPASS
Stripe payouts: report net vs bank amountEvery payout ties to the centPASS
Stripe group differences = fees + disputes per reportFees are booked exactly oncePASS
Proposed journals: total debits - total creditsJournals balancePASS
Proposed journals out of balanceEvery journal balances on its ownPASS
Journal bank lines vs exceptions needing a journal, by accountJournals post exactly what the register saysPASS
Exceptions vs 30 Sep Odoo-side reconciling items, by accountThe register explains every reconciling item at quarter endPASS
After proposed journals: Odoo + journals = statement + in transit, 30 SepPosting the journals closes the reconciliationPASS
Allocations exceeding an open item's residualNo invoice or bill is over-allocatedPASS
Allocations vs REG / REGBILL exception amountsAllocations post the full amountPASS
Transfers: operating to payroll vs payroll from operating (bank)Inter-account transfers net to nilPASS
Sweeps: merchant to operating vs operating from merchant (bank)Sweeps net to nilPASS
Dashboard unexplained differences (all rows)Sign-off view agrees with the statementsPASS
Dashboard statement lines = counted bank linesDashboard covers every linePASS
Engine regression test: items that disagree with the expected outcomematch.py is checked on every runPASS
Workbook groups = engine groupsThe workbook reflects this engine runPASS

Source: sample files (Checks / Controls tab, test output or run log)

07What the files show

Exhibit 6: What the sample files show
  • 1,636bank lines across 4 accounts
  • 99.7%matched by a rule
  • 0.00unexplained on all 12 statements
  • 28/28controls pass

Source: sample files, measured by script. Sample data, not a client result.

  • Statement lines roll forward to the bank's closing balance, and Odoo items to the trial balance, for all 12 account-months.
  • Every one of the 1,636 bank lines and 4,327 Odoo items sits in exactly one of 1,322 match groups.
  • After the proposed journals, Odoo plus items in transit equals the bank at 30 September on every account.
  • The engine's regression test agrees on 5,963 of 5,963 items.

08Risks and how the build handles them

Exhibit 7: Risks and mitigations
RiskMitigation built in
A payment is matched to the wrong invoiceExact amount plus remittance, reference or payee score of 0.85 or more; a reference that points to another customer is escalated
A duplicate import inflates the bank balanceDuplicates are removed first, and a roll-forward control fails if any slip through
Short payments are booked as paid in fullRemittance lines are compared to the invoice and the residual is reopened
An unknown receipt is allocated to tidy the recUnexplained items go to an escalation with an owner; nothing is allocated by amount alone
A rule change breaks an earlier caseA regression test compares all 5,963 items with the expected outcome on every run

Source: sample design

09Appendix: files

A. Screenshots of the deliverable

Dashboard tab: statement, in-transit, unpresented, Odoo balance and unexplained difference per account and month, with sign-off

Exhibit 8: Dashboard tab: statement, in-transit, unpresented, Odoo balance and unexplained difference per account and month, with sign-off

Source: sample files

Rec Statements tab: a standard bank reconciliation statement for the operating account

Exhibit 9: Rec Statements tab: a standard bank reconciliation statement for the operating account

Source: sample files

Exceptions register: reason code, type, owner, proposed action and journal for each item

Exhibit 10: Exceptions register: reason code, type, owner, proposed action and journal for each item

Source: sample files

Controls tab: 28 formula controls, all PASS

Exhibit 11: Controls tab: 28 formula controls, all PASS

Source: sample files

Report page: target month-end process across bank, bookkeeper, matching engine, Odoo and reviewer

Exhibit 12: Report page: target month-end process across bank, bookkeeper, matching engine, Odoo and reviewer

Source: sample files

Dashboard of the Odoo bank reconciliation sample: 12 account-month statements, each with 0.00 unexplained difference

Exhibit 13: Dashboard of the Odoo bank reconciliation sample: 12 account-month statements, each with 0.00 unexplained difference

Source: sample files

B. Downloadable files

FileWhat it isSize
Odoo-Bank-Reconciliation-Q1-FY27.xlsxWorkbook: dashboard and sign-off, 12 bank rec statements, exceptions register, proposed journals, match groups, rules, controls and test log1015.6 KB
Odoo-Reconciliation-Report.pdfReport (19 pages): current state and data profiling, options, target design, results, controls, cutover, RACI, risks, SOP786.4 KB
Executive-Summary.pdfOne-page executive summary146.7 KB
match.pyMatching engine: 14 rules, fuzzy payee matching, reason codes and the regression test21.9 KB
gen.pyBuilds the input data set: bank statements, Odoo exports, remittances, Stripe report28.5 KB
Odoo-Rec-Q1-FY27-data-and-code.zipInputs as exported (CSV), engine output, and the scripts that rebuild the workbook and the report232.1 KB

Sample build: realistic data, built to show how I'd handle this work. Names are placeholders and no client data is used.

Have a similar problem in your business?

Hire me on Upwork (opens in a new tab)