ThatFiscal Knowledge Base

Odoo ZIMRA Fiscalisation — Integration Guide

~5 minutes · native

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).

Step 1

Copy Your API Key

Portal → Settings & Branding → API Key → Copy.

Step 2

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.

Step 3

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.

Step 4

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.

Step 5

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.

What Happens If the Filter Is Missing: ThatFiscal refuses anything that is not a customer sale, so nothing bad reaches ZIMRA — but you will see noise in your Odoo log. The refusal is a normal 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.
Credit Notes: always create the credit note from the original invoice (Add Credit Note / Reverse Entry) so Odoo fills 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.
Tax-Inclusive Prices: we read Odoo's 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.
HS Codes — Nothing To Add In Odoo: you do not create a custom field for this. Earlier versions of this guide asked for 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.
Need a Hand? Email support@thatfiscal.com or call +263 78 674 5282. If it is quicker, we will do the setup with you on the call.
← All Knowledge Base Guides