Skip to content

Admin Support Runbook

Use this page for support-only fixes, production checks, and developer/admin recovery tasks. Frontline users should start with Troubleshooting; this runbook is for the person who is allowed to use the Odoo shell, review server logs, or correct configuration after an operational issue.

Support-only

Do not give shell access to warehouse, sales, retail, or accounting users as a workaround for normal workflow problems. If a user hits one of these cases, capture the record name, screenshot, and error message, then have an admin run the recovery.


When to use this runbook

Use it when:

  • A user-facing troubleshooting step says escalate to admin/support.
  • A workflow document was created with the wrong state or missing configuration.
  • You need to verify multi-company rules as a non-admin user.
  • You copied a production database into a development environment.
  • You are validating a deployment before users start work.

Do not use it to bypass normal controls. If the system blocks QC, allocation, shipping, settlement, or company visibility, fix the underlying cause first.


Production support intake

Before changing data, collect:

Field Example
User Warehouse user, sales user, accounting user
Company context Reyder only, Axis only, or both
Record P00029, S00030, PKG/00009, SETTLE/CON/...
Button/action Mark Complete, Allocate Devices, Mark Ready to Ship, Mark Shipped, Mark as Paid
Error text Exact popup or chatter warning
Screenshot Full form with status bar and smart buttons visible
Time Timestamp so logs can be checked

Open the Odoo shell

docker compose exec -T odoo odoo shell -c /etc/odoo/odoo.conf -d reyder_e2e --no-http

Replace reyder_e2e with the target database when working outside the local E2E database.


Verify record rules as a real user

The shell runs as superuser by default, which bypasses normal record rules. Use with_user() when checking what a non-admin user can see.

axis_user = env['res.users'].browse(5)
reports = env['consignment.settlement.report'].with_user(axis_user).search([])
orders = env['sale.order'].with_user(axis_user).search([])

Expected result for an Axis-only user:

  • They can see their owner-side settlement reports.
  • They cannot see Reyder sale orders.
  • They cannot open Reyder customer/order/sale-price data.
  • They cannot read Reyder-only retail sale records.

If the shell result disagrees with the UI, confirm the user's Allowed Companies and active cids browser context.


Device Allocation tab missing

Known UX issue: on a zero-allocation sales order, the Device Allocation tab can be hidden even though the Allocate button lives inside that tab.

Preferred resolution:

  1. Add or expose a header-level Allocate Devices button in the product code.
  2. Upgrade the module.
  3. Retest a brand-new quotation with zero allocations.

Temporary support-only workaround:

env['sale.order.line.device'].create({
    'sale_order_line_id': <so_line_id>,
    'lot_id': <available_lot_id>,
    'unit_price': <price>,
})

After the seeded allocation appears, the normal Device Allocation tab can be used. Remove or correct the seeded allocation if it was only used to reveal the UI.


Re-run a missing receiving GL entry

Receiving-path accounting can soft-fail if the accounting settings were missing when the manifest was completed. First fix Settings -> Inventory -> Device Inventory Accounting:

  • Device Stock Journal
  • Device Valuation Account
  • Device Stock Input Account

Then re-run the receiving entry:

manifest = env['device.manifest'].browse(<manifest_id>)
manifest._create_inventory_accounting_entry()

The method is intended to be idempotent. Still, verify the manifest's linked accounting entry before and after running it.


Create a missing settlement vendor bill

If the settlement report stayed confirmed without a vendor bill, check the report chatter first. Missing settlement journal or purchase journal configuration is the usual cause.

  1. Configure Settings -> Inventory -> Consignment Settlement -> Settlement Journal.
  2. Confirm a purchase journal exists for the company.
  3. Re-run vendor bill creation:
report = env['consignment.settlement.report'].browse(<report_id>)
report._create_settlement_vendor_bill()

Afterward, open the report and confirm the Vendor Bill smart button exists and the amount equals the owner amount.


Re-check retail reservation auto-close

Retail reservations close when remaining_count reaches 0. If a retail sale was created outside the normal UI flow, run:

env['device.retail.reservation'].browse(<reservation_id>)._check_auto_close()

Before doing this, verify the reservation partner, reserved devices, sold devices, and remaining count. Do not close a reservation that still has unsold devices.


Stamp a manual QC session ID

Use this only when the business intentionally accepts manual QC without M360 integration. The normal device form keeps the M360 session field readonly; support can stamp a placeholder so Mark QC Complete can enforce the rest of the QC checks.

lot = env['stock.lot'].browse(<lot_id>)
lot.write({'m360_session_id': 'manual-qc-<ticket-or-imei>'})
lot.message_post(body='Manual QC session placeholder stamped by support.')

Before marking QC complete, confirm the device is In QC and has a grade assigned.


Reset a device status

Use status resets only for data repair after you understand why the status is wrong.

lot = env['stock.lot'].browse(<lot_id>)
lot.device_status = 'available'

After changing a device, check:

  • Existing allocations
  • Retail reservation flags
  • Settlement status
  • Movement history
  • Chatter/audit notes

Neutralize a copied production database

If a copied local/dev database shows an enterprise subscription banner, neutralize it:

docker compose exec -T odoo odoo neutralize -c /etc/odoo/odoo.conf -d <db_name> --stop-after-init

If the banner persists, clear stale subscription parameters:

DELETE FROM ir_config_parameter WHERE key IN (
  'database.expiration_date', 'database.expiration_reason',
  'database.already_linked_email', 'database.already_linked_send_mail_url',
  'database.already_linked_subscription_url'
);
UPDATE ir_config_parameter SET value = gen_random_uuid()::text WHERE key='database.uuid';

Restart Odoo afterward:

docker compose restart odoo

Upgrade the module

docker compose exec -T odoo odoo -c /etc/odoo/odoo.conf -d reyder_e2e -u device_inventory --stop-after-init

After an upgrade, run the deployment smoke checks below before handing the database back to users.


Deployment smoke checks

Run these after module upgrades, production restores, or permission changes:

Area Check
Login Admin can open Inventory -> Device Inventory.
Receiving A test PO can show an IMEI manifest.
QC QC Handoff opens and lists pending devices.
Sales A quotation can open Device Allocation.
Packing A packing box can open Scan Devices.
Settlement Settlement Reports list loads and a consignee report opens.
Axis security Axis-only user sees owner reports only and cannot open Reyder sale orders.
Accounting Device accounting settings and settlement journal are configured.

If any check fails, keep users out of that workflow until the failure is fixed and retested.