Clawhub Package Full
by @nullnaveen
Full-featured Odoo 19 ERP connector for OpenClaw - Sales, CRM, Purchase, Inventory, Projects, HR, Fleet, Manufacturing (80+ operations, complete Python code included, XML-RPC integration).
clawhub install odoo-erp-connectorπ About This Skill
name: odoo description: Full-featured Odoo 19 ERP connector for OpenClaw - Sales, CRM, Purchase, Inventory, Projects, HR, Fleet, Manufacturing (80+ operations, complete Python code included, XML-RPC integration). repository: https://github.com/NullNaveen/openclaw-odoo-skill
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:
All operations use smart actions that handle fuzzy matching and auto-creation workflows.
Capabilities
Sales & CRM
Purchasing
Inventory & Products
Invoicing & Accounting
Projects & Tasks
Human Resources
Fleet Management
Manufacturing (MRP)
Calendar & Events
eCommerce
Command Examples
Sales
CRM
Purchasing
Inventory & Products
Invoicing
Projects & Tasks
HR
Fleet
Manufacturing
Calendar
eCommerce
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:
1. Searches for a customer named "Rocky" (case-insensitive, ilike matching)
2. If not found: Creates a new customer "Rocky" (auto-company flag)
3. Searches for product "Rock"
4. If not found: Creates a basic product "Rock" (consumable type, default price $0)
5. Creates the quotation, linking both the found/created customer and product
6. 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 + productssmart_create_purchase() β vendor + productssmart_create_lead() β partner (optional)smart_create_task() β project + tasksmart_create_employee() β departmentsmart_create_event() β event only (no dependencies)Benefits
Architecture
Core Components
OdooClient β Low-level XML-RPC wrapper
search(), read(), create(), write(), unlink() methodsModel Ops Classes β Business logic for each module
PartnerOps β Customers/suppliersSaleOrderOps β Quotations and sales ordersInvoiceOps β Customer invoicesInventoryOps β Products and stockCRMOps β Leads and opportunitiesPurchaseOrderOps β POs and vendorsProjectOps β Projects and tasksHROps β Employees, departments, expensesManufacturingOps β BOMs and MOsCalendarOps β Events and meetingsFleetOps β Vehicles and odometerEcommerceOps β Website orders and productsSmartActionHandler β High-level natural-language interface
Field Handling
The connector auto-detects required vs. optional fields in Odoo 19:
OdooError with field nameConfiguration
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
1. Log in to your Odoo instance
2. Go to Settings β Users & Companies β Users
3. Open your user record
4. Scroll to Access Tokens
5. Click Generate Token
6. 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, SmartActionHandlerLoad 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 PartnerOpspartners = 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, OdooNotFoundErrortry:
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
Purchasing
Inventory
Accounting
HR
Projects
Manufacturing
Fleet
Marketing
eCommerce
Tools
Plus 50+ more specialized modules
Limits & Constraints
Troubleshooting
Connection Issues
url, db, username, api_key in config.jsonhttp://your-odoo-url/webAuthentication Errors
Missing Field Errors
product_tmpl_id, not product_id)Smart Action Issues
name fieldid directlyPerformance
date_from, date_toExamples 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.pyRun single test module
python -m pytest tests/test_partners.py -vRun with coverage
python -m pytest --cov=odoo_skill tests/
Adding a New Smart Action
1. Implement the method in SmartActionHandler class
2. Use find_or_create_* primitives for dependencies
3. Return a dict with summary, the main record, and creation details
4. Add docstring with example usage
5. 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
βοΈ 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
1. Log in to your Odoo instance
2. Go to Settings β Users & Companies β Users
3. Open your user record
4. Scroll to Access Tokens
5. Click Generate Token
6. 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.
π Tips & Best Practices
Connection Issues
url, db, username, api_key in config.jsonhttp://your-odoo-url/webAuthentication Errors
Missing Field Errors
product_tmpl_id, not product_id)Smart Action Issues
name fieldid directlyPerformance
date_from, date_to