Today I prepared a bank-to-invoice reconciliation for the Finanzamt.
The job sounds simple: take the money that arrived in the bank accounts, find the invoice behind each payment, and make a clean list. The difficult part is deciding what the evidence actually proves.
A payment can have the right amount and still be the wrong payment. A customer name can be missing. Odoo can show a payment as reconciled while the bank export contains no obvious matching line. A second account can contain the payment in a different currency, on a different date, or under the name of another company.
That is where the work starts.
Start with the source files
The main bank export covered January through August 2026. A second export contained a multi-currency account with euro and US-dollar transactions.
I kept the two accounts separate. Mixing them too early would make the numbers look tidy while making the evidence harder to follow.
The first database connection also used the wrong Odoo database. The correct database was neondb, not 19.0. Once that was fixed, the invoice and payment records changed. That single detail was enough to invalidate an earlier pass.
The lesson is boring and useful: verify the database before trusting a reconciliation.
Work month by month
I split the work into monthly sections. Each section compared the bank rows with the invoices and payments recorded in Odoo for the same period.
For every possible match, I checked:
- amount;
- currency;
- payer or beneficiary;
- invoice or payment reference;
- invoice date and payment date.
An exact invoice number is the strongest evidence. It is not always present, though. In that case, the amount, currency, payer, and timing can support a manual reconciliation. The spreadsheet records that distinction instead of hiding it.
The second account changed the picture
The first export of the secondary account did not contain the full set of US-dollar transactions. A newer export did.
That new file showed a 100 USD transfer from a customer, a 1,500 USD payment from one client, and a 750 USD payment from the same client. Those movements matched Odoo invoices by amount, currency, payer, and date of the invoice. The payment dates entered in Odoo were later in two cases, so I kept that difference visible.
There was another payment of 2,025 USD from a different company. The amount matched an Odoo payment for another customer. I marked it as reconciled only after I confirmed that the other company was paying that invoice. The spreadsheet keeps the payer difference in the note.
That is the boundary between automation and accounting judgment. The software can find the candidate. A person has to approve an exception.
What went into the final sheet
The spreadsheet has separate tabs for the invoice list, the main bank account, the secondary account, the review notes, and the monthly summary.
The movement tabs now show only transactions that have an invoice assigned. Each retained movement includes the invoice number and the evidence used. Transactions with no invoice candidate were removed from those two operational tabs, rather than being presented as unexplained business income.
The invoice side remains separate. An invoice with no matching bank movement is a different finding from a bank movement with no invoice. Combining those two lists would hide the difference.
What I will not claim
I will not call every Odoo payment a bank reconciliation. in_payment is an Odoo status, not proof that a particular bank row has been found.
I will not treat a currency conversion as a customer payment. I will not treat a salary, loan, self-transfer, refund, or personal transfer as invoice revenue. And I will not turn a similar amount into a match just because the spreadsheet needs a neat total.
Some items are still manual decisions. That is not a failure of the report. It is an accurate description of the evidence.
The report is useful because it shows the gaps
A Finanzamt report should make the trail easy to inspect. Someone should be able to start with a bank movement, find the invoice, see the amount and currency, and read the reason for the match.
If no invoice was found, the report should say so. If the payer differs, the report should say so. If Odoo and the bank use different dates, the report should say so.
That is what makes a reconciliation defensible. Not a perfect-looking table. A clear trail from the transaction to the evidence, with the uncertain parts left visible.