Odoo ERP Connector
Full-featured Odoo 19 ERP integration for OpenClaw. Control your entire business via natural language chat commands.
📦 Full Source Code: https://github.com/NullNaveen/openclaw-odoo-skill
Quick Install
\ash
npx clawhub install odoo-erp-connector
\
Overview
The Odoo ERP Connector bridges OpenClaw and Odoo 19, enabling autonomous, chat-driven control over 153+ business modules including:
- Sales & CRM
- Purchasing & Inventory
- Invoicing & Accounting
- Projects & Task Management
- Human Resources
- Fleet Management
- Manufacturing (MRP)
- Calendar & Events
- eCommerce
All operations use smart actions that handle fuzzy matching and auto-creation workflows.
Capabilities
Sales & CRM
- Create quotations with dynamic line items
- Manage sales orders (draft → confirmed → done)
- Search and filter orders by status, customer, date range
- Create and qualify leads and opportunities
- Move leads through CRM pipeline stages
- View full sales pipeline with revenue forecasting
Purchasing
- Create purchase orders from vendors
- Manage PO status (draft → purchase → received)
- Receive and validate goods
- Search and filter POs by vendor, status, date
- Track purchase history and vendor performance
Inventory & Products
- Create products (consumables, stockable, services)
- Query stock levels and availability
- Set reorder points and receive low-stock alerts
- Search products by name, code, or category
- Track stock movements and valuations
Invoicing & Accounting
- Create and post customer invoices
- Manage payment terms and schedules
- Query unpaid and overdue invoices
- Search by customer, date range, or amount
- Track invoice status (draft → posted → paid)
Projects & Tasks
- Create projects and organize by team/status
- Create tasks with priority, dates, and assignments
- Log timesheets and track project hours
- Search and filter tasks by project, status, assignee
- Manage project stages and closure
Human Resources
- Create employees and departments
- Manage job titles and work schedules
- Process expense reports and reimbursements
- Search employees by name, department, job
- Track leave requests and attendance
Fleet Management
- Create and track vehicles
- Log odometer readings and service records
- Track maintenance schedules and costs
- Search fleet by license plate, status, brand
- Generate fleet reports
Manufacturing (MRP)
- Create Bills of Materials (BOMs)
- Manage manufacturing orders (MOs)
- Track component requirements and production status
- Search MOs by product or status
- Link BOMs to product variants
Calendar & Events
- Create meetings and events with attendees
- Set reminders and locations
- Search events by date range or attendee
- Track calendar availability
eCommerce
- Publish products to website
- View website orders and customer activity
- Manage product visibility and pricing
Command Examples
Sales
- "Create a quotation for Acme Corp with 10 Widgets at $50 each"
- "Confirm sales order SO00042"
- "Show me all draft quotations from the past week"
- "What's the total revenue from completed orders this month?"
- "Create a quote for Rocky with product Rock"
CRM
- "Create a lead for Rocky, email rocky@example.com, potential $50k deal"
- "Move lead #47 to Qualified stage"
- "Show me the sales pipeline with all open opportunities"
- "What leads are at proposal stage?"
- "Create an opportunity for Acme with $100k expected value"
Purchasing
- "Create a PO for 500 widgets from Supplier ABC"
- "Confirm purchase order PO00123"
- "Show all pending purchase orders"
- "Get me the vendor history for ABC Supplies"
- "What's on order that's overdue?"
Inventory & Products
- "Create a new product: TestWidget, $25 price, min stock 10"
- "Show products with stock below 20 units"
- "What's the stock level for Widget X?"
- "Search for all consumable products"
- "Set reorder point for Product Y to 50 units"
Invoicing
- "Create an invoice for Acme Corp with 5 units at $50 each"
- "Show me unpaid invoices"
- "What invoices are overdue?"
- "Post invoice INV-001"
- "Send a reminder for invoice INV-002"
Projects & Tasks
- "Create a project called Website Redesign"
- "Create a task 'Fix login button' in Website Redesign project"
- "Show me all tasks assigned to me"
- "Log 3 hours of work on task #42"
- "What's the status of the Website Redesign project?"
HR
- "Create employee John Smith, job title Developer"
- "Create department Engineering"
- "Show me all employees in Engineering"
- "Submit expense report for $45.99"
- "What are the pending leave requests?"
Fleet
- "Create vehicle: Tesla Model 3, license plate TESLA-001"
- "Log odometer reading: 50,000 miles for vehicle #1"
- "Show all vehicles with service due"
- "What's the maintenance cost for this month?"
- "Search for blue vehicles"
Manufacturing
- "Create BOM: Widget contains 3 Components A and 2 Components B"
- "Create manufacturing order: produce 50 Widgets"
- "Confirm production order #1"
- "What's the status of MO-001?"
- "Show all in-progress manufacturing orders"
Calendar
- "Create meeting: Team Standup, tomorrow at 10am, 1 hour"
- "Show me my meetings for next week"
- "What events do I have on the 15th?"
- "Schedule a 2-hour planning session with the team"
eCommerce
- "Publish Widget X to the website"
- "Show me website orders from this week"
- "What's my website revenue?"
Smart Actions
The connector handles fuzzy/incomplete requests with intelligent find-or-create logic.
How Smart Actions Work
Example: "Create quotation for Rocky with product Rock"
The system:
- Searches for a customer named "Rocky" (case-insensitive,
ilike matching)
- If not found: Creates a new customer "Rocky" (auto-company flag)
- Searches for product "Rock"
- If not found: Creates a basic product "Rock" (consumable type, default price $0)
- Creates the quotation, linking both the found/created customer and product
- Reports what was found vs. created:
- "Created quotation QT-001 for new customer Rocky with 1 × Rock at $0.00"
This pattern applies across all smart actions:
smart_create_quotation() — customer + products
smart_create_purchase() — vendor + products
smart_create_lead() — partner (optional)
smart_create_task() — project + task
smart_create_employee() — department
smart_create_event() — event only (no dependencies)
Benefits
- Fuzzy matching: Searches are case-insensitive and forgiving
- Auto-creation: Missing dependencies are created automatically
- Transparency: Each response explains what was created vs. found
- No IDs needed: Use names instead of Odoo IDs
- Batch operations: Create multiple related records in one call
Architecture
Core Components
OdooClient — Low-level XML-RPC wrapper
- Connects to Odoo 19 instance
- Handles authentication via API key
- Provides
search(), read(), create(), write(), unlink() methods
- Built-in retry logic and error handling
Model Ops Classes — Business logic for each module
PartnerOps — Customers/suppliers
SaleOrderOps — Quotations and sales orders
InvoiceOps — Customer invoices
InventoryOps — Products and stock
CRMOps — Leads and opportunities
PurchaseOrderOps — POs and vendors
ProjectOps — Projects and tasks
HROps — Employees, departments, expenses
ManufacturingOps — BOMs and MOs
CalendarOps — Events and meetings
FleetOps — Vehicles and odometer
EcommerceOps — Website orders and products
SmartActionHandler — High-level natural-language interface
- Wraps all Ops classes
- Implements find-or-create workflows
- Fuzzy name matching (case-insensitive)
- Multi-step transaction orchestration
- Detailed response summaries
Field Handling
The connector auto-detects required vs. optional fields in Odoo 19:
- Implicit defaults: Fields with Odoo defaults (e.g., state) are omitted
- Smart creation: Auto-fills reasonable defaults for optional fields
- Error reporting: Missing required fields raise clear
OdooError with field name
Configuration
config.json Format
{
"url": "http://localhost:8069",
"db": "your_database",
"username": "api_user@yourcompany.com",
"api_key": "your_api_key_from_odoo_preferences",
"timeout": 60,
"max_retries": 3,
"poll_interval": 60,
"log_level": "INFO",
"webhook_port": 8070,
"webhook_secret": ""
}
Getting Your API Key
- Log in to your Odoo instance
- Go to Settings → Users & Companies → Users
- Open your user record
- Scroll to Access Tokens
- Click Generate Token
- Copy the token and paste into
config.json
Environment Variables
Alternatively, set in .env:
ODOO_URL=http://localhost:8069
ODOO_DB=your_database
ODOO_USERNAME=api_user@yourcompany.com
ODOO_API_KEY=your_api_key
The client auto-loads from .env if config.json is missing.
Python API
Basic Usage
from odoo_skill import OdooClient, SmartActionHandler
# Load config from config.json
client = OdooClient.from_config("config.json")
# Test connection
status = client.test_connection()
print(f"Connected to Odoo {status['server_version']}")
# Use smart actions for natural workflows
smart = SmartActionHandler(client)
# Create a quotation with fuzzy partner and product matching
result = smart.smart_create_quotation(
customer_name="Rocky",
product_lines=[
{"name": "Rock", "quantity": 5, "price_unit": 19.99}
],
notes="Fuzzy match quotation"
)
print(result["summary"])
# Output: "Created quotation QT-001 for new customer Rocky with 1 × Rock at $19.99"
Smart Actions API
# Find-or-create a customer
result = smart.find_or_create_partner(
name="Acme Corp",
is_company=True,
city="New York"
)
partner = result["partner"]
created = result["created"]
# Find-or-create a product
result = smart.find_or_create_product(
name="Widget X",
list_price=49.99,
type="consu"
)
product = result["product"]
# Smart quotation (auto-creates customer & products)
result = smart.smart_create_quotation(
customer_name="Rocky",
product_lines=[
{"name": "Product A", "quantity": 10},
{"name": "Product B", "quantity": 5, "price_unit": 25.0}
],
notes="Created via smart action"
)
order = result["order"]
print(f"Order {order['name']} created with {len(result['products'])} product(s)")
# Smart lead creation
result = smart.smart_create_lead(
name="New Prospect",
contact_name="John Doe",
email="john@prospect.com",
expected_revenue=50000.0
)
lead = result["lead"]
# Smart task creation (auto-creates project if needed)
result = smart.smart_create_task(
project_name="Website Redesign",
task_name="Fix homepage",
description="Update hero section"
)
task = result["task"]
# Smart employee creation (auto-creates department if needed)
result = smart.smart_create_employee(
name="Jane Smith",
job_title="Developer",
department_name="Engineering"
)
employee = result["employee"]
Low-Level Ops API
from odoo_skill.models.sale_order import SaleOrderOps
from odoo_skill.models.partner import PartnerOps
partners = PartnerOps(client)
sales = SaleOrderOps(client)
# Get all customers
customers = partners.search_customers(limit=10)
for cust in customers:
print(f"{cust['name']} — {cust.get('email')}")
# Create a quotation with specific IDs
order = sales.create_quotation(
partner_id=42,
lines=[
{"product_id": 7, "quantity": 10, "price_unit": 49.99},
{"product_id": 8, "quantity": 5}
],
notes="Manual order"
)
print(f"Created {order['name']}")
# Confirm the order
confirmed = sales.confirm_order(order['id'])
print(f"Order {confirmed['name']} is now {confirmed['state']}")
Response Format
All API methods return structured dictionaries:
Smart Action Response
{
"summary": "Created quotation QT-001 for new customer Rocky with 1 × Rock",
"order": {
"id": 1,
"name": "QT-001",
"state": "draft",
"partner_id": [42, "Rocky"],
"amount_total": 19.99
},
"customer": {
"created": True,
"partner": {"id": 42, "name": "Rocky"}
},
"products": [
{
"created": True,
"product": {"id": 7, "name": "Rock"}
}
]
}
Standard Response
{
"id": 1,
"name": "QT-001",
"state": "draft",
"partner_id": [42, "Rocky"],
"amount_total": 19.99,
"order_line": [
{
"id": 1,
"product_id": [7, "Rock"],
"quantity": 1,
"price_unit": 19.99,
"price_subtotal": 19.99
}
]
}
Error Handling
The connector uses custom exceptions:
from odoo_skill.errors import OdooError, OdooAuthError, OdooNotFoundError
try:
result = smart.smart_create_quotation(
customer_name="Acme",
product_lines=[{"name": "Widget"}]
)
except OdooAuthError as e:
print(f"Authentication failed: {e}")
except OdooNotFoundError as e:
print(f"Record not found: {e}")
except OdooError as e:
print(f"Odoo error: {e}")
Supported Odoo Modules
The connector supports 153+ installed modules in Odoo 19:
Core
Sales & CRM
- sale, crm, sale_management, website_sale, event, survey
Purchasing
- purchase, purchase_stock, purchase_requisition
Inventory
- stock, stock_intrastat, stock_dropshipping
Accounting
- account, account_accountant, account_analytic, account_payment
HR
- hr, hr_attendance, hr_expense, hr_contract, hr_holidays, hr_org_chart
Projects
- project, project_enterprise, task_base, project_timesheet_forecast
Manufacturing
- mrp, mrp_byproduct, quality, batch, shelf_life
Fleet
Marketing
- marketing_automation, email_marketing, mass_mailing, sms, website_form
eCommerce
- website_sale, website_sale_analytics, website_sale_comparison, website_form_project
Tools
- calendar, documents, spreadsheet, discuss, mail, knowledge
Plus 50+ more specialized modules
Limits & Constraints
- Search limit: 100 records by default (configurable)
- Timeout: 60 seconds per request (configurable)
- Retries: 3 automatic retries on network failure
- Concurrency: Single-threaded; queue requests if needed
- Rate limiting: Follow your Odoo instance's API limits
Troubleshooting
Connection Issues
- Verify
url, db, username, api_key in config.json
- Check Odoo server is running:
http://your-odoo-url/web
- Ensure API key is generated in Odoo user settings
- Check network connectivity and firewall rules
Authentication Errors
- Regenerate API key in Odoo
- Verify username (email format)
- Check that the user has API access enabled
- Ensure database name matches exactly
Missing Field Errors
- Field names must match Odoo 19 exactly (e.g.,
product_tmpl_id, not product_id)
- Some fields are read-only in Odoo (state, computed fields)
- Check Odoo model definition: Settings → Technical → Database Structure → Models
Smart Action Issues
- Fuzzy matching is case-insensitive but searches only the
name field
- For exact matching, use the low-level Ops API with
id directly
- If a name exists in multiple records, the first match is used
Performance
- Large searches (limit > 100) may timeout
- Use date range filters:
date_from, date_to
- Consider batch operations for bulk data
Examples in OpenClaw
Natural Language Sales Order
User: "Create a quote for Acme Corp with 10 Widgets at $50 each"
OpenClaw → OdooClient (smart action):
1. Search for customer "Acme Corp"
2. Search for product "Widgets"
3. Create quotation with both
4. Return summary
Result: "✅ Created quotation QT-001 for Acme Corp with 10 × Widgets at $50"
Pipeline Status Check
User: "Show me the sales pipeline"
OpenClaw → CRMOps.get_pipeline():
- Query all leads/opportunities
- Group by stage
- Calculate total revenue by stage
- Return formatted summary
Result: "Qualified: $50k | Proposal: $100k | Negotiation: $75k | Total: $225k"
Inventory Alert
User: "What products are low on stock?"
OpenClaw → InventoryOps.get_low_stock_products():
- Query products with stock < reorder point
- List each product, stock level, reorder point
- Suggest PO quantities
Result: "Widget X: 5 on hand (min 20) | Component Y: 0 on hand (min 10)"
Development
Project Structure
OdooConnector/
├── odoo_skill/
│ ├── client.py # Core OdooClient
│ ├── config.py # Configuration loader
│ ├── errors.py # Custom exceptions
│ ├── retry.py # Retry logic
│ ├── smart_actions.py # Smart action handler
│ ├── models/
│ │ ├── partner.py
│ │ ├── sale_order.py
│ │ ├── invoice.py
│ │ ├── inventory.py
│ │ ├── crm.py
│ │ ├── purchase.py
│ │ ├── project.py
│ │ ├── hr.py
│ │ ├── manufacturing.py
│ │ ├── calendar_ops.py
│ │ ├── fleet.py
│ │ ├── ecommerce.py
│ ├── utils/
│ │ ├── formatting.py # Response formatting
│ │ ├── validators.py # Input validation
│ ├── sync/
│ │ ├── poller.py # Webhook poller
│ │ ├── webhook.py # Webhook handler
├── run_full_test.py # Integration test suite
├── config.json # Configuration (create from template)
├── config.template.json # Configuration template
├── requirements.txt # Python dependencies
├── README.md # User setup guide
├── SKILL.md # This file
└── setup.ps1 # PowerShell installer
Running Tests
# Run full integration test suite
python run_full_test.py
# Run single test module
python -m pytest tests/test_partners.py -v
# Run with coverage
python -m pytest --cov=odoo_skill tests/
Adding a New Smart Action
- Implement the method in
SmartActionHandler class
- Use
find_or_create_* primitives for dependencies
- Return a dict with
summary, the main record, and creation details
- Add docstring with example usage
- Test with
run_full_test.py
Example:
def smart_create_invoice(self, customer_name: str, product_lines: list[dict], **kwargs) -> dict:
"""Create invoice with fuzzy customer and product matching."""
# Find or create customer
customer_result = self.find_or_create_partner(customer_name)
customer = customer_result["partner"]
# Find or create products
products = []
for line in product_lines:
prod_result = self.find_or_create_product(line["name"], **line)
products.append(prod_result)
# Create invoice with resolved IDs
invoice = self.invoices.create_invoice(
partner_id=customer["id"],
lines=[...],
**kwargs
)
return {
"summary": f"Created invoice INV-001 for {customer['name']}",
"invoice": invoice,
"customer": customer_result,
"products": products
}
License & Support
This connector is part of the OpenClaw project. For issues, questions, or contributions, contact the development team.
Last Updated: 2026-02-09
Odoo Version: 19.0
Python: 3.10+
Status: Production Ready