@ixiam/n8n-nodes-civicrm 0.3.4 → 0.3.9
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/README.md +2 -1
- package/dist/nodes/CiviCrm/CiviCrm.node.js +112 -16
- package/dist/nodes/transport/GenericFunctions.d.ts +3 -3
- package/dist/nodes/transport/GenericFunctions.js +7 -6
- package/nodes/CiviCrm/CiviCrm.node.ts +172 -60
- package/nodes/transport/GenericFunctions.ts +7 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,4 +9,5 @@ Credentials:
|
|
|
9
9
|
- Use the **Save** button to verify connectivity.
|
|
10
10
|
|
|
11
11
|
Entities: Contact, Event, Case, Contribution, Membership → `get|getMany|create|update|delete`
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
Node developed by Ixiam Global Solution: `https://www.ixiam.com'
|
|
@@ -35,6 +35,21 @@ class CiviCrm {
|
|
|
35
35
|
properties: [
|
|
36
36
|
resources_1.resourceProp,
|
|
37
37
|
resources_1.operationProp,
|
|
38
|
+
{
|
|
39
|
+
displayName: 'Contact Type',
|
|
40
|
+
name: 'contactType',
|
|
41
|
+
type: 'options',
|
|
42
|
+
default: 'Individual',
|
|
43
|
+
options: [
|
|
44
|
+
{ name: 'Individual', value: 'Individual' },
|
|
45
|
+
{ name: 'Organization', value: 'Organization' },
|
|
46
|
+
{ name: 'Household', value: 'Household' },
|
|
47
|
+
],
|
|
48
|
+
displayOptions: {
|
|
49
|
+
show: { resource: ['contact'] },
|
|
50
|
+
},
|
|
51
|
+
description: 'Filter or assign contact type',
|
|
52
|
+
},
|
|
38
53
|
{
|
|
39
54
|
displayName: 'ID',
|
|
40
55
|
name: 'id',
|
|
@@ -62,10 +77,9 @@ class CiviCrm {
|
|
|
62
77
|
body: {
|
|
63
78
|
params: JSON.stringify({ limit: 5 }),
|
|
64
79
|
},
|
|
65
|
-
json:
|
|
80
|
+
json: true,
|
|
66
81
|
});
|
|
67
|
-
const
|
|
68
|
-
const values = (parsed?.values || []);
|
|
82
|
+
const values = (res?.values || []);
|
|
69
83
|
return values.map((v) => ({
|
|
70
84
|
name: v.label,
|
|
71
85
|
value: v.id,
|
|
@@ -84,7 +98,45 @@ class CiviCrm {
|
|
|
84
98
|
// === GET ===
|
|
85
99
|
if (operation === 'get') {
|
|
86
100
|
const id = this.getNodeParameter('id', i);
|
|
87
|
-
const
|
|
101
|
+
const contactType = this.getNodeParameter('contactType', i, '');
|
|
102
|
+
const where = [['id', '=', id]];
|
|
103
|
+
if (resource === 'contact' && contactType) {
|
|
104
|
+
where.push(['contact_type', '=', contactType]);
|
|
105
|
+
}
|
|
106
|
+
let params;
|
|
107
|
+
if (resource === 'contact') {
|
|
108
|
+
params = {
|
|
109
|
+
where,
|
|
110
|
+
limit: 1,
|
|
111
|
+
select: [
|
|
112
|
+
'id',
|
|
113
|
+
'display_name',
|
|
114
|
+
'first_name',
|
|
115
|
+
'last_name',
|
|
116
|
+
'contact_type',
|
|
117
|
+
'email.email',
|
|
118
|
+
'phone.phone',
|
|
119
|
+
'address.city',
|
|
120
|
+
'address.country_id:label',
|
|
121
|
+
'address.postal_code',
|
|
122
|
+
'address.street_address',
|
|
123
|
+
],
|
|
124
|
+
join: [
|
|
125
|
+
['Email AS email', 'LEFT'],
|
|
126
|
+
['Phone AS phone', 'LEFT'],
|
|
127
|
+
['Address AS address', 'LEFT'],
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// otras entidades: select básico
|
|
133
|
+
params = {
|
|
134
|
+
where,
|
|
135
|
+
limit: 1,
|
|
136
|
+
select: ['id', 'title', 'subject', 'display_name', 'name'],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, params);
|
|
88
140
|
out.push({ json: (res?.values?.[0] ?? {}) });
|
|
89
141
|
}
|
|
90
142
|
// === GET MANY ===
|
|
@@ -92,12 +144,43 @@ class CiviCrm {
|
|
|
92
144
|
const returnAll = this.getNodeParameter('returnAll', i, false);
|
|
93
145
|
const limit = this.getNodeParameter('limit', i, 100);
|
|
94
146
|
const whereJson = this.getNodeParameter('whereJson', i, '');
|
|
95
|
-
const
|
|
147
|
+
const contactType = this.getNodeParameter('contactType', i, '');
|
|
148
|
+
let where = whereJson ? JSON.parse(whereJson) : [];
|
|
149
|
+
if (resource === 'contact' && contactType) {
|
|
150
|
+
where.push(['contact_type', '=', contactType]);
|
|
151
|
+
}
|
|
152
|
+
let baseParams;
|
|
153
|
+
if (resource === 'contact') {
|
|
154
|
+
baseParams = {
|
|
155
|
+
where,
|
|
156
|
+
select: [
|
|
157
|
+
'id',
|
|
158
|
+
'display_name',
|
|
159
|
+
'first_name',
|
|
160
|
+
'last_name',
|
|
161
|
+
'contact_type',
|
|
162
|
+
'email.email',
|
|
163
|
+
'phone.phone',
|
|
164
|
+
'address.city',
|
|
165
|
+
'address.country_id:label',
|
|
166
|
+
'address.postal_code',
|
|
167
|
+
'address.street_address',
|
|
168
|
+
],
|
|
169
|
+
join: [
|
|
170
|
+
['Email AS email', 'LEFT'],
|
|
171
|
+
['Phone AS phone', 'LEFT'],
|
|
172
|
+
['Address AS address', 'LEFT'],
|
|
173
|
+
],
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
baseParams = { where, select: ['id', 'title', 'subject', 'display_name', 'name'] };
|
|
178
|
+
}
|
|
96
179
|
if (returnAll) {
|
|
97
180
|
let offset = 0;
|
|
98
181
|
const page = 500;
|
|
99
182
|
while (true) {
|
|
100
|
-
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`,
|
|
183
|
+
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...baseParams, limit: page, offset });
|
|
101
184
|
const vals = (res?.values ?? []);
|
|
102
185
|
for (const v of vals)
|
|
103
186
|
out.push({ json: v });
|
|
@@ -107,7 +190,7 @@ class CiviCrm {
|
|
|
107
190
|
}
|
|
108
191
|
}
|
|
109
192
|
else {
|
|
110
|
-
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`,
|
|
193
|
+
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...baseParams, limit });
|
|
111
194
|
const vals = (res?.values ?? []);
|
|
112
195
|
for (const v of vals)
|
|
113
196
|
out.push({ json: v });
|
|
@@ -116,29 +199,42 @@ class CiviCrm {
|
|
|
116
199
|
// === CREATE ===
|
|
117
200
|
if (operation === 'create') {
|
|
118
201
|
const pairs = this.getNodeParameter('fields.field', i, []);
|
|
119
|
-
const
|
|
202
|
+
const values = Object.fromEntries(pairs
|
|
120
203
|
.filter((p) => p.fieldName)
|
|
121
204
|
.map((p) => [p.fieldName, convertValue(p.fieldValue)]));
|
|
122
|
-
const
|
|
205
|
+
const contactType = this.getNodeParameter('contactType', i, '');
|
|
206
|
+
if (resource === 'contact' && contactType) {
|
|
207
|
+
values.contact_type = contactType;
|
|
208
|
+
}
|
|
209
|
+
const params = { values };
|
|
210
|
+
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/create`, params);
|
|
123
211
|
out.push({ json: res });
|
|
124
212
|
}
|
|
125
213
|
// === UPDATE ===
|
|
126
214
|
if (operation === 'update') {
|
|
127
215
|
const id = this.getNodeParameter('id', i);
|
|
128
216
|
const pairs = this.getNodeParameter('fields.field', i, []);
|
|
217
|
+
const values = Object.fromEntries(pairs
|
|
218
|
+
.filter((p) => p.fieldName)
|
|
219
|
+
.map((p) => [p.fieldName, convertValue(p.fieldValue)]));
|
|
220
|
+
const contactType = this.getNodeParameter('contactType', i, '');
|
|
221
|
+
if (resource === 'contact' && contactType) {
|
|
222
|
+
values.contact_type = contactType;
|
|
223
|
+
}
|
|
129
224
|
const params = {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
.filter((p) => p.fieldName)
|
|
133
|
-
.map((p) => [p.fieldName, convertValue(p.fieldValue)])),
|
|
225
|
+
values,
|
|
226
|
+
where: [['id', '=', id]],
|
|
134
227
|
};
|
|
135
|
-
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/update`,
|
|
228
|
+
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/update`, params);
|
|
136
229
|
out.push({ json: res });
|
|
137
230
|
}
|
|
138
231
|
// === DELETE ===
|
|
139
232
|
if (operation === 'delete') {
|
|
140
233
|
const id = this.getNodeParameter('id', i);
|
|
141
|
-
const
|
|
234
|
+
const params = {
|
|
235
|
+
where: [['id', '=', id]],
|
|
236
|
+
};
|
|
237
|
+
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/delete`, params);
|
|
142
238
|
out.push({ json: res });
|
|
143
239
|
}
|
|
144
240
|
}
|
|
@@ -167,5 +263,5 @@ function convertValue(val) {
|
|
|
167
263
|
catch { }
|
|
168
264
|
return val;
|
|
169
265
|
}
|
|
170
|
-
//
|
|
266
|
+
// Requerido por n8n >=1.110
|
|
171
267
|
exports.default = CiviCrm;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { IExecuteFunctions } from 'n8n-workflow';
|
|
2
2
|
/**
|
|
3
|
-
* Ejecuta una llamada a la API de CiviCRM v4 (
|
|
3
|
+
* Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
|
|
4
|
+
* Usa form-urlencoded con el campo "params" serializado
|
|
4
5
|
*/
|
|
5
6
|
export declare function civicrmApiRequest(this: IExecuteFunctions, method: 'POST', path: string, body: Record<string, unknown>): Promise<any>;
|
|
6
7
|
/**
|
|
7
|
-
* Devuelve el
|
|
8
|
-
* Solo los parámetros planos: where, limit, select...
|
|
8
|
+
* Devuelve el cuerpo estándar para las llamadas API4 (plano)
|
|
9
9
|
*/
|
|
10
10
|
export declare function api4(entity: string, action: string, params?: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.api4 = exports.civicrmApiRequest = void 0;
|
|
4
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
5
|
/**
|
|
6
|
-
* Ejecuta una llamada a la API de CiviCRM v4 (
|
|
6
|
+
* Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
|
|
7
|
+
* Usa form-urlencoded con el campo "params" serializado
|
|
7
8
|
*/
|
|
8
9
|
async function civicrmApiRequest(method, path, body) {
|
|
9
10
|
const { baseUrl, apiToken } = (await this.getCredentials('civiCrmApi'));
|
|
@@ -14,11 +15,11 @@ async function civicrmApiRequest(method, path, body) {
|
|
|
14
15
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
15
16
|
'X-Civi-Auth': `Bearer ${apiToken}`,
|
|
16
17
|
},
|
|
17
|
-
//
|
|
18
|
+
// cuerpo plano como espera Civi-Go
|
|
18
19
|
body: {
|
|
19
|
-
params: JSON.stringify(body),
|
|
20
|
+
params: JSON.stringify(body.params ?? body),
|
|
20
21
|
},
|
|
21
|
-
json: true,
|
|
22
|
+
json: true,
|
|
22
23
|
};
|
|
23
24
|
try {
|
|
24
25
|
const response = await this.helpers.httpRequest(options);
|
|
@@ -30,10 +31,10 @@ async function civicrmApiRequest(method, path, body) {
|
|
|
30
31
|
}
|
|
31
32
|
exports.civicrmApiRequest = civicrmApiRequest;
|
|
32
33
|
/**
|
|
33
|
-
* Devuelve el
|
|
34
|
-
* Solo los parámetros planos: where, limit, select...
|
|
34
|
+
* Devuelve el cuerpo estándar para las llamadas API4 (plano)
|
|
35
35
|
*/
|
|
36
36
|
function api4(entity, action, params = {}) {
|
|
37
|
+
// devolvemos los parámetros planos, no anidados
|
|
37
38
|
return params;
|
|
38
39
|
}
|
|
39
40
|
exports.api4 = api4;
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
IDataObject,
|
|
9
9
|
} from 'n8n-workflow';
|
|
10
10
|
|
|
11
|
-
import { civicrmApiRequest
|
|
11
|
+
import { civicrmApiRequest } from '../transport/GenericFunctions';
|
|
12
12
|
import { resourceProp, operationProp } from './descriptions/resources';
|
|
13
13
|
import { genericFields, upsertFields } from './descriptions/generic';
|
|
14
14
|
|
|
@@ -40,7 +40,6 @@ const ENTITY_MAP: Record<Resource, string> = {
|
|
|
40
40
|
activity: 'Activity',
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
|
|
44
43
|
type Operation = 'get' | 'getMany' | 'create' | 'update' | 'delete';
|
|
45
44
|
|
|
46
45
|
/**
|
|
@@ -61,6 +60,21 @@ export class CiviCrm implements INodeType {
|
|
|
61
60
|
properties: [
|
|
62
61
|
resourceProp,
|
|
63
62
|
operationProp,
|
|
63
|
+
{
|
|
64
|
+
displayName: 'Contact Type',
|
|
65
|
+
name: 'contactType',
|
|
66
|
+
type: 'options',
|
|
67
|
+
default: 'Individual',
|
|
68
|
+
options: [
|
|
69
|
+
{ name: 'Individual', value: 'Individual' },
|
|
70
|
+
{ name: 'Organization', value: 'Organization' },
|
|
71
|
+
{ name: 'Household', value: 'Household' },
|
|
72
|
+
],
|
|
73
|
+
displayOptions: {
|
|
74
|
+
show: { resource: ['contact'] },
|
|
75
|
+
},
|
|
76
|
+
description: 'Filter or assign contact type',
|
|
77
|
+
},
|
|
64
78
|
{
|
|
65
79
|
displayName: 'ID',
|
|
66
80
|
name: 'id',
|
|
@@ -94,11 +108,10 @@ export class CiviCrm implements INodeType {
|
|
|
94
108
|
body: {
|
|
95
109
|
params: JSON.stringify({ limit: 5 }),
|
|
96
110
|
},
|
|
97
|
-
json:
|
|
111
|
+
json: true,
|
|
98
112
|
});
|
|
99
113
|
|
|
100
|
-
const
|
|
101
|
-
const values = (parsed?.values || []) as Array<{ id: number; label: string }>;
|
|
114
|
+
const values = (res?.values || []) as Array<{ id: number; label: string }>;
|
|
102
115
|
return values.map((v): INodePropertyOptions => ({
|
|
103
116
|
name: v.label,
|
|
104
117
|
value: v.id,
|
|
@@ -116,51 +129,127 @@ export class CiviCrm implements INodeType {
|
|
|
116
129
|
const entity = ENTITY_MAP[resource];
|
|
117
130
|
|
|
118
131
|
for (let i = 0; i < items.length; i++) {
|
|
119
|
-
// === GET ===
|
|
120
|
-
if (operation === 'get') {
|
|
121
|
-
const id = this.getNodeParameter('id', i) as number;
|
|
122
|
-
const res = await civicrmApiRequest.call(
|
|
123
|
-
this,
|
|
124
|
-
'POST',
|
|
125
|
-
`/civicrm/ajax/api4/${entity}/get`,
|
|
126
|
-
api4(entity, 'get', { where: [['id', '=', id]], limit: 1 }),
|
|
127
|
-
);
|
|
128
|
-
out.push({ json: (res?.values?.[0] ?? {}) as IDataObject });
|
|
129
|
-
}
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
133
|
+
// === GET ===
|
|
134
|
+
if (operation === 'get') {
|
|
135
|
+
const id = this.getNodeParameter('id', i) as number;
|
|
136
|
+
const contactType = this.getNodeParameter('contactType', i, '') as string;
|
|
137
|
+
|
|
138
|
+
const where = [['id', '=', id]];
|
|
139
|
+
if (resource === 'contact' && contactType) {
|
|
140
|
+
where.push(['contact_type', '=', contactType]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let params: Record<string, unknown>;
|
|
144
|
+
|
|
145
|
+
if (resource === 'contact') {
|
|
146
|
+
params = {
|
|
147
|
+
where,
|
|
148
|
+
limit: 1,
|
|
149
|
+
select: [
|
|
150
|
+
'id',
|
|
151
|
+
'display_name',
|
|
152
|
+
'first_name',
|
|
153
|
+
'last_name',
|
|
154
|
+
'contact_type',
|
|
155
|
+
'email.email',
|
|
156
|
+
'phone.phone',
|
|
157
|
+
'address.city',
|
|
158
|
+
'address.country_id:label',
|
|
159
|
+
'address.postal_code',
|
|
160
|
+
'address.street_address',
|
|
161
|
+
],
|
|
162
|
+
join: [
|
|
163
|
+
['Email AS email', 'LEFT'],
|
|
164
|
+
['Phone AS phone', 'LEFT'],
|
|
165
|
+
['Address AS address', 'LEFT'],
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
} else {
|
|
169
|
+
// otras entidades: select básico
|
|
170
|
+
params = {
|
|
171
|
+
where,
|
|
172
|
+
limit: 1,
|
|
173
|
+
select: ['id', 'title', 'subject', 'display_name', 'name'],
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const res = await civicrmApiRequest.call(
|
|
178
|
+
this,
|
|
179
|
+
'POST',
|
|
180
|
+
`/civicrm/ajax/api4/${entity}/get`,
|
|
181
|
+
params,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
out.push({ json: (res?.values?.[0] ?? {}) as IDataObject });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// === GET MANY ===
|
|
188
|
+
if (operation === 'getMany') {
|
|
189
|
+
const returnAll = this.getNodeParameter('returnAll', i, false) as boolean;
|
|
190
|
+
const limit = this.getNodeParameter('limit', i, 100) as number;
|
|
191
|
+
const whereJson = this.getNodeParameter('whereJson', i, '') as string;
|
|
192
|
+
const contactType = this.getNodeParameter('contactType', i, '') as string;
|
|
193
|
+
|
|
194
|
+
let where = whereJson ? JSON.parse(whereJson) : [];
|
|
195
|
+
if (resource === 'contact' && contactType) {
|
|
196
|
+
where.push(['contact_type', '=', contactType]);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let baseParams: Record<string, unknown>;
|
|
200
|
+
|
|
201
|
+
if (resource === 'contact') {
|
|
202
|
+
baseParams = {
|
|
203
|
+
where,
|
|
204
|
+
select: [
|
|
205
|
+
'id',
|
|
206
|
+
'display_name',
|
|
207
|
+
'first_name',
|
|
208
|
+
'last_name',
|
|
209
|
+
'contact_type',
|
|
210
|
+
'email.email',
|
|
211
|
+
'phone.phone',
|
|
212
|
+
'address.city',
|
|
213
|
+
'address.country_id:label',
|
|
214
|
+
'address.postal_code',
|
|
215
|
+
'address.street_address',
|
|
216
|
+
],
|
|
217
|
+
join: [
|
|
218
|
+
['Email AS email', 'LEFT'],
|
|
219
|
+
['Phone AS phone', 'LEFT'],
|
|
220
|
+
['Address AS address', 'LEFT'],
|
|
221
|
+
],
|
|
222
|
+
};
|
|
223
|
+
} else {
|
|
224
|
+
baseParams = { where, select: ['id', 'title', 'subject', 'display_name', 'name'] };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (returnAll) {
|
|
228
|
+
let offset = 0;
|
|
229
|
+
const page = 500;
|
|
230
|
+
while (true) {
|
|
231
|
+
const res = await civicrmApiRequest.call(
|
|
232
|
+
this,
|
|
233
|
+
'POST',
|
|
234
|
+
`/civicrm/ajax/api4/${entity}/get`,
|
|
235
|
+
{ ...baseParams, limit: page, offset },
|
|
236
|
+
);
|
|
237
|
+
const vals = (res?.values ?? []) as IDataObject[];
|
|
238
|
+
for (const v of vals) out.push({ json: v });
|
|
239
|
+
if (vals.length < page) break;
|
|
240
|
+
offset += page;
|
|
241
|
+
}
|
|
242
|
+
} else {
|
|
243
|
+
const res = await civicrmApiRequest.call(
|
|
244
|
+
this,
|
|
245
|
+
'POST',
|
|
246
|
+
`/civicrm/ajax/api4/${entity}/get`,
|
|
247
|
+
{ ...baseParams, limit },
|
|
248
|
+
);
|
|
249
|
+
const vals = (res?.values ?? []) as IDataObject[];
|
|
250
|
+
for (const v of vals) out.push({ json: v });
|
|
251
|
+
}
|
|
252
|
+
}
|
|
164
253
|
|
|
165
254
|
// === CREATE ===
|
|
166
255
|
if (operation === 'create') {
|
|
@@ -168,16 +257,25 @@ export class CiviCrm implements INodeType {
|
|
|
168
257
|
fieldName: string;
|
|
169
258
|
fieldValue: string;
|
|
170
259
|
}>;
|
|
171
|
-
|
|
260
|
+
|
|
261
|
+
const values = Object.fromEntries(
|
|
172
262
|
pairs
|
|
173
263
|
.filter((p) => p.fieldName)
|
|
174
264
|
.map((p) => [p.fieldName, convertValue(p.fieldValue)]),
|
|
175
265
|
);
|
|
266
|
+
|
|
267
|
+
const contactType = this.getNodeParameter('contactType', i, '') as string;
|
|
268
|
+
if (resource === 'contact' && contactType) {
|
|
269
|
+
values.contact_type = contactType;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const params = { values };
|
|
273
|
+
|
|
176
274
|
const res = await civicrmApiRequest.call(
|
|
177
275
|
this,
|
|
178
276
|
'POST',
|
|
179
277
|
`/civicrm/ajax/api4/${entity}/create`,
|
|
180
|
-
|
|
278
|
+
params,
|
|
181
279
|
);
|
|
182
280
|
out.push({ json: res as IDataObject });
|
|
183
281
|
}
|
|
@@ -189,19 +287,28 @@ export class CiviCrm implements INodeType {
|
|
|
189
287
|
fieldName: string;
|
|
190
288
|
fieldValue: string;
|
|
191
289
|
}>;
|
|
290
|
+
|
|
291
|
+
const values = Object.fromEntries(
|
|
292
|
+
pairs
|
|
293
|
+
.filter((p) => p.fieldName)
|
|
294
|
+
.map((p) => [p.fieldName, convertValue(p.fieldValue)]),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const contactType = this.getNodeParameter('contactType', i, '') as string;
|
|
298
|
+
if (resource === 'contact' && contactType) {
|
|
299
|
+
values.contact_type = contactType;
|
|
300
|
+
}
|
|
301
|
+
|
|
192
302
|
const params = {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
pairs
|
|
196
|
-
.filter((p) => p.fieldName)
|
|
197
|
-
.map((p) => [p.fieldName, convertValue(p.fieldValue)]),
|
|
198
|
-
),
|
|
303
|
+
values,
|
|
304
|
+
where: [['id', '=', id]],
|
|
199
305
|
};
|
|
306
|
+
|
|
200
307
|
const res = await civicrmApiRequest.call(
|
|
201
308
|
this,
|
|
202
309
|
'POST',
|
|
203
310
|
`/civicrm/ajax/api4/${entity}/update`,
|
|
204
|
-
|
|
311
|
+
params,
|
|
205
312
|
);
|
|
206
313
|
out.push({ json: res as IDataObject });
|
|
207
314
|
}
|
|
@@ -209,11 +316,16 @@ export class CiviCrm implements INodeType {
|
|
|
209
316
|
// === DELETE ===
|
|
210
317
|
if (operation === 'delete') {
|
|
211
318
|
const id = this.getNodeParameter('id', i) as number;
|
|
319
|
+
|
|
320
|
+
const params = {
|
|
321
|
+
where: [['id', '=', id]],
|
|
322
|
+
};
|
|
323
|
+
|
|
212
324
|
const res = await civicrmApiRequest.call(
|
|
213
325
|
this,
|
|
214
326
|
'POST',
|
|
215
327
|
`/civicrm/ajax/api4/${entity}/delete`,
|
|
216
|
-
|
|
328
|
+
params,
|
|
217
329
|
);
|
|
218
330
|
out.push({ json: res as IDataObject });
|
|
219
331
|
}
|
|
@@ -239,5 +351,5 @@ function convertValue(val: string): unknown {
|
|
|
239
351
|
return val;
|
|
240
352
|
}
|
|
241
353
|
|
|
242
|
-
//
|
|
354
|
+
// Requerido por n8n >=1.110
|
|
243
355
|
export default CiviCrm;
|
|
@@ -2,7 +2,8 @@ import type { IExecuteFunctions, IHttpRequestOptions, JsonObject } from 'n8n-wor
|
|
|
2
2
|
import { NodeApiError } from 'n8n-workflow';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Ejecuta una llamada a la API de CiviCRM v4 (
|
|
5
|
+
* Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
|
|
6
|
+
* Usa form-urlencoded con el campo "params" serializado
|
|
6
7
|
*/
|
|
7
8
|
export async function civicrmApiRequest(
|
|
8
9
|
this: IExecuteFunctions,
|
|
@@ -22,11 +23,11 @@ export async function civicrmApiRequest(
|
|
|
22
23
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
23
24
|
'X-Civi-Auth': `Bearer ${apiToken}`,
|
|
24
25
|
},
|
|
25
|
-
//
|
|
26
|
+
// cuerpo plano como espera Civi-Go
|
|
26
27
|
body: {
|
|
27
|
-
params: JSON.stringify(body),
|
|
28
|
+
params: JSON.stringify(body.params ?? body),
|
|
28
29
|
},
|
|
29
|
-
json: true,
|
|
30
|
+
json: true,
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
try {
|
|
@@ -38,13 +39,13 @@ export async function civicrmApiRequest(
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
|
-
* Devuelve el
|
|
42
|
-
* Solo los parámetros planos: where, limit, select...
|
|
42
|
+
* Devuelve el cuerpo estándar para las llamadas API4 (plano)
|
|
43
43
|
*/
|
|
44
44
|
export function api4(
|
|
45
45
|
entity: string,
|
|
46
46
|
action: string,
|
|
47
47
|
params: Record<string, unknown> = {},
|
|
48
48
|
) {
|
|
49
|
+
// devolvemos los parámetros planos, no anidados
|
|
49
50
|
return params;
|
|
50
51
|
}
|