rodoo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4659d7f4bf1d0156dc09a4b417310c208ecf83c901b80dbdf99ac84ef80ae703
4
+ data.tar.gz: b9c048a9136da50585032eed8a1e267bdb6174f5623252b603ba1c188e2f8004
5
+ SHA512:
6
+ metadata.gz: de08af6d3ce14f9848b10598eb788b488e2b9dc5e6021a334cea754b4b50e6a5f00ea6370bc5e35ddb926f663e9b8f9ac57825acca78032d0b737e2854f80231
7
+ data.tar.gz: 4dfb5a9c3cfe0e281abed50567aeb3cac61a7e605f09ec29a0bbd6471d2b16c5da801521d1d6c1833de44f81c05c7195adddd9923d174a6b28ef7efa14c61b68
data/.env.example ADDED
@@ -0,0 +1,2 @@
1
+ ODOO_URL=https://myodoo.example.com
2
+ ODOO_API_KEY=your-api-key-here
data/.rubocop.yml ADDED
@@ -0,0 +1,32 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 3.1
4
+ SuggestExtensions: false
5
+
6
+ Layout/LineLength:
7
+ Max: 105
8
+
9
+ Metrics/MethodLength:
10
+ Max: 15
11
+ Exclude:
12
+ - "test/**/*"
13
+
14
+ Metrics/ClassLength:
15
+ Max: 105
16
+ Exclude:
17
+ - "test/**/*"
18
+
19
+ Style/Documentation:
20
+ Enabled: false
21
+
22
+ Style/StringLiterals:
23
+ EnforcedStyle: double_quotes
24
+
25
+ Style/StringLiteralsInInterpolation:
26
+ EnforcedStyle: double_quotes
27
+
28
+ # validate! is a bang method that raises exceptions, not a predicate method.
29
+ # Rubocop incorrectly flags it because it starts with "valid".
30
+ Naming/PredicateMethod:
31
+ AllowedMethods:
32
+ - validate!
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-12-24
4
+
5
+ - Initial release
data/CLAUDE.md ADDED
@@ -0,0 +1,25 @@
1
+ # CLAUDE.md
2
+
3
+ Rodoo is a Ruby gem wrapping Odoo's JSON-RPC 2.0 API (Odoo v19+) with an Active Record-style interface.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ rake test # Run tests
9
+ rake rubocop # Run linter
10
+ rake # Run both
11
+ bin/console # Interactive REPL
12
+ ```
13
+
14
+ ## Architecture
15
+
16
+ - `lib/rodoo.rb` - Module entry point, global configuration via `Rodoo.configure`, singleton connection via `Rodoo.connection`
17
+ - `lib/rodoo/configuration.rb` - Settings: url, api_key, timeout, open_timeout, logger, log_level (reads ODOO_URL/ODOO_API_KEY from env)
18
+ - `lib/rodoo/connection.rb` - HTTP transport, posts to `/json/2/{model}/{method}`, maps Odoo errors to Ruby exceptions
19
+ - `lib/rodoo/model.rb` - Base class with query methods (find, where, all, find_by, create) and persistence (save, update, reload)
20
+ - `lib/rodoo/errors.rb` - Exception hierarchy: Error → ConfigurationError, ConnectionError (→ TimeoutError), APIError (→ AuthenticationError, NotFoundError, ValidationError, AccessDeniedError)
21
+ - `lib/rodoo/models/` - Concrete models: Contact, Project, AnalyticAccount, AnalyticPlan, and accounting entries (CustomerInvoice, ProviderInvoice, CustomerCreditNote, ProviderCreditNote, JournalEntry via AccountingEntry base)
22
+
23
+ ## Testing
24
+
25
+ Minitest with mocked connections. Test files in `test/` mirror lib structure.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Rodrigo Serrano
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Odoo_API.md ADDED
@@ -0,0 +1,424 @@
1
+ # API
2
+
3
+ ## *Odoo*
4
+
5
+ Esta documentación detalla la interacción con el API de Odoo utilizando el estándar JSON-2 introducido en la versión 19, que es el estándar actual y la versión de Odoo que Dékuple utiliza.
6
+
7
+ El documento debería ser suficiente para trabajar con el API de Odoo. De todos modos, si se necesita más documentación, la documentación oficial se encuentra en:
8
+
9
+ * [https://www.odoo.com/documentation/19.0/developer/reference/external\_api.html](https://www.odoo.com/documentation/19.0/developer/reference/external_api.html) \- el sitio web público de documentación de Odoo
10
+ * [https://odoo.dekuple.es/doc](https://odoo.dekuple.es/doc) \- La documentación de todas las tablas y atributos de nuestra propia instancia.
11
+
12
+ # 1\. Servidores y Entornos
13
+
14
+ Disponemos de dos entornos activos. Es fundamental diferenciar el uso de cada uno:
15
+
16
+ | Entorno | BASE\_URL | Notas |
17
+ | :---- | :---- | :---- |
18
+ | Producción | https://odoo.dekuple.es | Datos reales. No usar para pruebas de escritura. |
19
+ | Staging | https://dekuple-odoo-staging-26757321.dev.odoo.com | La URL de Staging cambia cada vez que el entorno se reconstruye (el ID numérico varía) |
20
+
21
+ **Importante**: Los datos de Staging son una copia de Producción. Cualquier cambio realizado en Staging no afectará a los datos reales, pero permite hacer pruebas con datos reales.
22
+
23
+ # 2\. Autenticación
24
+
25
+ Odoo 19 utiliza autenticación mediante **API Keys**.
26
+
27
+ Sólo tenemos configurada una única API Key, que es la misma para ambos entornos (ya que Staging es una copia de los datos de Producción). La API Key que tenemos es la correspondiente al usuario Rodrigo Serrano, y está almacenada en Bitwarden.
28
+
29
+ Creo que un mismo usuario de Odoo (actualmente sólo tenemos tres usuarios en Odoo: Carlos, Gema y Rodrigo) podría tener varias API Key distintas configuradas.
30
+
31
+ El API Key debe incluirse en cada request, en la cabecera, como un Bearer token.
32
+
33
+ # 3\. Anatomía y ejemplo de una request
34
+
35
+ A diferencia de las APIs REST tradicionales donde el método HTTP (GET, POST, DELETE) define la acción, en Odoo **todas las peticiones son POST** y la acción se define en la URL.
36
+
37
+ ## **Estructura de la URL**
38
+
39
+ {BASE\_URL}/json/2/{modelo}/{método}
40
+
41
+ Más abajo se detallan los modelos y métodos que usaremos comunmente.
42
+
43
+ ## **Cabeceras Obligatorias**
44
+
45
+ \`Content-Type: application/json\`
46
+
47
+ \`Authorization: Bearer \<API\_KEY\>\`
48
+
49
+ ## **Ejemplo**
50
+
51
+ Usa este comando para verificar que tu conexión y API Key funcionan (este ejemplo hace una búsqueda en la tabla “res.users”, que es la tabla de usuarios de la instancia de Odoo):
52
+
53
+ ```shell
54
+ curl -X POST https://<BASE_URL>/json/2/res.users/search_read \
55
+ -H "Content-Type: application/json" \
56
+ -H "Authorization: Bearer <TU_API_KEY_DESDE_BITWARDEN>" \
57
+ -d '{
58
+ "domain": [],
59
+ "fields": ["name", "login"],
60
+ "limit": 1
61
+ }'
62
+ ```
63
+
64
+ # 4\. Métodos Principales (CRUD)
65
+
66
+ El API de Odoo es básicamente un interfaz CRUD a las tablas de la base de datos de Odoo. Las tablas más más típicas son \`res.partner\` (clientes/contactos), \`product.product\` (productos) y \`account.move\` (facturas).
67
+
68
+ ## **Leer registros (`search_read`)**
69
+
70
+ Se utiliza para buscar, en una tabla, un registro por un campo concreto (conceptualmente similar a `find_by` en Rails), y obtener los datos de los registros encontrados. El “payload” se construye como sigue:
71
+
72
+ \`\`\`json
73
+
74
+ // POST /json/2/res.partner/search\_read
75
+
76
+ {
77
+
78
+ "domain": \[\["is\_company", "=", true\]\], // Filtro (opcional)
79
+
80
+ "fields": \["name", "email", "phone"\], // Campos a devolver (opcional)
81
+
82
+ "limit": 5 // Paginación (opcional)
83
+
84
+ }
85
+
86
+ \`\`\`
87
+
88
+ ## **Crear registros (\`create\`)**
89
+
90
+ El método \`create\` siempre recibe una lista de diccionarios bajo la clave \`vals\_list\`.
91
+
92
+ \`\`\`json
93
+
94
+ // POST /json/2/res.partner/create
95
+
96
+ {
97
+
98
+ "vals\_list": \[
99
+
100
+ {
101
+
102
+ "name": "Nuevo Cliente SL",
103
+
104
+ "email": "contacto@cliente.es"
105
+
106
+ }
107
+
108
+ \]
109
+
110
+ }
111
+
112
+ \`\`\`
113
+
114
+ ## **C. Actualizar registros (\`write\`)**
115
+
116
+ Requiere una lista de IDs y un diccionario con los campos a cambiar.
117
+
118
+ \`\`\`json
119
+
120
+ // POST /json/2/res.partner/write
121
+
122
+ {
123
+
124
+ "ids": \[9\],
125
+
126
+ "vals": {
127
+
128
+ "phone": "+34 900 000 000"
129
+
130
+ }
131
+
132
+ }
133
+
134
+ \`\`\`
135
+
136
+ # 5\. Números "Mágicos" (Relaciones One2Many / Many2Many)
137
+
138
+ Para campos relacionales (como las líneas de una factura), Odoo utiliza una sintaxis especial basada en listas de comandos. Estos son los más comunes:
139
+
140
+ \* \*\*\`\[0, 0, {valores}\]\`\*\*: Crea un nuevo registro relacionado desde cero.
141
+
142
+ \* \*\*\`\[4, ID, 0\]\`\*\*: Enlaza un registro que ya existe mediante su ID.
143
+
144
+ \* \*\*\`\[6, 0, \[IDs\]\]\`\*\*: Reemplaza todos los enlaces actuales por esta lista de IDs.
145
+
146
+ \*\*Ejemplo de creación de factura con líneas:\*\*
147
+
148
+ \`\`\`json
149
+
150
+ {
151
+
152
+ "vals\_list": \[{
153
+
154
+ "move\_type": "out\_invoice",
155
+
156
+ "partner\_id": 9,
157
+
158
+ "invoice\_line\_ids": \[
159
+
160
+ \[0, 0, { "product\_id": 2, "quantity": 1, "price\_unit": 100.0 }\]
161
+
162
+ \]
163
+
164
+ }\]
165
+
166
+ }
167
+
168
+ \`\`\`
169
+
170
+ # 6\. Tablas y acciones
171
+
172
+ ## **Planes analíticos**
173
+
174
+ En Odoo tenemos dados de alta los planes analíticos siguientes:
175
+
176
+ * ID 1: Proyectos
177
+ * ID 2: Centros de coste
178
+
179
+ ## **Cuentas analíticas (`account.analytic.account`)**
180
+
181
+ ### **Atributos principales**
182
+
183
+ La lista completa de todos los atributos disponibles en las cuentas analíticas puede obtenerse ejecutando `curl -s -X POST https://dekuple-odoo-staging-26757321.dev.odoo.com/json/2/account.analytic.account/read -H "Content-Type: application/json" -H "Authorization: Bearer xxxxxxxxxx" -d '{ "ids": 92 }' | jq`, o leyendo la documentación en [https://dekuple-odoo-staging-26757321.dev.odoo.com/doc/account.analytic.account](https://dekuple-odoo-staging-26757321.dev.odoo.com/doc/account.analytic.account) . En esta sección se resumen los atributos principales, que son con los que se trabajará.
184
+
185
+ | Atributo | Nombre en interfaz web | Tipo | Descripción |
186
+ | :---- | :---- | :---- | :---- |
187
+ | active | Activo | boolean | ¿Quizá se pone a “false” cuando se archiva la cuenta analítica? Ej: true |
188
+ | code | Referencia (Reference) | char | El código o identificador interno de la cuenta analítica. Ej: “MAADLDIS” |
189
+ | display\_name | Nombre para mostrar | char | En el formulario de creación en el interfaz web no aparece, tiene pinta de que se construye automáticamente a partir de los campos code y name. Ej: “\[MAADLDIS\] Mags & Col Discount ADL” |
190
+ | id | ID | integer | Identificador único Ej: 92 |
191
+ | name | Cuenta analítica (Analytic Account) | char NOT NULL | Al crear una nueva cuenta analítica en el interfaz web, este es el nombre de la cuenta, el campo que tiene el “font” más grande. Ej: “Mags & Col Discount ADL” |
192
+ | plan\_id | Plan | FK hacia account.analytic.plan, NOT NULL | El plan analítico al que pertenece esta cuenta analítica, es obligatorio rellenarlo al crear la cuenta. Ej.: \[2, “Centro costes”\] |
193
+
194
+ ### **Ver los detalles de una cuenta analítica, por referencia**
195
+
196
+ (Si se buscase por ID, y no por referencia, se utilizaría el método read, no el método search\_read)
197
+
198
+ curl \-s \-X POST https://dekuple-odoo-staging-26757321.dev.odoo.com/json/2/account.analytic.account/search\_read \-H "Content-Type: application/json" \-H "Authorization: Bearer xxxxxxxxxx" \-d '{ "domain": \[\["code", "=", "MAADLDIS"\]\] }' | jq
199
+
200
+ La respuesta es un array, y cada elemento del array es un hash con los atributos.
201
+
202
+ ## **Proyectos (`project.project`)**
203
+
204
+ ### **Buscar un proyecto y leer sus atributos**
205
+
206
+ Para "destripar" un proyecto y ver exactamente qué valores tiene en esos campos, usaremos el método \`read\`. Es la mejor forma de obtener una plantilla real.
207
+
208
+ \*\*Sustituye \`ID\_DEL\_PROYECTO\` por el ID de un proyecto que ya sepas que está bien configurado:\*\*
209
+
210
+ ```shell
211
+ curl -s -X POST https://dekuple-odoo-staging-26757321.dev.odoo.com/json/2/project.project/read \
212
+ -H "Content-Type: application/json" \
213
+ -H "Authorization: Bearer TU_API_KEY" \
214
+ -d '{
215
+ "ids": [ID_DEL_PROYECTO]
216
+ }'
217
+ ```
218
+
219
+ \*(Si quieres ver \*\*todos\*\* los campos disponibles, simplemente elimina la línea de \`"fields": \[...\]\` del JSON).\*
220
+
221
+ \---
222
+
223
+ \#\#\# 3\. Cómo interpretar la respuesta
224
+
225
+ Cuando ejecutes el comando anterior, recibirás algo parecido a esto:
226
+
227
+ \`\`\`json
228
+
229
+ \[
230
+
231
+ {
232
+
233
+ "id": 123,
234
+
235
+ "display\_name": "Proyecto Marketing 2025",
236
+
237
+ "account\_id": \[45, "C.A. Proyecto Marketing"\],
238
+
239
+ "auto\_account\_id": \[45, "C.A. Proyecto Marketing"\],
240
+
241
+ "x\_plan2\_id": \[12, "CECO \- Madrid"\]
242
+
243
+ }
244
+
245
+ \]
246
+
247
+ \`\`\`
248
+
249
+ \*\*Lo que esto te dice:\*\*
250
+
251
+ 1\. \*\*Formato Many2one\*\*: Odoo te devuelve una lista: \`\[ID, "Nombre"\]\`. Para tus peticiones de \*\*escritura/creación\*\*, solo te importa el \*\*número (ID)\*\*.
252
+
253
+ 2\. \*\*Relación\*\*: Si ves que \`account\_id\` y \`auto\_account\_id\` tienen el mismo ID, ya sabes que debes rellenar ambos con el mismo valor al crear uno nuevo.
254
+
255
+ 3\. \*\*Centro de Costes\*\*: El ID que aparezca en \`x\_plan2\_id\` es el que deberás usar para asignar el centro de costes en tus automatizaciones.
256
+
257
+ \---
258
+
259
+ \#\#\# 4\. Ejemplo actualizado para Crear un Proyecto
260
+
261
+ Basándome en tu imagen, el comando de creación ahora sería así de preciso:
262
+
263
+ \`\`\`bash
264
+
265
+ curl \-s \-X POST https://odoo.dekuple.es/json/2/project.project/create \\
266
+
267
+ \-H "Content-Type: application/json" \\
268
+
269
+ \-H "Authorization: Bearer TU\_API\_KEY" \\
270
+
271
+ \-d '{
272
+
273
+ "vals\_list": \[
274
+
275
+ {
276
+
277
+ "name": "Proyecto API Test",
278
+
279
+ "account\_id": 45,
280
+
281
+ "auto\_account\_id": 45,
282
+
283
+ "x\_plan2\_id": 12
284
+
285
+ }
286
+
287
+ \]
288
+
289
+ }'
290
+
291
+ \`\`\`
292
+
293
+ \*\*Sugerencia:\*\* Ejecuta primero el \`read\` sobre un proyecto existente que te guste cómo está configurado. Si me pegas aquí el JSON de respuesta que te devuelva Odoo (borrando datos sensibles si quieres), puedo darte el comando \`create\` exacto para replicarlo.
294
+
295
+ ### **Crear un nuevo proyecto**
296
+
297
+ Al crear un nuevo proyecto, es necesario asociarlo con la cuenta analítica correspondiente a ese proyecto: el proyecto tiene un campo llamado `analytic_account_id` que apunta al registro de la cuenta analítica.
298
+
299
+ Aquí tienes los dos escenarios posibles:
300
+
301
+ \#\#\# Escenario A: El Proyecto se vincula a una Cuenta Analítica ya existente
302
+
303
+ Este es el método más limpio. Primero obtienes el ID de la cuenta analítica (usando \`search\_read\` como vimos antes) y luego creas el proyecto.
304
+
305
+ \*\*Comando cURL:\*\*
306
+
307
+ \`\`\`bash
308
+
309
+ curl \-s \-X POST https://odoo.dekuple.es/json/2/project.project/create \\
310
+
311
+ \-H "Content-Type: application/json" \\
312
+
313
+ \-H "X-Odoo-Database: 18.BASE" \\
314
+
315
+ \-H "Authorization: Bearer TU\_API\_KEY" \\
316
+
317
+ \-d '{
318
+
319
+ "vals\_list": \[
320
+
321
+ {
322
+
323
+ "name": "Nombre del Nuevo Proyecto",
324
+
325
+ "partner\_id": ID\_CLIENTE,
326
+
327
+ "analytic\_account\_id": ID\_CUENTA\_ANALITICA
328
+
329
+ }
330
+
331
+ \]
332
+
333
+ }'
334
+
335
+ \`\`\`
336
+
337
+ \---
338
+
339
+ \#\#\# Escenario B: Crear la Cuenta Analítica "al vuelo"
340
+
341
+ Si quieres que Odoo cree la cuenta analítica al mismo tiempo que el proyecto (usando la potencia del ORM), puedes usar la sintaxis de creación de registros relacionados. Sin embargo, dado que \`analytic\_account\_id\` es un campo \*\*Many2one\*\*, la API JSON-2 prefiere recibir un ID.
342
+
343
+ Si necesitas crear ambos de golpe, la mejor práctica es:
344
+
345
+ 1\. Crear la Cuenta Analítica en \`account.analytic.account\`.
346
+
347
+ 2\. Usar el ID devuelto para crear el Proyecto.
348
+
349
+ \*\*Paso 1: Crear Cuenta Analítica\*\*
350
+
351
+ \`\`\`bash
352
+
353
+ \# POST /json/2/account.analytic.account/create
354
+
355
+ {
356
+
357
+ "vals\_list": \[{
358
+
359
+ "name": "Cuenta Analítica: Proyecto X",
360
+
361
+ "plan\_id": ID\_DEL\_PLAN\_PROYECTOS // El plan analítico que mencionaste
362
+
363
+ }\]
364
+
365
+ }
366
+
367
+ \`\`\`
368
+
369
+ \*\*Paso 2: Crear Proyecto\*\* (usando el ID del paso anterior).
370
+
371
+ \---
372
+
373
+ \#\#\# Detalles Técnicos que debes conocer
374
+
375
+ 1\. \*\*El Plan Analítico\*\*: Mencionaste que los proyectos están "replicados" en un plan. En Odoo 19, las cuentas analíticas deben pertenecer a un \*\*Plan\*\* (\`account.analytic.plan\`). Asegúrate de incluir el \`plan\_id\` correcto al crear la cuenta analítica para que aparezca en la sección adecuada de tus informes.
376
+
377
+ 2\. \*\*Configuración Automática\*\*: En muchas instalaciones de Odoo, al crear un proyecto desde la interfaz, Odoo crea automáticamente la cuenta analítica. Sin embargo, \*\*por API este automatismo no siempre se dispara\*\* de la misma forma que en el cliente web. Ser explícito enviando el \`analytic\_account\_id\` es la única forma de asegurar la asociación al 100%.
378
+
379
+ 3\. \*\*Campos adicionales\*\*: Puedes añadir otros campos útiles al crear el proyecto, como:
380
+
381
+ \* \`allow\_billable\`: \`true\` (si vas a facturar horas).
382
+
383
+ \* \`label\_tasks\`: "Tareas" o "Hitos" (nombre de las tareas en este proyecto).
384
+
385
+ \#\#\# Resumen para tu documentación:
386
+
387
+ \* \*\*Modelo del Proyecto\*\*: \`project.project\`
388
+
389
+ \* \*\*Modelo Analítico\*\*: \`account.analytic.account\`
390
+
391
+ \* \*\*Campo de unión\*\*: \`analytic\_account\_id\` (en el modelo de proyecto).
392
+
393
+ ¿Te gustaría que te ayude a construir una consulta para listar todos los Planes Analíticos disponibles y así saber qué \`plan\_id\` usar para tus proyectos?
394
+
395
+ ## **Asientos contables y facturas (`account.move`)**
396
+
397
+ ### **Introducción**
398
+
399
+ Odoo, internamente, no diferencia entre un asiento contable manual, una factura de cliente, o una factura de proveedor: todos ellos son registros en la tabla `account.move`. El tipo de asiento se diferencia gracias al atributo `move_type`, un atributo de tipo enum que puede tomar cualquiera de los siguientes valores:
400
+
401
+ * `entry` \- Asiento contable
402
+ * `in_invoice` \- Factura de proveedor
403
+ * `in_receipt` \- Recibo de compra
404
+ * `in_refund` \- Factura rectificativa de proveedor
405
+ * `out_invoice` \- Factura de cliente
406
+ * `out_receipt` \- Recibo de ventas
407
+ * `out_refund` \- Factura rectificativa de cliente
408
+
409
+ Los tipos `in_receipt` y `out_receipt` nosotros no los usaremos, están pensados para transacciones en cash (ventas de una cafetería, y compras pequeñas en efectivo con la caja de la empresa).
410
+
411
+ ### **Atributos principales**
412
+
413
+ | Atributo | Nombre en interfaz web | Tipo | Descripción |
414
+ | :---- | :---- | :---- | :---- |
415
+ | auto\_post | Contabilizar automáticamente | selection, NOT NULL | Creo que sirve para indicar si el asiento debe contabilizarse automáticamente, en vez de dejarse como borrador, indicando en qué momento se contabilizará. Debe tomar uno de los valores siguientes: at\_date \- En fecha monthly \- Mensualmente no \- No quarterly \- Trimestralmente yearly \- Anualmente |
416
+ | currency\_id | Moneda | FK hacia res.currency, NOT NULL | Moneda del asiento |
417
+ | date | Fecha | date | Fecha del asiento o de la factura |
418
+ | journal\_id | Diario | FK hacia account.journal, NOT NULL | Diario en el que se almacenará el asiento |
419
+ | move\_type | Tipo | selection, NOT NULL | Ver Introducción. |
420
+ | state | Estado | selection, NOT NULL | Puede tomar los siguientes valores: cancel- Cancelado draft- Borrador posted- Publicado |
421
+
422
+ ### **Crear y contabilizar una factura de proveedor**
423
+
424
+ Hay que realizar dos pasos. La API de Odoo está diseñada para que el método `create` se encargue únicamente de la creación del registro (en estado "Borrador") y el método `action_post` se encargue de validarlo (contabilizarlo).