$npx -y skills add marcfargas/odoo-toolbox --skill odooOdoo ERP integration - connect, introspect, and automate your Odoo instance
| 1 | # /odoo |
| 2 | |
| 3 | Odoo ERP integration. Two ways to work: **CLI** (fastest for most tasks) and **Library** (for scripts and automation). |
| 4 | |
| 5 | ## Two Ways to Work with Odoo |
| 6 | |
| 7 | ### CLI — Fastest for Most Tasks |
| 8 | |
| 9 | The `odoo` CLI lets you search, create, update, and delete records without writing any code. |
| 10 | |
| 11 | ```bash |
| 12 | # 1. Verify connection (always do this first) |
| 13 | odoo config check |
| 14 | |
| 15 | # 2. Search records |
| 16 | odoo records search res.partner --fields name,email --limit 5 |
| 17 | |
| 18 | # 3. Create a record |
| 19 | odoo records create res.partner --data '{"name":"Acme Corp"}' --confirm |
| 20 | |
| 21 | # 4. Post a note on a record |
| 22 | odoo mail note crm.lead 42 "Called customer" --confirm |
| 23 | ``` |
| 24 | |
| 25 | ### Library — For Scripts and Automation |
| 26 | |
| 27 | ```typescript |
| 28 | import { createClient } from '@marcfargas/odoo-client'; |
| 29 | |
| 30 | const client = await createClient(); // reads ODOO_URL, ODOO_DB, ODOO_USER, ODOO_PASSWORD |
| 31 | |
| 32 | const partners = await client.searchRead('res.partner', [['is_company', '=', true]], { |
| 33 | fields: ['name', 'email'], |
| 34 | limit: 10, |
| 35 | }); |
| 36 | |
| 37 | await client.mail.postInternalNote('crm.lead', 42, '<p>Called customer.</p>'); |
| 38 | await client.modules.isModuleInstalled('sale'); |
| 39 | ``` |
| 40 | |
| 41 | --- |
| 42 | |
| 43 | ## Quick Start |
| 44 | |
| 45 | ### Step 1: Configure Environment |
| 46 | |
| 47 | ```bash |
| 48 | export ODOO_URL=https://mycompany.odoo.com |
| 49 | export ODOO_DB=mycompany |
| 50 | export ODOO_USER=admin |
| 51 | export ODOO_PASSWORD=yourpassword |
| 52 | ``` |
| 53 | |
| 54 | ### Step 2: Verify Connection |
| 55 | |
| 56 | ```bash |
| 57 | odoo config check |
| 58 | # ✓ Connected to https://mycompany.odoo.com (db: mycompany) |
| 59 | # User: Administrator (admin) [id: 2] |
| 60 | # Installed modules: 143 |
| 61 | ``` |
| 62 | |
| 63 | ### Step 3: Explore |
| 64 | |
| 65 | ```bash |
| 66 | # Search for records |
| 67 | odoo records search res.partner --fields name,email --limit 10 |
| 68 | |
| 69 | # Introspect schema |
| 70 | odoo schema fields crm.lead --type many2one |
| 71 | |
| 72 | # Check installed modules |
| 73 | odoo modules list --filter installed --search sale |
| 74 | ``` |
| 75 | |
| 76 | --- |
| 77 | |
| 78 | ## CLI Exit Codes |
| 79 | |
| 80 | All `odoo` CLI commands use these standard exit codes: |
| 81 | |
| 82 | | Code | Meaning | |
| 83 | |------|---------| |
| 84 | | `0` | Success | |
| 85 | | `1` | Usage error (bad flags, missing `--confirm`, invalid arguments) | |
| 86 | | `2` | Auth / network error (wrong credentials, Odoo unreachable) | |
| 87 | | `3` | Not found | |
| 88 | | `4` | Permission denied | |
| 89 | | `5` | Validation error (Odoo rejected the values) | |
| 90 | | `6` | Conflict (e.g., already clocked in) | |
| 91 | | `10` | Partial success | |
| 92 | |
| 93 | Use in scripts: |
| 94 | ```bash |
| 95 | odoo records get crm.lead 42 || echo "Exit code: $?" |
| 96 | ``` |
| 97 | |
| 98 | --- |
| 99 | |
| 100 | ## CLI Command Reference |
| 101 | |
| 102 | | CLI Command | Skill Doc | Description | |
| 103 | |-------------|-----------|-------------| |
| 104 | | `odoo config check/show` | `cli/config.md` | Verify connection, show resolved config | |
| 105 | | `odoo records search/get/create/write/delete/count/call` | `cli/records.md` | Generic CRUD on any model | |
| 106 | | `odoo schema models/fields/describe/codegen` | `base/introspection.md` | Discover models and fields | |
| 107 | | `odoo modules list/install/uninstall/upgrade/info/status` | `base/modules.md` | Manage Odoo modules | |
| 108 | | `odoo url record/portal` | `base/urls.md` | Generate version-agnostic record URLs | |
| 109 | | `odoo mail note/post` | `mail/chatter.md` | Post notes and messages on chatters | |
| 110 | | `odoo attendance clock-in/clock-out/status/list` | `modules/attendance.md` | Employee clock in/out | |
| 111 | | `odoo timesheets start/stop/running/log/list` | `modules/timesheets.md` | Time tracking | |
| 112 | | `odoo accounting cash-accounts/cash-balance/posted-moves/trace-recon/days-to-pay` | `modules/accounting.md` | Read-only accounting queries | |
| 113 | | `odoo state plan/apply/diff` ⚠ | `cli/state.md` | Experimental: state management | |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## Library API |
| 118 | |
| 119 | ### Service Accessors |
| 120 | |
| 121 | Domain-specific helpers are accessed via lazy getters on the client: |
| 122 | |
| 123 | | Accessor | CLI Command | Description | Skill doc | |
| 124 | |----------|-------------|-------------|-----------| |
| 125 | | `client.mail.*` | `odoo mail` | Post notes & messages on chatter | `mail/chatter.md` | |
| 126 | | `client.modules.*` | `odoo modules` | Install, uninstall, check modules | `base/modules.md` | |
| 127 | | `client.urls.*` | `odoo url` | Generate version-agnostic record URLs | `base/urls.md` | |
| 128 | | `client.properties.*` | — | Safe operations for properties fields | `base/properties.md` | |
| 129 | | `client.cdc.*` | — | Change Data Capture — field change history via mail.tracking.value | `modules/cdc.md` | |
| 130 | | `client.accounting.*` | `odoo accounting` | Cash discovery, reconciliation, partner resolution | `modules/accounting.md` | |
| 131 | | `client.attendance.*` | `odoo attendance` | Clock in/out, presence tracking | `modules/attendance.md` | |
| 132 | | `client.timesheets.*` | `odoo timesheets` | Timer start/stop, time logging | `modules/timesheets.md` | |
| 133 | |
| 134 | Core CRUD (`searchRead`, `create`, `write`, `unlink`, etc.) stays directly on `client`. |
| 135 | |
| 136 | ### Safety Model |
| 137 | |
| 138 | | Operation | Level | Notes | |
| 139 | |-----------|-------|-------| |
| 140 | | `client.search()`, `searchRead()`, `read()`, `searchCount()` | READ | | |
| 141 | | `client.create()` | WRITE | | |
| 142 | | `client.write()` | WRITE | | |
| 143 | | `client.unlink()` | DESTRUCTIVE | Permanent deletion | |
| 144 | | `client.call()` | VARIES | Depends on method — check per-skill docs | |
| 145 | | `client.mail.postInternalNo |