Skip to content

ADR 0008: Assembly-MRP Process with SA Governance

Status

Draft

Date

2026-06-18


Context

dirac-odoo already defines:

  1. SA governance model (ADR 0005): SAs govern POS transactions, with agents (cashiers), SA managers, and three-tier reporting.
  2. Fleet/ITEM model (ADR 0004): ov.fleet, ov.fleet_item, and native Odoo stock.production.lot (serialized ITEM).
  3. Asset registry (ADR 0007): ov.asset.registry and ov.asset.component created at MO completion.

The assembly-MRP process (CKD → FG transformation) is currently documented in asset-lifecycle repo (ADR 0001, ADR 0002). But the Odoo implementation needs SA-governed access control, following the same pattern as POS:

  • Assembly line = SA (like a retail shop)
  • Assembly cell = sub-SA or team within the line
  • Line worker = agent (like cashier)
  • Line manager = SA manager (like shop manager)

This ADR defines the SA governance layer for assembly-MRP, and how it produces ITEM-level asset tracking.


Decision

Adopt the SA governance model for assembly-MRP processes.

The assembly line and its cells are organized as SAs. Line workers and line managers have the same organizational structure as sales agents and sales managers in the POS model.


1. Assembly as MRO Function — MRP Process Reference

Design Principle

Assembly is a manufacturing resource planning (MRP) function, not a sales function. It references Odoo MRP processes and models directly.

Odoo MRP Models Used

Odoo Model Role in Assembly
mrp.production Manufacturing order (MO) — the assembly work order
mrp.bom Bill of Materials — CKD package → FG transformation
mrp.bom.line BoM line — CKD component consumption
stock.move Stock movement — CKD consumed, FG produced
stock.lot Lot (CKD) and serial (FG) tracking
stock.quant On-hand quantity at each stock location
stock.location OVT/CKD Materials, OVT/Assembly, OVT/Test, OVT/Quality, OVT/Finished Goods

Assembly Flow (MRP-Native)

  1. Plan: MRP run or manual MO creation
  2. Issue: CKD lot issued to assembly line (stock move: OVT/CKD MaterialsOVT/Assembly)
  3. Assemble: Capture component serials (chassis_id, motor_id, mcu_id)
  4. Test: Assembly line test (stock move: OVT/AssemblyOVT/Test)
  5. Quality: Quality check (stock move: OVT/TestOVT/Quality)
  6. Package: Packaging (stock move: OVT/QualityOVT/Finished Goods)
  7. Complete: MO completion → FG serial created → ov.asset.registry record created

2. Assembly Generates NEW Item — BoM Consumption + Stock Transfer

Design Principle

Assembly generates a new ITEM (serialized FG asset) by consuming BoM items (CKD package). Stock transfer happens within the assembly process.

What Happens at Assembly

Step Physical Action Odoo Transaction ITEM-Level Effect
CKD issued CKD lot moves to assembly line stock.move: OVT/CKD MaterialsOVT/Assembly CKD lot still lot-tracked
Component captured chassis_id, motor_id, mcu_id revealed Recorded in MO or custom form Component identity formed
FG produced Assembly complete → FG serial created mrp.production done → stock.lot (serial) created NEW ITEM exists in system
Registry created Asset birth certificate issued ov.asset.registry record created ITEM now governed
FG put away FG moves to finished goods stock.move: OVT/AssemblyOVT/Finished Goods ITEM now available for sale

Stock Transfer Chain

OVT/CKD Materials  →  OVT/Assembly  →  OVT/Test  →  OVT/Quality  →  OVT/Finished Goods
     (CKD lot)              (WIP)           (WIP)        (WIP)            (FG serial)

Each transfer is an Odoo stock.move. The assembly line SA governs which locations are accessible to which workers.

BoM Consumption

The BoM (mrp.bom) defines:

  • CKD package (lot-tracked input)
  • FG motorcycle (serial-tracked output)
  • Component serialization (captured at assembly, not pre-recorded)

BoM consumption happens at MO confirmation/completion. The CKD lot is consumed, and the FG serial is produced.


3. Model at ITEM Level — FLEET, ITEM, Odoo Serial

Design Principle

Asset tracking is modeled at ITEM level (serialized asset). ov.fleet, ov.fleet_item, and Odoo stock.production.lot (serial) are the basis.

ITEM Identity Stack

Layer Model Description
Conceptual asset-lifecycle repo Lifecycle rules, warranty scoping
Registry ov.asset.registry Stable asset identity anchor
Component ov.asset.component Component lineage and replacement history
ITEM stock.production.lot (serial) Odoo-native serialized ITEM
Fleet ov.fleet + ov.fleet_item Operational grouping (survives location change)
SA Governance ov.sa_fleet + ov.actor_sa_fleet Which SA governs which fleet/ITEM

How ITEM Enters SA Governance

After assembly (MO completion + ov.asset.registry creation), the ITEM (FG serial) may be:

  1. Assigned to a fleet (ov.fleet_item)
  2. Assigned to an SA (ov.sa_fleet)
  3. Transferred to sales (stock move to retail location)
  4. Sold to customer (POS transaction, SA-governed via ov.sa_pos_order)

The SA governance chain:

SA (assembly line)  →  ov.sa_fleet  →  ov.fleet  →  ov.fleet_item  →  stock.production.lot (ITEM)

This is the same pattern as POS: - POS: SA → ov.sa_pos_order → ov.sa_pos_order → pos.order - Assembly: SA → ov.sa_fleet → ov.fleet → ov.fleet_item → stock.production.lot


4. SA Governance for Assembly-MRP

Design Principle

Follow the same SA governance model as POS. Assembly line + cells organized as SAs. Line workers and line managers = sales agents and sales manager analog. SA context for each MO is recorded in association tables (ov.sa_mo, ov.actor_sa_mo), not in mrp.production itself (per ADR 0003).

SA Structure for Assembly

SA Level Analog Role
Assembly Line SA Retail shop SA Governs one assembly line
Assembly Cell (sub-SA) Shop team Governs one cell within the line (optional)
Line Worker Cashier (agent) Executes assembly on assigned MOs
Line Manager SA Manager Manages line, aggregates reports

SA Governance Rules for Assembly

Rule Description
SA governs MO via association table Every MO has a corresponding ov.sa_mo row linking it to its governing SA + assigned worker
Worker accesses assigned MOs Worker (agent) sees only MOs linked to them in ov.actor_sa_mo (or unassigned within SA)
Manager aggregates Line manager (SA manager) sees all MOs within the line
Parent SA rolls up Parent SA (regional) sees roll-up over child SAs (multiple lines)
Fleet/ITEM scoped to SA Fleets/ITEMs produced by this line are governed by this SA (until transfer)

Association Tables for Assembly SA

Table Purpose Points To
ov.sa_fleet Which SA governs this fleet? ov.serviced_account + ov.fleet
ov.actor_sa_fleet Which actor (worker) is assigned to this fleet? ov.sa_fleet + res.partner
ov.sa_mo (future) Which SA governs this MO? ov.serviced_account + mrp.production
ov.actor_sa_mo (future) Which worker is assigned to this MO? ov.sa_mo + res.partner

SA Context Recorded via Association Tables

When an MO is created, a corresponding row is inserted into ov.sa_mo linking the MO to its governing SA. When a worker is assigned, a row is inserted into ov.actor_sa_mo. No fields on mrp.production are modified.

SA context row in ov.sa_mo

Each row in ov.sa_mo links one MO to its governing SA:

# ov.sa_mo row (association table — does NOT modify mrp.production)
{
  'sa_id': ov.serviced_account.id,     # Which SA (assembly line) governs this MO
  'mo_id': mrp.production.id,          # Which MO
  'created_at': datetime,                # When the MO was created
}

Worker assignment is a separate row in ov.actor_sa_mo:

# ov.actor_sa_mo row (association table)
{
  'sa_mo_id': ov.sa_mo.id,            # Link to the SA-MO association
  'actor_id': res.partner.id,            # Which worker is assigned to this MO
  'assigned_at': datetime,               # When the worker was assigned
}

5. Assembly Worker Identity — System Level + SA Context Level

Design Principle

All assembly workers are identified at both system level and SA context level. Context of each action is recorded via ov.actor_sa_mo rows (per ADR 0003: no modification to native Odoo models).

Two-Level Identity (Same as POS)

Level What It Means Odoo Mechanism
System level Worker has an Odoo identity (res.partner + ov.membership) res.users login, res.partner record
SA context level Worker is a member of specific assembly SAs with defined role ov.membership record, ov.actor_sa_* records

Worker Action Context: recorded in ov.actor_sa_mo

Every assembly action (MO start, component capture, MO complete) triggers a row in ov.actor_sa_mo (or ov.sa_mo_event for action-level granularity). The SA + actor are never written to mrp.production.

Example ov.actor_sa_mo row for worker assignment:

# ov.actor_sa_mo row (association table — no modification to mrp.production)
{
  'sa_mo_id': ov.sa_mo.id,            # Link to the SA-MO association
  'actor_id': res.partner.id,            # Which worker
  'assigned_at': datetime,               # When assigned
}

For action-level tracking (optional future extension), ov.sa_mo_event rows capture:

{
  'sa_mo_id': ov.sa_mo.id,
  'actor_id': res.partner.id,
  'action': 'start' | 'capture_component' | 'complete',
  'timestamp': datetime,
}

6. Reporting Privileges — Three Tiers (Same as POS)

Design Principle

Each worker can view history data within an SA context. Aggregation among members of an SA is the privilege of the SA Manager only. Aggregation along the SA tree is the sole privilege of the parent SA over its child-SAs.

Tier 1: Worker — View Own + Assigned

A worker (assembly line agent) can view:

  • Their own MO history within the SA
  • MOs explicitly assigned to them (if scope_policy='assigned_only')
  • Unassigned MOs within the SA (if scope_policy='assigned_plus_unassigned')

They cannot see other workers' MOs within the same SA (unless scope_policy='sa_wide').

Tier 2: SA Manager — Aggregate Within SA

The SA Manager (ov.membership.is_sa_manager=True) can:

  • View all MOs within their SA (regardless of which worker executed them)
  • Generate aggregate reports (total units produced, yield rate, defect rate)
  • Export data for analysis
  • Manage membership (add/remove workers, change roles)

They cannot see MOs in other SAs (unless those SAs are child-SAs).

Tier 3: Parent SA — Aggregate Over Child-SAs

A parent SA (assembly regional SA with multiple lines) can:

  • View MOs across all child-SAs in the SA tree
  • Generate roll-up reports ("total production across all lines")
  • Compare performance across child-SAs

7. ITEM Production Tracking — Yield, Quality, Productivity

Design Principle

The birth certificate (ADR 0007) captures what was produced. The SA governance layer captures who, where, and how efficiently.

Production Data Captured at ITEM Level

Data Source Purpose
mo_id mrp.production Which MO produced this ITEM
sa_id ov.sa_mo Which assembly line produced it
actor_id ov.actor_sa_mo Which worker produced it
yield_rate MO time tracking How efficiently
quality_result Quality check Pass/Fail/Rework
component_ids ov.asset.component Which components were used

This data enables:

  • Productivity tracking: Which worker/line is most efficient?
  • Quality tracking: Which worker/line has highest defect rate?
  • Traceability: If a defect is found, which worker/line produced the affected ITEMs?

8. SA Scope = ACL (Same as POS)

Design Principle

SA scope is a field decision, but carries heavy responsibility — because this defines ACL.

What "Field Decision" Means for Assembly

The operations/field team decides:

  • How many assembly line SAs to create (one per line? per shift? per product model?)
  • Which workers belong to which line SA
  • What scope_policy each membership has

These are business decisions, not technical decisions. But they have security consequences — because SA scope = access scope.

SA Scope IS ACL

There is no separate "ACL configuration" step. The act of:

  1. Creating an SA (ov.serviced_account) for an assembly line
  2. Adding a worker to it (ov.membership)
  3. Setting scope_policy on the membership

... is the ACL configuration. The ir.rule (Track B in ADR 0006) then enforces this ACL on every query.


9. Open Questions

9.1 Multi-Line Worker

Can a worker belong to multiple assembly line SAs? (Yes — like a cashier with multiple shop memberships.)

9.2 Cross-Line Material Transfer

Can CKD materials be transferred between assembly line SAs? (Yes — but must be governed by a parent SA or material management SA.)

9.3 Quality Check SA

Is quality check a separate SA, or part of the assembly line SA? (Open — may be separate for independence.)

9.4 ITEM Transfer Between SAs

When an ITEM (FG serial) is transferred from assembly SA to sales SA, how is SA context updated? (Likely: new ov.sa_fleet record for the sales SA, old one marked inactive.)


Consequences

  1. Assembly line = SA — same governance model as POS, consistent across field operations
  2. Worker identity is two-level — system (Odoo user) + SA context (membership), action context recorded via ov.actor_sa_mo rows`
  3. ITEM-level trackingov.fleet, ov.fleet_item, stock.production.lot are the basis; SA governance attaches via ov.sa_fleet
  4. MO context via association tables — every MO has a ov.sa_mo row linking SA + actor; association tables enforce subset rule
  5. Reporting is three-tier — worker sees own, SA manager sees all in SA, parent SA sees roll-up over children
  6. SA scope = ACL — field team decides scope, but this directly defines access control; heavy responsibility
  7. Birth certificate + productivityov.asset.registry captures asset identity; SA governance captures who/where/how efficiently

Cross-Reference

  • Conceptual model: asset-lifecycle/docs/adr/0001-ckd-to-fg-transformation-and-asset-identity-regime.md
  • Asset registry implementation: dirac-odoo/docs/adr/0007-asset-registry-and-component-model-implementation.md
  • SA governance (POS analog): dirac-odoo/docs/adr/0005-v3-pos-applet-design.md
  • Fleet/ITEM model: dirac-odoo/docs/adr/0004-fleet-and-item-governance-layer.md
  • Association model pattern: dirac-odoo/docs/adr/0003-v3-association-model-migration-pattern.md