@ixiam/n8n-nodes-civicrm 1.1.19 → 1.1.23
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 +20 -104
- package/dist/credentials/CiviCrmApi.credentials.js +18 -27
- package/dist/nodes/CiviCrm/CiviCrm.node.js +47 -39
- package/dist/nodes/transport/GenericFunctions.js +4 -4
- package/package.json +2 -65
- package/reload-in-docker.md +68 -0
- package/src/credentials/CiviCrmApi.credentials.ts +2 -4
- package/src/nodes/CiviCrm/CiviCrm.node.ts +82 -75
- package/credentials/CiviCrmApi.credentials.ts +0 -58
- package/dist/credentials/CiviCrmApi.credentials.d.ts +0 -30
- package/dist/nodes/CiviCrm/CiviCrm.node.d.ts +0 -14
- package/dist/nodes/CiviCrm/descriptions/generic.d.ts +0 -3
- package/dist/nodes/CiviCrm/descriptions/resources.d.ts +0 -3
- package/dist/nodes/transport/GenericFunctions.d.ts +0 -10
- package/nodes/CiviCrm/CiviCrm.node.ts +0 -664
- package/nodes/CiviCrm/civicrm.svg +0 -28
- package/nodes/CiviCrm/descriptions/generic.ts +0 -9
- package/nodes/CiviCrm/descriptions/resources.ts +0 -41
- package/nodes/transport/GenericFunctions.ts +0 -51
package/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# n8n-nodes-civicrm
|
|
2
|
-
<<<<<<< HEAD
|
|
3
2
|
|
|
4
3
|

|
|
5
4
|

|
|
@@ -8,101 +7,37 @@
|
|
|
8
7
|
Community Node for **CiviCRM API v4** (Civi-Go compatible)
|
|
9
8
|
Developed and maintained by **Ixiam Global Solutions**.
|
|
10
9
|
|
|
11
|
-
This
|
|
12
|
-
Custom fields are **not** supported.
|
|
10
|
+
This node enables full integration between **n8n** and **CiviCRM API v4**, supporting create/update/delete operations, smart field mapping, dynamic location types, and advanced filtering on GET operations.
|
|
13
11
|
|
|
14
12
|
---
|
|
15
|
-
# About CiviCRM
|
|
16
|
-
|
|
17
|
-
CiviCRM is an open-source Constituent Relationship Management platform designed for nonprofits, NGOs, and advocacy organizations. It supports contact management, memberships, contributions, event registration, email marketing, case management, and reporting. CiviCRM integrates with WordPress, Drupal, and Joomla.
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
## About CiviCRM
|
|
20
15
|
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="https://civicrm.org/sites/civicrm.org/files/CiviCRM-logo-2019-F2-200px.png" alt="CiviCRM Logo" width="200"/>
|
|
18
|
+
</p>
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
CiviCRM is an open-source Constituent Relationship Management platform designed for nonprofits, NGOs, and advocacy organizations. It supports contact management, memberships, contributions, event registration, email marketing, case management, and reporting. CiviCRM integrates with WordPress, Drupal, and Joomla.
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
=======
|
|
26
|
-
Community Node for **CiviCRM API v4** (Civi-Go compatible)
|
|
27
|
-
Developed and maintained by **Ixiam Global Solutions**.
|
|
22
|
+
Download: https://civicrm.org/download
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
---
|
|
30
25
|
|
|
31
26
|
## 🚀 Installation
|
|
32
27
|
|
|
33
28
|
1. In your n8n instance, go to:
|
|
34
|
-
>>>>>>> 03f29e40d265531031a602d4bdcf4724e39bd809
|
|
35
29
|
**Settings → Community Nodes → Install**
|
|
36
30
|
2. Enter the package name:
|
|
37
31
|
|
|
38
32
|
```
|
|
39
|
-
<<<<<<< HEAD
|
|
40
33
|
@ixiam/n8n-nodes-civicrm
|
|
41
34
|
```
|
|
42
35
|
|
|
43
|
-
3.
|
|
36
|
+
3. Approve installation and enable Community Nodes.
|
|
44
37
|
4. If running n8n via Docker, restart/rebuild for the node to load.
|
|
45
38
|
|
|
46
39
|
---
|
|
47
40
|
|
|
48
|
-
## Credentials
|
|
49
|
-
|
|
50
|
-
Authentication uses **Bearer Token**.
|
|
51
|
-
|
|
52
|
-
| Field | Description |
|
|
53
|
-
|-------|-------------|
|
|
54
|
-
| **Base URL** | Root URL of your CiviCRM instance (no trailing slash). Example: `https://crm.example.org` |
|
|
55
|
-
| **API Token** | Sent as header `X-Civi-Auth: Bearer <token>` |
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## Supported Entities
|
|
60
|
-
|
|
61
|
-
This node implements API v4 operations for:
|
|
62
|
-
|
|
63
|
-
- Contact
|
|
64
|
-
- Membership
|
|
65
|
-
- Group
|
|
66
|
-
- Relationship
|
|
67
|
-
- Activity
|
|
68
|
-
- Custom API Call (raw API4 request)
|
|
69
|
-
|
|
70
|
-
Each entity supports:
|
|
71
|
-
- get
|
|
72
|
-
- getMany
|
|
73
|
-
- create
|
|
74
|
-
- update
|
|
75
|
-
- delete
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Features
|
|
80
|
-
|
|
81
|
-
### Email, phone and address with location types
|
|
82
|
-
Two mapping modes:
|
|
83
|
-
|
|
84
|
-
Simple:
|
|
85
|
-
```
|
|
86
|
-
email = test@example.org
|
|
87
|
-
address.city = Barcelona
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
With location prefixes:
|
|
91
|
-
```
|
|
92
|
-
work.email = user@company.org
|
|
93
|
-
billing.address.postal_code = 08014
|
|
94
|
-
home.phone.phone_type_id = 2
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### GET MANY with JSON filters
|
|
98
|
-
Example:
|
|
99
|
-
```json
|
|
100
|
-
=======
|
|
101
|
-
n8n-nodes-civicrm
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
3. Approve installation and enable Community Nodes.
|
|
105
|
-
|
|
106
41
|
## 🔐 Credentials
|
|
107
42
|
|
|
108
43
|
The node uses **Bearer Token Authentication**.
|
|
@@ -114,6 +49,8 @@ The node uses **Bearer Token Authentication**.
|
|
|
114
49
|
|
|
115
50
|
After entering credentials, click **Save** to validate the connection.
|
|
116
51
|
|
|
52
|
+
---
|
|
53
|
+
|
|
117
54
|
## 📦 Supported Entities
|
|
118
55
|
|
|
119
56
|
The node includes full API v4 support for the following entities:
|
|
@@ -127,6 +64,8 @@ The node includes full API v4 support for the following entities:
|
|
|
127
64
|
| **Activity** | get, getMany, create, update, delete |
|
|
128
65
|
| **Custom API Call** | full custom API4 request |
|
|
129
66
|
|
|
67
|
+
---
|
|
68
|
+
|
|
130
69
|
## 🧩 Key Features
|
|
131
70
|
|
|
132
71
|
### **1. Dynamic Field Mapping**
|
|
@@ -170,8 +109,8 @@ Accepted input formats:
|
|
|
170
109
|
Auto-normalized to `YYYY-MM-DD`.
|
|
171
110
|
|
|
172
111
|
### **5. GET MANY with JSON Filters**
|
|
173
|
-
|
|
174
|
-
|
|
112
|
+
Example:
|
|
113
|
+
```json
|
|
175
114
|
[
|
|
176
115
|
["first_name", "LIKE", "Ju%"],
|
|
177
116
|
["birth_date", ">", "1990-01-01"],
|
|
@@ -179,24 +118,9 @@ Auto-normalized to `YYYY-MM-DD`.
|
|
|
179
118
|
]
|
|
180
119
|
```
|
|
181
120
|
|
|
182
|
-
|
|
183
|
-
### Birth date normalization
|
|
184
|
-
Accepted input formats:
|
|
185
|
-
- YYYY-MM-DD
|
|
186
|
-
- DD/MM/YYYY
|
|
187
|
-
- DD-MM-YYYY
|
|
188
|
-
- YYYY/MM/DD
|
|
189
|
-
- YYYY.MM.DD
|
|
190
|
-
|
|
191
|
-
Normalized to `YYYY-MM-DD`.
|
|
192
|
-
|
|
193
|
-
### Custom API Call
|
|
121
|
+
### **6. Custom API Call Mode**
|
|
194
122
|
Example:
|
|
195
123
|
```json
|
|
196
|
-
=======
|
|
197
|
-
### **6. Custom API Call Mode**
|
|
198
|
-
```
|
|
199
|
-
>>>>>>> 03f29e40d265531031a602d4bdcf4724e39bd809
|
|
200
124
|
{
|
|
201
125
|
"entity": "Contact",
|
|
202
126
|
"action": "get",
|
|
@@ -204,7 +128,6 @@ Example:
|
|
|
204
128
|
}
|
|
205
129
|
```
|
|
206
130
|
|
|
207
|
-
<<<<<<< HEAD
|
|
208
131
|
---
|
|
209
132
|
|
|
210
133
|
## Compatibility
|
|
@@ -219,14 +142,14 @@ Example:
|
|
|
219
142
|
|
|
220
143
|
Clone the repository and run:
|
|
221
144
|
|
|
222
|
-
```
|
|
145
|
+
```bash
|
|
223
146
|
npm install
|
|
224
147
|
npm run dev
|
|
225
148
|
```
|
|
226
149
|
|
|
227
150
|
Build:
|
|
228
151
|
|
|
229
|
-
```
|
|
152
|
+
```bash
|
|
230
153
|
npm run build
|
|
231
154
|
```
|
|
232
155
|
|
|
@@ -238,20 +161,13 @@ Pull requests and issues are welcome in the GitHub repository.
|
|
|
238
161
|
|
|
239
162
|
---
|
|
240
163
|
|
|
241
|
-
## About Ixiam Global Solutions
|
|
242
|
-
Website: https://www.ixiam.com
|
|
243
|
-
Email: info@ixiam.com
|
|
244
|
-
|
|
245
|
-
---
|
|
246
|
-
|
|
247
|
-
## License
|
|
248
|
-
=======
|
|
249
164
|
## 🧑💻 About Ixiam Global Solutions
|
|
250
165
|
|
|
251
166
|
Website: **https://www.ixiam.com**
|
|
252
167
|
Contact: **info@ixiam.com**
|
|
253
168
|
|
|
169
|
+
---
|
|
170
|
+
|
|
254
171
|
## 📄 License
|
|
255
|
-
>>>>>>> 03f29e40d265531031a602d4bdcf4724e39bd809
|
|
256
172
|
|
|
257
173
|
MIT License
|
|
@@ -6,30 +6,6 @@ class CiviCrmApi {
|
|
|
6
6
|
this.name = 'civiCrmApi';
|
|
7
7
|
this.displayName = 'CiviCRM API';
|
|
8
8
|
this.documentationUrl = 'https://docs.civicrm.org/dev/en/latest/api/';
|
|
9
|
-
this.authenticate = {
|
|
10
|
-
type: 'generic',
|
|
11
|
-
properties: {
|
|
12
|
-
headers: {
|
|
13
|
-
'X-Civi-Auth': '={{"Bearer " + $credentials.apiToken}}',
|
|
14
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
// Credential test button
|
|
19
|
-
this.test = {
|
|
20
|
-
request: {
|
|
21
|
-
method: 'POST',
|
|
22
|
-
url: '={{$credentials.baseUrl.replace(/\\/$/, "")}}/civicrm/ajax/api4/Contact/get',
|
|
23
|
-
headers: {
|
|
24
|
-
'X-Civi-Auth': '={{"Bearer " + $credentials.apiToken}}',
|
|
25
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
26
|
-
},
|
|
27
|
-
body: {
|
|
28
|
-
params: '={"limit":1}', // API4 compatible
|
|
29
|
-
},
|
|
30
|
-
json: true,
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
9
|
this.properties = [
|
|
34
10
|
{
|
|
35
11
|
displayName: 'Base URL',
|
|
@@ -37,8 +13,6 @@ class CiviCrmApi {
|
|
|
37
13
|
type: 'string',
|
|
38
14
|
default: '',
|
|
39
15
|
required: true,
|
|
40
|
-
placeholder: 'https://crm.example.org',
|
|
41
|
-
description: 'Base URL without a trailing slash.',
|
|
42
16
|
},
|
|
43
17
|
{
|
|
44
18
|
displayName: 'API Token',
|
|
@@ -47,9 +21,26 @@ class CiviCrmApi {
|
|
|
47
21
|
typeOptions: { password: true },
|
|
48
22
|
default: '',
|
|
49
23
|
required: true,
|
|
50
|
-
description: 'Sent as "X-Civi-Auth: Bearer <token>"',
|
|
51
24
|
},
|
|
52
25
|
];
|
|
26
|
+
this.authenticate = {
|
|
27
|
+
type: 'generic',
|
|
28
|
+
properties: {
|
|
29
|
+
headers: {
|
|
30
|
+
'X-Civi-Auth': '={{ "Bearer " + $credentials.apiToken }}',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
this.test = {
|
|
35
|
+
request: {
|
|
36
|
+
url: '={{ $credentials.baseUrl }}/civicrm/ajax/api4/Contact/get',
|
|
37
|
+
method: 'POST',
|
|
38
|
+
body: {
|
|
39
|
+
limit: 1,
|
|
40
|
+
select: ['id']
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
53
44
|
}
|
|
54
45
|
}
|
|
55
46
|
exports.CiviCrmApi = CiviCrmApi;
|
|
@@ -29,7 +29,7 @@ async function getLocationTypeMap() {
|
|
|
29
29
|
limit: 0,
|
|
30
30
|
});
|
|
31
31
|
const map = {};
|
|
32
|
-
const values = (res
|
|
32
|
+
const values = ((res === null || res === void 0 ? void 0 : res.values) || []);
|
|
33
33
|
for (const v of values) {
|
|
34
34
|
const name = v.name || '';
|
|
35
35
|
const label = v.label || '';
|
|
@@ -169,7 +169,7 @@ class CiviCrm {
|
|
|
169
169
|
body: { params: JSON.stringify({ limit: 50, select: ['id', 'label'] }) },
|
|
170
170
|
json: true,
|
|
171
171
|
});
|
|
172
|
-
const values = (res
|
|
172
|
+
const values = ((res === null || res === void 0 ? void 0 : res.values) || []);
|
|
173
173
|
return values.map((v) => ({
|
|
174
174
|
name: v.label,
|
|
175
175
|
value: v.id,
|
|
@@ -182,6 +182,7 @@ class CiviCrm {
|
|
|
182
182
|
EXECUTE
|
|
183
183
|
============================================================================ */
|
|
184
184
|
async execute() {
|
|
185
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
185
186
|
const items = this.getInputData();
|
|
186
187
|
const out = [];
|
|
187
188
|
const resource = this.getNodeParameter('resource', 0);
|
|
@@ -226,7 +227,7 @@ class CiviCrm {
|
|
|
226
227
|
select: ['id', 'name', 'title', 'subject', 'display_name'],
|
|
227
228
|
};
|
|
228
229
|
const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, params);
|
|
229
|
-
out.push({ json: res
|
|
230
|
+
out.push({ json: (_b = (_a = res === null || res === void 0 ? void 0 : res.values) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : {} });
|
|
230
231
|
continue;
|
|
231
232
|
}
|
|
232
233
|
/* ======================================================
|
|
@@ -241,7 +242,7 @@ class CiviCrm {
|
|
|
241
242
|
try {
|
|
242
243
|
where = JSON.parse(whereJson);
|
|
243
244
|
}
|
|
244
|
-
catch {
|
|
245
|
+
catch (error) {
|
|
245
246
|
throw new Error('Invalid JSON in whereJson');
|
|
246
247
|
}
|
|
247
248
|
}
|
|
@@ -276,19 +277,23 @@ class CiviCrm {
|
|
|
276
277
|
if (returnAll) {
|
|
277
278
|
let offset = 0;
|
|
278
279
|
const page = 500;
|
|
279
|
-
|
|
280
|
+
let hasMore = true;
|
|
281
|
+
while (hasMore) {
|
|
280
282
|
const r = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...params, limit: page, offset });
|
|
281
|
-
const vals = r
|
|
283
|
+
const vals = (_c = r === null || r === void 0 ? void 0 : r.values) !== null && _c !== void 0 ? _c : [];
|
|
282
284
|
for (const v of vals)
|
|
283
285
|
out.push({ json: v });
|
|
284
|
-
if (vals.length < page)
|
|
285
|
-
|
|
286
|
-
|
|
286
|
+
if (vals.length < page) {
|
|
287
|
+
hasMore = false;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
offset += page;
|
|
291
|
+
}
|
|
287
292
|
}
|
|
288
293
|
}
|
|
289
294
|
else {
|
|
290
295
|
const r = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...params, limit });
|
|
291
|
-
const vals = r
|
|
296
|
+
const vals = (_d = r === null || r === void 0 ? void 0 : r.values) !== null && _d !== void 0 ? _d : [];
|
|
292
297
|
for (const v of vals)
|
|
293
298
|
out.push({ json: v });
|
|
294
299
|
}
|
|
@@ -322,31 +327,6 @@ class CiviCrm {
|
|
|
322
327
|
const emailData = {};
|
|
323
328
|
const phoneData = {};
|
|
324
329
|
const addressData = {};
|
|
325
|
-
function normalizeBirthDate(input) {
|
|
326
|
-
if (!input)
|
|
327
|
-
return input;
|
|
328
|
-
let v = input.trim();
|
|
329
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(v)) {
|
|
330
|
-
}
|
|
331
|
-
else if (/^\d{2}\/\d{2}\/\d{4}$/.test(v)) {
|
|
332
|
-
const [d, m, y] = v.split('/');
|
|
333
|
-
v = `${y}-${m}-${d}`;
|
|
334
|
-
}
|
|
335
|
-
else if (/^\d{2}-\d{2}-\d{4}$/.test(v)) {
|
|
336
|
-
const [d, m, y] = v.split('-');
|
|
337
|
-
v = `${y}-${m}-${d}`;
|
|
338
|
-
}
|
|
339
|
-
else if (/^\d{4}\/\d{2}\/\d{2}$/.test(v)) {
|
|
340
|
-
v = v.replace(/\//g, '-');
|
|
341
|
-
}
|
|
342
|
-
else if (/^\d{4}\.\d{2}\.\d{2}$/.test(v)) {
|
|
343
|
-
v = v.replace(/\./g, '-');
|
|
344
|
-
}
|
|
345
|
-
const dt = new Date(v);
|
|
346
|
-
if (isNaN(dt.getTime()))
|
|
347
|
-
throw new Error(`Invalid birth_date: ${input}`);
|
|
348
|
-
return v;
|
|
349
|
-
}
|
|
350
330
|
let locationTypeMap = {};
|
|
351
331
|
if (resource === 'contact') {
|
|
352
332
|
locationTypeMap = await getLocationTypeMap.call(this);
|
|
@@ -440,7 +420,7 @@ class CiviCrm {
|
|
|
440
420
|
let contactId = id;
|
|
441
421
|
if (isCreate) {
|
|
442
422
|
const r = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Contact/create', { values });
|
|
443
|
-
contactId = r
|
|
423
|
+
contactId = (_f = (_e = r === null || r === void 0 ? void 0 : r.values) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.id;
|
|
444
424
|
if (!contactId)
|
|
445
425
|
throw new Error('Failed to create contact.');
|
|
446
426
|
}
|
|
@@ -526,7 +506,7 @@ class CiviCrm {
|
|
|
526
506
|
}
|
|
527
507
|
: {}),
|
|
528
508
|
});
|
|
529
|
-
out.push({ json: res
|
|
509
|
+
out.push({ json: (_h = (_g = res === null || res === void 0 ? void 0 : res.values) === null || _g === void 0 ? void 0 : _g[0]) !== null && _h !== void 0 ? _h : {} });
|
|
530
510
|
}
|
|
531
511
|
return [out];
|
|
532
512
|
}
|
|
@@ -536,7 +516,7 @@ exports.CiviCrm = CiviCrm;
|
|
|
536
516
|
UTILS
|
|
537
517
|
============================================================================ */
|
|
538
518
|
function convertValue(val) {
|
|
539
|
-
const t = String(val
|
|
519
|
+
const t = String(val !== null && val !== void 0 ? val : '').trim();
|
|
540
520
|
if (t === '')
|
|
541
521
|
return '';
|
|
542
522
|
if (t === 'true')
|
|
@@ -550,7 +530,35 @@ function convertValue(val) {
|
|
|
550
530
|
if (typeof j === 'object')
|
|
551
531
|
return j;
|
|
552
532
|
}
|
|
553
|
-
catch {
|
|
533
|
+
catch (error) {
|
|
534
|
+
// Not valid JSON, return original value
|
|
535
|
+
}
|
|
554
536
|
return val;
|
|
555
537
|
}
|
|
538
|
+
function normalizeBirthDate(input) {
|
|
539
|
+
if (!input)
|
|
540
|
+
return input;
|
|
541
|
+
let v = input.trim();
|
|
542
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(v)) {
|
|
543
|
+
// Already in correct format
|
|
544
|
+
}
|
|
545
|
+
else if (/^\d{2}\/\d{2}\/\d{4}$/.test(v)) {
|
|
546
|
+
const [d, m, y] = v.split('/');
|
|
547
|
+
v = `${y}-${m}-${d}`;
|
|
548
|
+
}
|
|
549
|
+
else if (/^\d{2}-\d{2}-\d{4}$/.test(v)) {
|
|
550
|
+
const [d, m, y] = v.split('-');
|
|
551
|
+
v = `${y}-${m}-${d}`;
|
|
552
|
+
}
|
|
553
|
+
else if (/^\d{4}\/\d{2}\/\d{2}$/.test(v)) {
|
|
554
|
+
v = v.replace(/\//g, '-');
|
|
555
|
+
}
|
|
556
|
+
else if (/^\d{4}\.\d{2}\.\d{2}$/.test(v)) {
|
|
557
|
+
v = v.replace(/\./g, '-');
|
|
558
|
+
}
|
|
559
|
+
const dt = new Date(v);
|
|
560
|
+
if (isNaN(dt.getTime()))
|
|
561
|
+
throw new Error(`Invalid birth_date: ${input}`);
|
|
562
|
+
return v;
|
|
563
|
+
}
|
|
556
564
|
exports.default = CiviCrm;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.civicrmApiRequest = civicrmApiRequest;
|
|
4
|
+
exports.api4 = api4;
|
|
4
5
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
6
|
/**
|
|
6
7
|
* Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
|
|
7
8
|
* Usa form-urlencoded con el campo "params" serializado
|
|
8
9
|
*/
|
|
9
10
|
async function civicrmApiRequest(method, path, body) {
|
|
11
|
+
var _a;
|
|
10
12
|
const { baseUrl, apiToken } = (await this.getCredentials('civiCrmApi'));
|
|
11
13
|
const options = {
|
|
12
14
|
method,
|
|
@@ -17,7 +19,7 @@ async function civicrmApiRequest(method, path, body) {
|
|
|
17
19
|
},
|
|
18
20
|
// cuerpo plano como espera Civi-Go
|
|
19
21
|
body: {
|
|
20
|
-
params: JSON.stringify(body.params
|
|
22
|
+
params: JSON.stringify((_a = body.params) !== null && _a !== void 0 ? _a : body),
|
|
21
23
|
},
|
|
22
24
|
json: true,
|
|
23
25
|
};
|
|
@@ -29,7 +31,6 @@ async function civicrmApiRequest(method, path, body) {
|
|
|
29
31
|
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
|
-
exports.civicrmApiRequest = civicrmApiRequest;
|
|
33
34
|
/**
|
|
34
35
|
* Devuelve el cuerpo estándar para las llamadas API4 (plano)
|
|
35
36
|
*/
|
|
@@ -37,4 +38,3 @@ function api4(entity, action, params = {}) {
|
|
|
37
38
|
// devolvemos los parámetros planos, no anidados
|
|
38
39
|
return params;
|
|
39
40
|
}
|
|
40
|
-
exports.api4 = api4;
|
package/package.json
CHANGED
|
@@ -1,126 +1,63 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
2
|
"name": "@ixiam/n8n-nodes-civicrm",
|
|
4
|
-
|
|
5
|
-
"version": "1.1.19",
|
|
6
|
-
|
|
3
|
+
"version": "1.1.23",
|
|
7
4
|
"description": "Full-featured CiviCRM API v4 integration for n8n with support for Contacts, Memberships, Groups, Relationships, Activities and structured sub-entities like Email, Phone, and Address.",
|
|
8
|
-
|
|
9
5
|
"license": "MIT",
|
|
10
|
-
|
|
11
6
|
"keywords": [
|
|
12
|
-
|
|
13
7
|
"n8n-community-node-package",
|
|
14
|
-
|
|
15
8
|
"civicrm",
|
|
16
|
-
|
|
17
9
|
"api4",
|
|
18
|
-
|
|
19
10
|
"crm",
|
|
20
|
-
|
|
21
11
|
"automation"
|
|
22
|
-
|
|
23
12
|
],
|
|
24
|
-
|
|
25
13
|
"main": "dist/index.js",
|
|
26
|
-
|
|
27
14
|
"types": "dist/index.d.ts",
|
|
28
|
-
|
|
29
15
|
"scripts": {
|
|
30
|
-
|
|
31
16
|
"dev": "n8n-node dev",
|
|
32
|
-
|
|
33
17
|
"build": "n8n-node build && pnpm run copy:assets",
|
|
34
|
-
|
|
35
18
|
"copy:assets": "cp src/nodes/CiviCrm/civicrm.svg dist/nodes/CiviCrm/",
|
|
36
|
-
|
|
37
19
|
"lint": "n8n-node lint",
|
|
38
|
-
|
|
39
20
|
"release": "n8n-node release",
|
|
40
|
-
|
|
41
21
|
"test": "npm run build"
|
|
42
|
-
|
|
43
22
|
},
|
|
44
|
-
|
|
45
23
|
"repository": {
|
|
46
|
-
|
|
47
24
|
"type": "git",
|
|
48
|
-
|
|
49
25
|
"url": "git+https://github.com/ixiam/n8n-nodes-civicrm.git"
|
|
50
|
-
|
|
51
26
|
},
|
|
52
|
-
|
|
53
27
|
"homepage": "https://www.ixiam.com",
|
|
54
|
-
|
|
55
28
|
"bugs": {
|
|
56
|
-
|
|
57
29
|
"url": "https://github.com/ixiam/n8n-nodes-civicrm/issues"
|
|
58
|
-
|
|
59
30
|
},
|
|
60
|
-
|
|
61
31
|
"author": "Julian Reartes <j.reartes@ixiam.com>",
|
|
62
|
-
|
|
63
32
|
"engines": {
|
|
64
|
-
|
|
65
33
|
"node": ">=18"
|
|
66
|
-
|
|
67
34
|
},
|
|
68
|
-
|
|
69
35
|
"n8n": {
|
|
70
|
-
|
|
71
36
|
"nodes": [
|
|
72
|
-
|
|
73
37
|
"dist/nodes/CiviCrm/CiviCrm.node.js"
|
|
74
|
-
|
|
75
38
|
],
|
|
76
|
-
|
|
77
39
|
"credentials": [
|
|
78
|
-
|
|
79
40
|
"dist/credentials/CiviCrmApi.credentials.js"
|
|
80
|
-
|
|
81
41
|
]
|
|
82
|
-
|
|
83
42
|
},
|
|
84
|
-
|
|
85
43
|
"devDependencies": {
|
|
86
|
-
|
|
87
44
|
"@n8n/node-cli": "0.16.0",
|
|
88
|
-
|
|
89
45
|
"@types/node": "^20.11.30",
|
|
90
|
-
|
|
91
46
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
92
|
-
|
|
93
47
|
"@typescript-eslint/parser": "^7.0.0",
|
|
94
|
-
|
|
95
48
|
"eslint": "8.57.0",
|
|
96
|
-
|
|
97
49
|
"eslint-plugin-n8n-nodes-base": "1.16.4",
|
|
98
|
-
|
|
99
50
|
"n8n-core": "^1.0.0",
|
|
100
|
-
|
|
101
51
|
"n8n-workflow": "^1.0.0",
|
|
102
|
-
|
|
103
52
|
"typescript": "^5.0.0"
|
|
104
|
-
|
|
105
53
|
},
|
|
106
|
-
|
|
107
54
|
"pnpm": {
|
|
108
|
-
|
|
109
55
|
"overrides": {
|
|
110
|
-
|
|
111
56
|
"eslint": "8.57.0",
|
|
112
|
-
|
|
113
57
|
"@typescript-eslint/parser": "6.21.0",
|
|
114
|
-
|
|
115
58
|
"@typescript-eslint/eslint-plugin": "6.21.0",
|
|
116
|
-
|
|
117
59
|
"change-case": "4.1.2"
|
|
118
|
-
|
|
119
60
|
}
|
|
120
|
-
|
|
121
61
|
},
|
|
122
|
-
|
|
123
62
|
"packageManager": "pnpm@10.18.2+sha512.9fb969fa749b3ade6035e0f109f0b8a60b5d08a1a87fdf72e337da90dcc93336e2280ca4e44f2358a649b83c17959e9993e777c2080879f3801e6f0d999ad3dd"
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
63
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Reload Node in Docker n8n
|
|
2
|
+
|
|
3
|
+
If you're loading this node from a local folder in Docker and seeing cached/old versions, try these steps:
|
|
4
|
+
|
|
5
|
+
## Option 1: Restart Docker Container (Quick)
|
|
6
|
+
```bash
|
|
7
|
+
# Restart your n8n container
|
|
8
|
+
docker restart <container-name>
|
|
9
|
+
# or if using docker-compose
|
|
10
|
+
docker-compose restart
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Option 2: Clear n8n Cache (Better)
|
|
14
|
+
```bash
|
|
15
|
+
# Stop the container
|
|
16
|
+
docker stop <container-name>
|
|
17
|
+
|
|
18
|
+
# Remove the container (keeps volumes)
|
|
19
|
+
docker rm <container-name>
|
|
20
|
+
|
|
21
|
+
# Start fresh
|
|
22
|
+
docker-compose up -d
|
|
23
|
+
# or your docker run command
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Option 3: Verify Volume Mount
|
|
27
|
+
If you're using a volume mount like `-v /path/to/n8n-nodes-civicrm:/data/custom-nodes/n8n-nodes-civicrm`:
|
|
28
|
+
|
|
29
|
+
1. Make sure the path points to THIS directory
|
|
30
|
+
2. Verify the dist folder is being mounted:
|
|
31
|
+
```bash
|
|
32
|
+
docker exec <container-name> ls -la /data/custom-nodes/n8n-nodes-civicrm/dist/credentials/
|
|
33
|
+
docker exec <container-name> cat /data/custom-nodes/n8n-nodes-civicrm/dist/credentials/CiviCrmApi.credentials.js | grep baseURL
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Option 4: Check n8n Custom Nodes Path
|
|
37
|
+
If using `N8N_CUSTOM_EXTENSION_ENV` environment variable:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Check what path n8n is using
|
|
41
|
+
docker exec <container-name> env | grep N8N_CUSTOM
|
|
42
|
+
|
|
43
|
+
# Verify the file exists in that path
|
|
44
|
+
docker exec <container-name> ls -la <custom-path>/dist/credentials/
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Option 5: Force Rebuild and Reload
|
|
48
|
+
```bash
|
|
49
|
+
# In this directory, clean and rebuild
|
|
50
|
+
npm run build
|
|
51
|
+
|
|
52
|
+
# If using npm link
|
|
53
|
+
npm link
|
|
54
|
+
|
|
55
|
+
# Then restart n8n container
|
|
56
|
+
docker restart <container-name>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Verify the Fix
|
|
60
|
+
After restarting, check if the error is gone. The built file should have:
|
|
61
|
+
```javascript
|
|
62
|
+
baseURL: '={{ $credentials.baseUrl }}',
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
NOT:
|
|
66
|
+
```javascript
|
|
67
|
+
baseURL: '={{ $credentials.baseUrl.replace(/\\/$/, "") }}',
|
|
68
|
+
```
|