Skip to content

Consignment Agreements

Who this is for

The operator (admin) and anyone setting up the Reyder ↔ Axis business relationship. Once an agreement is active and running, sales ops and warehouse don't need to touch it.

What you'll accomplish: create the single agreement that lets Reyder see, sell, and earn commission on Axis Mobile's devices.


What a consignment agreement actually is

A formal record in the system that says:

"Axis Mobile owns these devices. They allow Reyder Enterprises to sell them and keep a commission. The commission is X."

Without an active agreement, Reyder can't see Axis's devices, can't allocate them to sales orders, and can't invoice customers for them. The agreement is the switch that connects the two companies.

In practice there's usually just one agreement at a time (Reyder ↔ Axis). You set it up once during onboarding, then leave it alone until the commission terms change.


Step 1 — Open the agreements list

Go to Inventory → Device Inventory → Agreements.

Consignment agreements list

You'll see the active agreement (and any historical ones, filtered out by default). Click New to create one, or click an existing row to edit.


Step 2 — Fill in the form

Consignment agreement form

Required

Field What to enter
Agreement Name Descriptive — e.g. Reyder-Axis Consignment 2026
Inventory Owner The company that owns the phones. For Reyder/Axis, set this to Axis Mobile.
Authorized Seller (Consignee) The company that will sell. Set to Reyder Enterprises.
Commission Type See the commission guide below
Commission Rate Depends on commission type

Optional

Field What it does
Start Date When the agreement takes effect (defaults to today)
End Date Expiry date — leave blank for an open-ended agreement
Owner Sees Device Status Can Axis see whether a phone is available / reserved / sold?
Owner Sees Commission Earned Owner-side visibility flag for commission summary information. Owner reports still do not expose customer, sale price, sale date, SO number, or per-device commission lines.
Terms & Conditions Free-text legal language

Step 3 — Pick a commission type

Percentage of sale (most common)

Reyder keeps a fixed % of each sale price. Axis gets the rest.

Enter as a decimal, not a whole number

To configure 15%, enter 0.15 in the Commission Rate field — not 15. Odoo's percentage widget will display 0.15 as 15% in the UI, but you must enter it as the decimal.

Entering 15 would be interpreted as 1500%, which is never what you want.

Examples at 15%:

Sale Price Commission Axis Gets
$800 $120 $680
$600 $90 $510
$450 $67.50 $382.50

Fixed amount per device

Reyder keeps a fixed dollar amount per sale, regardless of price. Axis gets the rest.

Enter the dollar amount in Commission Rate — e.g. 50 for $50/device.

The system caps the commission at the sale price (it won't go negative on a cheap device):

Sale Price Fixed Commission Axis Gets
$800 $50 $750
$300 $50 $250
$40 $40 (capped) $0

None

No commission. Axis receives the full sale price. Used for internal transfers or special cases where Reyder waives the fee.


Step 4 — Activate the agreement

Click Activate.

Agreement state buttons

The moment you activate, Reyder can see Axis's devices. Go to All Devices and you should see Axis's inventory show up for Reyder users. If it doesn't, the agreement isn't active — check the state badge at the top of the form.


Agreement states

Draft  →  Active  ⇄  Suspended  →  Terminated
State What it means Can Reyder sell Axis devices?
Draft Created but not in force No
Active Operational — normal state Yes
Suspended Temporarily paused No
Terminated Permanently ended No

Use Suspend to temporarily halt sales (e.g. during a dispute). Use Terminate when ending the business relationship.


Changing the commission rate mid-agreement

You can edit the Commission Rate directly on the active agreement — no need to terminate and recreate. Save the form and the new rate applies to future allocations from that moment forward.

What the rate change does NOT affect:

  • Already-allocated devices keep the commission rate they were allocated at.
  • Already-sold devices and their settlement reports are historical and unchanged.
  • Open/confirmed SOs with allocated devices keep their original commission.

To apply a new rate to an open order, de-allocate and re-allocate the devices — the re-allocation pulls the current rate.


Smart buttons on the agreement

The form header shows three live counters:

Counter What it shows
Consigned Devices Axis devices currently Available — Reyder's saleable inventory
Sold via Consignment Axis devices that Reyder has sold
Pending Settlement Sold devices whose settlement hasn't been marked paid yet

Click any of them to see the underlying device list.


Common problems

I can't see Axis's devices as a Reyder user

Check the agreement state — if it's not Active, Reyder can't see Axis inventory. Also check that you're logged in with a Reyder user (not Axis), since the record rule is company-scoped. Admin is a member of both, so test with a Reyder-only user to verify.

Commission isn't being calculated on new allocations

Most likely causes: (a) no active agreement between the owner and consignee, (b) the device's owner_company_id is set to Reyder (so it's not a consignment device — Reyder owns it directly, no commission applies).

??? question '"Only one agreement allowed between the same companies" error on create' There's already an agreement between Reyder and Axis (even a Terminated one — the unique constraint doesn't care about state). Find the existing row and either edit it or delete it first. Edit is usually preferred — you retain the history.

I changed the commission rate but old orders didn't update

That's by design. Historical allocations keep the rate they were created with to preserve accounting integrity. For an open order, de-allocate and re-allocate the devices to pick up the new rate.

What's the difference between Suspended and Terminated?

Suspended is reversible — click Activate to resume. Terminated is a hard stop; you'd create a new agreement if you wanted to resume (and the unique-pair constraint requires you to delete the terminated one first, or edit it instead of recreating).


Under the hood

Technical details for developers

Model: device.consignment.agreement

State methods:

  • action_activate()state='active' + _recompute_device_consignees()
  • action_suspend()state='suspended' + recompute
  • action_terminate()state='terminated' + recompute
  • action_reset_draft()state='draft' + recompute

Commission calculation:

agreement.calculate_commission(sale_price, currency=None)
# → (commission_amount, owner_amount) tuple

Uses odoo.tools.float_round with currency rounding. Returns (0.0, 0.0) for non-positive sale_price.

Device visibility mechanism:

stock.lot.consignee_company_ids is a stored, computed Many2many populated by _compute_consignee_companies(). For each device:

  1. Query all active agreements where owner_company_id == lot.owner_company_id
  2. Collect consignee_company_id values
  3. Store on the lot

Batch-optimized to do one search per set of owner companies, not per-device (avoids N+1).

Record rule in security/security.xml:

<field name="domain_force">[('consignee_company_ids', 'in', company_ids)]</field>

This is what opens cross-company visibility — a Reyder user (company_ids=[1]) sees Axis's lots because consignee_company_ids contains Reyder's id.

unlink() behavior: captures owner_company_ids before deletion, calls super().unlink(), then recomputes. Without this, deleted agreements would leave stale consignee_company_ids entries.

Constraints:

  • UNIQUE(owner_company_id, consignee_company_id) — one agreement per ordered pair
  • CHECK(owner_company_id != consignee_company_id) — no self-consignment
  • _check_dates() — end_date must be after start_date

get_active_agreement() class method:

@api.model
def get_active_agreement(self, owner_company_id, consignee_company_id):
    return self.search([
        ('owner_company_id', '=', owner_company_id),
        ('consignee_company_id', '=', consignee_company_id),
        ('state', '=', 'active'),
        '|', ('date_start', '=', False), ('date_start', '<=', fields.Date.today()),
        '|', ('date_end', '=', False), ('date_end', '>=', fields.Date.today()),
    ], limit=1)

Used by the allocation wizard and by _create_settlement_reports() to find the applicable agreement at computation time.

commission_rate storage gotcha:

Stored as fields.Float(digits=(16, 4)). Odoo 19's auto percentage widget multiplies by 100 for display — so 0.15 displays as 15%. calculate_commission() does sale_price * self.commission_rate directly (no /100 needed).