odoo/api-reference.md
... ...
@@ -1,7 +1,7 @@
1 1
---
2 2
title: Référence API Odoo — Complète
3 3
created: 2026-05-29
4
-updated: 2026-05-29
4
+updated: 2026-05-30
5 5
type: concept
6 6
tags: [odoo, api, json-rpc, reference, developpeur]
7 7
sources: [odoo-online skill, odoo-api skill, odoo.com/documentation]
... ...
@@ -13,10 +13,11 @@ confidence: high
13 13
> **Base URL** : `https://sarl-le-relais-de-louest.odoo.com/jsonrpc`
14 14
> **Protocole** : JSON-RPC 2.0
15 15
> **Auth** : `common.login` + API Key
16
+> **Modèles documentés** : ~250 modèles standards Odoo 19
16 17
17 18
---
18 19
19
-## 1. Authentification
20
+## 1. Authentification (inchangée)
20 21
21 22
### 1.1 Obtenir un UID
22 23
... ...
@@ -36,746 +37,594 @@ Content-Type: application/json
36 37
}
37 38
```
38 39
39
-**Réponse** :
40
-```json
41
-{"jsonrpc": "2.0", "id": 1, "result": 2}
42
-```
43
-
44
-`result` = UID (integer, généralement 2 pour l'admin).
45
-
46
-### 1.2 API Key
47
-
48
-Générée dans Odoo : **Profil → Preferences → Account Security → API Keys → New API Key**.
49
-
50
-⚠️ **Ne pas confondre** avec un token de session navigateur (SHA visible dans l'URL Odoo).
40
+**Réponse** : `{"jsonrpc": "2.0", "id": 1, "result": 2}`
51 41
52
-### 1.3 Helper Python
42
+### 1.2 Helper Python
53 43
54 44
```python
55 45
import requests
56
-
57
-DB = "sarl-le-relais-de-louest"
58
-UID = None
59
-PWD = None # API key
46
+DB, UID, PWD = "sarl-le-relais-de-louest", None, None
60 47
URL = f"https://{DB}.odoo.com/jsonrpc"
61 48
62 49
def odoo_call(model, method, *args):
63 50
payload = {
64 51
"jsonrpc": "2.0", "method": "call",
65 52
"params": {
66
- "service": "object",
67
- "method": "execute_kw",
53
+ "service": "object", "method": "execute_kw",
68 54
"args": [DB, UID, PWD, model, method] + list(args)
69 55
}, "id": 1
70 56
}
71
- resp = requests.post(URL, json=payload, timeout=30).json()
72
- if "error" in resp:
73
- raise Exception(resp["error"]["data"]["message"])
74
- return resp.get("result")
57
+ r = requests.post(URL, json=payload, timeout=30).json()
58
+ if "error" in r:
59
+ raise Exception(r["error"]["data"]["message"])
60
+ return r.get("result")
75 61
```
76 62
77
----
78
-
79 63
## 2. Méthodes génériques
80 64
81
-Tous les modèles supportent ces 7 méthodes :
82
-
83
-### search_read — Rechercher et lire
84
-```python
85
-records = odoo_call("model.name", "search_read",
86
- [domain], # liste de conditions
87
- {kwargs} # fields, offset, limit, order
88
-)
89
-```
90
-
91
-**Paramètres :**
92
-| Param | Type | Description |
93
-|-------|------|-------------|
94
-| `domain` | `list` | Conditions de filtrage (voir §2.1) |
95
-| `fields` | `list` | Champs à retourner |
96
-| `offset` | `int` | Pagination : sauter N enregistrements |
97
-| `limit` | `int` | Max résultats (défaut: 80) |
98
-| `order` | `str` | Tri : `"date_order desc"` |
99
-
100
-### search — Rechercher (IDs seulement)
101
-```python
102
-ids = odoo_call("model.name", "search", [domain])
103
-# Retourne [1, 5, 42, ...]
104
-```
65
+Tous les modèles supportent : `search`, `search_read`, `search_count`, `read`, `create`, `write`, `unlink`, `fields_get`.
105 66
106
-### search_count — Compter
107
-```python
108
-count = odoo_call("model.name", "search_count", [domain])
109
-# Retourne int
110
-```
67
+### Syntaxe des domaines
111 68
112
-### read — Lire par ID
113 69
```python
114
-data = odoo_call("model.name", "read", [[id1, id2]], {"fields": ["name", "email"]})
70
+["field", "=", value] # égalité
71
+["field", "!=", value] # différent
72
+["field", ">=", value] # supérieur ou égal
73
+["field", "=like", "xxx%"] # LIKE
74
+["field", "in", [v1, v2]] # IN
75
+[["f1", "=", v1], ["f2", "=", v2]] # AND
76
+[["f1", "=", v1], "|", ["f1", "=", v2]] # OR
115 77
```
116 78
117
-### create — Créer
118
-```python
119
-new_id = odoo_call("model.name", "create", [{champs}])
120
-# ⚠️ UN seul dict, pas une liste de dicts
121
-```
79
+### Commandes relationnelles
122 80
123
-### write — Modifier
124 81
```python
125
-odoo_call("model.name", "write", [[id1, id2], {champs}])
126
-```
127
-
128
-### unlink — Supprimer
129
-```python
130
-odoo_call("model.name", "unlink", [[id1, id2]])
131
-```
132
-
133
-### 2.1 Syntaxe des domaines
134
-
135
-```python
136
-# Égalité
137
-["field", "=", value]
138
-
139
-# Inégalité
140
-["field", "!=", value]
141
-["field", ">", value]
142
-["field", "<", value]
143
-["field", ">=", value]
144
-["field", "<=", value]
145
-
146
-# LIKE / NOT LIKE
147
-["field", "=like", "pattern%"] # % = wildcard
148
-["field", "not like", "xyz"]
149
-
150
-# IN / NOT IN
151
-["field", "in", [val1, val2]]
152
-["field", "not in", [val1, val2]]
153
-
154
-# AND = liste de conditions
155
-[["field1", "=", v1], ["field2", "=", v2]]
156
-# field1 = v1 ET field2 = v2
157
-
158
-# OR = conditions dans une sous-liste
159
-[["field1", "=", v1], "|", ["field1", "=", v2]]
160
-# field1 = v1 OU field1 = v2
161
-```
162
-
163
-### 2.2 Many2one / One2many / Many2many
164
-
165
-```python
166
-# Many2one → integer
82
+# Many2one → int
167 83
"partner_id": 42
168 84
169
-# Many2many → commandes spéciales
170
-"taxes_id": [(6, 0, [id1, id2])] # Remplacer par cette liste
171
-"taxes_id": [(4, id3)] # Ajouter un élément
172
-"taxes_id": [(3, id3)] # Supprimer un élément
173
-"taxes_id": [(5, 0, 0)] # Vider tout
85
+# Many2many
86
+"taxes_id": [(6, 0, [id1, id2])] # remplacer
87
+"taxes_id": [(4, id3)] # ajouter
88
+"taxes_id": [(3, id3)] # supprimer
89
+"taxes_id": [(5, 0, 0)] # vider
174 90
175
-# One2many → commandes identiques
176
-"order_line": [(0, 0, {vals})] # Créer et lier
177
-"order_line": [(1, id, {vals})] # Modifier existant
178
-"order_line": [(2, id)] # Supprimer existant
91
+# One2many
92
+"order_line": [(0, 0, {vals})] # créer + lier
93
+"order_line": [(1, id, {vals})] # modifier
94
+"order_line": [(2, id)] # supprimer
179 95
```
180 96
181 97
---
182 98
183
-## 3. Modèles — Référence exhaustive
99
+## 3. Catalogue complet des modèles Odoo 19
100
+
101
+> Organisé par module. Chaque modèle est accessible via `odoo_call("nom.modele", ...)`.
102
+> ⚠️ = piège connu | 📖 = détaillé plus bas
103
+
104
+### 3.0 Technique / Base (ir.*)
105
+
106
+| Modèle | Description |
107
+|--------|-------------|
108
+| `ir.model` | Registre de tous les modèles |
109
+| `ir.model.fields` | Champs de chaque modèle |
110
+| `ir.module.module` | Modules installés/à installer |
111
+| `ir.ui.view` | Vues XML (form, tree, kanban...) |
112
+| `ir.ui.menu` | Menus |
113
+| `ir.actions.act_window` | Actions fenêtre |
114
+| `ir.actions.server` | Actions serveur / automations |
115
+| `ir.actions.report` | Rapports PDF |
116
+| `ir.actions.url` | Actions URL |
117
+| `ir.cron` | Tâches planifiées |
118
+| `ir.mail_server` | Serveurs SMTP sortants |
119
+| `ir.config_parameter` | Paramètres système (clé/valeur) |
120
+| `ir.sequence` | Séquences de numérotation |
121
+| `ir.translation` | Traductions |
122
+| `ir.attachment` | Pièces jointes / documents |
123
+| `ir.qweb` | Templates QWeb |
124
+| `ir.filters` | Filtres sauvegardés utilisateur |
125
+| `ir.default` | Valeurs par défaut utilisateur |
126
+| `ir.logging` | Logs applicatifs |
127
+| `ir.property` | Propriétés champ |
128
+
129
+### 3.1 Contacts (res.* — resources)
130
+
131
+| Modèle | Description |
132
+|--------|-------------|
133
+| `res.partner` | 📖 Contacts, clients, fournisseurs |
134
+| `res.partner.category` | Étiquettes / tags |
135
+| `res.partner.bank` | Comptes bancaires |
136
+| `res.partner.title` | Titres (M., Mme, Dr...) |
137
+| `res.partner.industry` | Secteurs d'activité |
138
+| `res.company` | Sociétés |
139
+| `res.users` | Utilisateurs |
140
+| `res.groups` | Groupes de sécurité |
141
+| `res.lang` | Langues |
142
+| `res.country` | Pays |
143
+| `res.country.state` | Régions/États |
144
+| `res.currency` | Devises |
145
+| `res.currency.rate` | Taux de change |
146
+| `res.bank` | Banques |
147
+| `res.config.settings` | Configuration générale |
148
+
149
+### 3.2 Ventes (sale.*)
150
+
151
+| Modèle | Description |
152
+|--------|-------------|
153
+| `sale.order` | 📖 Commandes / devis |
154
+| `sale.order.line` | 📖 Lignes de commande |
155
+| `sale.order.template` | Modèles de devis |
156
+| `sale.order.template.line` | Lignes de modèle de devis |
157
+| `sale.order.template.option` | Options de modèles |
158
+| `sale.advance.payment.inv` | Assistant facture d'acompte |
159
+| `sale.order.cancel` | Assistant annulation |
160
+| `sale.payment.provider.onboarding.wizard` | Assistant onboarding paiement |
161
+| `sale.order.line.margin` | Marge par ligne (lecture) |
162
+
163
+### 3.3 PDV / Point de Vente (pos.*)
164
+
165
+| Modèle | Description |
166
+|--------|-------------|
167
+| `pos.order` | 📖 Commandes PDV |
168
+| `pos.order.line` | 📖 Lignes PDV |
169
+| `pos.session` | 📖 Sessions de caisse |
170
+| `pos.config` | 📖 Configuration PDV |
171
+| `pos.payment` | Paiements PDV |
172
+| `pos.payment.method` | Modes de paiement |
173
+| `pos.category` | Catégories de produits PDV |
174
+| `pos.bill` | Tickets/reçus |
175
+| `pos.session.statement` | Relevés de session |
176
+| `pos.cash.box.in` | Entrée caisse |
177
+| `pos.cash.box.out` | Sortie caisse |
178
+| `pos.order.return` | Remboursement PDV |
179
+| `pos.discount` | Remises PDV |
180
+| `pos.combo` | Combos (menus) |
181
+| `pos.combo.line` | Lignes de combo |
182
+| `pos.close.session.wizard` | Assistant fermeture session |
183
+| `pos.printer` | Imprimantes IoT |
184
+| `pos.pack.operation.lot` | N° de lot/série |
185
+
186
+### 3.4 Produits (product.*)
187
+
188
+| Modèle | Description |
189
+|--------|-------------|
190
+| `product.template` | Modèles de produits |
191
+| `product.product` | 📖 Variantes produits |
192
+| `product.category` | 📖 Catégories |
193
+| `product.attribute` | Attributs (taille, couleur...) |
194
+| `product.attribute.value` | Valeurs d'attribut |
195
+| `product.template.attribute.line` | Ligne attribut-modèle |
196
+| `product.template.attribute.value` | Valeur attribut-modèle |
197
+| `product.packaging` | Colisage |
198
+| `product.supplierinfo` | Infos fournisseur par produit |
199
+| `product.pricelist` | Listes de prix |
200
+| `product.pricelist.item` | Règles de prix |
201
+| `product.uom` | Unités de mesure |
202
+| `product.uom.categ` | Catégories d'unités |
203
+| `product.image` | Images (obsolète, utiliser `ir.attachment`) |
204
+| `product.label.layout` | Mise en page étiquettes |
205
+| `product.replenish` | Assistant réapprovisionnement |
206
+
207
+### 3.5 Inventaire / Stock (stock.*)
208
+
209
+| Modèle | Description |
210
+|--------|-------------|
211
+| `stock.picking` | Transferts / bons de livraison |
212
+| `stock.move` | Mouvements de stock |
213
+| `stock.move.line` | Lignes de mouvement |
214
+| `stock.quant` | 📖 Quantités en stock |
215
+| `stock.location` | Emplacements |
216
+| `stock.warehouse` | Entrepôts |
217
+| `stock.inventory.adjustment.name` | Ajustement d'inventaire |
218
+| `stock.rule` | Règles de réapprovisionnement |
219
+| `stock.picking.type` | Types d'opération |
220
+| `stock.package.type` | Types de colis |
221
+| `stock.package.destination` | Destination colis |
222
+| `stock.package.level` | Niveau colis |
223
+| `stock.lot` | Lots / numéros de série |
224
+| `stock.storage.category` | Catégories de stockage |
225
+| `stock.putaway.rule` | Règles de rangement |
226
+| `stock.scrap` | Mise au rebut |
227
+| `stock.warn.insufficient.qty` | Assistant stock insuffisant |
228
+| `stock.quantity.history` | Historique quantités |
229
+| `stock.track.confirmation` | Traçabilité |
230
+| `stock.track.line` | Ligne de traçabilité |
231
+| `stock.assign.serial` | Assignation n° série |
232
+| `stock.scheduler.compute` | Calcul du scheduler MTS/MTO |
233
+| `stock.change.product.qty` | Modification quantité |
234
+| `stock.return.picking` | Retour de transfert |
235
+
236
+### 3.6 Facturation / Comptabilité (account.*)
237
+
238
+| Modèle | Description |
239
+|--------|-------------|
240
+| `account.move` | 📖 Écritures comptables / Factures |
241
+| `account.move.line` | Lignes d'écriture |
242
+| `account.journal` | Journaux (ventes, banque, caisse...) |
243
+| `account.tax` | 📖 Taxes |
244
+| `account.tax.group` | 📖 Groupes de taxes |
245
+| `account.fiscal.position` | Positions fiscales |
246
+| `account.fiscal.position.tax` | Mapping taxes position fiscale |
247
+| `account.fiscal.position.account` | Mapping comptes position fiscale |
248
+| `account.payment` | 📖 Paiements |
249
+| `account.payment.register` | Assistant enregistrement paiement |
250
+| `account.payment.term` | Conditions de paiement |
251
+| `account.payment.term.line` | Lignes conditions de paiement |
252
+| `account.chart.template` | Modèle plan comptable ⚠️ SaaS restreint |
253
+| `account.account` | Comptes comptables |
254
+| `account.account.type` | Types de comptes |
255
+| `account.account.tag` | Étiquettes comptes |
256
+| `account.group` | Groupes de comptes |
257
+| `account.bank.statement` | Relevés bancaires |
258
+| `account.bank.statement.line` | Lignes relevé |
259
+| `account.reconcile.model` | Modèles de lettrage |
260
+| `account.reconcile.model.line` | Lignes modèle |
261
+| `account.analytic.account` | Comptes analytiques |
262
+| `account.analytic.line` | Lignes analytiques |
263
+| `account.analytic.plan` | Plans analytiques |
264
+| `account.analytic.tag` | Étiquettes analytiques |
265
+| `account.asset` | Immobilisations |
266
+| `account.asset.category` | Catégories d'immobilisation |
267
+| `account.budget.post` | Postes budgétaires |
268
+| `account.cash.rounding` | Arrondi espèces |
269
+| `account.financial.year.op` | Ouverture exercice |
270
+| `account.aged.trial.balance` | Balance âgée |
271
+| `account.general.ledger` | Grand livre |
272
+| `account.trial.balance` | Balance |
273
+| `account.tax.report` | Rapport de taxes |
274
+| `account.report` | Rapports comptables |
275
+| `account.report.line` | Lignes de rapport |
276
+| `account.accrued.orders.wizard` | Assistant OD |
277
+| `account.automatic.entry.wizard` | Assistant écritures auto |
278
+| `wizard.multi.charts.accounts` | Assistant plan comptable ⚠️ SaaS restreint |
279
+
280
+### 3.7 Événements (event.*)
281
+
282
+| Modèle | Description |
283
+|--------|-------------|
284
+| `event.event` | 📖 Événements |
285
+| `event.event.ticket` | 📖 Types de billets |
286
+| `event.registration` | 📖 Participants / inscriptions |
287
+| `event.type` | Catégories d'événements |
288
+| `event.tag` | Étiquettes événements |
289
+| `event.mail` | Emails événement planifiés |
290
+| `event.mail.registration` | Emails inscription |
291
+| `event.track` | Programme / sessions |
292
+| `event.track.location` | Lieux de session |
293
+| `event.track.tag` | Étiquettes session |
294
+| `event.sponsor` | Sponsors |
295
+| `event.sponsor.type` | Types de sponsor |
296
+| `event.registration.cancel` | Assistant annulation inscription |
297
+
298
+### 3.8 CRM (crm.*)
299
+
300
+| Modèle | Description |
301
+|--------|-------------|
302
+| `crm.lead` | Pistes / Leads |
303
+| `crm.team` | Équipes commerciales |
304
+| `crm.stage` | Étapes du pipeline |
305
+| `crm.tag` | Étiquettes CRM |
306
+| `crm.lead.lost` | Assistant perte de piste |
307
+| `crm.lead.to.opportunity` | Conversion lead → opportunité |
308
+| `crm.merge.opportunity` | Fusion opportunités |
309
+| `crm.iap.lead.mining.request` | Lead Mining IAP |
310
+| `crm.iap.lead.role` | Rôles IAP |
311
+| `crm.iap.lead.seniority` | Séniorité IAP |
312
+| `crm.quotation.partner` | Partenaire de devis |
313
+
314
+### 3.9 Ressources Humaines (hr.*)
315
+
316
+| Modèle | Description |
317
+|--------|-------------|
318
+| `hr.employee` | Employés |
319
+| `hr.employee.category` | Catégories employés |
320
+| `hr.department` | Départements |
321
+| `hr.job` | Postes |
322
+| `hr.contract` | Contrats |
323
+| `hr.leave` | Congés |
324
+| `hr.leave.type` | Types de congés |
325
+| `hr.leave.allocation` | Allocations de congés |
326
+| `hr.expense` | Notes de frais |
327
+| `hr.expense.sheet` | Feuilles de frais |
328
+| `hr.expense.category` | Catégories de frais |
329
+| `hr.attendance` | Présences/pointages |
330
+| `hr.applicant` | Candidats |
331
+| `hr.recruitment.stage` | Étapes recrutement |
332
+| `hr.plan` | Plans RH |
333
+| `hr.plan.activity.type` | Types d'activité plan RH |
334
+| `hr.work.entry.type` | Types d'entrée de travail |
335
+
336
+### 3.10 Projets (project.*)
337
+
338
+| Modèle | Description |
339
+|--------|-------------|
340
+| `project.project` | Projets |
341
+| `project.task` | Tâches |
342
+| `project.task.type` | Étapes de tâche |
343
+| `project.tags` | Étiquettes projet |
344
+| `project.milestone` | Jalons |
345
+| `project.task.recurrence` | Tâches récurrentes |
346
+| `project.update` | Mises à jour projet |
347
+| `project.share.wizard` | Assistant partage projet |
348
+| `project.delete.wizard` | Assistant suppression projet |
349
+
350
+### 3.11 Facturation / Temps (account.analytic.*)
351
+
352
+| Modèle | Description |
353
+|--------|-------------|
354
+| `account.analytic.account` | Comptes analytiques |
355
+| `account.analytic.line` | Lignes analytiques (timesheet) |
356
+| `account.analytic.plan` | Plans analytiques |
357
+| `account.analytic.tag` | Étiquettes analytiques |
358
+| `account.analytic.distribution.model` | Modèles de distribution |
359
+
360
+### 3.12 Timesheet (hr_timesheet.*)
361
+
362
+| Modèle | Description |
363
+|--------|-------------|
364
+| `account.analytic.line` | Feuilles de temps (même modèle que 3.11) |
365
+| `project.task.create.timesheet` | Assistant création timesheet |
366
+| `timesheet.analysis.report` | Rapport d'analyse |
367
+
368
+### 3.13 Achats (purchase.*)
369
+
370
+| Modèle | Description |
371
+|--------|-------------|
372
+| `purchase.order` | Commandes fournisseur |
373
+| `purchase.order.line` | Lignes commande fournisseur |
374
+| `purchase.requisition` | Appels d'offres |
375
+| `purchase.requisition.line` | Lignes appel d'offres |
376
+| `purchase.bill.union` | Regroupement factures |
377
+| `purchase.bill.line.union` | Lignes regroupement |
378
+
379
+### 3.14 Abonnements (sale.subscription.*)
380
+
381
+| Modèle | Description |
382
+|--------|-------------|
383
+| `sale.subscription` | Abonnements |
384
+| `sale.subscription.line` | Lignes d'abonnement |
385
+| `sale.subscription.template` | Modèles d'abonnement |
386
+| `sale.subscription.alert` | Alertes abonnement |
387
+| `sale.subscription.close.reason` | Raisons clôture |
388
+| `sale.subscription.recurrence.period` | Périodes récurrentes |
389
+
390
+### 3.15 E-commerce (website.* + product.public.*)
391
+
392
+| Modèle | Description |
393
+|--------|-------------|
394
+| `website` | Sites web |
395
+| `website.page` | Pages |
396
+| `website.menu` | Menus du site |
397
+| `website.rewrite` | Redirections |
398
+| `website.visitor` | Visiteurs |
399
+| `website.track` | Tracking |
400
+| `product.public.category` | Catégories e-commerce |
401
+| `product.ribbon` | Rubans produit |
402
+| `website.sale.extra.field` | Champs supplémentaires checkout |
403
+| `website.sale.extra.line` | Lignes frais supplémentaires |
404
+| `payment.provider` | Fournisseurs de paiement |
405
+| `payment.token` | Tokens de paiement sauvegardés |
406
+| `payment.transaction` | Transactions de paiement |
407
+| `payment.link.wizard` | Assistant lien de paiement |
408
+
409
+### 3.16 Messagerie / Emails (mail.*)
410
+
411
+| Modèle | Description |
412
+|--------|-------------|
413
+| `mail.message` | Messages (fil de discussion) |
414
+| `mail.activity` | Activités planifiées |
415
+| `mail.activity.type` | Types d'activité |
416
+| `mail.template` | Modèles d'email |
417
+| `mail.mail` | 📖 Emails en file d'attente |
418
+| `mail.compose.message` | Assistant composition |
419
+| `mail.channel` | Canaux de discussion |
420
+| `mail.channel.member` | Membres du canal |
421
+| `mail.followers` | Abonnés |
422
+| `mail.notification` | Notifications |
423
+| `mail.tracking.value` | Valeurs de suivi |
424
+| `mail.alias` | Alias email |
425
+| `mail.alias.domain` | Domaines alias |
426
+| `mail.shortcode` | Codes courts |
427
+| `mail.link.preview` | Aperçus de lien |
428
+| `fetchmail.server` | Serveur entrant (IMAP/POP) |
429
+
430
+### 3.17 Marketing / Email (mass_mailing.* + link.tracker.*)
431
+
432
+| Modèle | Description |
433
+|--------|-------------|
434
+| `mailing.mailing` | Campagnes email |
435
+| `mailing.list` | Listes de diffusion |
436
+| `mailing.contact` | Contacts liste |
437
+| `mailing.trace` | Traces (ouvertures, clics) |
438
+| `link.tracker` | Traqueurs de lien |
439
+| `link.tracker.click` | Clics sur liens |
440
+| `link.tracker.code` | Codes de lien |
441
+
442
+### 3.18 Sondages (survey.*)
443
+
444
+| Modèle | Description |
445
+|--------|-------------|
446
+| `survey.survey` | Sondages |
447
+| `survey.question` | Questions |
448
+| `survey.question.answer` | Réponses possibles |
449
+| `survey.user_input` | Réponses utilisateur |
450
+| `survey.user_input.line` | Lignes de réponse |
451
+| `survey.invite` | Invitations |
452
+
453
+### 3.19 Événements Live / Forum
454
+
455
+| Modèle | Description |
456
+|--------|-------------|
457
+| `event.booth` | Stands salon |
458
+| `event.booth.category` | Catégories stand |
459
+| `forum.forum` | Forums |
460
+| `forum.post` | Messages forum |
461
+| `forum.tag` | Étiquettes forum |
462
+
463
+### 3.20 Base de connaissances (knowledge.*)
464
+
465
+| Modèle | Description |
466
+|--------|-------------|
467
+| `knowledge.article` | Articles base de connaissance |
468
+| `knowledge.article.favorite` | Favoris article |
469
+| `knowledge.article.member` | Membres article |
470
+| `knowledge.cover` | Couverture |
471
+
472
+### 3.21 Planning (planning.*)
473
+
474
+| Modèle | Description |
475
+|--------|-------------|
476
+| `planning.slot` | Créneaux planning |
477
+| `planning.slot.template` | Modèles de créneau |
478
+| `planning.role` | Rôles planning |
479
+| `planning.calendar` | Calendriers |
480
+
481
+### 3.22 Documents (documents.*)
482
+
483
+| Modèle | Description |
484
+|--------|-------------|
485
+| `documents.document` | Documents |
486
+| `documents.folder` | Dossiers |
487
+| `documents.tag` | Étiquettes document |
488
+| `documents.share` | Partage de documents |
489
+
490
+### 3.23 Approbations (approvals.*)
491
+
492
+| Modèle | Description |
493
+|--------|-------------|
494
+| `approval.request` | Demandes d'approbation |
495
+| `approval.category` | Catégories d'approbation |
496
+| `approval.approver` | Approbateurs |
184 497
185
-### 3.1 res.partner — Contacts / Clients
498
+---
186 499
187
-| Champ | Type | Obligatoire | Description |
188
-|-------|------|:----------:|-------------|
189
-| `name` | char | ✅ | Nom complet |
190
-| `email` | char | | Email |
191
-| `phone` | char | | Téléphone fixe |
192
-| `mobile` | char | | Téléphone mobile |
193
-| `street` | char | | Rue |
194
-| `city` | char | | Ville |
195
-| `zip` | char | | Code postal |
196
-| `country_id` | m2o | | Pays |
197
-| `customer_rank` | int | | 1 = client, 0 = prospect |
198
-| `supplier_rank` | int | | 1 = fournisseur |
199
-| `is_company` | bool | | True = société, False = particulier |
200
-| `company_type` | selection | | `person` ou `company` |
201
-| `vat` | char | | N° TVA intracommunautaire |
202
-| `barcode` | char | | Code-barres client |
203
-| `active` | bool | | False = archivé |
204
-| `comment` | text | | Notes internes |
205
-| `category_id` | m2m | | Étiquettes (tags) |
206
-
207
-**Recherche par email :**
208
-```python
209
-partner = odoo_call("res.partner", "search_read",
210
- [[["email", "=", "jean@email.com"]]],
211
- {"fields": ["id", "name", "email"]})
212
-```
500
+## 4. Modèles détaillés (les plus utilisés)
213 501
214
-### 3.2 sale.order — Commandes / Devis
502
+### 4.1 sale.order — Commande
215 503
216 504
| Champ | Type | Obligatoire | Description |
217 505
|-------|------|:----------:|-------------|
218 506
| `name` | char | ✅ | Référence commande |
219 507
| `partner_id` | m2o → res.partner | ✅ | Client |
220
-| `partner_invoice_id` | m2o → res.partner | ✅ | Adresse facturation |
221
-| `partner_shipping_id` | m2o → res.partner | ✅ | Adresse livraison |
222
-| `company_id` | m2o → res.company | ✅ | Société (généralement 1) |
223
-| `date_order` | datetime | ✅ | Date commande |
224
-| `picking_policy` | selection | ✅ | `direct` (livraison immédiate) ou `one` |
225
-| `state` | selection | | `draft`, `sent`, `sale`, `done`, `cancel` |
226
-| `client_order_ref` | char | | Référence externe (ex: BilletWeb) |
227
-| `team_id` | m2o → crm.team | | Équipe de vente |
228
-| `user_id` | m2o → res.users | | Vendeur |
229
-| `partner_shipping_id` | m2o | | Adresse livraison |
230
-| `warehouse_id` | m2o | | Entrepôt |
231
-| `payment_term_id` | m2o | | Conditions de paiement |
232
-| `pricelist_id` | m2o | | Liste de prix |
233
-| `currency_id` | m2o | | Devise (automatique) |
234
-| `note` | text | | Notes (visibles sur le PDF) |
235
-| `amount_untaxed` | float | | Total HT (lecture seule) |
236
-| `amount_tax` | float | | Total TVA (lecture seule) |
237
-| `amount_total` | float | | Total TTC (lecture seule) |
238
-| `invoice_status` | selection | | `to invoice`, `invoiced`, `no` |
239
-| `require_signature` | bool | | Signature requise |
240
-| `require_payment` | bool | | Paiement requis avant confirmation |
241
-| `order_line` | o2m | | Lignes de commande |
242
-
243
-**Création minimale :**
244
-```python
245
-so_id = odoo_call("sale.order", "create", [{
246
- "name": "SO-REF-123",
247
- "partner_id": partner_id,
248
- "partner_invoice_id": partner_id,
249
- "partner_shipping_id": partner_id,
250
- "company_id": 1,
251
- "date_order": "2026-05-29 10:00:00",
252
- "picking_policy": "direct",
253
- "state": "draft",
254
-}])
255
-```
256
-
257
-### 3.3 sale.order.line — Lignes de commande
258
-
259
-| Champ | Type | Description |
260
-|-------|------|-------------|
261
-| `order_id` | m2o → sale.order | Commande parente |
262
-| `product_id` | m2o → product.product | Produit |
263
-| `product_uom_qty` | float | Quantité |
264
-| `product_uom` | m2o | Unité de mesure |
265
-| `price_unit` | float | Prix unitaire |
266
-| `discount` | float | Remise (%) |
267
-| `name` | char | Description |
268
-| `event_ticket_id` | m2o → event.event.ticket | Billet lié |
269
-| `registration_ids` | o2m → event.registration | Inscriptions liées |
270
-| `tax_id` | m2m → account.tax | Taxes |
271
-| `customer_lead` | float | Délai de livraison (jours) |
272
-| `state` | selection | `draft`, `sale`, `done`, `cancel` |
273
-
274
-### 3.4 product.product — Produits
275
-
276
-| Champ | Type | Obligatoire | Description |
277
-|-------|------|:----------:|-------------|
278
-| `name` | char | ✅ | Nom du produit |
279
-| `type` | selection | | `consu`, `service`, `product` |
280
-| `list_price` | float | | Prix de vente TTC |
281
-| `standard_price` | float | | Prix de revient |
282
-| `barcode` | char | | Code-barres |
283
-| `categ_id` | m2o → product.category | | Catégorie |
284
-| `sale_ok` | bool | | Disponible à la vente |
285
-| `purchase_ok` | bool | | Disponible à l'achat |
286
-| `available_in_pos` | bool | | Visible dans le PDV |
287
-| `active` | bool | | Actif |
288
-| `taxes_id` | m2m → account.tax | | Taxes à la vente |
289
-| `supplier_taxes_id` | m2m | | Taxes à l'achat |
290
-| `description_sale` | text | | Description sur les devis |
291
-| `default_code` | char | | Référence interne |
292
-| `weight` | float | | Poids (kg) |
293
-
294
-**⚠️** `detailed_type` n'existe pas sur Odoo Online SaaS → utiliser `type`.
295
-
296
-### 3.5 product.category — Catégories
508
+| `partner_invoice_id` | m2o | ✅ | Adresse facturation |
509
+| `partner_shipping_id` | m2o | ✅ | Adresse livraison |
510
+| `company_id` | m2o | ✅ | Société (1) |
511
+| `date_order` | datetime | ✅ | Date |
512
+| `picking_policy` | selection | ✅ | `direct` ou `one` |
513
+| `state` | selection | | `draft`/`sent`/`sale`/`done`/`cancel` |
514
+| `client_order_ref` | char | | Réf externe |
515
+| `team_id` | m2o → crm.team | | Équipe |
516
+| `user_id` | m2o | | Vendeur |
517
+| `note` | text | | Notes |
518
+
519
+### 4.2 product.product — Produit
297 520
298 521
| Champ | Type | Description |
299 522
|-------|------|-------------|
300 523
| `name` | char ✅ | Nom |
301
-| `parent_id` | m2o | Catégorie parente |
302
-| `complete_name` | char | Chemin complet (lecture seule) |
303
-
304
-### 3.6 product.template — Modèles de produits
305
-
306
-Mêmes champs que `product.product` pour l'essentiel. La différence :
307
-- `product.template` = produit générique
308
-- `product.product` = variante spécifique
309
-
310
-### 3.7 event.event — Événements
311
-
312
-| Champ | Type | Obligatoire | Description |
313
-|-------|------|:----------:|-------------|
314
-| `name` | char | ✅ | Nom de l'événement |
315
-| `date_begin` | datetime | | Date début |
316
-| `date_end` | datetime | | Date fin |
317
-| `seats_max` | int | | Places maximum |
318
-| `seats_limited` | bool | | Limiter les places |
319
-| `seats_available` | int | | Places restantes (lecture seule) |
320
-| `auto_confirm` | bool | | ⚠️ Confirmation auto par email |
321
-| `event_ticket_ids` | o2m | | Types de billets |
322
-| `registration_ids` | o2m | | Inscriptions |
323
-| `state` | selection | | `draft`, `confirm`, `done`, `cancel` |
324
-| `user_id` | m2o | | Responsable |
325
-| `address_id` | m2o | | Lieu |
326
-| `country_id` | m2o | | Pays |
327
-
328
-### 3.8 event.event.ticket — Types de billets
329
-
330
-| Champ | Type | Obligatoire | Description |
331
-|-------|------|:----------:|-------------|
332
-| `name` | char | ✅ | Nom du billet |
333
-| `event_id` | m2o → event.event | ✅ | Événement parent |
334
-| `product_id` | m2o → product.product | ✅ | Produit associé |
335
-| `price` | float | | Prix |
336
-| `seats_limited` | bool | | Nombre limité |
337
-| `seats_max` | int | | Places max |
338
-| `description` | text | | Description |
339
-
340
-### 3.9 event.registration — Participants
341
-
342
-| Champ | Type | Description |
343
-|-------|------|-------------|
344
-| `event_id` | m2o → event.event | Événement |
345
-| `name` | char | Nom du participant |
346
-| `email` | char | Email |
347
-| `phone` | char | Téléphone |
348
-| `barcode` | char | **QR/Barcode** (utilisé pour BilletWeb) |
349
-| `state` | selection | `draft`, `open`, `done`, `cancel` |
350
-| `event_ticket_id` | m2o → event.event.ticket | Type de billet |
351
-| `sale_order_id` | m2o → sale.order | Commande liée |
352
-| `sale_order_line_id` | m2o → sale.order.line | Ligne de commande liée |
353
-| `attendee_partner_id` | m2o → res.partner | Contact participant |
354
-| `date_closed` | datetime | Date de clôture |
355
-
356
-**⚠️** `description` n'existe pas → utiliser `barcode` pour les références externes.
357
-
358
-### 3.10 pos.order — Commandes PDV
359
-
360
-| Champ | Type | Description |
361
-|-------|------|-------------|
362
-| `name` | char | Référence (ex: `POS/2026/05/29/001`) |
363
-| `date_order` | datetime | Date |
364
-| `session_id` | m2o → pos.session | Session PDV |
365
-| `partner_id` | m2o → res.partner | Client (si renseigné) |
366
-| `amount_total` | float | Total TTC |
367
-| `amount_tax` | float | Total TVA |
368
-| `amount_paid` | float | Montant payé |
369
-| `amount_return` | float | Rendu monnaie |
370
-| `state` | selection | `draft`, `paid`, `done`, `invoiced`, `cancel` |
371
-| `lines` | o2m → pos.order.line | Lignes |
372
-| `payment_ids` | o2m → pos.payment | Paiements |
373
-
374
-### 3.11 pos.order.line — Lignes PDV
375
-
376
-| Champ | Type | Description |
377
-|-------|------|-------------|
378
-| `order_id` | m2o → pos.order | Commande parente |
379
-| `product_id` | m2o → product.product | Produit |
380
-| `qty` | float | Quantité |
381
-| `price_unit` | float | Prix unitaire |
382
-| `discount` | float | Remise |
383
-| `price_subtotal` | float | Sous-total |
384
-| `tax_ids` | m2m → account.tax | Taxes |
385
-
386
-### 3.12 pos.session — Sessions PDV
387
-
388
-| Champ | Type | Description |
389
-|-------|------|-------------|
390
-| `name` | char | Nom session |
391
-| `config_id` | m2o → pos.config | Configuration PDV |
392
-| `start_at` | datetime | Ouverture |
393
-| `stop_at` | datetime | Fermeture |
394
-| `state` | selection | `opening_control`, `opened`, `closing_control`, `closed` |
395
-| `cash_register_balance_start` | float | Solde ouverture |
396
-| `cash_register_balance_end` | float | Solde fermeture |
397
-| `order_ids` | o2m → pos.order | Commandes |
398
-
399
-### 3.13 pos.config — Configuration PDV
400
-
401
-| Champ | Type | Description |
402
-|-------|------|-------------|
403
-| `name` | char ✅ | Nom ("Parc de la Luge - Caisse") |
404
-| `iface_cashdrawer` | bool | Tiroir caisse |
405
-| `iface_print_via_proxy` | bool | Impression ticket |
406
-| `iface_scan_via_proxy` | bool | Scanner |
407
-| `module_pos_restaurant` | bool | Mode restaurant |
408
-| `company_id` | m2o | Société |
409
-
410
-### 3.14 account.move — Factures / Écritures comptables
411
-
412
-| Champ | Type | Description |
413
-|-------|------|-------------|
414
-| `name` | char | Numéro de facture |
415
-| `move_type` | selection | `out_invoice`, `out_refund`, `in_invoice`, `in_refund` |
416
-| `partner_id` | m2o → res.partner | Client/Fournisseur |
417
-| `invoice_date` | date | Date facture |
418
-| `invoice_date_due` | date | Date d'échéance |
419
-| `state` | selection | `draft`, `posted`, `cancel` |
420
-| `amount_untaxed` | float | HT |
421
-| `amount_tax` | float | TVA |
422
-| `amount_total` | float | TTC |
423
-| `amount_residual` | float | Restant dû |
424
-| `payment_state` | selection | `not_paid`, `in_payment`, `paid`, `partial`, `reversed` |
425
-| `invoice_line_ids` | o2m | Lignes de facture |
426
-| `ref` | char | Référence externe |
427
-
428
-### 3.15 account.payment — Paiements
429
-
430
-| Champ | Type | Description |
431
-|-------|------|-------------|
432
-| `payment_type` | selection | `inbound` (reçu) / `outbound` (envoyé) |
433
-| `partner_type` | selection | `customer` / `supplier` |
434
-| `partner_id` | m2o | Client |
435
-| `amount` | float | Montant |
436
-| `date` | date | Date |
437
-| `journal_id` | m2o → account.journal | Journal (banque, caisse) |
438
-| `payment_method_id` | m2o | Mode de paiement |
439
-| `state` | selection | `draft`, `posted`, `sent`, `reconciled`, `cancelled` |
440
-
441
-### 3.16 account.tax — Taxes
442
-
443
-| Champ | Type | Description |
444
-|-------|------|-------------|
445
-| `name` | char ✅ | Nom ("TVA 8.5% Réunion") |
446
-| `amount` | float | Taux (8.5, 2.1, 0) |
447
-| `amount_type` | selection | `percent`, `fixed`, `division`, `group` |
448
-| `type_tax_use` | selection | `sale`, `purchase`, `none` |
449
-| `tax_group_id` | m2o | Groupe |
524
+| `type` | selection | `consu`/`service`/`product` ⚠️ pas `detailed_type` |
525
+| `list_price` | float | Prix vente TTC |
526
+| `barcode` | char | Code-barres |
527
+| `categ_id` | m2o | Catégorie |
528
+| `sale_ok` | bool | Vente |
529
+| `available_in_pos` | bool | Visible en PDV |
530
+| `taxes_id` | m2m | Taxes |
450 531
| `active` | bool | Actif |
451
-| `price_include` | bool | Prix TTC |
452
-| `description` | char | Texte sur la facture |
453
-
454
-### 3.17 account.tax.group — Groupes de taxes
455
-
456
-| Champ | Type | Description |
457
-|-------|------|-------------|
458
-| `name` | char ✅ | Nom |
459
-| `country_id` | m2o | Pays (⚠️ ne pas mettre si DOM !) |
460
-
461
-### 3.18 stock.quant — Inventaire
462
-
463
-| Champ | Type | Description |
464
-|-------|------|-------------|
465
-| `product_id` | m2o | Produit |
466
-| `location_id` | m2o | Emplacement |
467
-| `quantity` | float | Quantité |
468
-| `inventory_quantity` | float | Qté comptée |
469
-| `inventory_diff_quantity` | float | Écart |
470 532
471
-### 3.19 ir.module.module — Modules
533
+### 4.3 event.registration — Inscription
472 534
473 535
| Champ | Type | Description |
474 536
|-------|------|-------------|
475
-| `name` | char | Nom technique |
476
-| `display_name` | char | Nom affiché |
477
-| `state` | selection | `uninstalled`, `installed`, `to install`, `to upgrade` |
478
-
479
-**Installer un module :**
480
-```python
481
-mid = odoo_call("ir.module.module", "search_read",
482
- [[["name", "=", "point_of_sale"]]], {"fields": ["id"]})[0]["id"]
483
-odoo_call("ir.module.module", "button_immediate_install", [[mid]])
484
-```
485
-
486
-### 3.20 mail.mail — Emails en file d'attente
487
-
488
-| Champ | Type | Description |
489
-|-------|------|-------------|
490
-| `state` | selection | `outgoing`, `sent`, `exception`, `cancel` |
491
-| `subject` | char | Sujet |
492
-| `email_to` | char | Destinataires |
493
-
494
-### 3.21 ir.mail_server — Serveur d'envoi
495
-
496
-| Champ | Type | Description |
497
-|-------|------|-------------|
498
-| `name` | char | Nom |
499
-| `smtp_host` | char | Serveur SMTP |
500
-| `active` | bool | `False` pour désactiver |
501
-
502
-### 3.22 ir.cron — Tâches planifiées
503
-
504
-| Champ | Type | Description |
505
-|-------|------|-------------|
506
-| `name` | char | Nom |
507
-| `model_id` | m2o | Modèle |
508
-| `active` | bool | Actif |
509
-| `interval_number` | int | Fréquence |
510
-| `interval_type` | selection | `minutes`, `hours`, `days`, `weeks`, `months` |
511
-
512
-### 3.23 res.company — Société
513
-
514
-| Champ | Type | Description |
515
-|-------|------|-------------|
516
-| `name` | char | Nom |
517
-| `country_id` | m2o | Pays (187 = Réunion) |
518
-| `currency_id` | m2o | Devise (EUR) |
519
-| `phone` | char | Téléphone |
537
+| `event_id` | m2o | Événement |
538
+| `name` | char | Nom participant |
520 539
| `email` | char | Email |
521
-| `street` | char | Adresse |
522
-
523
----
540
+| `barcode` | char | QR/Barcode BilletWeb |
541
+| `state` | selection | `draft`/`open`/`done`/`cancel` |
542
+| `event_ticket_id` | m2o | Type billet |
543
+| `sale_order_id` | m2o | Commande liée |
544
+| `sale_order_line_id` | m2o | Ligne liée |
524 545
525
-## 4. Flux BilletWeb → Odoo
526
-
527
-### 4.1 Ordre des opérations
528
-
529
-```
530
-① res.partner — find or create (par email)
531
-② product.product — find (par barcode BW-*)
532
-③ event.event.ticket — find or create (produit + event)
533
-④ sale.order — create
534
-⑤ sale.order.line — create (lié au ticket)
535
-⑥ event.registration — create (avec barcode BilletWeb)
536
-⑦ sale.order.line — write registration_ids ← lier
537
-```
538
-
539
-### 4.2 Anti-doublon
540
-
541
-```python
542
-# Charger TOUS les barcodes existants au démarrage
543
-existing = odoo_call("event.registration", "search_read",
544
- [[]], {"fields": ["barcode"]})
545
-done = {r["barcode"] for r in existing if r.get("barcode")}
546
-
547
-# Vérifier avant création
548
-if barcode in done:
549
- continue # déjà importé
550
-
551
-# Réutiliser les commandes existantes
552
-existing_so = odoo_call("sale.order", "search_read",
553
- [[["client_order_ref", "=", ref]]], {"fields": ["id"]})
554
-so_id = existing_so[0]["id"] if existing_so else None
555
-```
556
-
557
-### 4.3 Désactiver les emails (avant import massif)
558
-
559
-```python
560
-# 1. Vider la file d'attente
561
-stuck = odoo_call("mail.mail", "search",
562
- [[["state", "in", ["outgoing", "exception"]]]])
563
-for mid in stuck:
564
- odoo_call("mail.mail", "unlink", [[mid]])
565
-
566
-# 2. Désactiver serveur SMTP
567
-servers = odoo_call("ir.mail_server", "search_read", [],
568
- {"fields": ["id"]})
569
-for s in servers:
570
- odoo_call("ir.mail_server", "write", [[s["id"]], {"active": False}])
571
-
572
-# 3. Désactiver fetchmail
573
-for s in odoo_call("fetchmail.server", "search_read", [],
574
- {"fields": ["id"]}):
575
- odoo_call("fetchmail.server", "write", [[s["id"]], {"active": False}])
576
-
577
-# 4. Désactiver templates d'email
578
-for t in odoo_call("mail.template", "search_read", [],
579
- {"fields": ["id"]}):
580
- odoo_call("mail.template", "write", [[t["id"]], {"auto_delete": True}])
581
-
582
-# 5. Désactiver cron jobs email
583
-for c in odoo_call("ir.cron", "search_read", [],
584
- {"fields": ["id", "name"]}):
585
- if any(kw in c["name"].lower() for kw in
586
- ["mail", "email", "send", "notification"]):
587
- odoo_call("ir.cron", "write", [[c["id"]], {"active": False}])
588
-
589
-# 6. Désactiver confirmation auto événements
590
-for ev_id in event_ids:
591
- odoo_call("event.event", "write", [[ev_id],
592
- {"auto_confirm": False}])
593
-```
546
+⚠️ `description` n'existe pas → utiliser `barcode`.
594 547
595 548
---
596 549
597
-## 5. TVA Réunion (DOM)
598
-
599
-### 5.1 Taux applicables
600
-
601
-| Taux | Vente (ID) | Achat (ID) | Usage |
602
-|------|:---------:|:---------:|-------|
603
-| 8,5% | 79 | 32 | Taux normal DOM |
604
-| 2,1% | 80 | 35 | Taux réduit |
605
-| 0% | 61-70 | 50 | Exonéré |
606
-
607
-### 5.2 Créer une taxe DOM
608
-
609
-```python
610
-# Groupe (sans country_id !)
611
-grp = odoo_call("account.tax.group", "create",
612
- [{"name": "TVA 8.5%"}])
613
-
614
-# Taxe vente
615
-odoo_call("account.tax", "create", [{
616
- "name": "8.5% S (Réunion)",
617
- "amount": 8.5,
618
- "amount_type": "percent",
619
- "type_tax_use": "sale",
620
- "tax_group_id": grp,
621
- "price_include": False,
622
-}])
623
-```
550
+## 5. Flux BilletWeb → Odoo
624 551
625
-### 5.3 Désactiver les taux métropole
552
+Ordre : `res.partner` → `product.product` → `event.event.ticket` → `sale.order` → `sale.order.line` → `event.registration` → lien `registration_ids`.
626 553
554
+### Anti-doublon
627 555
```python
628
-# Désactiver 20%
629
-for t in odoo_call("account.tax", "search_read",
630
- [[["amount", "=", 20.0]]], {"fields": ["id"]}):
631
- odoo_call("account.tax", "write", [[t["id"]], {"active": False}])
632
-# Idem pour 10%, 5.5%
556
+existing = odoo_call("event.registration", "search_read", [[]], {"fields": ["barcode"]})
557
+done = {r["barcode"] for r in existing if r.get("barcode")}
558
+if barcode in done: continue
633 559
```
634 560
635
-### 5.4 Appliquer une taxe à un produit
636
-
561
+### Désactiver les emails (6 étapes)
637 562
```python
638
-odoo_call("product.product", "write",
639
- [[product_id], {"taxes_id": [(6, 0, [tax_id])]}])
563
+# 1. mail.mail → unlink stuck
564
+# 2. ir.mail_server → active=False
565
+# 3. fetchmail.server → active=False
566
+# 4. mail.template → auto_delete=True
567
+# 5. ir.cron → active=False (jobs mail/email/send)
568
+# 6. event.event → auto_confirm=False
640 569
```
641 570
642 571
---
643 572
644
-## 6. Modules de localisation française
573
+## 6. TVA Réunion (DOM)
645 574
646
-| Module | Rôle |
647
-|--------|------|
648
-| `l10n_fr` | Base localisation France |
649
-| `l10n_fr_account` | Plan comptable français + templates taxes |
650
-| `l10n_fr_pos_cert` | Certification **NF 525** (obligatoire) |
651
-| `l10n_fr_reports` | Rapports comptables français |
575
+| Taux | Vente ID | Achat ID |
576
+|------|:-------:|:-------:|
577
+| 8,5% | 79 | 32 |
578
+| 2,1% | 80 | 35 |
579
+| 0% | 61-70 | 50 |
652 580
653 581
```python
654
-# Vérifier les modules installés
655
-modules = odoo_call("ir.module.module", "search_read",
656
- [[["name", "in",
657
- ["l10n_fr", "l10n_fr_account",
658
- "l10n_fr_pos_cert", "l10n_fr_reports"]]]],
659
- {"fields": ["name", "state"]})
660
-
661
-# Installer
662
-for m in modules:
663
- if m["state"] != "installed":
664
- odoo_call("ir.module.module",
665
- "button_immediate_install", [[m["id"]]])
582
+grp = odoo_call("account.tax.group", "create", [{"name": "TVA 8.5%"}]) # sans country_id !
583
+odoo_call("account.tax", "create", [{"name": "8.5% S", "amount": 8.5, "type_tax_use": "sale", ...}])
666 584
```
667 585
668
-⚠️ Le plan comptable (`l10n_fr_account`) doit être installé manuellement via l'interface web (Paramètres → Comptabilité → Localisation fiscale). L'API ne peut pas déclencher l'installation du plan comptable sur SaaS.
669
-
670 586
---
671 587
672
-## 7. Pièges et erreurs courantes
588
+## 7. Pièges
673 589
674 590
| N° | Erreur | Solution |
675 591
|----|--------|---------|
676
-| 1 | `AccessDenied` | Utiliser `common.login` (pas `/web/session/authenticate`) |
677
-| 2 | `create` retourne `None` | Il manque un champ obligatoire → `fields_get` |
678
-| 3 | `create` prend une liste | Non → UN dict. Passer `[{...}]` pas `[[{...}]]` |
679
-| 4 | `detailed_type` introuvable | Ne pas utiliser → `type` uniquement |
680
-| 5 | Taxe "country_id mismatch" | Créer les groupes de taxe sans `country_id` |
681
-| 6 | Taxes écrasées après `l10n_fr_account` | Ré-appliquer après installation |
682
-| 7 | `auto_confirm` envoie des emails | Désactiver avant import massif |
683
-| 8 | `unlink` échoue | Utiliser `write` → `{"active": False}` |
684
-| 9 | `search_read` limit=80 par défaut | Utiliser `limit=0` pour tout récupérer |
685
-| 10 | `barcode` champ inexistant | Vérifier le modèle — `event.registration` l'a, `sale.order` non |
686
-| 11 | BilletWeb 403 Forbidden | Ajouter `User-Agent: Mozilla/5.0` |
687
-| 12 | API key scope événement | La clé doit être créée avec "Tous les événements" |
592
+| 1 | `AccessDenied` | `common.login` pas `/web/session/authenticate` |
593
+| 2 | `create` retourne None | champs obligatoires manquants → `fields_get` |
594
+| 3 | `create` prend UN dict | `[{...}]` pas `[[{...}]]` |
595
+| 4 | `detailed_type` | Ne pas utiliser → `type` |
596
+| 5 | Taxe country_id mismatch | Groupe sans `country_id` |
597
+| 6 | auto_confirm envoie emails | Désactiver avant import |
598
+| 7 | `unlink` échoue | `{"active": False}` |
599
+| 8 | `search_read` limit=80 | `limit=0` pour tout |
600
+| 9 | BilletWeb 403 | `User-Agent: Mozilla/5.0` |
601
+| 10 | `sale.order` 7 champs requis | name, partner_id ×3, company_id, date_order, picking_policy |
688 602
689 603
---
690 604
691
-## 8. Limites Odoo Online (SaaS)
605
+## 8. Limites SaaS
692 606
693
-| ✅ Possible | ❌ Impossible |
694
-|------------|--------------|
695
-| API JSON-RPC complète | SSH / accès serveur |
607
+| ✅ | ❌ |
608
+|----|-----|
609
+| API JSON-RPC | SSH |
696 610
| CRUD tous modèles standards | Modules Python customs |
697
-| Modules Studio (UI) | Accès direct PostgreSQL |
698
-| Imports CSV/XML | Modification du core Odoo |
699
-| Webhooks sortants | Installation packages Python |
700
-| Extensions Chrome (DOM) | Scripts serveur personnalisés |
611
+| Modules Studio | Accès PostgreSQL |
612
+| Webhooks sortants | Core mods |
613
+| Extensions Chrome | Packages Python |
701 614
702 615
---
703 616
704
-## 9. Exemples pratiques
705
-
706
-### 9.1 Créer un client
707
-
708
-```python
709
-partner_id = odoo_call("res.partner", "create", [{
710
- "name": "Jean Dupont",
711
- "email": "jean@email.com",
712
- "phone": "+262692123456",
713
- "customer_rank": 1,
714
-}])
715
-```
716
-
717
-### 9.2 Créer une commande complète
617
+## 9. Exemples
718 618
619
+### Créer un client
719 620
```python
720
-# Étape 1 : créer la commande
721
-so_id = odoo_call("sale.order", "create", [{
722
- "name": "CMD-2026-001",
723
- "partner_id": partner_id,
724
- "partner_invoice_id": partner_id,
725
- "partner_shipping_id": partner_id,
726
- "company_id": 1,
727
- "date_order": "2026-05-29 10:00:00",
728
- "picking_policy": "direct",
729
- "client_order_ref": "BW-ORDER-456",
730
- "team_id": 4, # BilletWeb
731
-}])
732
-
733
-# Étape 2 : ajouter une ligne
734
-line_id = odoo_call("sale.order.line", "create", [{
735
- "order_id": so_id,
736
- "product_id": 13,
737
- "product_uom_qty": 2,
738
- "price_unit": 11.00,
739
- "name": "Luge - Forfait 4 tours",
740
-}])
741
-
742
-# Étape 3 : confirmer en commande
743
-odoo_call("sale.order", "write", [[so_id], {"state": "sale"}])
621
+pid = odoo_call("res.partner", "create", [{"name": "Jean", "email": "j@mail.com", "customer_rank": 1}])
744 622
```
745 623
746
-### 9.3 Créer une inscription événement
747
-
748
-```python
749
-reg_id = odoo_call("event.registration", "create", [{
750
- "event_id": 1,
751
- "name": "Jean Dupont",
752
- "email": "jean@email.com",
753
- "barcode": "1234567890",
754
- "state": "open",
755
- "event_ticket_id": 8,
756
- "sale_order_id": so_id,
757
-}])
758
-```
759
-
760
-### 9.4 Lier inscription → ligne de commande
761
-
762
-```python
763
-odoo_call("sale.order.line", "write",
764
- [[line_id], {"registration_ids": [(6, 0, [reg_id])]}])
765
-```
766
-
767
-### 9.5 Rechercher avec pagination
768
-
624
+### Créer une commande + ligne + inscription
769 625
```python
770
-all_records = []
771
-offset = 0
772
-while True:
773
- batch = odoo_call("event.registration", "search_read",
774
- [[["event_id", "=", 1]]],
775
- {"fields": ["id", "name", "barcode", "state"],
776
- "offset": offset, "limit": 100})
777
- if not batch:
778
- break
779
- all_records.extend(batch)
780
- offset += 100
626
+so = odoo_call("sale.order", "create", [{"name": "CMD-001", "partner_id": pid, "partner_invoice_id": pid, "partner_shipping_id": pid, "company_id": 1, "date_order": "2026-05-29 10:00:00", "picking_policy": "direct"}])
627
+line = odoo_call("sale.order.line", "create", [{"order_id": so, "product_id": 13, "product_uom_qty": 1, "price_unit": 11.00}])
628
+reg = odoo_call("event.registration", "create", [{"event_id": 1, "name": "Jean", "email": "j@mail.com", "barcode": "1234567890", "state": "open"}])
629
+odoo_call("sale.order.line", "write", [[line], {"registration_ids": [(6, 0, [reg])]}])
781 630
```