Odoo ZIMRA Fiscalisation — Integration Guide
Overview. Odoo posts an invoice → an Automation Rule fires → ThatFiscal signs, submits to ZIMRA, and writes the QR back. Only two Odoo document types are fiscalised: customer invoices (out_invoice) and customer credit notes (out_refund).
Before You Begin: Odoo 14 or newer with developer mode on, and your ThatFiscal API key (Portal → Settings & Branding → API Key — it starts with tf_; it is issued the moment your account goes Live).
Copy Your API Key
Portal → Settings & Branding → API Key → Copy.
Create the Automation Rule
Odoo → Settings → Technical → Automation Rules → New. Model: Journal Entry (account.move). Trigger: On Update, and set the trigger field to Status with trigger value Posted.
Restrict the Rule to Customer Sales — Do Not Skip This
In Apply on, switch the domain to code view and paste exactly:
[("move_type", "in", ["out_invoice", "out_refund"]), ("state", "=", "posted")] Without this filter the rule also fires on vendor bills, vendor credit notes and plain journal entries. Those are not sales and must never be declared to ZIMRA as output VAT.
Paste the ThatFiscal Action
Action type: Execute Python Code. Paste odoo_automated_action.py from your welcome email and set API_KEY = "tf_…" at the top. The script POSTs to https://api.thatfiscal.com/webhooks/odoo with your key in the X-Api-Key header.
Test With One Invoice
Confirm any customer invoice. Within seconds it shows in Portal → Invoices with a green Fiscalised badge, QR and verification code. Reverse it from Odoo (Add Credit Note) and post the reversal — it fiscalises as a credit note automatically, linked to the invoice it reverses.
200 OK (never an error, so Odoo does not flag a red banner on a perfectly good journal entry) with a body like: {"ok": true, "skipped": true, "fiscalised": false,
"reason": "Odoo sent a vendor bill (move_type='in_invoice'). Only
customer invoices and customer credit notes are fiscalised…"} Vendor bills, vendor credit notes, journal entries, sales-receipt drafts and purchase receipts are all skipped this way. A document in any state other than Posted is skipped too.reversed_entry_id. That is what the script sends as refund_of, and it is how we link the credit note to the original receipt. A credit note against an invoice that was never fiscalised on this device is refused with RCPT015.price_subtotal (tax-exclusive) per line and let ZIMRA's tax table add the VAT. You do not need to change your Odoo tax configuration.x_hs_code; the script no longer reads it, so that work bought nothing. It sends the product name, quantity and price, and ThatFiscal fills the HS code from your Items Master, then its built-in Zimbabwe classifier, then your default code. Missing codes are the #1 cause of ZIMRA error RCPT047, and this is why you will not see it. If a product needs a specific code, set it once in Portal → Items & HS Codes against the same product name — one place, so it is right on every channel and not only on Odoo.