Skip to main content
Odoo · Audit method

Auditing an inherited Odoo connector: what to check in one afternoon before touching a line

You have inherited a marketplace, carrier, e-signature or EDI connector someone else built. It fails, or nobody trusts it. Ten points, the symptom that gives each one away and the query that confirms it in minutes.

Instance form of the Mirakl connector in Odoo: test connection OK, 206 offers and the call-log counter at 0

A useful audit of an Odoo connector does not start with the tests. It starts with the log and with one real operation end to end: an order coming in, a shipment going out, a refund going back. The Mirakl connector passed its suite green on Odoo 19, 18 and 17 and hid 18 confirmed defects; another marketplace connector scored 236 of 236 on real Odoo.sh builds and hid 20 contract defects and 12 version defects. That article tells the failure; this one, the method: ten points in order, the symptom that gives each away and the check that fits in an afternoon.

Key idea: the connector you inherit already tells you what is wrong, in the log table and in the deactivated crons.

What to gather before you sit down

Four facts that do not depend on whoever built the connector. The real Odoo version: SELECT latest_version FROM ir_module_module WHERE name = 'base';. The third-party API version the code assumes, almost always visible in the base URL. The date of the last change to the mocks: git log -1 --format=%cd -- tests/. And who receives the errors: an email, an activity, a file, or nobody.

The ten points, in order

1. Does the log actually write?

Symptom: the log table has zero rows after months of crons. Check: SELECT last_value FROM pg_sequences WHERE sequencename = '<log_table>_id_seq';. A NULL there means that sequence has never been read: nobody deleted the rows, none was ever written. That is what came out of the Mirakl connector's production. The helper returning the log model returned an empty recordset on success, and in Odoo an empty recordset is falsy, so if not log_model: return False was always true and every "we log this" was a no-op. The fix is if log_model is False.

2. The sync cutoff date

Symptom: an order created in the morning and shipped in the afternoon keeps its morning status in Odoo. Check: three orders that changed status yesterday on the marketplace, compared with write_date and the status in Odoo. In Mirakl the connector asked for start_date, which filters by creation date, instead of start_update_date, which filters by change date.

3. Idempotency: double order, double refund

Symptom: two sale.order records with the same external reference, or a refund that shows twice on the marketplace. Check: SELECT client_order_ref, count(*) FROM sale_order GROUP BY 1 HAVING count(*) > 1;, then create a duplicate from odoo shell to see whether the database really rejects it: a constraint written in the model does not mean a constraint in Postgres. On Odoo 19 a leftover _sql_constraints creates nothing and the ORM only leaves a log warning, so you lose the guarantee without noticing; the other way round is noisy, because models.Constraint does not exist on 17 or 18 and there the module will not even import. And the HTTP client: in Mirakl it retried on 5xx and timeout for any method, including the refund PUT.

4. HTTP errors and retries

Symptom: the account wakes up "unauthorised" with every sync stopped. Check: force a 401, a 429 and, if possible, a quota 403. In the second case, the quota 403 did not come in the documented error format and was read as a permission failure: a rate limit stopped everything. What should be there: Retry-After honoured and capped, 5xx and timeouts retried only on reads, the 429 on writes too because the server rejected it without processing it, and the account blocked only by a real authentication failure.

5. Mocks versus the real contract

Symptom: a field that always arrives empty, a filter that "does not filter". Check: put the provider's current OpenAPI in the repository and compare each wrapper's parameters, the keys of each write body and the fields each parser reads. In the second case 16 such discrepancies came out of 88 operations, and four more only by calling: a relative pagination header blocked every order past page one.

6. Permissions and SSRF via redirect

Symptom: none, which is why it is on the list. Check: grep -rn "allow_redirects\|\.sudo()\|has_group" models/. Every outbound call must carry allow_redirects=False and refuse a 3xx, because requests follows redirects by default and a compromised host can send you to an internal IP. And every action_* working under sudo() must check the group server-side: the button's groups= is interface only. In July 2026 we applied it to some sixteen connectors of our own.

7. Crons: numbercall and intervals

Symptom: "the cron stopped on Tuesday", no error, no trace. Check on Odoo 17: SELECT cron_name, active, numbercall, nextcall FROM ir_cron WHERE cron_name ILIKE '%connector%';. On 17 numbercall defaults to 1, so a cron declared without it runs once and deactivates itself, as the 17.0 series' ir_cron.py says. Odoo 18 removed the field and 19 does not have it, so whoever tested on 18 or 19 never saw it. And look at the interval: a full sync every ten minutes ends in a 429.

8. The Odoo version the code assumes

Symptom: a form without chatter, a blank "payload" tab, an order cancelled on the marketplace that stays confirmed in Odoo. Check: grep -rn "<chatter/>\|widget=\"json\"\|read_group\|<tree\|<list" views/ models/. In Mirakl all four showed up at once: <chatter/> exists from 18, widget="json" only on 19, read_group is deprecated on 19, and sale.order.action_cancel() returns a wizard on 17 and 18 for a confirmed order, so the cancellation never happened. It is the list from a module that compiles on Odoo 19 and will not install.

9. Migrating the historical data

Symptom: you fix the calculation and the old orders stay wrong, because the connector never touches an existing order. Check: count the records from before the fix that break the new rule and decide between a migration script and a one-off, documented correction. In Mirakl it was 18 orders with VAT doubled in the total; the 15 active ones were fixed, only when the total matched the marketplace's. And a trap: noupdate data in base, groups included, is not reapplied on upgrade, so a membership change leaves the group empty in production and full in your clean database.

10. The third party's documentation versus real behaviour

Symptom: the code does what the PDF says and the server does something else. Check: one real call per endpoint family and a review of which endpoints are deprecated today. In Mirakl the file-import model was still current, but messaging used a deprecated endpoint. In the second case, an endpoint accepted a single value where the documentation said list, and that referential had been empty from day one. It comes last because it is the most expensive.

The afternoon, summarised

PointSymptomCheck
LogZero rows after months of cronscount(*) and pg_sequences.last_value
Cutoff dateFrozen statusesYesterday's orders vs write_date
IdempotencyDuplicates, double refundGROUP BY HAVING; does the database reject the duplicate?
HTTP errors"Unauthorised" after a 429/403Force 401, 429, 403
MocksField always emptyCurrent OpenAPI vs wrappers and parsers
SSRF and permissionsNonegrep allow_redirects, sudo(), has_group
CronsSwitches off silently (17)SELECT active, numbercall FROM ir_cron
Odoo versionBlank chatter or payloadgrep chatter, widget json, read_group, tree/list
HistoryOld records still wrong after the fixCount prior records breaking the rule
DocumentationServer does not do what the PDF saysOne real call per endpoint family

What the audit produces: a report with severity, not a wish list

The report sorts by damage: money first (double refund, duplicated order, VAT twice), then data (frozen status, log that does not write, switched-off cron), then ergonomics. Every finding carries its reproduction and what cannot be reproduced is struck out: the Mirakl audit started with 121 candidates, 33 refuted in a sceptical pass and only 18 surviving.

The second output is the gate: the existing suite, green before and after, does not prove the fix. The proof is the run across the three series on real builds, 163 of 163 on 19, 18 and 17 for Mirakl, plus a live verification. It is what separates a well-made native connector from a middleware layer that survives by never committing.

When to patch and when to rewrite

You patch when the data model is right (one table per third-party object, a log, a unique external reference) and the defects live in the HTTP layer, the windows and the versions: it fits in one release, as with Mirakl. You rewrite when the foundation is wrong: an API the provider has retired, no log or external reference, non-idempotent writes by design, or a connector tied to one Odoo series when you need three. It is the decision we prepare for consultancies and technology partners inheriting integrations, and also when the connector is for their own software.

Frequently asked questions

Why not start with the test suite?

Because a green suite says the code matches its mock, not the provider nor production. The suite comes at the end, as the gate for the fix.

Do you need production access?

For points 1, 2, 3, 7 and 9 yes, or a copy: the log sequence, frozen statuses, duplicates and switched-off crons only show in real data.

What do you deliver at the end?

A report with every finding proven and ranked by money, data and ergonomics; the patch-or-rewrite recommendation; and, if agreed, the fix with its gate on the client's Odoo series. Details are on services.

Useful links inside FlexigoTech

The tests were green and the connector was broken32 defects the suite could not seeMirakl Odoo ConnectorWhat it must solve on a real marketplaceOdoo engineering for consultanciesAudit and support for inherited integrationsTechnology partnersHow we work with Odoo partnersAn Odoo connector for your softwareWhen the connector to audit is your platform's

What we do about this

Custom integrationsWhat it does, screenshots, versions and price.

Inherited a connector that fails or that nobody trusts?

Tell us what it integrates, which Odoo version it runs on and what symptom you see. We will tell you which points on the list we would check first and what is needed to do it. Email comercial@flexigobe.com or call +34 616 809 504.

Talk to an engineer