100 lines
4.0 KiB
Markdown
100 lines
4.0 KiB
Markdown
---
|
|
name: odoo-shopify-integration
|
|
description: "Connect Odoo with Shopify: sync products, inventory, orders, and customers using the Shopify API and Odoo's external API or connector modules."
|
|
---
|
|
|
|
# Odoo ↔ Shopify Integration
|
|
|
|
## Overview
|
|
|
|
This skill guides you through integrating Odoo with Shopify — syncing your product catalog, real-time inventory levels, incoming orders, and customer data. It covers both using the official Odoo Shopify connector (Enterprise) and building a custom integration via Shopify REST + Odoo XMLRPC APIs.
|
|
|
|
## When to Use This Skill
|
|
|
|
- Selling on Shopify while managing inventory in Odoo.
|
|
- Automatically creating Odoo sales orders from Shopify purchases.
|
|
- Keeping Odoo stock levels in sync with Shopify product availability.
|
|
- Mapping Shopify product variants to Odoo product templates.
|
|
|
|
## How It Works
|
|
|
|
1. **Activate**: Mention `@odoo-shopify-integration` and describe your sync scenario.
|
|
2. **Design**: Receive the data flow architecture and field mapping.
|
|
3. **Build**: Get code snippets for the Shopify webhook receiver and Odoo API caller.
|
|
|
|
## Data Flow Architecture
|
|
|
|
```
|
|
SHOPIFY ODOO
|
|
-------- ----
|
|
Product Catalog <──────sync────── Product Templates + Variants
|
|
Inventory Level <──────sync────── Stock Quants (real-time)
|
|
New Order ───────push──────> Sale Order (auto-confirmed)
|
|
Customer ───────push──────> res.partner (created if new)
|
|
Fulfillment <──────push────── Delivery Order validated
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Example 1: Push an Odoo Sale Order for a Shopify Order (Python)
|
|
|
|
```python
|
|
import xmlrpc.client, requests
|
|
|
|
# Odoo connection
|
|
odoo_url = "https://myodoo.example.com"
|
|
db, uid, pwd = "my_db", 2, "api_key"
|
|
models = xmlrpc.client.ServerProxy(f"{odoo_url}/xmlrpc/2/object")
|
|
|
|
def create_odoo_order_from_shopify(shopify_order):
|
|
# Find or create customer
|
|
partner = models.execute_kw(db, uid, pwd, 'res.partner', 'search_read',
|
|
[[['email', '=', shopify_order['customer']['email']]]],
|
|
{'fields': ['id'], 'limit': 1}
|
|
)
|
|
partner_id = partner[0]['id'] if partner else models.execute_kw(
|
|
db, uid, pwd, 'res.partner', 'create', [{
|
|
'name': shopify_order['customer']['first_name'] + ' ' + shopify_order['customer']['last_name'],
|
|
'email': shopify_order['customer']['email'],
|
|
}]
|
|
)
|
|
|
|
# Create Sale Order
|
|
order_id = models.execute_kw(db, uid, pwd, 'sale.order', 'create', [{
|
|
'partner_id': partner_id,
|
|
'client_order_ref': f"Shopify #{shopify_order['order_number']}",
|
|
'order_line': [(0, 0, {
|
|
'product_id': get_odoo_product_id(line['sku']),
|
|
'product_uom_qty': line['quantity'],
|
|
'price_unit': float(line['price']),
|
|
}) for line in shopify_order['line_items']],
|
|
}])
|
|
return order_id
|
|
|
|
def get_odoo_product_id(sku):
|
|
result = models.execute_kw(db, uid, pwd, 'product.product', 'search_read',
|
|
[[['default_code', '=', sku]]], {'fields': ['id'], 'limit': 1})
|
|
return result[0]['id'] if result else False
|
|
```
|
|
|
|
### Example 2: Shopify Webhook for Real-Time Orders
|
|
|
|
```python
|
|
from flask import Flask, request
|
|
app = Flask(__name__)
|
|
|
|
@app.route('/webhook/shopify/orders', methods=['POST'])
|
|
def shopify_order_webhook():
|
|
shopify_order = request.json
|
|
order_id = create_odoo_order_from_shopify(shopify_order)
|
|
return {"odoo_order_id": order_id}, 200
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
- ✅ **Do:** Use Shopify's **webhook system** for real-time order sync instead of polling.
|
|
- ✅ **Do:** Match products using **SKU / Internal Reference** as the unique key between both systems.
|
|
- ✅ **Do:** Validate Shopify webhook HMAC signatures before processing any payload.
|
|
- ❌ **Don't:** Sync inventory from both systems simultaneously without a "master system" — pick one as the source of truth.
|
|
- ❌ **Don't:** Use Shopify product IDs as the key — use SKUs which are stable across platforms.
|