← Back to Skills
Browser

odoo-manager

willykinfoussia By willykinfoussia 👁 4 views ▲ 0 votes

Manage Odoo (contacts, any business objects, and metadata)

GitHub
---
name: odoo-manager
description: Manage Odoo (contacts, any business objects, and metadata) via the official External XML-RPC API. Supports generic CRUD operations on any model using execute_kw, with ready-made flows for res.partner and model introspection. Features dynamic instance and database switching with context-aware URL, database, and credential resolution.
homepage: https://www.odoo.com/documentation/
metadata: {"openclaw":{"emoji":"🏢","requires":{"env":["ODOO_URL","ODOO_DB","ODOO_USERNAME","ODOO_PASSWORD"]},"primaryEnv":"ODOO_PASSWORD"}}
---

# Odoo Manager Skill

## 🔐 URL, Database & Credential Resolution

### URL Resolution

Odoo server URL precedence (highest to lowest):

1. `temporary_url` — one-time URL for a specific operation
2. `user_url` — user-defined URL for the current session
3. `ODOO_URL` — environment default URL

This allows you to:

- Switch between multiple Odoo instances (production, staging, client-specific)
- Test against demo databases
- Work with different client environments without changing global config

**Examples (conceptual):**

```text
// Default: uses ODOO_URL from environment
{{resolved_url}}/xmlrpc/2/common

// Override for one operation:
temporary_url = "https://staging.mycompany.odoo.com"
{{resolved_url}}/xmlrpc/2/common

// Override for session:
user_url = "https://client-xyz.odoo.com"
{{resolved_url}}/xmlrpc/2/common
```

### Database Resolution

Database name (`db`) precedence:

1. `temporary_db`
2. `user_db`
3. `ODOO_DB`

Use this to:

- Work with multiple databases on the same Odoo server
- Switch between test and production databases

### Username & Secret Resolution

Username precedence:

1. `temporary_username`
2. `user_username`
3. `ODOO_USERNAME`

Secret (password or API key) precedence:

1. `temporary_api_key` or `temporary_password`
2. `user_api_key` or `user_password`
3. `ODOO_API_KEY` (if set) or `ODOO_PASSWORD`

**Important:**

- Odoo API keys are used **in place of** the password, with the usual login.
- Store passwords / API keys like real passwords; never log or expose them.

Environment variables are handled via standard OpenClaw metadata: `requires.env` declares **required** variables (`ODOO_URL`, `ODOO_DB`, `ODOO_USERNAME`, `ODOO_PASSWORD`). `ODOO_API_KEY` is an **optional** environment variable used instead of the password when present; it is not listed in metadata and should simply be set in the environment when needed.

### Resolved Values

At runtime the skill always works with:

- `{{resolved_url}}` — final URL
- `{{resolved_db}}` — final database name
- `{{resolved_username}}` — final login
- `{{resolved_secret}}` — password **or** API key actually used to authenticate

These are computed using the precedence rules above.

---

## 🔄 Context Management

> The `temporary_*` and `user_*` names are **runtime context variables used by the skill logic**, not OpenClaw metadata fields. OpenClaw does **not** have an `optional.context` metadata key; context is resolved dynamically at runtime as described below.

### Temporary Context (One-Time Use)

**User examples:**

- "Pour cette requête, utilise l’instance staging Odoo"
- "Utilise la base `odoo_demo` juste pour cette opération"
- "Connecte-toi avec cet utilisateur uniquement pour cette action"

**Behavior:**

- Set `temporary_*` (url, db, username, api_key/password)
- Use them for **a single logical operation**
- Automatically clear after use

This is ideal for:

- Comparing data between two environments
- Running a single check on a different database

### Session Context (Current Session)

**User examples:**

- "Travaille sur l’instance Odoo du client XYZ"
- "Utilise la base `clientx_prod` pour cette session"
- "Connecte-toi avec mon compte administrateur pour les prochaines opérations"

**Behavior:**

- Set `user_*` (url, db, username, api_key/password)
- Persist for the whole current session
- Overridden only by `temporary_*` or by clearing `user_*`

### Resetting Context

**User examples:**

- "Reviens à la configuration Odoo par défaut"
- "Efface mon contexte utilisateur Odoo"

**Action:**

- Clear `user_url`, `user_db`, `user_username`, `user_password`, `user_api_key`
- Skill falls back to environment variables (`ODOO_URL`, `ODOO_DB`, `ODOO_USERNAME`, `ODOO_PASSWORD` / `ODOO_API_KEY`)

### Viewing Current Context

**User examples:**

- "Sur quelle instance Odoo es-tu connecté ?"
- "Montre la configuration Odoo actuelle"

**Response should show (never full secrets):**

```text
Current Odoo Context:
- URL: https://client-xyz.odoo.com (user_url)
- DB: clientxyz_prod (user_db)
- Username: api_integration (user_username)
- Secret: using API key (user_api_key)
- Fallback URL: https://default.odoo.com (ODOO_URL)
- Fallback DB: default_db (ODOO_DB)
```

---

## ⚙️ Odoo XML-RPC Basics

Odoo exposes part of its server framework over **XML-RPC** (not REST).
The External API is documented here: https://www.odoo.com/documentation/18.0/fr/developer/reference/external_api.html

Two main endpoints:

- `{{resolved_url}}/xmlrpc/2/common` — authentication and meta calls
- `{{resolved_url}}/xmlrpc/2/object` — model methods via `execute_kw`

### 1. Checking Server Version

Call `version()` on the `common` endpoint to verify URL and connectivity:

```python
common = xmlrpc.client.ServerProxy(f"{resolved_url}/xmlrpc/2/common")
version_info = common.version()
```

Example result:

```json
{
  "server_version": "18.0",
  "server_version_info": [18, 0, 0, "final", 0],
  "server_serie": "18.0",
  "protocol_version": 1
}
```

### 2. Authenticating

Use `authenticate(db, username, password_or_api_key, {})` on the `common` endpoint:

```python
uid = common.authenticate(resolved_db, resolved_username, resolved_secret, {})
```

`uid` is an integer user ID and will be used in all subsequent calls.

If authentication fails, `uid` is `False` / `0` — the skill should:

- Inform the user that credentials or database are invalid
- Suggest checking `ODOO_URL`, `ODOO_DB`, username, and secret

### 3. Calling Model Methods with execute_kw

Build an XML-RPC client for the `object` endpoint:

```python
models = xmlrpc.client.ServerProxy(f"{resolved_url}/xmlrpc/2/object")
```

Then use `execute_kw` with the following signature:

```python
models.execute_kw(
    resolved_db,
    uid,
    resolved_secret,
    "model.name",     # e.g. "res.partner"
    "method_name",    # e.g. "search_read"
    [positional_args],
    {keyword_args}
)
```

All ORM operations in this skill are expressed in terms of `execute_kw`.

---

## 🔍 Domains & Data Types (Odoo ORM)

### Domain Filters

Domains are lists of conditions:

```python
domain = [["field_name", "operator", value], ...]
```

Examples:

- All companies: `[['is_company', '=', True]]`
- Partners in France: `[['country_id', '=', france_id]]`
- Leads with probability > 50%: `[['probability', '>', 50]]`

Common operators:

- `"="`, `"!="`, `">"`, `">="`, `"<"`, `"<="`
- `"like"`, `"ilike"` (case-insensitive)
- `"in"`, `"not in"`
- `"child_of"` (hierarchical relations)

### Field Value Conventions

- **Integer / Float / Char / Text**: use native types.
- **Date / Datetime**: strings in `YYYY-MM-DD` or ISO 8601 format.
- **Many2one**: usually send the **record ID** (`int`) when writing; reads often return `[id, display_name]`.
- **One2many / Many2many**: use the Odoo **command list** protocol for writes (not fully detailed here; see Odoo docs if needed).

---

## 🧩 Generic ORM Operations (execute_kw)

Each subsection below shows typical user queries and the corresponding
`execute_kw` usage. They are applicable to **any** model (not only `res.partner`).

### List / Search Records (search)

**User queries:**

- "Liste tous les partenaires société"
- "Cherche les commandes de vente confirmées"

**Action (generic):**

```python
ids = models.execute_kw(
    resolved_db, uid, resolved_secret,
    "model.name", "search",
    [domain],
    {"offset": 0, "limit": 80}
)
```

Notes:

- `domain` is a list (can be empty `[]` to match all records).
- Use `offset` and `limit` for pagination.

### Count Records (search_count)

**User queries:**

- "Combien de partenaires sont des sociétés ?"
- "Compte les tâches en cours"

**Action:**

```python
count = models.execute_kw(
    resolved_db, uid, resolved_secret,
    "model.name", "search_count",
    [domain]
)
```

### Read Records by ID (read)

**User queries:**

- "Affiche les détails du partenaire 7"
- "Donne-moi les champs name et country_id pour ces IDs"

**Action:**

```python
records = models.execute_kw(
    resolved_db, uid, resolved_secret,
    "model.name", "read",
    [ids],
    {"fields": ["name", "country_id", "comment"]}
)
```

If `fields` is omitted, Odoo returns all readable fields (often a lot).

### Search and Read in One Step (search_read)

Shortcut for `search()` + `read()` in a single call.

**User queries:**

- "Liste les sociétés (nom, pays, commentaire)"
- "Montre les 5 premiers partenaires avec leurs pays"

**Action:**

```python
records = models.execute_kw(
    resolved_db, uid, resolved_secret,
    "model.name", "search_read",
    [domain],
    {
        "fields": ["name", "country_id", "comment"],
        "limit": 5,
        "offset": 0,
        # Optional: "order": "name asc"
    }
)
```

### Create Records (create)

**User queries:**

- "Crée un nouveau partenaire 'New Partner'"
- "Crée une nouvelle tâche dans le projet X"

**Action:**

```python
new_id = models.execute_kw(
    resolved_db, uid, resolved_secret,
    "model.name", "create",
    [{
        "name": "New Partner"
        # other fields...
    }]
)
```

Returns the newly created record ID.

### Updat

... (truncated)
browser

Comments

Sign in to leave a comment

Loading comments...