mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-16 01:24:05 -08:00
fbdb5eb0fa
* added odoo scaffolding * update getting data from odoo instance * added scaffolding for main loop and request functions * added functions for CRUD opperations * improoved error handling for odooJSONRPCRequest * updated odoo node and fixing nodelinter issues * fixed alpabetical order * fixed types in odoo node * fixing linter errors * fixing linter errors * fixed data shape returned from man loop * updated node input types, added fields list to models * update when custom resource is selected options for fields list will be populated dynamicly * minor fixes * 🔨 fixed credential test, updating CRUD methods * 🔨 added additional fields to crm resource * 🔨 added descriptions, fixed credentials test bug * 🔨 standardize node and descriptions design * 🔨 removed comments * 🔨 added pagination to getAll operation * ⚡ removed leftover function from previous implementation, removed required from optional fields * ⚡ fixed id field, added indication of type and if required to field description, replaced string input in filters to fetched list of fields * 🔨 fetching list of models from odoo, added selection of fields to be returned to predefined models, fixes accordingly to review * ⚡ Small improvements * 🔨 extracted adress fields into collection, changed fields to include in descriptions, minor tweaks * ⚡ Improvements * 🔨 working on review * 🔨 fixed linter errors * 🔨 review wip * 🔨 review wip * 🔨 review wip * ⚡ updated display name for URL in credentials * 🔨 added checks for valid id to delete and update * ⚡ Minor improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
437 lines
9.6 KiB
TypeScript
437 lines
9.6 KiB
TypeScript
import {
|
|
OptionsWithUri,
|
|
} from 'request';
|
|
|
|
import {
|
|
IExecuteFunctions,
|
|
IExecuteSingleFunctions,
|
|
IHookFunctions,
|
|
ILoadOptionsFunctions,
|
|
} from 'n8n-core';
|
|
|
|
import {
|
|
IDataObject,
|
|
JsonObject,
|
|
NodeApiError,
|
|
} from 'n8n-workflow';
|
|
|
|
const serviceJSONRPC = 'object';
|
|
const methodJSONRPC = 'execute';
|
|
|
|
export const mapOperationToJSONRPC = {
|
|
create: 'create',
|
|
get: 'read',
|
|
getAll: 'search_read',
|
|
update: 'write',
|
|
delete: 'unlink',
|
|
};
|
|
|
|
export const mapOdooResources: { [key: string]: string } = {
|
|
contact: 'res.partner',
|
|
opportunity: 'crm.lead',
|
|
note: 'note.note',
|
|
};
|
|
|
|
export const mapFilterOperationToJSONRPC = {
|
|
equal: '=',
|
|
notEqual: '!=',
|
|
greaterThen: '>',
|
|
lesserThen: '<',
|
|
greaterOrEqual: '>=',
|
|
lesserOrEqual: '<=',
|
|
like: 'like',
|
|
in: 'in',
|
|
notIn: 'not in',
|
|
childOf: 'child_of',
|
|
};
|
|
|
|
type FilterOperation =
|
|
| 'equal'
|
|
| 'notEqual'
|
|
| 'greaterThen'
|
|
| 'lesserThen'
|
|
| 'greaterOrEqual'
|
|
| 'lesserOrEqual'
|
|
| 'like'
|
|
| 'in'
|
|
| 'notIn'
|
|
| 'childOf';
|
|
|
|
export interface IOdooFilterOperations {
|
|
filter: Array<{
|
|
fieldName: string;
|
|
operator: string;
|
|
value: string;
|
|
}>;
|
|
}
|
|
|
|
export interface IOdooNameValueFields {
|
|
fields: Array<{
|
|
fieldName: string;
|
|
fieldValue: string;
|
|
}>;
|
|
}
|
|
|
|
export interface IOdooResponceFields {
|
|
fields: Array<{
|
|
field: string;
|
|
fromList?: boolean;
|
|
}>;
|
|
}
|
|
|
|
type OdooCRUD = 'create' | 'update' | 'delete' | 'get' | 'getAll';
|
|
|
|
export function odooGetDBName (databaseName: string | undefined, url: string) {
|
|
if (databaseName) return databaseName;
|
|
const odooURL = new URL(url);
|
|
const hostname = odooURL.hostname;
|
|
if (!hostname) return '';
|
|
return odooURL.hostname.split('.')[0];
|
|
}
|
|
|
|
function processFilters(value: IOdooFilterOperations) {
|
|
return value.filter?.map((item) => {
|
|
const operator = item.operator as FilterOperation;
|
|
item.operator = mapFilterOperationToJSONRPC[operator];
|
|
return Object.values(item);
|
|
});
|
|
}
|
|
|
|
export function processNameValueFields(value: IDataObject) {
|
|
const data = value as unknown as IOdooNameValueFields;
|
|
return data?.fields?.reduce((acc, record) => {
|
|
return Object.assign(acc, { [record.fieldName]: record.fieldValue });
|
|
}, {});
|
|
}
|
|
|
|
// function processResponceFields(value: IDataObject) {
|
|
// const data = value as unknown as IOdooResponceFields;
|
|
// return data?.fields?.map((entry) => entry.field);
|
|
// }
|
|
|
|
export async function odooJSONRPCRequest(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
body: IDataObject,
|
|
url: string,
|
|
): Promise<IDataObject | IDataObject[]> {
|
|
try {
|
|
const options: OptionsWithUri = {
|
|
headers: {
|
|
'User-Agent': 'n8n',
|
|
Connection: 'keep-alive',
|
|
Accept: '*/*',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
method: 'POST',
|
|
body,
|
|
uri: `${url}/jsonrpc`,
|
|
json: true,
|
|
};
|
|
|
|
const responce = await this.helpers.request!(options);
|
|
if (responce.error) {
|
|
throw new NodeApiError(this.getNode(), responce.error.data, {
|
|
message: responce.error.data.message,
|
|
});
|
|
}
|
|
return responce.result;
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooGetModelFields(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
db: string,
|
|
userID: number,
|
|
password: string,
|
|
resource: string,
|
|
url: string,
|
|
) {
|
|
try {
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: serviceJSONRPC,
|
|
method: methodJSONRPC,
|
|
args: [
|
|
db,
|
|
userID,
|
|
password,
|
|
mapOdooResources[resource] || resource,
|
|
'fields_get',
|
|
[],
|
|
['string', 'type', 'help', 'required', 'name'],
|
|
],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
|
|
const result = await odooJSONRPCRequest.call(this, body, url);
|
|
return result;
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooCreate(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
db: string,
|
|
userID: number,
|
|
password: string,
|
|
resource: string,
|
|
operation: OdooCRUD,
|
|
url: string,
|
|
newItem: IDataObject,
|
|
) {
|
|
try {
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: serviceJSONRPC,
|
|
method: methodJSONRPC,
|
|
args: [
|
|
db,
|
|
userID,
|
|
password,
|
|
mapOdooResources[resource] || resource,
|
|
mapOperationToJSONRPC[operation],
|
|
newItem || {},
|
|
],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
|
|
const result = await odooJSONRPCRequest.call(this, body, url);
|
|
return { id: result };
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooGet(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
db: string,
|
|
userID: number,
|
|
password: string,
|
|
resource: string,
|
|
operation: OdooCRUD,
|
|
url: string,
|
|
itemsID: string,
|
|
fieldsToReturn?: IDataObject[],
|
|
) {
|
|
try {
|
|
if (!/^\d+$/.test(itemsID) || !parseInt(itemsID, 10)) {
|
|
throw new NodeApiError(this.getNode(), {
|
|
status: 'Error',
|
|
message: `Please specify a valid ID: ${itemsID}`,
|
|
});
|
|
}
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: serviceJSONRPC,
|
|
method: methodJSONRPC,
|
|
args: [
|
|
db,
|
|
userID,
|
|
password,
|
|
mapOdooResources[resource] || resource,
|
|
mapOperationToJSONRPC[operation],
|
|
[+itemsID] || [],
|
|
fieldsToReturn || [],
|
|
],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
|
|
const result = await odooJSONRPCRequest.call(this, body, url);
|
|
return result;
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooGetAll(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
db: string,
|
|
userID: number,
|
|
password: string,
|
|
resource: string,
|
|
operation: OdooCRUD,
|
|
url: string,
|
|
filters?: IOdooFilterOperations,
|
|
fieldsToReturn?: IDataObject[],
|
|
limit = 0,
|
|
) {
|
|
try {
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: serviceJSONRPC,
|
|
method: methodJSONRPC,
|
|
args: [
|
|
db,
|
|
userID,
|
|
password,
|
|
mapOdooResources[resource] || resource,
|
|
mapOperationToJSONRPC[operation],
|
|
(filters && processFilters(filters)) || [],
|
|
fieldsToReturn || [],
|
|
0, // offset
|
|
limit,
|
|
],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
|
|
const result = await odooJSONRPCRequest.call(this, body, url);
|
|
return result;
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooUpdate(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
db: string,
|
|
userID: number,
|
|
password: string,
|
|
resource: string,
|
|
operation: OdooCRUD,
|
|
url: string,
|
|
itemsID: string,
|
|
fieldsToUpdate: IDataObject,
|
|
) {
|
|
try {
|
|
if (!Object.keys(fieldsToUpdate).length) {
|
|
throw new NodeApiError(this.getNode(), {
|
|
status: 'Error',
|
|
message: `Please specify at least one field to update`,
|
|
});
|
|
}
|
|
if (!/^\d+$/.test(itemsID) || !parseInt(itemsID, 10)) {
|
|
throw new NodeApiError(this.getNode(), {
|
|
status: 'Error',
|
|
message: `Please specify a valid ID: ${itemsID}`,
|
|
});
|
|
}
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: serviceJSONRPC,
|
|
method: methodJSONRPC,
|
|
args: [
|
|
db,
|
|
userID,
|
|
password,
|
|
mapOdooResources[resource] || resource,
|
|
mapOperationToJSONRPC[operation],
|
|
[+itemsID] || [],
|
|
fieldsToUpdate,
|
|
],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
|
|
await odooJSONRPCRequest.call(this, body, url);
|
|
return { id: itemsID };
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooDelete(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
db: string,
|
|
userID: number,
|
|
password: string,
|
|
resource: string,
|
|
operation: OdooCRUD,
|
|
url: string,
|
|
itemsID: string,
|
|
) {
|
|
if (!/^\d+$/.test(itemsID) || !parseInt(itemsID, 10)) {
|
|
throw new NodeApiError(this.getNode(), {
|
|
status: 'Error',
|
|
message: `Please specify a valid ID: ${itemsID}`,
|
|
});
|
|
}
|
|
try {
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: serviceJSONRPC,
|
|
method: methodJSONRPC,
|
|
args: [
|
|
db,
|
|
userID,
|
|
password,
|
|
mapOdooResources[resource] || resource,
|
|
mapOperationToJSONRPC[operation],
|
|
[+itemsID] || [],
|
|
],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
|
|
await odooJSONRPCRequest.call(this, body, url);
|
|
return { success: true };
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooGetUserID(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
db: string,
|
|
username: string,
|
|
password: string,
|
|
url: string,
|
|
): Promise<number> {
|
|
try {
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: 'common',
|
|
method: 'login',
|
|
args: [db, username, password],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
const loginResult = await odooJSONRPCRequest.call(this, body, url);
|
|
return loginResult as unknown as number;
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|
|
|
|
export async function odooGetServerVersion(
|
|
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
|
url: string,
|
|
) {
|
|
try {
|
|
const body = {
|
|
jsonrpc: '2.0',
|
|
method: 'call',
|
|
params: {
|
|
service: 'common',
|
|
method: 'version',
|
|
args: [],
|
|
},
|
|
id: Math.floor(Math.random() * 100),
|
|
};
|
|
const result = await odooJSONRPCRequest.call(this, body, url);
|
|
return result;
|
|
} catch (error) {
|
|
throw new NodeApiError(this.getNode(), error as JsonObject);
|
|
}
|
|
}
|