MONTA PLUGIN DOCUMENTATION

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.

Monta NL ↔ Odoo Integration

A production-ready Odoo add‑on that connects your Odoo Sales & Purchasing flows with Monta (api‑v6). It covers: order export, order status sync with snapshots, stock pulls, and inbound forecast push — with robust logging and security controls.

Module name: Monta-Odoo-Integration
License: LGPL‑3
Category: Sales
Tested with: Odoo 17–18 (API and UI notes below)

1) What the module does

1.1 Sales orders → Monta (create / update / cancel)

  • Builds a compliant Monta order payload from Odoo sale.order (customer, addresses, lines, references).

  • SKU expansion: pack/phantom BoMs are flattened to leaf SKUs; duplicate SKUs are aggregated.

  • Manual actions (from the Sales Order):

    • Check SKUs → validates/expands lines and writes a structured log.

    • Create/Update on Monta (create, then JSON‑Patch update for changes).

    • Cancel/Delete on Monta when the Odoo order is cancelled or deleted.

  • Instance guard: optional allow‑list prevents pushing from non‑production instances.

1.2 Order status ← Monta (cron + manual)

  • Resolves the freshest status using Shipments → Order Events → Orders (header) with a
    strict override: Header Blocked > Header Backorder > other sources.

  • Writes a normalized snapshot in model monta.order.status (one row per SO per account) including:

    • status, status_code, source, track_trace, delivery_date, last_sync, status_raw (JSON).

  • Adds a Sales Order button “Sync Monta” for on‑demand refresh.

  • Ships with a half‑hourly cron to refresh recent orders.

1.3 Stock pull (Monta → Odoo)

  • Service MontaQtySync fetches StockAvailable and MinimumStock per SKU.

  • For non‑kits: mirrors Monta stock to the main stock location in Odoo; writes available_threshold.

  • For kits/packs: never writes kit stock; computes feasibility from components.

  • 6‑hour cron provided.

1.4 Inbound Forecast (Odoo PO → Monta)

  • On PO confirm, pushes an idempotent Inbound Forecast (header + lines). Can also be pushed manually from PO.

  • Respects a feature flag so you can enable it per tenant.

⚠️ Optional EDD (Expected Delivery Date) push hooks are included but commented out; enable if your tenant requires automatic inbound EDD updates on pickings.

2) Installation & compatibility

2.1 Odoo dependencies

  • sale_management, purchase, mrp (for BoM expansion), stock (implicit).

2.2 Monta prerequisites

  • Monta api‑v6 endpoint and a Basic Auth API user with access to Orders, Shipments, Events, Products, and Inbound Forecast endpoints.

  • Your product SKUs in Odoo must match Monta’s product catalog; barcodes are recommended (Monta may reject products without barcodes in some tenants).

2.3 Install steps

  1. Install the module as a standard Odoo add‑on.

  2. Set the System Parameters (Settings ▸ Technical ▸ Parameters ▸ System Parameters) as listed below.

  3. (Optional) Add the Sales Order button view if you customized sales forms (this module already includes it by default).

  4. Verify scheduled actions (crons) were created.

3) Configuration (System Parameters)

Set these in Settings ▸ Technical ▸ Parameters ▸ System Parameters.

Key

Example

Required

Description

monta.base_url

https://api-v6.monta.nl

Base URL for Monta API (v6). Alternative key monta.api.base_url is also recognized.

monta.username

tenant_user

Basic Auth username.

monta.password

••••••

Basic Auth password (stored in ICP).

monta.timeout

20

 

Request timeout (seconds).

monta.match_loose

1

 

If 1, resolver accepts partial matches when searching by references. Set 0 to require exact matches.

monta.allowed_base_urls

https://app.example.com

 

Instance guard: comma‑separated allow‑list of Odoo base URLs allowed to push orders. Empty = no guard.

monta.origin

Moyee_Odoo

 

Optional “Origin” field for order payload. If empty, it’s omitted to avoid tenant‑specific validation errors.

monta.warehouse_tz

Europe/Amsterdam

 

Time zone used for inbound forecast windows.

monta.inbound_enable

1

 

Enables Inbound Forecast push on PO confirm. Set 0 to disable.

monta.inbound_warehouse_display_name

Main DC

 

Label shown for the receiving warehouse in Monta (per tenant conventions).

monta.default_supplier_code

DEFAULT

 

Fallback supplier code when vendor code is missing.

monta.supplier_code_map

{“Vendor A”:”A”,”Vendor B”:”B”}

 

JSON map to normalize supplier names to codes.

monta.supplier_code_override

ACME

 

Force a single supplier code regardless of mapping/PO vendor.

Tip: keep credentials in a dedicated “API user” with the least privileges necessary.

4) User interface additions

4.1 Menus

  • Monta ▸ Order Status: opens monta.order.status list with latest snapshots (group by Status or SO).

4.2 Sales Order actions

  • Sync Monta: runs status resolution immediately for the current SO.

  • (Optional) Check SKUs: runs a local flattened‑SKU validation and writes a structured log (no API call).

4.3 Purchase Order actions

  • Push Inbound Forecast (also auto‑runs on Confirm if enabled).

5) How it works (data flows)

5.1 Create/Update/Delete orders

  1. User prepares a confirmed SO in Odoo.

  2. The module expands pack/phantom BoMs to leaf SKUs and aggregates quantities; raises a clear error if lines resolve to zero.

  3. POST /order to create, then PATCH /order/{webshopOrderId} (JSON‑Patch) for subsequent updates.

  4. On cancel/delete in Odoo, the module sends a DELETE with a reason note.

5.2 Status resolution (freshest wins + header override)

  1. Attempt to locate the order by: OrderNumber, Reference, ClientReference, EorderGUID, WebshopOrderId (and variants); supports exact or loose matching.

  2. Pull Shipments (prefers newest), then Order Events, finally Order Header.

  3. Pick the most recent non‑empty status; override to “Blocked” if header indicates blocked; override to “Backorder” if header indicates backorder and the current status is not already shipped/picked/etc.

  4. Upsert a snapshot row with trace fields and raw JSON.

5.3 Stock pull

  1. For each SKU, call GET /product/{sku}/stock (or tenant‑specific stock endpoint) using Basic Auth.

  2. For simple products, write on‑hand/threshold; for kits, compute availability from components and never write kit on‑hand directly.

5.4 Inbound Forecast

  1. On PO confirm (or manual action), build the inbound forecast window + lines (quantities, SKUs).

  2. POST /inbound/forecast (idempotent create/update) following tenant conventions.

6) Security model & logging

6.1 Access controls

  • Models

    • monta.order.status: read for all internal users; write for Sales Managers; full access for System Admins.

  • Record rules

    • Global read rule for monta.order.status so business users can inspect snapshots.

6.2 Secrets & transport

  • Monta credentials are stored in System Parameters (server‑side) and sent via Basic Auth over HTTPS.

  • Timeouts are configurable; the client disables caching headers.

6.3 Audit logs

  • Server logs: each push/pull writes concise lines with order identifiers and outcomes.

  • Database logs: model monta.sale.log stores structured JSON payloads per SO for later forensics.

  • Snapshots: monta.order.status.status_raw keeps the relevant raw Monta fragments used for the last resolution.

6.4 Instance guard (anti‑mistake)

  • If monta.allowed_base_urls is set, API calls that change Monta state are blocked unless the current web.base.url matches the allow‑list. Every block is logged to DB and server.

7) Cron jobs (scheduled actions)

Name

Model / Method

Frequency

Purpose

Monta: Sync Sales Order Status (half‑hourly)

sale.order.cron_monta_sync_status()

every 30 min

Refresh statuses for recent confirmed/done orders until shipped.

Monta: Sync StockAvailable + MinStock (6h)

product.product.cron_monta_qty_sync()

every 6h

Pull Monta stock and mirror into Odoo.

Both crons are created idempotently on install; you can adjust intervals in Scheduled Actions.

8) Error handling & troubleshooting

8.1 Common API validation messages

  • “Missing the following mandatory field(s): Barcodes” — your Monta tenant requires barcodes for products; ensure each SKU has a barcode.

  • “Provided SKU does not exist for a single known product” — check product SKU consistency between Odoo and Monta; avoid packs as SKUs.

  • HTTP 404 on /product/{sku}/stock — Monta has no such SKU or the endpoint differs for your tenant. Verify the SKU exactly and tenant‑specific stock endpoint.

8.2 Status not found for an order

  • Ensure the order was created in Monta with one of the searchable references (OrderNumber / Reference / ClientReference / EorderGUID / WebshopOrderId).

  • If your tenant uses unusual keys, enable loose matching (monta.match_loose = 1).

8.3 Nothing happens when pushing orders

  • Check instance guard (monta.allowed_base_urls); pushes are blocked on non‑allowed hosts and a log entry is created under monta.sale.log.

  • Check server logs for Monta Guard messages.

8.4 Cron isn’t running

  • Verify Scheduled Actions are Active and the Next Execution Date is moving.

  • Ensure no global cron lock is stuck (rare); re‑start workers if needed.

9) Developer guide

9.1 Key models & services

  • Models

    • sale.order: push/update/delete actions; SKU logging tools; guards and API plumbing.

    • monta.order.status: snapshot store; helper methods; uniqueness per account.

    • monta.sale.log: structured logs of API interactions.

  • Services

    • monta.status.resolver: finds freshest status across shipments/events/header with header override.

    • monta.http / MontaClient: thin HTTP clients with Basic Auth + timeouts.

    • monta.qty.sync: stock pull & application logic.

    • monta.inbound.forecast.service: PO → Inbound Forecast (idempotent upserts).

9.2 System param keys referenced in code

monta.base_url, monta.api.base_url, monta.username, monta.password, monta.timeout, monta.match_loose, monta.allowed_base_urls, monta.origin, monta.warehouse_tz, monta.inbound_enable, monta.inbound_warehouse_display_name, monta.default_supplier_code, monta.supplier_code_map, monta.supplier_code_override.

9.3 Hooks

  • post_init_hook: creates the qty sync cron if missing.

  • Module install/uninstall hooks also manage the status sync cron.

9.4 Views

  • views/monta_order_status_views.xml: list/form/search + Monta top menu.

  • views/sale_order_monta_sync_button.xml: adds Sync Monta to Sales Order header.

9.5 Extensibility hints

  • Override _prepare_monta_order_payload to customize address/reference mapping.

  • Override _endpoint() in MontaStockPull if your tenant uses a different stock URL.

  • Use _create_monta_log(payload, level, tag) to append arbitrary diagnostic data to monta.sale.log.

10) Quick start (ops)

  1. Configure parameters (base URL, username, password).

  2. Open a Sales Order, click Check SKUs (optional), then run Create/Update on Monta.

  3. Use Sync Monta to pull the latest status; inspect Monta ▸ Order Status snapshots.

  4. Confirm a Purchase Order to push an Inbound Forecast (if enabled).

  5. Let the crons keep statuses and stock aligned.

11) FAQ

Q: Can I test safely from staging?
Yes — set monta.allowed_base_urls to only include your production URL. Staging will be blocked from mutating API calls, but you can still run read‑only status syncs.

Q: My pack products don’t exist in Monta.
That’s fine — the module flattens packs to leaf SKUs. Ensure the component SKUs exist in Monta.

Q: Where do I see raw JSON used for a status?
Open the snapshot record (monta.order.status) and check Raw Status (JSON).

Q: Can I change the resolution priority?
Yes — extend MontaStatusResolver and override the selection logic; or plug a different resolver and call it from _monta_sync_batch().

12) Support & maintenance checklist

  • Rotate the Monta API password periodically.

  • Monitor server logs for [Monta] entries.

  • Review monta.sale.log periodically for error patterns (validation errors, SKU mismatches).

  • Keep the cron schedules aligned with your operational latency SLAs (e.g., increase status sync to every 10 minutes if needed).

Changelog (high‑level)

  • v1.0.1 — Header‑authoritative override for Blocked/Backorder; safer matching; improved snapshot model; stock sync cron; PO → Inbound Forecast push; instance guard.