Skip to content

Commit db67e3d

Browse files
authored
New Components - odoo (#17246)
* new components * pnpm-lock.yaml * remove console.log
1 parent 4cc580e commit db67e3d

File tree

7 files changed

+279
-6
lines changed

7 files changed

+279
-6
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import odoo from "../../odoo.app.mjs";
2+
3+
export default {
4+
key: "odoo-create-record",
5+
name: "Create Record",
6+
description: "Create a new record in Odoo. [See the documentation](https://www.odoo.com/documentation/18.0/developer/reference/external_api.html#create-records)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
odoo: {
11+
...odoo,
12+
reloadProps: true,
13+
},
14+
},
15+
async additionalProps() {
16+
return await this.odoo.getFieldProps();
17+
},
18+
async run({ $ }) {
19+
const {
20+
odoo,
21+
...data
22+
} = this;
23+
const response = await odoo.createRecord([
24+
data,
25+
]);
26+
$.export("$summary", `Successfully created record with ID: ${response}`);
27+
return response;
28+
},
29+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import odoo from "../../odoo.app.mjs";
2+
import { parseObject } from "../../common/utils.mjs";
3+
4+
export default {
5+
key: "odoo-search-read-records",
6+
name: "Search and Read Records",
7+
description: "Search and read records from Odoo. [See the documentation](https://www.odoo.com/documentation/18.0/developer/reference/external_api.html#search-and-read)",
8+
version: "0.0.1",
9+
type: "action",
10+
props: {
11+
odoo,
12+
filter: {
13+
type: "string",
14+
label: "Search Filter",
15+
description: "The criterion to search by. E.g. `[[[\"is_company\", \"=\", true]]]`. [See the documentation](https://www.odoo.com/documentation/18.0/developer/reference/backend/orm.html#search-domains) for information about constructing a search domain",
16+
optional: true,
17+
},
18+
fields: {
19+
propDefinition: [
20+
odoo,
21+
"fields",
22+
],
23+
},
24+
},
25+
async run({ $ }) {
26+
const args = this.fields
27+
? {
28+
fields: this.fields,
29+
}
30+
: {};
31+
const response = await this.odoo.searchAndReadRecords(parseObject(this.filter), args);
32+
$.export("$summary", `Successfully retrieved ${response.length} record${response.length === 1
33+
? ""
34+
: "s"}`);
35+
return response;
36+
},
37+
};
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import odoo from "../../odoo.app.mjs";
2+
const DEFAULT_LIMIT = 20;
3+
4+
export default {
5+
key: "odoo-update-record",
6+
name: "Update Record",
7+
description: "Update an existing record in Odoo. [See the documentation](https://www.odoo.com/documentation/18.0/developer/reference/external_api.html#update-records)",
8+
version: "0.0.1",
9+
type: "action",
10+
props: {
11+
odoo: {
12+
...odoo,
13+
reloadProps: true,
14+
},
15+
},
16+
async additionalProps() {
17+
const fieldProps = await this.odoo.getFieldProps({
18+
update: true,
19+
});
20+
const recordId = {
21+
type: "integer",
22+
label: "Record ID",
23+
description: "The ID of the record to update",
24+
options: async ({ page }) => await this.getRecordIdOptions(page),
25+
};
26+
return {
27+
recordId,
28+
...fieldProps,
29+
};
30+
},
31+
methods: {
32+
async getRecordIdOptions(page) {
33+
const records = await this.odoo.searchAndReadRecords([], {
34+
limit: DEFAULT_LIMIT,
35+
offset: page * DEFAULT_LIMIT,
36+
});
37+
return records?.map(({
38+
id: value, display_name: label,
39+
}) => ({
40+
value,
41+
label,
42+
})) || [];
43+
},
44+
},
45+
async run({ $ }) {
46+
const {
47+
odoo,
48+
// eslint-disable-next-line no-unused-vars
49+
getRecordIdOptions,
50+
recordId,
51+
...data
52+
} = this;
53+
const response = await odoo.updateRecord([
54+
[
55+
recordId,
56+
],
57+
data,
58+
]);
59+
$.export("$summary", `Successfully updated record with ID: ${recordId}`);
60+
return response;
61+
},
62+
};

components/odoo/common/utils.mjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export const parseObject = (obj) => {
2+
if (!obj) {
3+
return undefined;
4+
}
5+
if (typeof obj === "string") {
6+
try {
7+
return JSON.parse(obj);
8+
} catch (e) {
9+
return obj;
10+
}
11+
}
12+
if (Array.isArray(obj)) {
13+
return obj.map(parseObject);
14+
}
15+
if (typeof obj === "object") {
16+
return Object.fromEntries(Object.entries(obj).map(([
17+
key,
18+
value,
19+
]) => [
20+
key,
21+
parseObject(value),
22+
]));
23+
}
24+
return obj;
25+
};

components/odoo/odoo.app.mjs

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,104 @@
1+
import xmlrpc from "xmlrpc";
2+
13
export default {
24
type: "app",
35
app: "odoo",
4-
propDefinitions: {},
6+
propDefinitions: {
7+
fields: {
8+
type: "string[]",
9+
label: "Fields",
10+
description: "The fields to return in the results. If not provided, all fields will be returned.",
11+
optional: true,
12+
async options() {
13+
const fields = await this.getFields([], {
14+
attributes: [
15+
"string",
16+
],
17+
});
18+
return Object.keys(fields)?.map((key) => ({
19+
value: key,
20+
label: fields[key].string,
21+
})) || [];
22+
},
23+
},
24+
},
525
methods: {
6-
// this.$auth contains connected account data
7-
authKeys() {
8-
console.log(Object.keys(this.$auth));
26+
getClient(type = "common") {
27+
return xmlrpc.createSecureClient(`${this.$auth.server_url}/xmlrpc/2/${type}`);
28+
},
29+
async getUid() {
30+
const db = this.$auth.db;
31+
const username = this.$auth.username;
32+
const password = this.$auth.password;
33+
const common = this.getClient("common");
34+
const uid = await new Promise((resolve, reject) => {
35+
common.methodCall("authenticate", [
36+
db,
37+
username,
38+
password,
39+
{},
40+
], (error, value) => {
41+
if (error) reject(error);
42+
resolve(value);
43+
});
44+
});
45+
return uid;
46+
},
47+
async makeRequest(method, filter = [], args = {}) {
48+
const db = this.$auth.db;
49+
const uid = await this.getUid();
50+
const password = this.$auth.password;
51+
const models = this.getClient("object");
52+
const results = await new Promise((resolve, reject) => {
53+
models.methodCall("execute_kw", [
54+
db,
55+
uid,
56+
password,
57+
"res.partner",
58+
method,
59+
filter,
60+
args,
61+
], (error, value) => {
62+
if (error) reject(error);
63+
resolve(value);
64+
});
65+
});
66+
return results;
67+
},
68+
async getFieldProps({ update = false } = {}) {
69+
const props = {};
70+
const fields = await this.getFields();
71+
Object.keys(fields).forEach((key) => {
72+
if (fields[key].readonly === true) return;
73+
props[key] = {
74+
type: fields[key].type === "integer" || fields[key].type === "boolean"
75+
? fields[key].type
76+
: fields[key].type.includes("id")
77+
? "integer"
78+
: fields[key].type.includes("2many")
79+
? "string[]"
80+
: "string",
81+
label: fields[key].string,
82+
description: `Value for "${key}"`,
83+
optional: (key !== "name" || update) && fields[key].required === false,
84+
};
85+
});
86+
return props;
87+
},
88+
getFields(filter = [], args = {}) {
89+
return this.makeRequest("fields_get", filter, args);
90+
},
91+
searchAndReadRecords(filter = [], args = {}) {
92+
return this.makeRequest("search_read", filter, args);
93+
},
94+
readRecord(data) {
95+
return this.makeRequest("read", data);
96+
},
97+
createRecord(data) {
98+
return this.makeRequest("create", data);
99+
},
100+
updateRecord(data) {
101+
return this.makeRequest("write", data);
9102
},
10103
},
11104
};

components/odoo/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pipedream/odoo",
3-
"version": "0.0.1",
3+
"version": "0.1.0",
44
"description": "Pipedream Odoo Components",
55
"main": "odoo.app.mjs",
66
"keywords": [
@@ -11,5 +11,8 @@
1111
"author": "Pipedream <[email protected]> (https://pipedream.com/)",
1212
"publishConfig": {
1313
"access": "public"
14+
},
15+
"dependencies": {
16+
"xmlrpc": "^1.3.2"
1417
}
1518
}

pnpm-lock.yaml

Lines changed: 25 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)