AI-generated Odoo modules: audit the business contract

Back
Kevin Riedl

12 min read · 5 Nov 2026
Last reviewed

Next
Made on your device, with no Instagram connection. We copy the post link for Instagram’s Link sticker.

A discount approval looks small: set a flag and record who approved it. In our deliberately flawed specimen, that code approves a cancelled quotation, trusts a caller’s invented approver and leaves partial changes after an injected failure. The ordinary demonstration still passes.

Audit an AI-generated Odoo module against an approved business contract and the exact installed Odoo version. Reproduce consequential failure cases, inspect final records and verify corrections independently. A passing local model helps define the checks; native installation, authorization, transaction and upgrade evidence still decide whether the real module can go live.

Research checked: 5 November 2026. We reviewed official Odoo 20 sources and ran thirteen synthetic approval-contract cases. Both Python specimens were written for this article; they are not sampled client code or a benchmark of an AI tool. No Odoo addon was installed, no native upgrade ran, and every proposed native acceptance check remains NOT_RUN.

What should the module audit decide?

The module audit should decide whether a specified customization has enough evidence to release, needs a bounded repair, or should be replaced by an approved simpler implementation. Start with what the business command is allowed to change. A code-quality score cannot supply a missing approval rule or decide which person has authority to approve it.

Ask the owner to demonstrate the requirement against the current configuration before expanding the custom code. If an existing supported workflow already meets it, compare that option with maintaining an override. This is a fit decision to verify on the installed version, not an assumption that every custom approval is unnecessary.

Then freeze the review scope: module commit, Odoo version and edition, dependency revisions, affected records and execution identities. Include the configuration that changes behavior. A review of a Git branch without its required settings can miss the exact path the business will use.

The general QA guide for AI-generated code owns the wider production-readiness checklist. Here, the unit of review is a deterministic Odoo customization. The separate agent business-state guide covers an agent’s complete task and tool choices.

What is the approval specimen supposed to do?

The specimen approves the current revision of a draft quotation only when the fixture actor has approval authority for its company and the requested discount falls within an invented delegation limit. It records the trusted actor once. It must reject stale or prohibited decisions without leaving a partial approval, including when a later item in a batch fails.

Our fictional quotation Q-17 belongs to company A, has revision 3 and starts with a 5.00% discount. User 7 may approve discounts from 0% through 10.00%. A 10.01% request needs another decision. These are example business rules, not Odoo defaults. The fields named approval and approved_revision belong to the Python specimen.

Approved contract for the fictional discount command
RuleAllowed outcomeRequired failure behavior
Authority and companyThe current approved actor acts within company A.A missing role or unauthorized company leaves the record unchanged.
Revision and lifecycleThe reviewed revision is still current and the quotation remains draft.A stale revision or cancelled quotation is rejected.
Delegated limit10.00% is included in the example’s limit.10.01% cannot receive this approval.
Actor evidenceThe approval records trusted fixture user 7.A caller-supplied label cannot substitute user 99.
Repeated selectionOne approval and one audit entry per quotation revision.A replay or duplicate selection creates no additional approval effect.
Batch failureThe agreed batch completes with its audit evidence.A rejected item or injected audit failure leaves no partial batch changes.

Approval here changes a review field. It does not confirm the quotation, create a delivery or post accounting. That boundary matters when a reviewer asks what “success” means. If the real module also performs a later business action, add that action’s authorization and final-state contract.

Settle disputed rules before generating the expected results. The business-rule conflict guide explains how to assign that decision. A reviewer cannot determine whether 10.00% is acceptable by inspecting a function that already accepts it.

Which defects does the annotated review expose?

The annotated review exposes missing business preconditions, an untrusted approver label and changes that survive an incomplete action. Repeated calls also append another audit effect. Each finding ties a specific statement to a failed contract case. This is more useful for a release decision than labeling the whole module “AI-generated” and assigning a general risk score.

The flawed specimen contains this sequence, shortened here to show its order:

quote["approval"] = "approved"
quote["approved_revision"] = expected_revisions[key]
quote["approved_by"] = claimed_approver or actor["uid"]
if key == fail_audit_for:
    raise InjectedAuditFailure(key)
store["audits"].append({
    "quote": key,
    "revision": expected_revisions[key],
    "actor": quote["approved_by"],
})

Nothing in that sequence checks whether the actor may approve the current record. Odoo’s public-method guidance treats supplied records and parameters as untrusted; CRUD access checks do not establish every business precondition. Review the actual receiving method, not only its visible button.

Findings in the intentionally flawed review specimen
FindingBusiness consequence in the fixtureCorrection to verify
No current authority or record checksAn unauthorized actor or company receives approval.Validate the trusted identity and the target record before mutation.
No revision, state or limit preconditionsA stale, cancelled or out-of-limit request is marked approved.Compare the approved contract with the current record values.
Caller chooses the recorded approverThe audit attributes user 99 instead of user 7.Derive attribution from the trusted execution identity.
Every selection appends an effectA repeat or duplicated item creates two audit entries.Recognize an already completed approval of that revision.
Mutation precedes failure without an atomic boundaryA failed audit write leaves an approved record or partial batch.Prove the agreed all-or-nothing outcome on the real implementation.

The corrected Python specimen validates the selection and applies changes to a staged copy before replacing the model state. That models the required outcome. It is not an implementation of Odoo transactions. The official coding guidelines explain framework transaction ownership and why unexplained manual commits require review; exceptional explicitly owned cursors need separate reasoning.

Download the annotated finding record for the mapping from each defect to its reproducer. The detailed Odoo 20 company-access migration tests own the version-specific permission transition. A generic old ACL checklist is insufficient context for that migration.

What changed in the thirteen contract tests?

The flawed specimen violates eleven of the thirteen fixed expectations. The corrected specimen meets all thirteen. Both pass ordinary approval and the exact limit, which explains why a successful demonstration can conceal the other defects. These counts describe deliberately constructed examples; they are not a defect rate for AI-generated Odoo code.

Executed local contract results on 5 November 2026
CaseFlawed specimenCorrected specimen
Ordinary 5.00% approvalApproved; one audit entryApproved; one audit entry
Exact 10.00% boundaryApproved; one audit entryApproved; one audit entry
10.01% requestIncorrectly approvedRejected; unchanged
Actor lacks approval authorityIncorrectly approvedRejected; unchanged
Record belongs to unauthorized BIncorrectly approvedRejected; unchanged
Review names revision 3, record is revision 4Incorrectly approved against revision 3Rejected; unchanged
Quotation is cancelledApproval flag still setRejected; unchanged
Same quotation selected twice in one requestTwo audit entriesOne audit entry
Same approval called twiceTwo audit entriesOne audit entry
Caller supplies approver 99Attributes user 99Attributes trusted user 7
Audit failure after approval assignmentApproved flag remains; no audit entryNo changes
Second batch record belongs to unauthorized BBoth records approvedNeither record changed
Second batch audit write failsBoth approved; only one audit entryNeither record changed

Download the runnable approval-review specimen and full expected and observed states. Save the Python file and run:

python3 approval-review-model.py

The script uses Python’s standard library, with decimal comparison for the invented percentage rule. It does not import Odoo or access a network. Its expected states are specified from the contract, independently of either approval function. The output includes errors and final approval fields, so an exception alone cannot make a partial write look acceptable.

The model does not test simultaneous native requests. A real method may need additional protection when two callers approve the same revision concurrently. The n8n recovery article examines the separate boundary for external order creation; this fixture’s repeated audit effect does not establish connector idempotency.

What must be verified in the real Odoo module?

Verify the real entry points and affected records under the actual build before applying the model’s conclusions to Odoo. Inspect custom overrides and their dependencies, then execute the approved business cases through the receiving methods. Confirm which identity performs each change. An isolated function can satisfy its contract while its integration into the application remains wrong.

Native review questions beyond the Python specimen
AreaReview questionEvidence required
Entry pointsCan a button, API call or automation reach the same behavior?Approved identity and final-state checks for every relevant path.
DependenciesDoes the manifest declare the modules this customization uses?A reproducible installation from the declared dependency set.
OverridesWhy is each base behavior replaced or extended?Regression cases showing required standard workflows still work.
Company and field behaviorDoes the command use the intended record, company and value?Native role/context evidence and representative field checks.
Failure and concurrencyWhat remains after interruption or simultaneous approvals?Resulting records and audit effects under controlled failure schedules.
Existing dataWhat happens to quotations created before this module revision?Approved upgrade expectations and observed records after rehearsal.

The proposed native acceptance pack contains these gates and the contract cases. It starts with NOT_RUN and pending policy approval. Replace illustrative expectations with approved rules, record exact identities and revisions, and attach actual evidence before treating a row as passed.

Review each override with the standard behavior beside it. An unexplained replacement creates an obligation to discover what was removed. If the module only needs one extra decision check, ask whether the chosen extension is narrower than replacing the complete workflow. Verify that judgment with the affected standard cases.

How should installation and upgrade evidence be checked?

Check installation, upgrade and runtime behavior as separate gates. A clean installation can reveal missing dependencies, while an existing-data rehearsal addresses records and configuration created before the change. Neither proves that the right business tests ran. Bind the report to the exact module revision, target environment and selected cases.

Odoo’s test documentation requires test modules to be imported and explains how enabling and selection determine execution. Ask for the runner output identifying the intended tests. A green command with the relevant tests absent leaves their behavior unverified.

The customized-database upgrade guide separates empty-database installation from installation on upgraded data and runtime rehearsal. Our Python run supplies none of those native results.

For this approval customization, include an older quotation without the new approval fields populated, a previously approved quotation whose business content changed, and a record awaiting review when the upgrade began. Decide the target state before the rehearsal. A default value that makes an old record look approved is a business decision, not a convenient way to eliminate an error.

Retain a controlled recovery plan for the rehearsal. Reverting the code alone cannot establish that data changes have been reversed. The migration reconciliation guide covers the wider expected-versus-observed comparison.

What should the audit handover contain?

The audit handover should make every release decision traceable to an approved rule and reproducible evidence. For each blocker, record the affected revision, reproducer and business consequence, then attach the correction and independent retest. Keep unexecuted checks visible. A list of stylistic suggestions does not answer whether a quotation can receive an unauthorized approval.

Our specimen’s finding record distinguishes a confirmed local contract failure from a native question still requiring execution. Carry that distinction into the real audit. “The model rejects a stale approval” and “the deployed Odoo method rejects it under these identities” are different evidence statements.

Separate an implementation fix from policy approval. The reviewer may show that the function enforces 10.00%; the business owner must decide whether that is the intended delegation. If the rule changes during review, revise the expected outcomes and rerun the affected cases against the new contract.

The release QA checklist provides the broader launch context. The general AI-built software audit guide explains a wider audit engagement; this module review should preserve its narrower, testable scope.

When would we release, repair or remove the customization?

Release the customization only for the scope supported by approved native evidence. Repair demonstrated contract violations and retest their affected workflows. Consider removing an unnecessary customization when an approved supported alternative satisfies the requirement, with a plan for its existing data. A polished demonstration should not determine any of those decisions.

We would begin with one consequential command, its real entry point and a pair of allowed and denied cases. Add the failure cases that can leave the business with a wrong record. This gives the audit a concrete first decision before expanding into every file in the repository.

For Wavect’s software quality assurance service, bring the module commit, installed-version details and one business rule the owner can approve. The useful deliverable is a finding with a reproducible test and a clear native release gate, followed by evidence that the agreed correction works.

AI-generated Odoo module audit FAQ

Is the downloadable specimen an Odoo addon?
No. It is a standard-library Python model containing deliberately flawed and corrected approval functions, with fixed expected states. It cannot be installed into Odoo. Use it to inspect the review logic and failure cases, then implement and execute the separate native checks against your actual module, dependencies and business policy.
Do thirteen passing cases mean AI-generated code is reliable?
They establish only that this corrected specimen meets these thirteen expectations. Both implementations were written for the article, and no AI output sample was measured. The count is neither a model comparison nor a production defect estimate. A real module still needs its own approved scope and native evidence.
Is 10.00% Odoo’s standard approval limit?
No. It is an invented delegation rule chosen to make the boundary test explicit. The ordinary example uses 5.00%, the inclusive boundary is 10.00%, and 10.01% requires another decision. Your business owner must approve the actual rule, including which values and revision it applies to, before the reviewer defines expected results.
Can the same AI generate the expected results?
It can propose cases, but the approved expected behavior needs an independent basis in the business rule. If the implementation and its expected output share the same mistaken assumption, they can agree while remaining wrong. Have the owner settle the rule, then review the fixtures and final-record assertions against that decision.
Does a discount approval mean the quotation is confirmed?
Not in this specimen. Approval updates a custom review field while the quotation’s draft lifecycle stays unchanged. Confirmation or any later business action needs its own explicit contract and authorization. Name the exact state the real command may produce, then inspect that state; do not infer it from a successful approval response.
Should every sudo call or explicit commit be removed automatically?
Review its purpose and boundary before changing it. An elevated operation needs a justified authority model and denied-path evidence; an explicitly owned transaction needs failure and recovery reasoning. The official guidance identifies why these choices deserve scrutiny. Removing a line without understanding its callers can create a different defect, so verify the replacement behavior.
Can a clean installation replace testing on existing data?
No. A new database does not contain the historical records or configuration your module will encounter after an upgrade. Approve the expected treatment of those records and rehearse it on a protected copy. Keep installation evidence and business-state evidence separate, including what happens to pending or previously approved work.

From prototype to production

Got a vibe-coded or AI-generated product that needs to survive real users, due diligence, or investor scrutiny? Wavect audits, hardens, and rebuilds the parts that matter.

Best next step:

Inbox, without the noise

Follow the work that matters to you

Get a short email when we publish something new. Follow the whole blog or only the problems you care about.

What would you like to receive?
Choose your topics

Free, double opt-in, no tracking pixels.

Back
Kevin Riedl

12 min read · 5 Nov 2026
Last reviewed

Next

Get the next Delivery and QA field note

One concise email when we publish. No tracking pixels, and no inbox filler.

Free, double opt-in, no tracking pixels.