Skip to content

Operations Setup Guide — Sales Workflow

Purpose: Step-by-step configuration checklist for the Odoo operations team to enable the full sales-to-cash workflow described in SALES_WORKFLOW.md.

Who this is for: Odoo administrators and operations leads who configure the Odoo backend.
Who this is NOT for: Developers. For API endpoint details see SALES_WORKFLOW.md. For customer governance see CUSTOMER_LIFECYCLE.md.

Module version: abs_connector 18.0.1.1.4


Before You Start — Installed Modules Checklist

Verify these Odoo modules are installed before configuring anything. Go to Settings → Apps.

Module Technical name Required for
Sales sale_management Quotations, orders, approval workflow
Inventory stock Warehouses, deliveries, stock tracking
Invoicing / Accounting account or account_accountant Invoices, payments, journals
Helpdesk helpdesk Support tickets
Subscriptions sale_subscription Recurring billing
ABS Connector abs_connector All custom governance, SA, employee JWT

If any are missing, ask your Odoo administrator to install them before proceeding.


1. Company Settings

Path: Settings → General Settings → Companies

1a. Verify your company record

Field What to set Why
Name Your legal entity name Appears on invoices and PDFs
Currency Default currency (e.g. XOF, KES, USD) Controls all invoice and payment amounts
Country Correct country Controls tax rules and address format
Logo Upload company logo Appears on pro-forma and invoices

1b. Multi-company (if you operate in multiple countries)

Each country / legal entity should be its own Company in Odoo.

  • Each company gets its own warehouse(s).
  • Each company has its own chart of accounts.
  • Service Accounts (ov.serviced_account) are company-scoped — a seed SA belongs to one company.

Go to Settings → Users & Companies → Companies to create additional companies.


2. Sales Settings

Path: Settings → Sales → Quotations & Orders

2a. Order approval workflow

The API endpoints POST /api/orders/<id>/request-approval, approve, and reject only work if this setting is enabled.

Setting Value Where
Sales Order Approval ✅ Enabled Settings → Sales → Quotations & Orders
Minimum order amount Set your threshold (e.g. 500 USD) Same section — orders above this need approval
Lock Confirmed Sales ✅ Enabled (recommended) Prevents editing after confirmation

2b. Quotation settings

Setting Value Why
Default Quotation Validity e.g. 30 days Sets expiry on new quotations
Pro-Forma Invoice ✅ Enabled Required for GET /api/orders/<id>/proforma-pdf
Default Terms & Conditions Add your legal text Printed on every quotation

If you sell in multiple currencies or have customer-specific pricing:

Path: Sales → Configuration → Pricelists

  • Create one pricelist per currency.
  • Set currency_id on each pricelist.
  • Assign the correct pricelist to each customer (res.partner.property_product_pricelist).

If you do not use pricelists, Odoo defaults to the product's sale price.


3. Inventory / Warehouse Settings

Path: Settings → Inventory

3a. Enable required features

Setting Value Required for
Storage Locations ✅ Enabled Sub-locations within a warehouse
Multi-Step Routes ✅ Enabled 2-step or 3-step delivery/receiving
Lots & Serial Numbers ✅ Enabled Tracking individual solar kit serial numbers
Expiration Dates Optional Only needed if products expire

3b. Create your warehouse(s)

Path: Inventory → Configuration → Warehouses → New

One warehouse per physical depot or country.

Field Example value Notes
Warehouse Name Main Warehouse Human-readable name shown in all reports
Short Name WH Used as prefix on picking names (WH/OUT/00001)
Company Select your company Each company can have multiple warehouses
Outgoing Shipments Ship only (1 step) or Pick + Ship (2 steps) Start with 1-step unless you have a packing area
Incoming Shipments Receive only (1 step) or Receive + Quality (2 steps) 1-step is sufficient for most operations

Odoo automatically creates the required picking types (Receipts, Deliveries, Internal Transfers) and stock locations when you save a new warehouse.

3c. Verify auto-created locations

After saving the warehouse, check that these locations exist:

Path: Inventory → Configuration → Locations

Location Usage Notes
WH/Stock internal Main storage — source of all deliveries
WH/Input internal Goods arrive here (only if 2/3-step receiving)
WH/Output internal Staging area before dispatch (only if 2-step delivery)
Partners/Customers customer Virtual — delivered units "live" here
Partners/Suppliers supplier Virtual — source of all receipts
Virtual/Inventory inventory Used for stock adjustments
Virtual/Scrap inventory Damaged / end-of-life units

These are created automatically. You only need to create sub-locations (e.g. WH/Stock/Solar Kits, WH/Stock/Accessories) if you want more granular reporting.

3d. Optional sub-locations

Create sub-locations under WH/Stock to organise by product family:

Path: Inventory → Configuration → Locations → WH/Stock → Create Child

Suggested structure for this system:

WH/Stock
  ├── WH/Stock/Solar Kits
  ├── WH/Stock/E-Mobility
  ├── WH/Stock/Accessories
  └── WH/Stock/Spare Parts

3e. Verify picking types

Path: Inventory → Configuration → Operations Types

Each warehouse must have these three operation types:

Operation Type Code Default from Default to
Receipts incoming Vendors (virtual) WH/Input or WH/Stock
Delivery Orders outgoing WH/Stock or WH/Output Customers (virtual)
Internal Transfers internal WH/Stock WH/Stock

If the picking types are missing, delete and re-create the warehouse.


4. Product Configuration

This is the most critical section. How a product is configured determines whether it creates a delivery, tracks serial numbers, and when it can be invoiced.

4a. Product type — the most important field

Path: Inventory → Products → [Product] → General Information tab

product_type Odoo label Creates delivery on sale Stock tracked When to use
product Storable Product ✅ Yes ✅ Yes + serial numbers Solar kits, batteries, physical hardware
consu Consumable ✅ Yes (no stock check) ❌ No Cables, small accessories, installation materials
service Service ❌ No delivery ❌ No Installation fee, warranty fee, SIM card plan

Rule: Every physical unit that needs a serial number must be storable.

4b. Serial number tracking

Path: Product → General Information → Tracking

Only set this on storable products.

Value When to use
By Unique Serial Number One serial per unit (e.g. each solar kit gets its own SN)
By Lots Batch of identical units share one lot number (e.g. bulk accessories)
No Tracking Product is storable but individual units are not tracked

Rule for this system: All solar kits and batteries must be By Unique Serial Number. This is required for asset governance — ov.asset links to a stock.lot (serial number).

4c. Invoice policy

Path: Product → General Information → Invoicing Policy

Value What it means When to use
Ordered quantities Invoice can be created as soon as the order is confirmed Services, subscriptions, consumables
Delivered quantities Invoice cannot be created until the delivery is validated Physical hardware (storable products)

Rule for this system: - Solar kits, batteries, accessories → Delivered quantities - Installation, warranty, service → Ordered quantities

If you set Delivered quantities on a storable product, POST /api/orders/<id>/invoice will fail until POST /api/stock/deliveries/<id>/validate has been called first.

4d. Wangvision PU custom fields

Path: Product → [Custom tab or inline fields]

These custom fields drive the Wangvision PU taxonomy. They must be set for all products sold through the system.

Field Technical name Values Required for
PU Category x_pu_category solar_home, e_mobility, cross_grid, off_grid Product filtering in API
PU Metric x_pu_metric e.g. watt_peak, kwh, count Reporting and pricelist logic
Service Type x_service_type hardware, service, subscription, warranty Subscription and invoicing routing
Contract Type x_contract_type one_off, lease, paygo, subscription Subscription module behaviour

If these fields are not visible on the product form, ask the developer to verify the abs_connector module is installed and the views are loaded.

4e. Set a sales price and tax

Path: Product → General Information → Sales Price + Customer Taxes

Field What to set
Sales Price Default unit price (can be overridden on the order line)
Customer Taxes Select the correct VAT or sales tax for this product

Tax must be configured before it appears in the dropdown. See Section 6.

4f. Bill of Products (BOP) — for bundled kits

If you sell bundled products (e.g. a "Solar Home System 200W" that contains a panel, battery, and charge controller), you need a Bill of Products.

Path: Product → Bill of Products tab (or via GET/POST /api/products/<ref>/bom)

Each BOP line defines: - Component product - Quantity - Whether it is substitutable

The BOP is not a manufacturing Bill of Materials. It is a custom bundle definition specific to this system. Do not use the standard Odoo BOM (mrp.bom) unless manufacturing is enabled.

4g. Product categories

Path: Inventory → Configuration → Product Categories → New

Odoo uses product.category for accounting rules (which income account to credit on invoice).

Minimum set to create:

Category Mapped to
Solar Kits Solar Kit products
E-Mobility E-bike and e-mobility products
Accessories & Spare Parts Non-tracked accessories
Services & Warranties Service-type products

Each category must have: - Account Properties → Income Account → correct revenue account - Account Properties → Expense Account → correct COGS account

If accounts are not set, Odoo cannot post the invoice.


5. Customer (Contact) Configuration

Path: Sales → Orders → Customers → New
Or via API: POST /api/contacts

5a. Required fields for a customer to receive a sale order

Field Technical name Mandatory? Notes
Name name ✅ Yes Customer display name
Customer Rank customer_rank ✅ Yes Must be ≥ 1 for Odoo to treat as customer
Email email Recommended Required for invoice email (POST /api/invoices/<id>/send)
Phone phone Recommended Required for field operations
Address / Country street, country_id Recommended Required for proper invoice PDF
Payment Terms property_payment_term_id Optional Overrides default
Pricelist property_product_pricelist Optional Customer-specific pricing

5b. SA governance (Level 2 customers)

If the customer should be visible only within a specific Service Account:

  1. The customer must be created via POST /api/contacts with a valid employee JWT (not API key).
  2. The JWT carries the sub (employee ID) which determines which SA the customer belongs to.
  3. An ov.sa_customer_assignment record is created automatically linking the customer to the SA.

Customers created with an API key (no JWT) are plain res.partner records with no SA governance. They are visible to all users.


6. Accounting Setup

Path: Accounting → Configuration

6a. Chart of accounts

Odoo installs a localised chart of accounts when the Accounting module is first set up. Verify:

  • At least one bank journal exists (for cash payments)
  • At least one revenue account (e.g. 4000 - Sales Revenue)
  • At least one receivables account (e.g. 1100 - Accounts Receivable)

Path: Accounting → Configuration → Chart of Accounts

6b. Journals

Journal Type Required for
Customer Invoices sale All customer invoice posting
Customer Credit Notes sale Refunds / credit notes
Bank bank Payment registration
Cash cash Cash payments

Path: Accounting → Configuration → Journals

Verify each journal has: - Correct currency_id - Correct default_account_id (income account for sale journals)

6c. Taxes

Path: Accounting → Configuration → Taxes → New

Create your applicable taxes before configuring products.

Field Example
Tax Name VAT 16%
Tax Type Sales
Tax Computation Percentage of Price
Amount 16
Tax Account e.g. 2100 - VAT Payable

Taxes must be set on each product (Section 4e) for them to appear on invoices.

6d. Payment terms

Path: Accounting → Configuration → Payment Terms → New

Term Lines
Immediate Payment 100% due in 0 days
30 Days Net 100% due in 30 days
50% Upfront 50% now, 50% after 30 days

Assign a default payment term on the company: Path: Settings → Accounting → Default Payment Terms


7. Service Account (SA) Governance Setup

This is the custom Omnivoltaic governance layer. It must be configured before any agent (employee) can create governed customers or orders.

7a. What is a Service Account?

A Service Account (SA) (ov.serviced_account) represents a governed operational context — typically a country, region, or depot. All customers, orders, and assets created within an SA are visible only to members of that SA.

7b. Create a Service Account

Path: (Custom menu — ask developer to point you to the ov.serviced_account list view)

Field Example Notes
Name Togo - Lomé Human-readable SA name
Company Select company SA is company-scoped
Code TG-LOM Short identifier used in filters
State active Must be active for visibility to work
SA Type seed or branch Seed = country root. Branch = sub-region under seed
Parent SA Select parent Only for branch SAs — links to seed SA

Every company needs at least one seed SA before agents can be onboarded.

7c. Assign employees to a Service Account (create memberships)

Every employee who will use the system must be a member of at least one SA.

Path: (Custom menu — ov.membership list view)

Field Value
Employee Select abs.employee record
Service Account Select ov.serviced_account
Role agent or manager
State active
Date From Start date of membership

Manager role: Can approve orders (POST /api/orders/<id>/approve) and manage SA membership. Agent role: Can create customers, quotations, and view data within their SA.

7d. Create the employee record

Before you can create a membership, the employee must exist as an abs.employee record.

Path: (HR or custom employee menu)

Field Value
Name Full name
Email Work email — used for JWT login
Phone Phone number
Company Must match the SA's company
Active ✅ Yes

The employee record is what the JWT is issued for. The sub claim in the JWT is the abs.employee.id.


8. Subscription Configuration

Path: Sales → Configuration → Subscription Plans
Or via the sale_subscription settings.

8a. Subscription plans

A subscription plan defines the billing cycle.

Field Example Notes
Name Monthly PAYGO
Billing Period Monthly Can be monthly, quarterly, annually
Auto-renewal ✅ Yes Required for recurring billing

8b. Subscription products

Any product that should generate recurring invoices must: 1. Have product_type = service 2. Have x_contract_type = subscription or paygo 3. Be linked to a subscription plan

Path: Product → Sales tab → Subscription

If a sale order contains a subscription product, Odoo creates a sale.subscription record upon order confirmation. The subscription then generates invoices automatically on each billing date.

8c. Subscription invoicing

Verify: - Path: Settings → Sales → Subscriptions → Invoice automatically on renewal → ✅ Enabled - Set the invoicing journal to your Customer Invoices journal.


9. Helpdesk Configuration

Path: Helpdesk → Configuration → Teams

9a. Create a helpdesk team

Field Value
Team Name e.g. Customer Support
Visibility All internal users (or specific team)
Assignment Automatic or manual

9b. Configure ticket stages

Path: Helpdesk → Configuration → Stages

The POST /api/tickets/<id>/close endpoint moves a ticket to the first stage with is_close = True. You must configure at least one closing stage:

Stage name is_close Notes
New Default for new tickets
In Progress Being worked on
Waiting on Customer Pending customer reply
Resolved This stage must exist — close endpoint targets it
Cancelled Optional second closed stage

If no stage has is_close = True, the close endpoint will return an error.

9c. Email alias (optional)

If customers should be able to open tickets by email:

Path: Helpdesk → Configuration → Teams → [Team] → Email Alias

Set an email alias (e.g. support@yourcompany.com). Odoo creates tickets from incoming emails automatically.


10. Email / Outbound Mail Configuration

The following API endpoints send emails. They will silently fail or log errors if outbound mail is not configured:

  • POST /api/orders/<id>/send — quotation email
  • POST /api/invoices/<id>/send — invoice email
  • Helpdesk reply notifications

Path: Settings → Technical → Outgoing Mail Servers → New

Field Value
SMTP Server Your mail server (e.g. smtp.gmail.com)
SMTP Port 587 (TLS) or 465 (SSL)
Security TLS or SSL
Username Your sending email address
Password App-specific password

Test the configuration using Settings → Technical → Outgoing Mail Servers → [Server] → Test Connection.


11. Roles & Players — Who Does What

This section defines every role in the ABS governance system, what they can see, and how to set them up in Odoo.


11a. The Four Roles at a Glance

Role role_code Where they live Visibility scope Login method
Admin admin Global Root SA only Every record across every company and every SA Employee JWT
SA Manager staff + manager_member_id = NULL A specific SA All records within their SA Employee JWT
Staff staff + has manager_member_id A specific SA All records within their SA Employee JWT
Agent agent A specific SA Only records explicitly assigned to them Employee JWT

These roles are ABS governance roles. They are separate from Odoo user groups (which apply to the Odoo UI only).


11b. Role Details

Admin ← The King

  • Who: The highest authority in the system. Typically OV HQ leadership, national directors, or the system owner. This is the person who sits at the top of the Global Root SA.
  • What they control:
  • Create, modify, and deactivate any SA anywhere in the system
  • Enroll or revoke members of any SA across all companies
  • See every record — every res.partner, sale.order, account.move, stock.picking, ov.asset, helpdesk.ticket, and subscription — across all companies
  • Manage system-wide governance settings
  • How it works: They are ov.membership records in the Global Root SA with role_code = 'admin'. The API applies no SA filter when the authenticated employee is an admin.
  • Constraint: admin role is only valid for memberships in the Global Root SA. You cannot assign admin role to any other SA. A validation error is raised if you try.
  • Setup:
  • The Global Root SA is created automatically by migration 18.0.1.1.4 (named OV Global Root SA, code OVGLOBAL-ROOT).
  • Create an abs.employee for the person.
  • Create an ov.membership record: account_id = Global Root SA, employee_id = the employee, role_code = admin, scope_policy = sa_wide.

SA Manager

  • Who: The person responsible for a single Service Account (branch, territory, or team). There is exactly one SA Manager per SA.
  • What they see: All records tagged to their SA — customers, orders, invoices, deliveries, assets, and tickets.
  • How it works: The SA Manager's membership has role_code = 'staff' and manager_member_id = NULL. The ov.serviced_account.sa_manager field points to this membership. Because manager_member_id = NULL, the system identifies them as the SA manager.
  • Setup:
  • Create an abs.employee for the person.
  • When creating the SA, pass sa_manager (or the first enrollment automatically promotes the first staff member to SA manager).
  • To explicitly set: create ov.membership with role_code = 'staff', manager_member_id = False, then set ov.serviced_account.sa_manager to that membership ID.

Staff

  • Who: Operational team members who need full visibility within the SA but are not the SA Manager. Examples: back-office coordinators, operations leads.
  • What they see: All records tagged to the SA (same scope as SA Manager).
  • How it works: role_code = 'staff' and manager_member_id points to the SA Manager or another senior staff member. scope_policy is typically sa_wide or assigned_plus_unassigned.
  • Setup:
  • Create abs.employee.
  • Enroll via POST /api/service-accounts/<id>/enroll with body { "employee_id": X, "role_code": "staff", "scope_policy": "sa_wide" } or create ov.membership directly in Odoo.

Agent

  • Who: Field workers, sales agents, technicians. The front-line people who are assigned to specific customers and orders.
  • What they see: Only the records explicitly assigned to them (their assigned customers, their delivery tasks, their tickets).
  • How it works: role_code = 'agent' and scope_policy = assigned_only. The system filters records by checking x_actor_id = employee.partner_id (V2) and ov.sa_*_assignment.actor_id (V3).
  • Setup:
  • Create abs.employee.
  • Enroll via POST /api/service-accounts/<id>/enroll with role_code = "agent".
  • Assign the agent to customers: POST /api/contacts/<id>/assign with actor_id.
  • The agent's orders, deliveries, and assets are then automatically SA-scoped.

11c. The Global Root SA

The Global Root SA is the single cross-company root of the entire SA hierarchy. It is intentionally not tied to any company (company_id = NULL) — it transcends all tenants and acts as the true system root.

OV Global Root SA   ← is_global_root=True, parent_id=NULL, company_id=NULL
  ├── Oves Holdings (HK)   company root SA  (source_company_id = Oves Holdings)
  ├── Oves Kenya           company root SA  (source_company_id = Oves Kenya)
  ├── Oves Togo            company root SA  (source_company_id = Oves Togo)
  │     ├── Branch SA A
  │     │     ├── SA Manager (staff)
  │     │     └── Agents
  │     └── Branch SA B
  └── … (one root SA per company)
Field Value Why
is_global_root True System-wide identifier
company_id NULL Belongs to no company — truly global
parent_id NULL Nothing is above it
source_company_id NULL Not seeded from any company
account_code OVGLOBAL-ROOT Fixed reference code

How it is created: - Migration 18.0.1.1.5 creates it automatically when abs_connector is upgraded. - Migration 18.0.1.1.6 detaches it from any company (company_id → NULL). - A validation constraint prevents a second global root SA from being created. - All existing company root SAs are automatically re-parented under it.

How to verify it exists (API):

GET /api/system/global-root
X-API-KEY: <your-api-key>
Expected response: "exists": true, "company": null, "is_global_root": true.

How to verify the full SA tree (API):

GET /api/system/sa-hierarchy?flat=true
X-API-KEY: <your-api-key>

How to add an Admin (script):

# Edit ADMINS list in the script, then run:
python scripts/add_global_root_admins.py

Or via the API directly:

POST /api/service-accounts/26/members
X-API-KEY: <your-api-key>

{ "person_partner_id": <partner_id>, "role_code": "admin" }

The Admin employee can then authenticate with their JWT and will have unrestricted visibility and control across all companies and SAs.


11d. Odoo User Groups (for UI access)

Employees who also use the Odoo web UI need a res.users account with the correct group. Agents who only use the mobile app do not need a res.users account.

Path: Settings → Users & Companies → Users

Staff role Odoo group to assign
Admin (Global Root SA member) Settings / Technical (or Odoo Administrator)
Sales Manager / SA Manager Sales / Administrator
Sales Staff / Agent Sales / User
Warehouse Staff Inventory / User
Warehouse Manager Inventory / Administrator
Accountant Accounting / Accountant or Administrator
Helpdesk Agent Helpdesk / User
Helpdesk Manager Helpdesk / Administrator

11e. Two login systems side by side

System Used for Credential
res.users (Odoo) Odoo UI, reports, admin tasks Username + password
abs.employee + JWT Mobile app, all /api/* endpoints Authorization: Bearer <jwt>

The same person can have both accounts. Create the abs.employee record first, link it to the res.partner (person record), then optionally create the res.users account.

11f. API key vs employee JWT

Auth method Header Used for SA governance
Employee JWT Authorization: Bearer <token> All governed endpoints; scopes data to the employee's SA and role ✅ Full SA + role filtering
API Key X-API-KEY: <key> System integrations, bulk imports, non-governed reads 🔴 No SA filtering (sees all)
Customer JWT Authorization: Bearer <customer_token> Customer self-service portal Scoped to customer's own records

Warning: Operations staff should always use Employee JWT, not the API key. The API key bypasses all SA visibility rules.

11g. Technical settings for API access

The API key (X-API-KEY) is currently hardcoded in the connector module. Ask your developer for the value and ensure it is kept secret. Rotate it by updating the module configuration.


12. Verification Checklist — Before Going Live

Use this checklist to confirm the system is ready for a first sale.

✅ Warehouse & Stock

  • [ ] At least one warehouse exists with a WH/Stock location
  • [ ] At least one Receipts and one Delivery Orders picking type exist
  • [ ] Storage Locations feature is enabled
  • [ ] Lots & Serial Numbers feature is enabled
  • [ ] Stock has been received via POST /api/stock/receive or manual receipt in Odoo

✅ Products

  • [ ] All storable hardware products have product_type = product
  • [ ] All hardware has tracking = serial
  • [ ] All hardware has invoice_policy = delivery
  • [ ] All service products have product_type = service and invoice_policy = order
  • [ ] All products have x_pu_category set
  • [ ] All products have a Sales Price and at least one Customer Tax

✅ Customers

  • [ ] At least one customer exists with customer_rank ≥ 1
  • [ ] Customer has a valid email address

✅ Accounting

  • [ ] Chart of accounts is configured
  • [ ] Customer Invoices journal exists
  • [ ] Bank journal exists
  • [ ] At least one tax exists and is assigned to products
  • [ ] Income accounts are assigned to product categories

✅ SA Governance

  • [ ] Global Root SA exists (OV Global Root SA, code OVGLOBAL-ROOT, is_global_root = True)
  • [ ] At least one company root SA exists with source_company_id set
  • [ ] At least one seed SA (leaf SA) exists and is active
  • [ ] At least one abs.employee exists
  • [ ] That employee has an ov.membership to the seed SA with state active
  • [ ] At least one Admin membership exists in the Global Root SA (role_code = admin)

✅ Sales Settings

  • [ ] Order Approval is enabled in Settings → Sales
  • [ ] Approval amount threshold is set correctly
  • [ ] Pro-Forma Invoice is enabled

✅ Helpdesk

  • [ ] At least one helpdesk team exists
  • [ ] At least one stage with is_close = True exists

✅ Email

  • [ ] Outgoing mail server is configured and tested

13. Common Configuration Mistakes and How to Fix Them

Symptom Cause Fix
POST /api/orders/<id>/invoice returns error "Nothing to invoice" All products have invoice_policy = delivery but delivery not validated Validate delivery first via POST /api/stock/deliveries/<id>/validate
POST /api/stock/deliveries/<id>/validate returns "Insufficient stock" Products ordered but not received in warehouse Receive stock first via POST /api/stock/receive
POST /api/orders/<id>/request-approval returns error Order Approval not enabled in Settings Enable in Settings → Sales → Quotations & Orders
POST /api/invoices/<id>/send sends but no email received Outbound mail not configured Configure SMTP in Settings → Technical → Outgoing Mail Servers
POST /api/tickets/<id>/close returns "No closing stage" No helpdesk stage has is_close = True Add a closed stage in Helpdesk → Configuration → Stages
Serial number reused error on delivery tracking = serial but same serial already in Partners/Customers Return the unit first, or check GET /api/stock/lots/<lot_name> for its current location
Invoice posts but no SA filter works on it account.move has no SA stamp This is a known Phase 5 governance gap. See SALES_WORKFLOW.md
Agent cannot see customer in their SA Customer created with API key, not JWT Re-create customer using JWT — API key creates ungoverned plain contacts

14. Day-to-Day Operations Reference

Once configured, the typical daily operations flow maps to these API calls:

1. Morning — check stock levels
   GET /api/stock/levels?warehouse_id=1

2. Check pending deliveries
   GET /api/stock/deliveries?state=assigned

3. Validate a delivery (goods dispatched)
   POST /api/stock/deliveries/<id>/validate
   Body: { "lines": [{ "move_id": 501, "qty_done": 1, "lot_id": 55 }] }

4. Create invoice after delivery
   POST /api/orders/<id>/invoice

5. Confirm and send invoice
   POST /api/orders/<id>/invoices/<inv_id>/confirm
   POST /api/invoices/<inv_id>/send

6. Register payment received
   POST /api/orders/<id>/register-payment

7. Check inbound receipts
   GET /api/stock/receipts?state=assigned

8. Validate a receipt (stock received from supplier)
   POST /api/stock/receive
   Body: { "warehouse_id": 1, "validate": true, "lines": [...] }

9. Locate a specific serial number
   GET /api/stock/lots/SN-2025-00123

Companion Documents

Document Purpose
SALES_WORKFLOW.md Full technical workflow, state machines, governance gaps, complete API reference
CUSTOMER_LIFECYCLE.md Customer creation, SA assignment, three-level governance model
ODOO_MODULES_REFERENCE.md All Odoo models used, field inventory, SA governance status