# Qualifying Odoo 20 AI Access: Company, Write and PDF Evidence

Published: 2026-10-01
Last updated: 2026-10-01
Review by: 2026-10-31
Canonical: https://erpipe.com/guides/odoo-20-multi-company-write-pdf-qualification

## Answer first

An Odoo 20 AI integration is ready for a particular workflow when its authorized result and its forbidden cases are both evidenced. Ask three questions: which company's data can this identity see, which route can change a record, and what can a generated document disclose or modify? A correct happy-path answer covers only part of that contract.

The [Odoo 20 AI overview](/guides/odoo-20-ai-mcp) describes release capabilities, while the [native MCP guide](/guides/odoo-20-mcp-server) explains native setup. Use the [native MCP versus ERPipe comparison](/guides/odoo-20-mcp-vs-erpipe) when choosing architecture. This field note concerns acceptance evidence after that choice.

**Evidence boundary:** these lessons come from ERPipe's exact reviewed local Odoo 20 Community candidate, not a customer testimonial or native-MCP benchmark. Independent review 03 passed 77 scoped files. Authenticated hosted gateway smoke through ERPipe's public MCP endpoint to the pinned Community 20 lab passed on October 1, 2026. The broader workflow matrix remains local qualification evidence. Other editions, arbitrary custom workflows and older Bridge PDF ports remain outside this qualification.

## Environment

The local qualification used pinned Odoo 20 Community source, JSON-2 with RPC-scoped credentials, a restricted operator and two companies. The optional 20.0 Bridge supplied the tested quotation report path. Production smoke used that same owned lab through the public gateway; customer installations remain separate.

## Method: check the company and identity

Odoo's multi-company guidance ties access to company security rules and distinguishes company-dependent values from shared records. A record available in several companies can have values that depend on the current company. Those concerns need explicit acceptance cases. [Official multi-company guidance](https://raw.githubusercontent.com/odoo/documentation/64e81e4e45c44e57aff6679213752bb01fa41eb2/content/developer/howtos/company.rst).

Consider an illustrative partner-managed database with Company A and Company B. Create a staging user intended to operate only in A, with a known A quotation and a separate B quotation. The A read should return its expected customer. The B request and a forged company context should not disclose B's record. Shared contacts need their own expectation; they are not automatically company-exclusive.

Record the actor, company context and actual filters, then compare the result with Odoo under that actor. A prompt saying “Company A only” cannot compensate for a credential that grants broader access or a tool that receives a different context.

ERPipe's pinned 20 checks include company isolation and forged-context negatives. Their meaning is bounded: they qualify the tested models and users. A custom model with different rules still needs the corresponding positive and negative read.

## Result: approval is specific to a route

For one permitted structured change, test approval, rejection and expiry, then inspect the resulting record. A rejected proposal should produce no effect. A repeated execution attempt should not create an extra record in the qualified operation path.

The hosted test retained an especially useful result: **unlink was denied**. The record stayed unchanged, and the request never reached owner approval. Calling that an “approved delete test” would hide the policy that actually protected the record.

Generic methods, named verbs, chatter and connection lifecycle operations have distinct gates. They are not covered by a blanket statement that all writes require human approval. For example, a workflow that approves a sales-record update still needs a separate decision about posting a chatter message or invoking a business method.

Test hard-denied security models too. The candidate preserved those refusals even when an automatic policy rule matched. The operator's acceptance record should explain the denied operation and its unchanged state, not count every refusal as a malfunction.

The expiry evidence also has a limit: forcing expiry in the local fixture proved that refusal path. It did not establish a separately observed elapsed-time expiry test. Preserve that distinction when handing over the workflow.

## A PDF is a second data surface

A rendered document can include fields beyond the tool's structured record response. Hiding a field in JSON does not demonstrate that a PDF template omits it. Embedded XML is another surface to inspect alongside the visible page.

In ERPipe's local qualification, rendering used restricted uid 14 with `su=false` in a fresh read-only transaction. The parsed PDF contained the intended customer's text; foreign-company customer content was absent from both visible text and embedded UBL XML. The tests also checked report-group access, report/model matching, byte limits, cache suppression and transaction cleanup.

Those observations establish the tested report path. They do not guarantee every template installed by a partner. For a custom invoice layout, seed recognizable company-specific markers and inspect the returned document and attachments under the intended restricted user.

Under field restrictions, the candidate refuses opaque PDF output. It does not promise arbitrary template redaction. A refusal here preserves a disclosure boundary that cannot be proved from the structured fields alone.

## Failure boundaries: printing may require a write

The stock-print qualification exposed another practical boundary: a print operation that needed to write was refused. The printed flag and attachments stayed unchanged. Read-only acceptance must inspect persistent effects as well as the returned file.

For an operator, this means classifying the exact report before putting it into an automated daily task. A purely readable quotation and a stock print with state changes need different acceptance expectations. Do not enable broad writes just to make an unqualified print succeed.

Attachments need the same discipline. In the reviewed adapter, `datas` and `raw` are protected aliases: denying either blocks both, and a restrictive allow policy must permit both. Check the denied content route before the positive download. A compatibility rename should preserve the restriction.

## Limits and reusable evidence

For each workflow, retain the exact candidate, intended actor/company, known expected result, denied counterpart and observed side effect. Store identifiers and redacted outcomes rather than customer documents in a public campaign or support note. Repeat the cases when modules, permissions, report templates or client configuration change.

The local qualification includes 29 common and 11 restricted20 checks, plus separate companion fresh/base/upgrade suites of 39/30/37. Suite counts locate evidence; they cannot replace the customer's business acceptance. The [migration decisions guide](/guides/odoo-20-integration-migration-decisions) explains which adapter contracts to check during an upgrade.

## Qualify your first read

[Open your ERPipe workspace](/app/login) and start with one known record in one company, with writes disabled. Expand to a write or PDF only after its allowed result, refusal behavior and persistent effects have a clear acceptance record.
