Skip to content

Odoo Model Extension Strategy

Purpose

This note defines the current design guideline for extending Odoo models in dirac-odoo.

Read this document as the current V2 refinement layer in the progressive SA design.

Its purpose is to explain how durable Odoo objects become visible and manageable inside SA governance once V0 basic stamping and V1 hierarchy are already understood.

It exists to keep model discussions consistent when deciding whether to:

  • extend a native Odoo model directly
  • add SA governance fields to an existing model
  • introduce an ov.* wrapper object

This note should be read together with:

1. Core Rule

Stay within Odoo.

The starting assumption is:

  • business objects should remain native Odoo objects or Odoo-extended objects
  • SA should not become a parallel object universe
  • SA exists to govern login access, object visibility, attribution, and controlled operations inside Odoo

Therefore, the default design move is not to create a new wrapper.

The default design move is:

  • use the native Odoo object when it already expresses the business identity and lifecycle
  • add governance fields or governance behavior only where needed

2. SA Responsibility Boundary

Serviced Account (SA) is fundamentally a governance layer.

Its core responsibilities are:

  • login-governed access
  • visibility scoping
  • attribution of governed operations
  • controlled operational scope inside the current SA context

The core governing stamp is:

  • {actor, sa}

Interpretation:

  • sa defines the visibility and tenancy boundary
  • actor defines assignment or personal scope inside that SA

This means SA should normally control:

  • who can see an object
  • who can act on an object
  • whether the object is shared or actor-assigned inside one SA

This does not mean SA must redefine the object's full business structure.

3. Prefer Direct Extension First

Prefer direct extension of a native Odoo model when all of the following are true:

  • the native model already represents the real business object
  • the native model already owns the correct lifecycle
  • the main added need is visibility, attribution, or governance filtering
  • the object does not need a separate SA-specific identity apart from the native Odoo record

Typical direct-extension shape:

  • keep the native model as the primary object
  • add SA governance fields such as SA reference and actor reference where needed
  • apply PA/proxy filtering and invariants through those fields

Examples of likely direct extension:

  • contacts on res.partner
  • transactional records that remain native Odoo documents
  • asset-related records when SA only needs governed visibility over the native record

4. Use A Wrapper Only When It Adds Real Semantic Value

An ov.* wrapper object is justified only when the wrapper carries business or governance meaning that the native Odoo object does not express cleanly.

A wrapper is more defensible when one or more of these are true:

  • the governed object needs its own SA-specific lifecycle
  • the governed object needs a stable identity while its native reference may change over time
  • the governed object aggregates or normalizes multiple native Odoo object types behind one governed concept
  • the governed object needs governance semantics that should not be pushed directly into the native object model
  • the governed object must persist even when the underlying native reference is temporarily null, detached, or replaced

If these conditions are not present, a wrapper is probably unnecessary.

5. A Wrapper Must Not Be Created Just To Repeat Native Structure

Do not introduce an ov.* wrapper merely because:

  • the object participates in SA visibility
  • the object needs {actor, sa} stamps
  • the object is accessed through PA
  • the object is important to the business domain

Those reasons alone usually justify direct extension, not a wrapper.

A wrapper must earn its existence by adding a distinct semantic layer.

6. Native Object First, Governance Layer Second

When deciding model shape, ask in this order:

  1. What is the real Odoo object of record?
  2. Does that object already carry the correct business identity and lifecycle?
  3. Is SA only adding governed visibility and controlled action scope?
  4. If not, what new semantic layer is missing that justifies an ov.* object?

If the answer stops at step 3, extend the native model.

If step 4 reveals a genuinely distinct governed object, a wrapper may be appropriate.

7. Naming Rule

If a wrapper is justified, it may still use the ov.* namespace.

That does not imply:

  • it is tightly coupled to every other ov.* model
  • it must mirror the full SA business vocabulary in the technical model name

Model relationships must remain explicit in fields and invariants.

Namespace similarity alone is not architecture.

8. Current Practical Guidance For This Repo

Current repo direction is:

  • use native Odoo objects as the business substrate wherever possible
  • keep SA focused on login governance, visibility, and operational scoping
  • use {actor, sa} as the primary current-state governance stamp
  • introduce ov.* wrappers only where they add a real semantic layer that cannot be expressed cleanly by direct extension

Additional assignment rule:

  • do not inherit PA visibility broadly from res.partner structure
  • do not build one universal SA-visibility engine for every model
  • use explicit SA scoping only where governance truly matters
  • keep some records global when SA scoping is unnecessary
  • prefer structural derivation over duplicate assignment when an object's SA scope is already implied by an SA-scoped parent or container

This is a conservative design rule.

It reduces:

  • duplicated object graphs
  • unclear ownership between native and wrapper records
  • accidental divergence between Odoo truth and SA-governed truth

9. Visibility Regimes And CRUD Baselines

The same model may appear under different usage regimes.

Do not derive CRUD policy from model name alone.

Derive it from the role the record is playing in the governed workflow.

9.1 Actor-Assigned Records

These are work objects naturally tied to a person.

Typical examples:

  • tasks, activities, and tickets
  • deals or opportunities
  • sales orders in PA workflow
  • reservations
  • assignment edges for customers or assets

Default rule:

  • Read
  • filtered by {actor, sa} or approved hierarchy expansion
  • Create
  • allowed in the active PA context when the actor is valid in the current SA
  • Update
  • allowed to the assigned actor, authorized manager, or explicit reassignment flow
  • Delete
  • usually restricted; prefer cancel, close, or reassignment over destruction

9.2 SA-Shared Records

These are durable records visible to the SA as a whole rather than to one actor.

Typical examples:

  • products made available to one SA
  • shared fleets or locations
  • shared asset pools
  • shared catalogs, pricing, or reference objects
  • customer records visible to the whole SA

Default rule:

  • Read
  • controlled primarily by SA affiliation
  • Create
  • restricted to authorized management or setup authority, not ordinary actor touch history
  • Update
  • restricted to authorized stewardship roles because the object is shared
  • Delete
  • usually replaced by archive, retire, deactivate, or de-affiliation

For these records, actor may exist for audit or temporary assignment, but it should not be assumed to be the primary visibility selector.

Common implementation shapes for SA-shared records may include:

  • direct SA reference on the record
  • an explicit SA-link or affiliation record
  • derived visibility from an already SA-scoped parent/container

The choice should be made per model.

It should not be forced into one universal assignment pattern.

9.3 Structurally Affiliated Records

These are long-lived records whose meaning comes from structure, containment, or reference relationships.

Typical examples:

  • company or partner trees
  • product masters and variants
  • location hierarchies
  • serialized stock items
  • warehouse structures
  • SA membership and SA hierarchy objects

Default rule:

  • Read
  • derived from structural affiliation and SA-governed operating scope
  • Create
  • controlled because structural objects define or reshape the operating universe
  • Update
  • highly conservative because changes may affect many downstream records
  • Delete
  • usually forbidden after operational use; prefer archive, detach, retire, or exceptional migration flow

For these records, the important manipulation is often not free-form CRUD, but controlled structural operations such as:

  • attach
  • detach
  • assign
  • reassign
  • transfer
  • retire
  • archive

res.partner hierarchy must not be treated as the universal inheritance path for PA visibility.

Reason:

  • res.partner structure represents business identity and CRM/commercial reality
  • SA represents PA governance reality

These may overlap, but they are not the same thing.

Broadly inheriting PA visibility from partner structure would blur:

  • legal or commercial relationship
  • portal governance scope
  • operational asset access

9.4 Practical Rule

Use these shorthand tests:

  • work object -> actor_assigned
  • shared resource -> sa_shared
  • master or structure object -> structurally_affiliated

The same underlying Odoo model may move between regimes depending on how it is used in PA.

10. Open Application To Asset Design

This note does not itself decide the final ov.asset shape.

It does define the review test that ov.asset must pass:

  • if assets only need SA visibility and controlled operations, direct extension of native Odoo asset-related objects is the preferred baseline
  • if ov.asset adds a real governed semantic layer with its own justified identity and lifecycle, it may still be appropriate

Current open direction to test explicitly:

  • locations or fleets are strong candidates for explicit SA scoping
  • asset/item visibility should derive from assigned fleet or location where that structure already expresses SA scope
  • products should remain global unless SA-specific catalog exposure is actually required
  • customer master visibility, customer SA scope, and customer actor assignment should be treated as separate concerns rather than collapsed into one rule

That evaluation should be done explicitly rather than assumed from naming alone.

11. Conservative SA-Stamping Summary

Use the following table as the default guidance for PA developers and Odoo executive controllers.

The bias is conservative:

  • do not stamp until a real SA visibility need is known
  • prefer no extension over placeholder extension
  • prefer sa only over {actor, sa} when actor assignment is not truly needed
Odoo model or record class Suggested starting rule Typical visibility source Notes
res.partner customer master defer Not yet settled Keep customer identity, SA visibility, and actor ownership separate until the workflow is clear
res.partner company or site records no stamp Native Odoo identity and structure Do not turn partner hierarchy into the universal PA visibility engine
product.template no stamp Global unless SA-specific catalog exposure is required Add SA logic only if catalogs really differ by SA
product.product no stamp Usually inherited from product/catalog rules Extend only if variant-level SA visibility becomes necessary
sale.order in PA workflow sa + actor Current SA and current actor Natural actor-scoped commercial session/work object
Lead, opportunity, ticket, task, case sa + actor Current SA and current actor Workload and ownership are actor-driven
Payment status summary for a current customer interaction no direct stamp on payment object by default Derived from the customer session/order/service context Expose through PA by bounded query, not broad accounting access
ov.outlet sa only if SA governance is needed; otherwise no stamp Usually outlet or channel affiliation Use only if outlet visibility must differ by SA
stock.location used as governed fleet or service location sa only Explicit SA affiliation Strong candidate for explicit SA scope because it is shared and structural
stock.location internal logistics not exposed through PA no stamp Native Odoo access only Do not add SA semantics where PA governance is irrelevant
stock.production.lot or serialized asset item no stamp initially Derived from SA-scoped location or fleet Add direct SA or actor fields only if derivation fails for a real use case
Reservation, custody, issuance, return, or assignment record sa + actor Current SA and assigned actor True actor-assigned operational records
Shared customer assignment edge sa + actor on the assignment record Assignment relation, not customer master alone Better than forcing actor ownership onto the durable customer master
SA membership object separate SA-native governance object ov.membership / SA hierarchy Not a generic stamp case
Optional ov.asset defer Not yet settled Introduce only if it adds real semantic identity or lifecycle beyond native Odoo structure

Practical Decision Rule

If the situation is... Use this approach
Visibility is already correctly determined by existing Odoo relations Add no stamp
Record is shared within one SA Add sa only
Record is assigned to one actor within one SA Add sa and actor
Visibility design is still unresolved Defer extension