@openfn/language-odoo 2.0.0 → 2.1.1

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.
package/ast.json CHANGED
@@ -278,6 +278,207 @@
278
278
  ]
279
279
  },
280
280
  "valid": true
281
+ },
282
+ {
283
+ "name": "searchRecord",
284
+ "params": [
285
+ "model",
286
+ "domain"
287
+ ],
288
+ "docs": {
289
+ "description": "Search a record from Odoo. Only returns record IDs. Use `searchReadRecord` to download full\nrecords which match the criteria.",
290
+ "tags": [
291
+ {
292
+ "title": "public",
293
+ "description": null,
294
+ "type": null
295
+ },
296
+ {
297
+ "title": "example",
298
+ "description": "searchRecord('res.partner', {\n country_id: 'United States',\n});"
299
+ },
300
+ {
301
+ "title": "function",
302
+ "description": null,
303
+ "name": null
304
+ },
305
+ {
306
+ "title": "param",
307
+ "description": "The specific record model i.e. \"res.partner\"",
308
+ "type": {
309
+ "type": "NameExpression",
310
+ "name": "string"
311
+ },
312
+ "name": "model"
313
+ },
314
+ {
315
+ "title": "param",
316
+ "description": "Optional search domain to filter records.",
317
+ "type": {
318
+ "type": "NameExpression",
319
+ "name": "object"
320
+ },
321
+ "name": "domain"
322
+ },
323
+ {
324
+ "title": "state",
325
+ "description": "{OdooState}"
326
+ },
327
+ {
328
+ "title": "state",
329
+ "description": "data - An array of matching record IDs"
330
+ },
331
+ {
332
+ "title": "returns",
333
+ "description": null,
334
+ "type": {
335
+ "type": "NameExpression",
336
+ "name": "Operation"
337
+ }
338
+ }
339
+ ]
340
+ },
341
+ "valid": true
342
+ },
343
+ {
344
+ "name": "searchReadRecord",
345
+ "params": [
346
+ "model",
347
+ "domain",
348
+ "fields",
349
+ "options"
350
+ ],
351
+ "docs": {
352
+ "description": "Search and a read record from Odoo. It returns the records that match the search criteria, with the specified fields or full records if no fields are given.",
353
+ "tags": [
354
+ {
355
+ "title": "public",
356
+ "description": null,
357
+ "type": null
358
+ },
359
+ {
360
+ "title": "example",
361
+ "description": "searchReadRecord('res.partner', {\n country_id: 'United States',\n});",
362
+ "caption": "Search and read a record with a domain filter"
363
+ },
364
+ {
365
+ "title": "example",
366
+ "description": "searchReadRecord(\n 'res.partner',\n {\n is_company: true,\n },\n ['name']\n);",
367
+ "caption": "Search and read a record with specific fields"
368
+ },
369
+ {
370
+ "title": "example",
371
+ "description": "searchReadRecord('res.partner', {}, [], {\n limit: 200,\n});",
372
+ "caption": "Fetch records with a limit"
373
+ },
374
+ {
375
+ "title": "function",
376
+ "description": null,
377
+ "name": null
378
+ },
379
+ {
380
+ "title": "param",
381
+ "description": "The specific record model i.e. \"res.partner\"",
382
+ "type": {
383
+ "type": "NameExpression",
384
+ "name": "string"
385
+ },
386
+ "name": "model"
387
+ },
388
+ {
389
+ "title": "param",
390
+ "description": "Optional search domain to filter records.",
391
+ "type": {
392
+ "type": "NameExpression",
393
+ "name": "object"
394
+ },
395
+ "name": "domain"
396
+ },
397
+ {
398
+ "title": "param",
399
+ "description": "An optional array of field strings to read from the record. i.e ['name', 'state_id']",
400
+ "type": {
401
+ "type": "TypeApplication",
402
+ "expression": {
403
+ "type": "NameExpression",
404
+ "name": "Array"
405
+ },
406
+ "applications": [
407
+ {
408
+ "type": "NameExpression",
409
+ "name": "string"
410
+ }
411
+ ]
412
+ },
413
+ "name": "fields"
414
+ },
415
+ {
416
+ "title": "param",
417
+ "description": "Additional options to configure the search.",
418
+ "type": {
419
+ "type": "OptionalType",
420
+ "expression": {
421
+ "type": "NameExpression",
422
+ "name": "object"
423
+ }
424
+ },
425
+ "name": "options",
426
+ "default": "{}"
427
+ },
428
+ {
429
+ "title": "param",
430
+ "description": "Maximum number of records to fetch. If undefined, defaults to 1000, and all records available will be fetched.",
431
+ "type": {
432
+ "type": "OptionalType",
433
+ "expression": {
434
+ "type": "NameExpression",
435
+ "name": "number"
436
+ }
437
+ },
438
+ "name": "options.limit",
439
+ "default": "1000"
440
+ },
441
+ {
442
+ "title": "param",
443
+ "description": "The index of the first record to return.",
444
+ "type": {
445
+ "type": "OptionalType",
446
+ "expression": {
447
+ "type": "NameExpression",
448
+ "name": "number"
449
+ }
450
+ },
451
+ "name": "options.offset",
452
+ "default": "0"
453
+ },
454
+ {
455
+ "title": "param",
456
+ "description": "The number of records to fetch in each request. Defaults to 200.",
457
+ "type": {
458
+ "type": "OptionalType",
459
+ "expression": {
460
+ "type": "NameExpression",
461
+ "name": "number"
462
+ }
463
+ },
464
+ "name": "options.pageSize",
465
+ "default": "200"
466
+ },
467
+ {
468
+ "title": "state",
469
+ "description": "{OdooState}"
470
+ },
471
+ {
472
+ "title": "returns",
473
+ "description": null,
474
+ "type": {
475
+ "type": "NameExpression",
476
+ "name": "Operation"
477
+ }
478
+ }
479
+ ]
480
+ },
481
+ "valid": false
281
482
  }
282
483
  ],
283
484
  "exports": [],
package/dist/index.cjs CHANGED
@@ -39,6 +39,8 @@ __export(src_exports, {
39
39
  lastReferenceValue: () => import_language_common2.lastReferenceValue,
40
40
  merge: () => import_language_common2.merge,
41
41
  read: () => read,
42
+ searchReadRecord: () => searchReadRecord,
43
+ searchRecord: () => searchRecord,
42
44
  setMockClient: () => setMockClient,
43
45
  sourceValue: () => import_language_common2.sourceValue,
44
46
  update: () => update
@@ -61,6 +63,8 @@ __export(Adaptor_exports, {
61
63
  lastReferenceValue: () => import_language_common2.lastReferenceValue,
62
64
  merge: () => import_language_common2.merge,
63
65
  read: () => read,
66
+ searchReadRecord: () => searchReadRecord,
67
+ searchRecord: () => searchRecord,
64
68
  setMockClient: () => setMockClient,
65
69
  sourceValue: () => import_language_common2.sourceValue,
66
70
  update: () => update
@@ -175,6 +179,58 @@ function deleteRecord(model, recordId) {
175
179
  return (0, import_language_common.composeNextState)(state, response);
176
180
  };
177
181
  }
182
+ function searchRecord(model, domain = {}) {
183
+ return async (state) => {
184
+ const [resolvedModel, resolvedDomain] = (0, import_util.expandReferences)(
185
+ state,
186
+ model,
187
+ domain
188
+ );
189
+ console.log(`Searching ${resolvedModel} resource...`);
190
+ const response = await odooConn.search(resolvedModel, resolvedDomain);
191
+ return (0, import_language_common.composeNextState)(state, response);
192
+ };
193
+ }
194
+ function searchReadRecord(model, domain = {}, fields2 = [], options = {}) {
195
+ return async (state) => {
196
+ const results = [];
197
+ const [resolvedModel, resolvedDomain, resolvedFields, resolvedOptions] = (0, import_util.expandReferences)(state, model, domain, fields2, options);
198
+ const { limit = 1e3, offset = 0, pageSize = 200 } = resolvedOptions;
199
+ let totalFetched = 0;
200
+ let nextOffset = offset;
201
+ if (limit <= 0 || pageSize <= 0) {
202
+ return (0, import_language_common.composeNextState)(state, {
203
+ rows: results,
204
+ nextOffset: null,
205
+ totalFetched
206
+ });
207
+ }
208
+ while (totalFetched < limit) {
209
+ const remainingItems = limit - totalFetched;
210
+ const fetchSize = Math.min(pageSize, remainingItems);
211
+ console.log(
212
+ `Searching and reading ${resolvedModel} resources. From offset ${nextOffset} with limit ${fetchSize}...`
213
+ );
214
+ const rows = await odooConn.searchRead(
215
+ resolvedModel,
216
+ resolvedDomain,
217
+ resolvedFields,
218
+ {
219
+ offset: nextOffset,
220
+ limit: fetchSize
221
+ }
222
+ );
223
+ results.push(...rows);
224
+ totalFetched += rows.length;
225
+ nextOffset += rows.length;
226
+ if (rows.length === 0 || rows.length < fetchSize || totalFetched >= limit) {
227
+ nextOffset = null;
228
+ break;
229
+ }
230
+ }
231
+ return (0, import_language_common.composeNextState)(state, { rows: results, nextOffset, totalFetched });
232
+ };
233
+ }
178
234
 
179
235
  // src/index.js
180
236
  var src_default = Adaptor_exports;
@@ -193,6 +249,8 @@ var src_default = Adaptor_exports;
193
249
  lastReferenceValue,
194
250
  merge,
195
251
  read,
252
+ searchReadRecord,
253
+ searchRecord,
196
254
  setMockClient,
197
255
  sourceValue,
198
256
  update
package/dist/index.js CHANGED
@@ -20,6 +20,8 @@ __export(Adaptor_exports, {
20
20
  lastReferenceValue: () => lastReferenceValue,
21
21
  merge: () => merge,
22
22
  read: () => read,
23
+ searchReadRecord: () => searchReadRecord,
24
+ searchRecord: () => searchRecord,
23
25
  setMockClient: () => setMockClient,
24
26
  sourceValue: () => sourceValue,
25
27
  update: () => update
@@ -148,6 +150,58 @@ function deleteRecord(model, recordId) {
148
150
  return composeNextState(state, response);
149
151
  };
150
152
  }
153
+ function searchRecord(model, domain = {}) {
154
+ return async (state) => {
155
+ const [resolvedModel, resolvedDomain] = expandReferences(
156
+ state,
157
+ model,
158
+ domain
159
+ );
160
+ console.log(`Searching ${resolvedModel} resource...`);
161
+ const response = await odooConn.search(resolvedModel, resolvedDomain);
162
+ return composeNextState(state, response);
163
+ };
164
+ }
165
+ function searchReadRecord(model, domain = {}, fields2 = [], options = {}) {
166
+ return async (state) => {
167
+ const results = [];
168
+ const [resolvedModel, resolvedDomain, resolvedFields, resolvedOptions] = expandReferences(state, model, domain, fields2, options);
169
+ const { limit = 1e3, offset = 0, pageSize = 200 } = resolvedOptions;
170
+ let totalFetched = 0;
171
+ let nextOffset = offset;
172
+ if (limit <= 0 || pageSize <= 0) {
173
+ return composeNextState(state, {
174
+ rows: results,
175
+ nextOffset: null,
176
+ totalFetched
177
+ });
178
+ }
179
+ while (totalFetched < limit) {
180
+ const remainingItems = limit - totalFetched;
181
+ const fetchSize = Math.min(pageSize, remainingItems);
182
+ console.log(
183
+ `Searching and reading ${resolvedModel} resources. From offset ${nextOffset} with limit ${fetchSize}...`
184
+ );
185
+ const rows = await odooConn.searchRead(
186
+ resolvedModel,
187
+ resolvedDomain,
188
+ resolvedFields,
189
+ {
190
+ offset: nextOffset,
191
+ limit: fetchSize
192
+ }
193
+ );
194
+ results.push(...rows);
195
+ totalFetched += rows.length;
196
+ nextOffset += rows.length;
197
+ if (rows.length === 0 || rows.length < fetchSize || totalFetched >= limit) {
198
+ nextOffset = null;
199
+ break;
200
+ }
201
+ }
202
+ return composeNextState(state, { rows: results, nextOffset, totalFetched });
203
+ };
204
+ }
151
205
 
152
206
  // src/index.js
153
207
  var src_default = Adaptor_exports;
@@ -166,6 +220,8 @@ export {
166
220
  lastReferenceValue,
167
221
  merge,
168
222
  read,
223
+ searchReadRecord,
224
+ searchRecord,
169
225
  setMockClient,
170
226
  sourceValue,
171
227
  update
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@openfn/language-odoo",
3
3
  "label": "Odoo",
4
- "version": "2.0.0",
5
- "description": "OpenFn adaptor for Odoo",
4
+ "version": "2.1.1",
5
+ "description": "OpenFn adaptor for Odoo (ERP)",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": {
@@ -12,6 +12,15 @@
12
12
  * @property {number} externalId - An optional id to be used in the request
13
13
  * @property {boolean} downloadNewRecord - An option defaulted to `false` incase a user intends to receive the whole created resource in the response. The collective response will be written in `state.data`.
14
14
  */
15
+ /**
16
+ * Options object
17
+ * @typedef {Object} SearchOptions
18
+ * @property {number} limit - Limit the number of records to return
19
+ * @property {number} offset - Set to the number of records to skip
20
+ * @property {string} order - Order to sort the records by. i.e "name, desc"
21
+ * @property {object} context - Context to be used in the request. i.e `{lang: 'en_US', timezone: 'UTC'}`.
22
+ *
23
+ */
15
24
  /**
16
25
  * Execute a sequence of operations.
17
26
  * Wraps `language-common/execute` to make working with this API easier.
@@ -83,6 +92,57 @@ export function update(model: string, recordId: number, data: object): Operation
83
92
  * @returns {Operation}
84
93
  */
85
94
  export function deleteRecord(model: string, recordId: number): Operation;
95
+ /**
96
+ * Search a record from Odoo. Only returns record IDs. Use `searchReadRecord` to download full
97
+ * records which match the criteria.
98
+ * @public
99
+ * @example
100
+ * searchRecord('res.partner', {
101
+ * country_id: 'United States',
102
+ * });
103
+ * @function
104
+ * @param {string} model - The specific record model i.e. "res.partner"
105
+ * @param {object} domain - Optional search domain to filter records.
106
+ * @state {OdooState}
107
+ * @state data - An array of matching record IDs
108
+ * @returns {Operation}
109
+ */
110
+ export function searchRecord(model: string, domain?: object): Operation;
111
+ /**
112
+ * Search and a read record from Odoo. It returns the records that match the search criteria, with the specified fields or full records if no fields are given.
113
+ * @public
114
+ * @example <caption>Search and read a record with a domain filter</caption>
115
+ * searchReadRecord('res.partner', {
116
+ * country_id: 'United States',
117
+ * });
118
+ * @example <caption>Search and read a record with specific fields</caption>
119
+ * searchReadRecord(
120
+ * 'res.partner',
121
+ * {
122
+ * is_company: true,
123
+ * },
124
+ * ['name']
125
+ * );
126
+ * @example <caption> Fetch records with a limit</caption>
127
+ * searchReadRecord('res.partner', {}, [], {
128
+ * limit: 200,
129
+ * });
130
+ * @function
131
+ * @param {string} model - The specific record model i.e. "res.partner"
132
+ * @param {object} domain - Optional search domain to filter records.
133
+ * @param {string[]} fields - An optional array of field strings to read from the record. i.e ['name', 'state_id']
134
+ * @param {object} [options = {}] - Additional options to configure the search.
135
+ * @param {number} [options.limit=1000] - Maximum number of records to fetch. If undefined, defaults to 1000, and all records available will be fetched.
136
+ * @param {number} [options.offset=0] - The index of the first record to return.
137
+ * @param {number} [options.pageSize=200] - The number of records to fetch in each request. Defaults to 200.
138
+ * @state {OdooState}
139
+ * @returns {Operation}
140
+ */
141
+ export function searchReadRecord(model: string, domain?: object, fields?: string[], options?: {
142
+ limit?: number;
143
+ offset?: number;
144
+ pageSize?: number;
145
+ }): Operation;
86
146
  /**
87
147
  * State object
88
148
  */
@@ -113,4 +173,25 @@ export type CreateOptions = {
113
173
  */
114
174
  downloadNewRecord: boolean;
115
175
  };
176
+ /**
177
+ * Options object
178
+ */
179
+ export type SearchOptions = {
180
+ /**
181
+ * - Limit the number of records to return
182
+ */
183
+ limit: number;
184
+ /**
185
+ * - Set to the number of records to skip
186
+ */
187
+ offset: number;
188
+ /**
189
+ * - Order to sort the records by. i.e "name, desc"
190
+ */
191
+ order: string;
192
+ /**
193
+ * - Context to be used in the request. i.e `{lang: 'en_US', timezone: 'UTC'}`.
194
+ */
195
+ context: object;
196
+ };
116
197
  export { dataPath, dataValue, dateFns, each, field, fields, fn, lastReferenceValue, merge, sourceValue } from "@openfn/language-common";