Files
Odoo-Modules/docs/superpowers/specs/2026-03-31-fusion-woo-odoo-design.md
gsinghpal 149a45a752 Fix remaining spec review issues (round 2)
Add company_id to woo.shipment, woo.sync.log, woo.return.line. Add
order_id to woo.conflict for order-type conflicts. Add _odoo_messages
to WP meta table. Fix section numbering. Document lib/ import path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 19:37:30 -04:00

31 KiB

Fusion WooOdoo — Design Specification

Date: 2026-03-31 Project: Bidirectional Odoo 19 ↔ WooCommerce Sync System Components: Odoo module (fusion_woocommerce) + WordPress plugin (fusion-woodoo)


1. Overview

A production-ready, plug-and-play integration between Odoo 19 and WooCommerce that syncs products, prices, inventory, orders, invoices, customers, and documents bidirectionally. Designed for non-technical users — install, enter API keys, and it works.

Two deployable components:

  • fusion_woocommerce (Odoo module) — the brain. All sync logic, product mapping, scheduling, conflict resolution, and dashboards.
  • fusion-woodoo (WordPress plugin) — thin display layer. Receives data from Odoo, displays documents in customer portal, fires webhooks on events.

2. Architecture

Communication Pattern: Direct REST API (Approach A)

Odoo ──── WooCommerce REST API ────→ WordPress
Odoo ←─── WooCommerce Webhooks ───── WordPress
Odoo ──── Custom REST endpoints ───→ WP Plugin (invoices, docs, status)
  • Odoo is the brain — all sync logic, mapping, scheduling, conflict resolution
  • WordPress is the display layer — receives data, displays to customers, fires webhooks
  • Deduplication via external IDs — every synced record carries a unique reference
  • HTTPS only — all API communication encrypted
  • Multi-site ready — one Odoo instance can connect to multiple WooCommerce sites
  • Cross-server compatible — works regardless of where Odoo and WordPress are hosted

Sync Strategy: Hybrid (Webhooks + Cron Fallback)

  • Real-time webhooks for orders, customer creation, product changes
  • Scheduled cron runs at configurable intervals to catch missed webhooks
  • Manual "Sync Now" button for on-demand sync
  • No duplications — every record checked against external IDs before creation

Authentication: Bidirectional API Keys

  • Odoo → WooCommerce: WC REST API consumer key + consumer secret (both encrypted at rest)
  • WC Webhooks → Odoo: Validated via HMAC signature (X-WC-Webhook-Signature header) using the WC webhook secret — NOT the Odoo API key
  • WP Plugin custom endpoints → Odoo: Odoo API key stored in WP plugin settings, sent as bearer token
  • These are two distinct auth flows — webhook signature validation vs. API key authentication

WooCommerce API Version

  • Target: WC REST API v3 (current, recommended)
  • All endpoints use /wp-json/wc/v3/ prefix

3. Data Models

3.1 Odoo Models

woo.instance — WooCommerce Site Connection

Field Type Purpose
name Char Display name (e.g., "Westin WooCommerce")
url Char WooCommerce site URL
consumer_key Char WC API consumer key (encrypted)
consumer_secret Char WC API consumer secret (encrypted)
webhook_secret Char WC webhook HMAC secret (encrypted)
wc_api_version Char WC API version (default: "wc/v3")
company_id Many2one (res.company) Company (multi-company support)
odoo_api_key Char API key for WP plugin to call back
sync_interval Selection 5min / 15min / 30min / 1hr
sync_products Boolean Enable product sync
sync_orders Boolean Enable order sync
sync_invoices Boolean Enable invoice sync
sync_inventory Boolean Enable inventory sync
sync_customers Boolean Enable customer sync
default_warehouse_id Many2one (stock.warehouse) Where WC orders pull stock
notify_on_failure Boolean Email on sync failure
notify_user_ids Many2many (res.users) Who gets notified
state Selection draft / connected / error
last_sync Datetime Last successful sync

woo.product.map — Product Mapping (1:1)

Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
product_id Many2one (product.product) Odoo product
woo_product_id Integer WooCommerce product ID
woo_product_name Char WC product name (display)
woo_sku Char WC SKU
woo_product_type Selection simple / variable / grouped / external
woo_parent_id Integer WC parent product ID (for variations)
is_variation Boolean Whether this maps a WC variation
sync_price Boolean Sync price for this product
sync_inventory Boolean Sync stock for this product
sync_images Boolean Sync images for this product
woo_image_ids Char JSON list of WC media IDs for image tracking
last_synced Datetime Last sync time
company_id Many2one (res.company) Company
state Selection unmapped / mapped / conflict / error

woo.order — Synced Order Tracking

Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
sale_order_id Many2one (sale.order) Odoo sales order
woo_order_id Integer WooCommerce order ID
woo_order_number Char WC order display number
woo_status Char Current WC status
invoice_id Many2one (account.move) Linked Odoo invoice
invoice_synced Boolean Whether invoice PDF was pushed to WC
company_id Many2one (res.company) Company
state Selection new / confirmed / shipped / completed / cancelled

woo.shipment — Per-Shipment Tracking (child of woo.order)

Field Type Purpose
order_id Many2one (woo.order) Parent order
picking_id Many2one (stock.picking) Odoo delivery order
carrier_id Many2one (woo.shipping.carrier) Shipping carrier
tracking_number Char Tracking number
shipped_date Datetime When shipped
is_backorder Boolean Whether this is a backorder shipment
synced_to_woo Boolean Whether WC was notified
company_id Many2one (res.company) Company

woo.shipping.carrier — Configurable Carrier List

Field Type Purpose
name Char Carrier name (e.g., "Canada Post")
code Char Short code (e.g., "canada_post")
tracking_url Char Tracking URL template (e.g., "https://www.canadapost.ca/track/{tracking}")
active Boolean Whether enabled

woo.sync.log — Sync History

Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
sync_type Selection product / order / invoice / inventory / customer
direction Selection odoo_to_woo / woo_to_odoo
record_ref Char Reference (e.g., "SO0042")
state Selection success / failed / conflict
message Text Details or error message
create_date Datetime Timestamp
company_id Many2one (res.company) Company
Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
partner_id Many2one (res.partner) Odoo partner
woo_customer_id Integer WooCommerce customer/user ID
woo_email Char WC customer email
last_synced Datetime Last sync time
company_id Many2one (res.company) Company

woo.tax.map — Tax Class Mapping

Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
tax_id Many2one (account.tax) Odoo tax
woo_tax_class Char WC tax class slug
woo_tax_class_name Char WC tax class display name
company_id Many2one (res.company) Company

woo.pricelist.map — Price Tier Mapping

Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
pricelist_id Many2one (product.pricelist) Odoo pricelist
woo_role Char WC customer role (e.g., "wholesale_customer")
woo_role_name Char WC role display name
company_id Many2one (res.company) Company

woo.return — Return/RMA Tracking

Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
order_id Many2one (woo.order) Original synced order
picking_id Many2one (stock.picking) Odoo return picking
reason Text Customer's return reason
line_ids One2many (woo.return.line) Items being returned
state Selection requested / approved / received / refunded / rejected
company_id Many2one (res.company) Company

woo.return.line — Return Line Items

Field Type Purpose
return_id Many2one (woo.return) Parent return
product_id Many2one (product.product) Product being returned
quantity Float Quantity to return
reason Selection defective / wrong_item / not_needed / damaged / other
company_id Many2one (res.company) Company

woo.conflict — Data Conflicts

Field Type Purpose
instance_id Many2one (woo.instance) Which WC site
conflict_type Selection product / customer / order
map_id Many2one (woo.product.map) Product map (if product conflict)
customer_id Many2one (woo.customer) Customer (if customer conflict)
order_id Many2one (woo.order) Order (if order conflict)
field_name Char Which field conflicts
odoo_value Char Value in Odoo
woo_value Char Value in WooCommerce
resolution Selection pending / use_odoo / use_woo
resolved_by Many2one (res.users) Who resolved it
company_id Many2one (res.company) Company

3.2 WordPress Meta (No Custom Tables)

Meta Key Stored On Purpose
_odoo_order_id Order Linked Odoo sales order ID
_odoo_invoice_id Order Linked Odoo invoice ID
_odoo_invoice_pdf Order Invoice PDF stored in wp-content/uploads/fusion-woodoo/invoices/ (access-controlled)
_odoo_delivery_pdf Order Delivery PDF stored in wp-content/uploads/fusion-woodoo/deliveries/ (access-controlled)
_odoo_tracking_number Order Tracking number from Odoo
_odoo_shipping_carrier Order Carrier name
_odoo_order_status Order Odoo-side status for timeline
_odoo_product_id Product Linked Odoo product ID
_odoo_customer_id User Linked Odoo partner ID
_odoo_messages Order JSON array of customer-visible messages [{author, date, body}]
_odoo_instance_url Options Odoo server URL
_odoo_api_key Options API key for Odoo auth

4. Sync Workflows

4.1 Order Lifecycle (WooCommerce → Odoo → WooCommerce)

  1. Customer places order on WooCommerce
  2. WC webhook fires → Odoo receives order
  3. Odoo checks customer by email → match existing partner or create new
  4. Odoo checks dedup by woo_order_id → skip if exists
  5. Odoo creates sale.order with mapped products, quantities, prices
  6. Odoo confirms sale order, creates draft invoice
  7. Odoo pushes sales order details back to WC via REST API
  8. User validates invoice in Odoo
  9. User processes delivery in Odoo
  10. User enters tracking number + selects shipping carrier
  11. Odoo pushes tracking + carrier to WC → WC status: "shipped" → Email #1: Shipping notification with tracking
  12. User marks order "Completed" in Odoo
  13. Odoo pushes status to WC → WC status: "completed" → Email #2: Order completed
  14. Odoo pushes invoice PDF + delivery receipt PDF to WC custom endpoint
  15. Customer can view/download all documents from My Account

4.2 Product Sync

Supported WC Product Types:

  • Simple products — standard 1:1 mapping to product.product
  • Variable products — parent maps to product.template, each variation maps to a product.product variant
  • Grouped products — mapped as a set of linked simple products
  • External/affiliate products — excluded from sync (no inventory/price to sync)
  • Downloadable/virtual products — mapped but inventory sync disabled automatically

Initial Setup:

  1. User clicks "Fetch WooCommerce Products" in Odoo
  2. Odoo calls WC REST API → GET /products (paginated, includes variations)
  3. For variable products: fetch /products/{id}/variations to get all variants
  4. Auto-match by SKU (internal_reference = sku) → auto-map (matches both products and variants)
  5. Suggest by name similarity for unmatched → user confirms/rejects
  6. Remaining unmatched shown with actions: "Create in Odoo" / "Create in WooCommerce" / "Ignore"

Ongoing Sync (cron):

  1. For each mapped product with sync_price enabled:
    • Compare Odoo price vs WC price
    • Same → skip
    • Changed on one side → update the other
    • Changed on both → create woo.conflict record
  2. For each mapped product with sync_inventory enabled:
    • Push Odoo qty_available to WC stock_quantity

Ongoing Sync (webhook):

  1. WC fires product.updated webhook
  2. Odoo finds mapping by woo_product_id
  3. Updates Odoo product or creates conflict

4.3 Customer Sync

  1. Order webhook arrives with customer email
  2. Search res.partner by email
    • Found → link, update address if changed
    • Not found → create with name, email, phone, billing/shipping addresses, tag "WooCommerce Customer"
  3. Store odoo_customer_id as WC user meta
  4. Ongoing: address changes flow Odoo → WooCommerce (Odoo is master)

4.4 Inventory Sync

Triggered by: stock move confirmed in Odoo, or cron fallback

  1. For each mapped product with sync_inventory enabled
  2. Get Odoo qty_available for configured warehouse
  3. PUT to WC REST API → update stock_quantity
  4. Log to woo.sync.log

Backorder Handling:

  1. Odoo creates partial delivery → push shipped items with tracking
  2. Remaining items ship later → push second tracking update
  3. Customer sees both shipments in portal timeline

4.5 Price Tier Sync

  • Configured via woo.pricelist.map model — maps Odoo pricelists to WC customer roles
  • When a WC customer with a specific role (e.g., "wholesale_customer") places an order, Odoo uses the mapped pricelist for pricing
  • When syncing prices to WC, if WC supports role-based pricing plugins (e.g., "Wholesale Prices"), push pricelist-specific prices
  • Fallback: if no role mapping exists, use Odoo's default public pricelist
  • Configurable per woo.instance

4.6 Product Image Sync

  • Images sync bidirectionally for mapped products with sync_images enabled
  • Odoo product images push to WC media library; WC media IDs stored in woo_image_ids on the map record
  • WC images pull into Odoo as ir.attachment linked to the product
  • Image order preserved (first image = WC featured image)
  • On sync, compare image checksums to avoid re-uploading unchanged images

4.7 Tax Mapping

  • Configured via woo.tax.map model — maps Odoo account.tax records to WC tax class slugs
  • Supports Canadian HST/GST/PST configurations
  • When creating orders from WC: look up WC tax class → find mapped Odoo tax → apply to SO lines
  • When pushing products to WC: look up Odoo product's tax → find mapped WC tax class → set on WC product
  • Configurable mapping table per woo.instance

4.8 Return/RMA

  1. Customer clicks "Request Return" in WP My Account
  2. Fills return form: selects order, selects items + quantities, selects reason (defective / wrong_item / not_needed / damaged / other), submits
  3. WP plugin sends return request to Odoo custom endpoint
  4. Odoo creates woo.return record (state: requested)
  5. Odoo user reviews and approves/rejects the return
  6. If approved: Odoo creates a reverse stock.picking (NOT stock.return.picking which is a transient wizard) linked to the woo.return
  7. Status updates push back to WC → customer sees progress: requested → approved → received → refunded (or rejected)
  8. When return is received and refund issued, Odoo creates credit note → maps to WC refund

4.9 Refund Handling

  • WooCommerce native refunds (partial or full) sync to Odoo as credit notes on the linked invoice
  • Odoo credit notes sync back to WC as refunds on the order
  • Refund amounts and line items are tracked to prevent double-refunding
  • Dedup key: woo_order_id + refund ID

4.10 Communication History Sync

  • When Odoo pushes order status updates, it also pushes recent mail.message records from the sale.order's chatter
  • Messages are sent as part of the order status push (same REST endpoint, included in payload)
  • WP plugin stores messages as order meta (_odoo_messages — JSON array of {author, date, body})
  • Only internal notes marked "visible to customer" are synced — private internal notes stay in Odoo
  • New messages pushed on each status update (incremental, not full history each time)

4.11 Deduplication Rules

Record Unique Key Check Before Creating
Order woo_order_id per instance Always check woo.order
Customer email Always search res.partner by email
Product map woo_product_id per instance Always check woo.product.map
Invoice sale_order_id One invoice per SO
Sync log N/A Append-only

5. Product Mapping UI (Odoo)

Design Principles

  • Modern, intuitive, production-grade
  • Live AJAX search — instant filtering as user types (debounced ~300ms)
  • No page reloads for search/filter operations

Layout

Top Bar:

  • Instance selector dropdown (which WC site)
  • "Fetch Products" button (initial import)
  • "Sync Now" button
  • Stats bar: X mapped / Y unmatched / Z conflicts

Three Tabs:

Tab 1: Mapped Products

  • Table: Odoo Product | SKU | WC Product | WC SKU | Price (Odoo) | Price (WC) | Stock | Status | Actions
  • Live search bar filters both Odoo and WC product names/SKUs in real time
  • Bulk actions: Unmap selected, Sync selected, Enable/disable price sync, Enable/disable inventory sync
  • Conflict indicator (amber icon) on rows with price conflicts
  • Click row to expand details

Tab 2: Unmatched Products

  • Split view: Odoo products on left, WC products on right
  • Each side has its own live search bar
  • Click to select from each side and map together (v1); drag-and-drop as a v2 enhancement
  • Action buttons per product: "Create in WooCommerce" / "Create in Odoo" / "Ignore"
  • Auto-suggest section at top showing name-based matches with confidence score

Tab 3: Conflicts

  • Table: Product | Field | Odoo Value | WC Value | Actions
  • Actions: "Use Odoo Value" / "Use WC Value" / "Ignore"
  • Bulk resolve: "Use all Odoo values" / "Use all WC values"

Search Behaviour

  • Debounced at 300ms — starts filtering after user stops typing briefly
  • Filters product name, SKU, and internal reference simultaneously
  • No enter key required
  • Results update in-place without page reload
  • Built using Odoo 19 OWL framework with RPC calls to controller endpoints

6. Customer Portal (WordPress — My Account)

New Tabs in My Account

Tab: Sales Orders

  • List of all Odoo-created sales orders
  • Columns: Order #, Date, Items, Total, Status
  • Click to view full order details
  • "Reorder" button → creates new WC cart with same products (Odoo pushes WC product IDs per line in the order data so the plugin can build the cart directly)

Tab: Invoices

  • List of all Odoo invoices
  • Columns: Invoice #, Date, Amount, Status (Draft/Paid)
  • "Download PDF" button for each invoice
  • PDF is the actual Odoo-generated invoice

Tab: Deliveries

  • List of all delivery/inventory transfer receipts
  • Columns: Delivery #, Date, Carrier, Tracking #, Status
  • "Download PDF" button for delivery receipt
  • Tracking number is a clickable link to carrier's tracking page

Tab: Returns

  • List of return requests
  • Columns: Return #, Date, Items, Status
  • "Request Return" button to initiate new return
  • Return form: select order, select items, reason, submit

Order Status Timeline

Visual timeline/tracker on each order detail page:

● Confirmed → ● Processing → ● Shipped → ● Delivered → ● Completed
     ✓              ✓             ✓            ○              ○
  • Green checkmark for completed stages
  • Blue dot for current stage
  • Grey dot for upcoming stages
  • Each stage shows date/time when it occurred
  • Shipping stage shows carrier + tracking number with link

Communication History

  • Messages/notes exchanged between customer and team about an order
  • Displayed as a threaded conversation view
  • Synced from Odoo chatter (mail.message on sale.order) — only messages marked visible to customer
  • Stored as _odoo_messages order meta (JSON array)
  • Pushed incrementally with each order status update

7. Settings & Configuration

7.1 Odoo Settings Page (fusion_woocommerce)

Connection Section:

  • WooCommerce URL (with "Test Connection" button)
  • Consumer Key + Consumer Secret
  • Auto-generated Odoo API Key (with "Regenerate" button)
  • Connection status indicator (green/red)

Sync Configuration:

  • Sync interval dropdown (5min / 15min / 30min / 1hr)
  • Toggle switches for each sync type: Products, Orders, Invoices, Inventory, Customers
  • Default warehouse selector
  • Price sync direction: Odoo → WC / WC → Odoo / Bidirectional

Shipping Carriers:

  • Enabled carriers checklist: Canada Post, UPS, FedEx, Purolator, DHL, Other
  • "Other" allows custom carrier name

Tax Mapping:

  • Table: Odoo Tax | WC Tax Class | Actions
  • Add/edit/remove mappings

Notifications:

  • Toggle: Email on sync failure
  • User selector: who receives notifications
  • Toggle: Email on new WC order received

Setup Wizard:

  • First-time setup walks user through: enter URL → enter API keys → test connection → select warehouse → fetch products → initial mapping
  • No technical knowledge required

7.2 WordPress Settings Page (fusion-woodoo)

Connection Section:

  • Odoo Instance URL
  • API Key
  • "Test Connection" button
  • Status indicator

Portal Settings:

  • Toggle: Show Sales Orders tab
  • Toggle: Show Invoices tab
  • Toggle: Show Deliveries tab
  • Toggle: Show Returns tab
  • Toggle: Show Order Timeline
  • Toggle: Enable Reorder button

Webhook Configuration:

  • Auto-configured on activation (registers WC webhooks pointing to Odoo)
  • Display registered webhooks with status
  • On plugin deactivation: unregister all WC webhooks pointing to Odoo
  • On Odoo URL change: automatically re-register webhooks with new URL
  • Stale webhook detection: if webhooks point to an unreachable Odoo URL, show warning

8. Dashboard Widget (Odoo)

An Odoo dashboard widget showing sync health at a glance:

  • Orders pending sync: count with link to list
  • Last sync time: timestamp + "X minutes ago"
  • Errors in last 24h: count with link to sync log (filtered)
  • Products mapped / unmapped: ratio with progress bar
  • Inventory sync status: last run + items synced
  • Quick actions: Sync Now, View Conflicts, Open Mapping

9. Folder Structure

fusion-woo-odoo/
├── fusion_woocommerce/                 # Odoo 19 module
│   ├── __init__.py
│   ├── __manifest__.py
│   ├── controllers/
│   │   ├── __init__.py
│   │   ├── webhook.py                  # Receive WC webhooks
│   │   ├── api.py                      # REST API for WP plugin
│   │   └── product_search.py           # AJAX search endpoints
│   ├── lib/
│   │   ├── __init__.py
│   │   └── woo_api_client.py           # WooCommerce REST API wrapper (NOT an Odoo model)
│   ├── models/
│   │   ├── __init__.py
│   │   ├── woo_instance.py             # WC site connection config
│   │   ├── woo_product_map.py          # Product mapping
│   │   ├── woo_order.py                # Order sync tracking
│   │   ├── woo_shipment.py             # Per-shipment tracking
│   │   ├── woo_shipping_carrier.py     # Configurable carrier list
│   │   ├── woo_customer.py             # Customer link tracking
│   │   ├── woo_tax_map.py              # Tax class mapping
│   │   ├── woo_pricelist_map.py        # Price tier mapping
│   │   ├── woo_return.py               # Return/RMA tracking + lines
│   │   ├── woo_sync_log.py             # Sync history
│   │   ├── woo_conflict.py             # Conflict resolution
│   │   ├── sale_order.py               # sale.order extensions
│   │   ├── stock_picking.py            # Delivery extensions (tracking)
│   │   ├── account_move.py             # Invoice extensions
│   │   └── res_partner.py              # Partner extensions (WC link)
│   ├── views/
│   │   ├── woo_instance_views.xml      # Settings / connection config
│   │   ├── woo_product_map_views.xml   # Product mapping UI
│   │   ├── woo_order_views.xml         # Order tracking views
│   │   ├── woo_sync_log_views.xml      # Sync log views
│   │   ├── woo_conflict_views.xml      # Conflict resolution views
│   │   ├── woo_dashboard.xml           # Dashboard widget
│   │   ├── sale_order_views.xml        # SO view extensions
│   │   ├── stock_picking_views.xml     # Delivery view extensions
│   │   └── res_config_settings.xml     # Settings page
│   ├── wizard/
│   │   ├── __init__.py
│   │   ├── woo_setup_wizard.py         # First-time setup wizard
│   │   ├── woo_setup_wizard_views.xml
│   │   ├── woo_product_fetch.py        # Fetch & auto-match wizard
│   │   └── woo_product_fetch_views.xml
│   ├── data/
│   │   ├── cron.xml                    # Scheduled sync jobs + log cleanup cron
│   │   ├── mail_template.xml           # Notification email templates
│   │   └── shipping_carriers.xml       # Default carrier data (Canada Post, UPS, FedEx, Purolator, DHL)
│   ├── security/
│   │   ├── ir.model.access.csv         # Access rights
│   │   └── woo_security.xml            # Record rules & groups
│   ├── static/
│   │   ├── description/
│   │   │   └── icon.png                # Module icon (placeholder)
│   │   └── src/
│   │       ├── js/
│   │       │   ├── product_mapping.js  # OWL component: mapping UI
│   │       │   ├── ajax_search.js      # Live search component
│   │       │   └── dashboard.js        # Dashboard widget
│   │       ├── css/
│   │       │   └── woo_styles.css      # Custom styles
│   │       └── xml/
│   │           ├── product_mapping.xml # OWL templates
│   │           └── dashboard.xml       # Dashboard template
│   └── i18n/
│       └── (translation files)
│
└── fusion-woodoo/                      # WordPress plugin
    ├── fusion-woodoo.php               # Plugin entry point
    ├── includes/
    │   ├── class-fusion-woodoo.php     # Main plugin class
    │   ├── class-api-client.php        # Odoo API client
    │   ├── class-rest-endpoints.php    # Custom REST endpoints (receive from Odoo)
    │   ├── class-webhooks.php          # WC webhook registration
    │   ├── class-my-account.php        # My Account tab registration
    │   ├── class-order-timeline.php    # Order status timeline
    │   ├── class-returns.php           # Return/RMA handling
    │   └── class-admin-settings.php    # WP admin settings page
    ├── templates/
    │   ├── my-account/
    │   │   ├── sales-orders.php        # Sales orders tab
    │   │   ├── invoices.php            # Invoices tab
    │   │   ├── deliveries.php          # Deliveries tab
    │   │   ├── returns.php             # Returns tab
    │   │   ├── order-timeline.php      # Status timeline component
    │   │   └── communication.php       # Communication history
    │   └── admin/
    │       └── settings.php            # Admin settings page
    ├── assets/
    │   ├── css/
    │   │   ├── my-account.css          # Customer portal styles
    │   │   └── admin.css               # Admin styles
    │   ├── js/
    │   │   ├── my-account.js           # Portal interactions
    │   │   └── admin.js                # Admin JS (test connection, etc.)
    │   └── images/
    │       └── icon.png                # Plugin icon (placeholder)
    ├── languages/
    │   └── fusion-woodoo.pot           # Translation template
    └── readme.txt                      # WordPress plugin readme

10. Error Handling & Reliability

  • Retry logic: Failed API calls retry up to 3 times with exponential backoff
  • Queue system: Failed syncs are queued and retried on next cron run
  • Graceful degradation: If WC site is down, Odoo continues working normally; queued syncs process when connection restores
  • Sync log: Every operation logged with success/failure status and error details
  • Email alerts: Configurable notifications on sync failures
  • Connection health check: Periodic ping to verify WC site is reachable
  • Sync log retention: Cron purges logs older than 90 days (configurable). Keeps error logs for 180 days.
  • PDF file access control: Invoice and delivery PDFs stored in protected directories with .htaccess deny rules. Served via PHP handler that validates the requesting user owns the order.

11. Security

  • API keys stored encrypted in both systems
  • HTTPS required for all API communication
  • Odoo API key validated on every incoming request from WP
  • WC consumer key/secret validated on every outgoing request from Odoo
  • WordPress nonce verification on all admin AJAX calls
  • Rate limiting on webhook endpoints to prevent abuse
  • Input sanitization on all data received from external systems
  • WC webhook signature validation via HMAC-SHA256 (separate from API key auth)
  • PDF files served through access-controlled PHP handler, not direct file URLs

12. Odoo 19 Technical Requirements

  • All HTTP controller routes must use type="jsonrpc" (NOT type="json" which is deprecated)
  • Frontend JS uses Interaction class from @web/public/interaction
  • Backend OWL components use standalone rpc() from @web/core/network/rpc
  • OWL components: static props = [] not {}
  • API client class in lib/ directory (NOT in models/ — would cause ORM registration errors). Import via from ..lib.woo_api_client import WooApiClient
  • All custom models include company_id field for multi-company support

13. Multi-Currency Support

  • Odoo currency syncs to WooCommerce product prices
  • Exchange rates managed in Odoo (existing currency rate feature)
  • Products can have different prices per currency
  • Invoice amounts respect the order's original currency

14. Target Deployments

Pairing Odoo WordPress
Westin odoo-westin (192.168.1.40, VM101) westinhealthcare.ca (192.168.1.152, VM301)
Mobility odoo-mobility (192.168.1.102, VM115) mobilityspecialties.ca (192.168.1.153, VM305)
Any third party Any Odoo 19 instance Any WooCommerce site