n8n-nodes-mautic-advanced 1.2.0 → 1.3.0

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.
@@ -14,25 +14,6 @@ class MauticAdvancedApi {
14
14
  default: '',
15
15
  placeholder: 'https://name.mautic.net',
16
16
  },
17
- {
18
- displayName: 'Mautic Version',
19
- name: 'mauticVersion',
20
- type: 'options',
21
- default: 'v6',
22
- options: [
23
- {
24
- name: 'v6 or lower',
25
- value: 'v6',
26
- description: 'Use legacy v1 API endpoints.',
27
- },
28
- {
29
- name: 'v7 or higher',
30
- value: 'v7',
31
- description: 'Use v2 API endpoints where available.',
32
- },
33
- ],
34
- description: 'Select the major Mautic version of this instance so the node can route API calls correctly.',
35
- },
36
17
  {
37
18
  displayName: 'Username',
38
19
  name: 'username',
@@ -21,25 +21,6 @@ class MauticAdvancedOAuth2Api {
21
21
  default: '',
22
22
  placeholder: 'https://name.mautic.net',
23
23
  },
24
- {
25
- displayName: 'Mautic Version',
26
- name: 'mauticVersion',
27
- type: 'options',
28
- default: 'v6',
29
- options: [
30
- {
31
- name: 'v6 or lower',
32
- value: 'v6',
33
- description: 'Use legacy v1 API endpoints.',
34
- },
35
- {
36
- name: 'v7 or higher',
37
- value: 'v7',
38
- description: 'Use v2 API endpoints where available.',
39
- },
40
- ],
41
- description: 'Select the major Mautic version of this instance so the node can route API calls correctly.',
42
- },
43
24
  {
44
25
  displayName: 'Authorization URL',
45
26
  name: 'authUrl',
@@ -226,6 +226,16 @@ exports.companyFields = [
226
226
  type: 'number',
227
227
  default: 0,
228
228
  },
229
+ {
230
+ displayName: 'Owner Name or ID',
231
+ name: 'owner',
232
+ type: 'options',
233
+ description: 'User to assign as company owner. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
234
+ typeOptions: {
235
+ loadOptionsMethod: 'getOwners',
236
+ },
237
+ default: '',
238
+ },
229
239
  {
230
240
  displayName: 'Overwrite With Blank',
231
241
  name: 'overwriteWithBlank',
@@ -431,6 +441,16 @@ exports.companyFields = [
431
441
  type: 'number',
432
442
  default: 0,
433
443
  },
444
+ {
445
+ displayName: 'Owner Name or ID',
446
+ name: 'owner',
447
+ type: 'options',
448
+ description: 'User to assign as company owner. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
449
+ typeOptions: {
450
+ loadOptionsMethod: 'getOwners',
451
+ },
452
+ default: '',
453
+ },
434
454
  {
435
455
  displayName: 'Overwrite With Blank',
436
456
  name: 'overwriteWithBlank',
@@ -446,11 +446,14 @@ exports.contactFields = [
446
446
  default: '',
447
447
  },
448
448
  {
449
- displayName: 'Owner ID',
450
- name: 'ownerId',
451
- type: 'string',
449
+ displayName: 'Owner Name or ID',
450
+ name: 'owner',
451
+ type: 'options',
452
+ description: 'User to assign as contact owner. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
453
+ typeOptions: {
454
+ loadOptionsMethod: 'getOwners',
455
+ },
452
456
  default: '',
453
- description: 'ID of a Mautic user to assign this contact to',
454
457
  },
455
458
  {
456
459
  displayName: 'Phone',
@@ -1002,16 +1005,19 @@ exports.contactFields = [
1002
1005
  default: '',
1003
1006
  },
1004
1007
  {
1005
- displayName: 'Owner ID',
1006
- name: 'ownerId',
1007
- type: 'string',
1008
+ displayName: 'Owner Name or ID',
1009
+ name: 'owner',
1010
+ type: 'options',
1011
+ description: 'User to assign as contact owner. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
1012
+ typeOptions: {
1013
+ loadOptionsMethod: 'getOwners',
1014
+ },
1008
1015
  displayOptions: {
1009
1016
  show: {
1010
1017
  '/jsonParameters': [false],
1011
1018
  },
1012
1019
  },
1013
1020
  default: '',
1014
- description: 'ID of a Mautic user to assign this contact to',
1015
1021
  },
1016
1022
  {
1017
1023
  displayName: 'Phone',
@@ -1,8 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateJSON = exports.serialiseMauticWhere = exports.mauticApiRequestAllItems = exports.DEFAULT_MAUTIC_PAGE_SIZE = exports.mauticApiRequest = void 0;
3
+ exports.validateJSON = exports.serialiseMauticWhere = exports.mauticApiRequestAllItems = exports.DEFAULT_MAUTIC_PAGE_SIZE = exports.mauticApiRequest = exports.getMauticVersion = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  const authenticatedRequest_1 = require("./utils/authenticatedRequest");
6
+ const versionCache = new Map();
7
+ const VERSION_CACHE_TTL_MS = 5 * 60 * 1000;
8
+ function normalizeInstanceUrl(raw) {
9
+ const trimmed = raw.trim();
10
+ if (!trimmed)
11
+ return '';
12
+ try {
13
+ const u = new URL(trimmed);
14
+ u.protocol = u.protocol.toLowerCase();
15
+ u.hostname = u.hostname.toLowerCase();
16
+ u.hash = '';
17
+ u.search = '';
18
+ u.pathname = u.pathname.replace(/\/+$/, '');
19
+ return u.toString().replace(/\/+$/, '');
20
+ }
21
+ catch {
22
+ return trimmed.replace(/\/+$/, '');
23
+ }
24
+ }
25
+ async function getMauticVersion(context) {
26
+ const authMethod = context.getNodeParameter('authentication', 0, 'credentials');
27
+ const credentialType = authMethod === 'credentials' ? 'mauticAdvancedApi' : 'mauticAdvancedOAuth2Api';
28
+ const credentials = await context.getCredentials(credentialType);
29
+ const baseUrl = normalizeInstanceUrl(credentials.url || '');
30
+ const cacheKey = `${credentialType}:${baseUrl}`;
31
+ const cached = versionCache.get(cacheKey);
32
+ if (cached && Date.now() < cached.expiresAt) {
33
+ return cached.version;
34
+ }
35
+ let version;
36
+ try {
37
+ await mauticApiRequest.call(context, 'GET', '/v2/companies', {}, { page: 1 }, undefined, {
38
+ Accept: 'application/json',
39
+ });
40
+ version = 'v7';
41
+ }
42
+ catch (error) {
43
+ // 403 = v2 route exists but no permission → still v7; 404 = route absent → v6
44
+ version = error?.httpCode === '403' ? 'v7' : 'v6';
45
+ }
46
+ versionCache.set(cacheKey, { version, expiresAt: Date.now() + VERSION_CACHE_TTL_MS });
47
+ return version;
48
+ }
49
+ exports.getMauticVersion = getMauticVersion;
6
50
  async function mauticApiRequest(method, endpoint, body = {}, query, uri, headers) {
7
51
  const authenticationMethod = this.getNodeParameter('authentication', 0, 'credentials');
8
52
  const options = {
@@ -17,7 +61,7 @@ async function mauticApiRequest(method, endpoint, body = {}, query, uri, headers
17
61
  }
18
62
  try {
19
63
  const returnData = await (0, authenticatedRequest_1.requestMauticAuthenticated)(this, authenticationMethod, options);
20
- if (returnData.errors) {
64
+ if (returnData?.errors) {
21
65
  // They seem to sometimes return 200 status but still error.
22
66
  // Preserve the full error object including details for better error handling
23
67
  throw new n8n_workflow_1.NodeApiError(this.getNode(), returnData, {
@@ -390,15 +390,13 @@ class MauticAdvanced {
390
390
  // Get all the available owners (users) for filtering
391
391
  async getOwners() {
392
392
  const returnData = [];
393
- const response = await GenericFunctions_1.mauticApiRequest.call(this, 'GET', '/contacts/list/owners');
394
- const owners = response || [];
395
- for (const owner of owners) {
396
- returnData.push({
397
- name: `${owner.firstName || ''} ${owner.lastName || ''}`.trim() ||
398
- owner.username ||
399
- `User ${owner.id}`,
400
- value: owner.id,
401
- });
393
+ const response = await GenericFunctions_1.mauticApiRequest.call(this, 'GET', '/users');
394
+ const users = response?.users ? Object.values(response.users) : [];
395
+ for (const user of users) {
396
+ const fullName = `${user.firstName || ''} ${user.lastName || ''}`.trim();
397
+ const display = fullName || user.username || `User ${user.id}`;
398
+ const label = user.email ? `${display} (${user.email})` : display;
399
+ returnData.push({ name: label, value: user.id });
402
400
  }
403
401
  return returnData;
404
402
  },
@@ -69,13 +69,9 @@ function buildFilters(params) {
69
69
  async function apiRequest(context, method, endpoint, body = {}, query = {}) {
70
70
  return GenericFunctions_1.mauticApiRequest.call(context, method, endpoint, body, query);
71
71
  }
72
- // Detect mautic version from credentials
73
72
  async function getMauticVersionFromContext(context) {
74
73
  try {
75
- const authMethod = context.getNodeParameter('authentication', 0, 'credentials');
76
- const credName = authMethod === 'oAuth2' ? 'mauticAdvancedOAuth2Api' : 'mauticAdvancedApi';
77
- const credentials = await context.getCredentials(credName);
78
- return credentials.mauticVersion || 'v6';
74
+ return await (0, GenericFunctions_1.getMauticVersion)(context);
79
75
  }
80
76
  catch {
81
77
  return 'v6';
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.executeCompanyOperation = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  const ApiHelpers_1 = require("../utils/ApiHelpers");
6
+ const GenericFunctions_1 = require("../GenericFunctions");
6
7
  const DataHelpers_1 = require("../utils/DataHelpers");
7
8
  async function executeCompanyOperation(context, operation, i) {
8
9
  let responseData;
@@ -36,135 +37,311 @@ exports.executeCompanyOperation = executeCompanyOperation;
36
37
  async function createCompany(context, itemIndex) {
37
38
  const simple = (0, ApiHelpers_1.getOptionalParam)(context, 'simple', itemIndex, false);
38
39
  const name = (0, ApiHelpers_1.getRequiredParam)(context, 'name', itemIndex);
39
- const body = { companyname: name };
40
+ const mauticVersion = await (0, GenericFunctions_1.getMauticVersion)(context);
40
41
  const additionalFields = (0, ApiHelpers_1.getOptionalParam)(context, 'additionalFields', itemIndex, {});
41
- const { addressUi, customFieldsUi, companyEmail, fax, industry, numberOfEmployees, phone, website, annualRevenue, description, ...rest } = additionalFields;
42
- if (addressUi?.addressValues) {
43
- const { addressValues } = addressUi;
44
- body.companyaddress1 = addressValues.address1;
45
- body.companyaddress2 = addressValues.address2;
46
- body.companycity = addressValues.city;
47
- body.companystate = addressValues.state;
48
- body.companycountry = addressValues.country;
49
- body.companyzipcode = addressValues.zipCode;
50
- }
51
- if (companyEmail)
52
- body.companyemail = companyEmail;
53
- if (fax)
54
- body.companyfax = fax;
55
- if (industry)
56
- body.companyindustry = industry;
57
- if (numberOfEmployees)
58
- body.companynumber_of_employees = numberOfEmployees;
59
- if (phone)
60
- body.companyphone = phone;
61
- if (website)
62
- body.companywebsite = website;
63
- if (annualRevenue)
64
- body.companyannual_revenue = annualRevenue;
65
- if (description)
66
- body.companydescription = description;
42
+ const { addressUi, customFieldsUi, companyEmail, fax, industry, isPublished, numberOfEmployees, owner, phone, website, annualRevenue, description, ...rest } = additionalFields;
43
+ const body = {};
44
+ if (mauticVersion === 'v7') {
45
+ body.name = name;
46
+ if (addressUi?.addressValues) {
47
+ const { addressValues } = addressUi;
48
+ if (addressValues.address1)
49
+ body.address1 = addressValues.address1;
50
+ if (addressValues.address2)
51
+ body.address2 = addressValues.address2;
52
+ if (addressValues.city)
53
+ body.city = addressValues.city;
54
+ if (addressValues.state)
55
+ body.state = addressValues.state;
56
+ if (addressValues.country)
57
+ body.country = addressValues.country;
58
+ if (addressValues.zipCode)
59
+ body.zipcode = addressValues.zipCode;
60
+ }
61
+ if (companyEmail)
62
+ body.email = companyEmail;
63
+ if (industry)
64
+ body.industry = industry;
65
+ if (isPublished !== undefined)
66
+ body.isPublished = isPublished;
67
+ if (owner)
68
+ body.owner = `/api/v2/users/${owner}`;
69
+ if (phone)
70
+ body.phone = phone;
71
+ if (website)
72
+ body.website = website;
73
+ if (description)
74
+ body.description = description;
75
+ // fax, numberOfEmployees, annualRevenue not in v7 Company entity write group — omitted
76
+ }
77
+ else {
78
+ body.companyname = name;
79
+ if (addressUi?.addressValues) {
80
+ const { addressValues } = addressUi;
81
+ body.companyaddress1 = addressValues.address1;
82
+ body.companyaddress2 = addressValues.address2;
83
+ body.companycity = addressValues.city;
84
+ body.companystate = addressValues.state;
85
+ body.companycountry = addressValues.country;
86
+ body.companyzipcode = addressValues.zipCode;
87
+ }
88
+ if (companyEmail)
89
+ body.companyemail = companyEmail;
90
+ if (fax)
91
+ body.companyfax = fax;
92
+ if (industry)
93
+ body.companyindustry = industry;
94
+ if (numberOfEmployees)
95
+ body.companynumber_of_employees = numberOfEmployees;
96
+ if (owner)
97
+ body.owner = owner;
98
+ if (phone)
99
+ body.companyphone = phone;
100
+ if (website)
101
+ body.companywebsite = website;
102
+ if (annualRevenue)
103
+ body.companyannual_revenue = annualRevenue;
104
+ if (description)
105
+ body.companydescription = description;
106
+ }
67
107
  if (customFieldsUi?.customFieldValues) {
68
108
  const { customFieldValues } = customFieldsUi;
69
109
  const data = customFieldValues.reduce((obj, value) => Object.assign(obj, { [`${value.fieldId}`]: value.fieldValue }), {});
70
110
  Object.assign(body, data);
71
111
  }
72
- Object.assign(body, rest);
73
- const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'POST', '/companies/new', body);
74
- let result = response.company;
112
+ // v7 API Platform rejects unknown fields; rest only applies to v1
113
+ if (mauticVersion !== 'v7')
114
+ Object.assign(body, rest);
115
+ let result;
116
+ if (mauticVersion === 'v7') {
117
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'POST', '/v2/companies', body, {}, undefined, {
118
+ 'Content-Type': 'application/json',
119
+ Accept: 'application/json',
120
+ });
121
+ result = response;
122
+ }
123
+ else {
124
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'POST', '/companies/new', body);
125
+ result = response.company;
126
+ }
75
127
  if (simple) {
76
- result = result.fields.all;
128
+ result = toSimpleCompany(result);
77
129
  }
78
130
  return result;
79
131
  }
80
132
  async function updateCompany(context, itemIndex) {
81
133
  const companyId = (0, ApiHelpers_1.getRequiredParam)(context, 'companyId', itemIndex);
82
134
  const simple = (0, ApiHelpers_1.getOptionalParam)(context, 'simple', itemIndex, false);
135
+ const mauticVersion = await (0, GenericFunctions_1.getMauticVersion)(context);
83
136
  const body = {};
84
137
  const updateFields = (0, ApiHelpers_1.getOptionalParam)(context, 'updateFields', itemIndex, {});
85
- const { addressUi, customFieldsUi, companyEmail, name, fax, industry, numberOfEmployees, phone, website, annualRevenue, description, ...rest } = updateFields;
86
- if (addressUi?.addressValues) {
87
- const { addressValues } = addressUi;
88
- body.companyaddress1 = addressValues.address1;
89
- body.companyaddress2 = addressValues.address2;
90
- body.companycity = addressValues.city;
91
- body.companystate = addressValues.state;
92
- body.companycountry = addressValues.country;
93
- body.companyzipcode = addressValues.zipCode;
94
- }
95
- if (companyEmail)
96
- body.companyemail = companyEmail;
97
- if (name)
98
- body.companyname = name;
99
- if (fax)
100
- body.companyfax = fax;
101
- if (industry)
102
- body.companyindustry = industry;
103
- if (numberOfEmployees)
104
- body.companynumber_of_employees = numberOfEmployees;
105
- if (phone)
106
- body.companyphone = phone;
107
- if (website)
108
- body.companywebsite = website;
109
- if (annualRevenue)
110
- body.companyannual_revenue = annualRevenue;
111
- if (description)
112
- body.companydescription = description;
138
+ const { addressUi, customFieldsUi, companyEmail, name, fax, industry, isPublished, numberOfEmployees, owner, phone, website, annualRevenue, description, ...rest } = updateFields;
139
+ if (mauticVersion === 'v7') {
140
+ if (name)
141
+ body.name = name;
142
+ if (addressUi?.addressValues) {
143
+ const { addressValues } = addressUi;
144
+ if (addressValues.address1)
145
+ body.address1 = addressValues.address1;
146
+ if (addressValues.address2)
147
+ body.address2 = addressValues.address2;
148
+ if (addressValues.city)
149
+ body.city = addressValues.city;
150
+ if (addressValues.state)
151
+ body.state = addressValues.state;
152
+ if (addressValues.country)
153
+ body.country = addressValues.country;
154
+ if (addressValues.zipCode)
155
+ body.zipcode = addressValues.zipCode;
156
+ }
157
+ if (companyEmail)
158
+ body.email = companyEmail;
159
+ if (industry)
160
+ body.industry = industry;
161
+ if (isPublished !== undefined)
162
+ body.isPublished = isPublished;
163
+ if (owner)
164
+ body.owner = `/api/v2/users/${owner}`;
165
+ if (phone)
166
+ body.phone = phone;
167
+ if (website)
168
+ body.website = website;
169
+ if (description)
170
+ body.description = description;
171
+ // fax, numberOfEmployees, annualRevenue not in v7 Company entity write group — omitted
172
+ }
173
+ else {
174
+ if (name)
175
+ body.companyname = name;
176
+ if (addressUi?.addressValues) {
177
+ const { addressValues } = addressUi;
178
+ body.companyaddress1 = addressValues.address1;
179
+ body.companyaddress2 = addressValues.address2;
180
+ body.companycity = addressValues.city;
181
+ body.companystate = addressValues.state;
182
+ body.companycountry = addressValues.country;
183
+ body.companyzipcode = addressValues.zipCode;
184
+ }
185
+ if (companyEmail)
186
+ body.companyemail = companyEmail;
187
+ if (fax)
188
+ body.companyfax = fax;
189
+ if (industry)
190
+ body.companyindustry = industry;
191
+ if (numberOfEmployees)
192
+ body.companynumber_of_employees = numberOfEmployees;
193
+ if (owner)
194
+ body.owner = owner;
195
+ if (phone)
196
+ body.companyphone = phone;
197
+ if (website)
198
+ body.companywebsite = website;
199
+ if (annualRevenue)
200
+ body.companyannual_revenue = annualRevenue;
201
+ if (description)
202
+ body.companydescription = description;
203
+ }
113
204
  if (customFieldsUi?.customFieldValues) {
114
205
  const { customFieldValues } = customFieldsUi;
115
206
  const data = customFieldValues.reduce((obj, value) => Object.assign(obj, { [`${value.fieldId}`]: value.fieldValue }), {});
116
207
  Object.assign(body, data);
117
208
  }
118
- Object.assign(body, rest);
119
- const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'PATCH', `/companies/${companyId}/edit`, body);
120
- let result = response.company;
209
+ // v7 API Platform rejects unknown fields; rest only applies to v1
210
+ if (mauticVersion !== 'v7')
211
+ Object.assign(body, rest);
212
+ let result;
213
+ if (mauticVersion === 'v7') {
214
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'PATCH', `/v2/companies/${companyId}`, body, {}, undefined, { 'Content-Type': 'application/merge-patch+json', Accept: 'application/json' });
215
+ result = response;
216
+ }
217
+ else {
218
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'PATCH', `/companies/${companyId}/edit`, body);
219
+ result = response.company;
220
+ }
121
221
  if (simple) {
122
- result = result.fields.all;
222
+ result = toSimpleCompany(result);
123
223
  }
124
224
  return result;
125
225
  }
126
226
  async function getCompany(context, itemIndex) {
127
227
  const companyId = (0, ApiHelpers_1.getRequiredParam)(context, 'companyId', itemIndex);
128
228
  const simple = (0, ApiHelpers_1.getOptionalParam)(context, 'simple', itemIndex, false);
129
- const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', `/companies/${companyId}`);
130
- let result = response.company;
229
+ const mauticVersion = await (0, GenericFunctions_1.getMauticVersion)(context);
230
+ let result;
231
+ if (mauticVersion === 'v7') {
232
+ result = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', `/v2/companies/${companyId}`, {}, {}, undefined, {
233
+ Accept: 'application/json',
234
+ });
235
+ }
236
+ else {
237
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', `/companies/${companyId}`);
238
+ result = response.company;
239
+ }
131
240
  if (simple) {
132
- result = result.fields.all;
241
+ result = toSimpleCompany(result);
133
242
  }
134
- return (0, DataHelpers_1.convertNumericStrings)(result);
243
+ // v7 returns proper JSON types already; convertNumericStrings only needed for v1 string responses
244
+ return mauticVersion === 'v7' ? result : (0, DataHelpers_1.convertNumericStrings)(result);
135
245
  }
136
246
  async function getAllCompanies(context, itemIndex) {
137
247
  const returnAll = (0, ApiHelpers_1.getOptionalParam)(context, 'returnAll', itemIndex, false);
138
248
  const simple = (0, ApiHelpers_1.getOptionalParam)(context, 'simple', itemIndex, false);
139
- const additionalFields = (0, ApiHelpers_1.getOptionalParam)(context, 'additionalFields', itemIndex, {});
140
- const qs = (0, DataHelpers_1.buildQueryFromOptions)(additionalFields);
141
- if (!qs.orderBy)
142
- qs.orderBy = 'id';
143
- if (!qs.orderByDir)
144
- qs.orderByDir = 'asc';
249
+ const mauticVersion = await (0, GenericFunctions_1.getMauticVersion)(context);
145
250
  let responseData;
146
- if (returnAll) {
147
- const limit = (0, ApiHelpers_1.getOptionalParam)(context, 'limit', itemIndex, undefined);
148
- responseData = await (0, ApiHelpers_1.makePaginatedRequest)(context, 'companies', 'GET', '/companies', {}, qs, limit);
251
+ if (mauticVersion === 'v7') {
252
+ // v7: page-based pagination only (no start/limit/orderBy/search)
253
+ if (returnAll) {
254
+ const limit = (0, ApiHelpers_1.getOptionalParam)(context, 'limit', itemIndex, undefined);
255
+ const allItems = [];
256
+ let page = 1;
257
+ while (true) {
258
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', '/v2/companies', {}, { page }, undefined, { Accept: 'application/json' });
259
+ const pageItems = Array.isArray(response)
260
+ ? response
261
+ : (response?.['hydra:member'] ?? []);
262
+ if (!pageItems.length)
263
+ break;
264
+ allItems.push(...pageItems);
265
+ if (limit !== undefined && allItems.length >= limit)
266
+ break;
267
+ page++;
268
+ }
269
+ responseData = limit !== undefined ? allItems.slice(0, limit) : allItems;
270
+ }
271
+ else {
272
+ // page through until limit satisfied — v7 page size is fixed (~30), limit may exceed it
273
+ const limit = (0, ApiHelpers_1.getRequiredParam)(context, 'limit', itemIndex);
274
+ const allItems = [];
275
+ let page = 1;
276
+ while (allItems.length < limit) {
277
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', '/v2/companies', {}, { page }, undefined, { Accept: 'application/json' });
278
+ const pageItems = Array.isArray(response)
279
+ ? response
280
+ : (response?.['hydra:member'] ?? []);
281
+ if (!pageItems.length)
282
+ break;
283
+ allItems.push(...pageItems);
284
+ page++;
285
+ }
286
+ responseData = allItems.slice(0, limit);
287
+ }
149
288
  }
150
289
  else {
151
- const limit = (0, ApiHelpers_1.getRequiredParam)(context, 'limit', itemIndex);
152
- qs.limit = limit;
153
- const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', '/companies', {}, qs);
154
- responseData = (response.companies ? Object.values(response.companies) : []);
290
+ const additionalFields = (0, ApiHelpers_1.getOptionalParam)(context, 'additionalFields', itemIndex, {});
291
+ const qs = (0, DataHelpers_1.buildQueryFromOptions)(additionalFields);
292
+ if (!qs.orderBy)
293
+ qs.orderBy = 'id';
294
+ if (!qs.orderByDir)
295
+ qs.orderByDir = 'asc';
296
+ if (returnAll) {
297
+ const limit = (0, ApiHelpers_1.getOptionalParam)(context, 'limit', itemIndex, undefined);
298
+ responseData = await (0, ApiHelpers_1.makePaginatedRequest)(context, 'companies', 'GET', '/companies', {}, qs, limit);
299
+ }
300
+ else {
301
+ const limit = (0, ApiHelpers_1.getRequiredParam)(context, 'limit', itemIndex);
302
+ qs.limit = limit;
303
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', '/companies', {}, qs);
304
+ responseData = (response.companies ? Object.values(response.companies) : []);
305
+ }
155
306
  }
156
307
  if (simple) {
157
- responseData = responseData.map((item) => item.fields.all);
308
+ responseData = responseData.map((item) => toSimpleCompany(item));
158
309
  }
159
- return (0, DataHelpers_1.convertNumericStrings)(responseData);
310
+ // v7 returns proper JSON types already; convertNumericStrings only needed for v1 string responses
311
+ return mauticVersion === 'v7' ? responseData : (0, DataHelpers_1.convertNumericStrings)(responseData);
160
312
  }
161
313
  async function deleteCompany(context, itemIndex) {
162
314
  const simple = (0, ApiHelpers_1.getOptionalParam)(context, 'simple', itemIndex, false);
163
315
  const companyId = (0, ApiHelpers_1.getRequiredParam)(context, 'companyId', itemIndex);
316
+ const mauticVersion = await (0, GenericFunctions_1.getMauticVersion)(context);
317
+ if (mauticVersion === 'v7') {
318
+ // v7 DELETE returns 204 no body
319
+ await (0, ApiHelpers_1.makeApiRequest)(context, 'DELETE', `/v2/companies/${companyId}`, {}, {}, undefined, {
320
+ Accept: 'application/json',
321
+ });
322
+ return { id: Number(companyId) };
323
+ }
164
324
  const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'DELETE', `/companies/${companyId}/delete`);
165
325
  let result = response.company;
166
326
  if (simple) {
167
- result = result.fields.all;
327
+ result = toSimpleCompany(result);
168
328
  }
169
329
  return result;
170
330
  }
331
+ function toSimpleCompany(company) {
332
+ if (company?.fields?.all) {
333
+ // v1: fields nested under company.fields.all
334
+ return {
335
+ id: company.id,
336
+ owner: company.owner ?? null,
337
+ ...company.fields.all,
338
+ };
339
+ }
340
+ // v7: fields are at the top level; owner is a User object
341
+ const { id, owner, score, socialCache, dateAdded, dateModified, isPublished, ...fields } = company;
342
+ return {
343
+ id,
344
+ owner: owner ?? null,
345
+ ...fields,
346
+ };
347
+ }
@@ -660,7 +660,7 @@ async function getContactsWithDncFilter(context, qs, options, limit) {
660
660
  return contacts;
661
661
  }
662
662
  async function getContactOwners(context) {
663
- const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', '/contacts/list/owners');
663
+ const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'GET', '/users');
664
664
  return (0, DataHelpers_1.convertNumericStrings)(response);
665
665
  }
666
666
  async function getContactFields(context) {
@@ -3,18 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deleteTagV2 = exports.getAllTagsV2 = exports.getTagV2 = exports.updateTagV2 = exports.createTagV2 = exports.deleteTagV1 = exports.getAllTagsV1 = exports.getTagV1 = exports.updateTagV1 = exports.createTagV1 = exports.getMauticVersion = void 0;
4
4
  const ApiHelpers_1 = require("../utils/ApiHelpers");
5
5
  const DataHelpers_1 = require("../utils/DataHelpers");
6
- async function getMauticVersion(context) {
7
- const authenticationMethod = context.getNodeParameter('authentication', 0, 'credentials');
8
- if (authenticationMethod === 'credentials') {
9
- const credentials = await context.getCredentials('mauticAdvancedApi');
10
- const version = credentials.mauticVersion || 'v6';
11
- return version === 'v7' ? 'v7' : 'v6';
12
- }
13
- const credentials = await context.getCredentials('mauticAdvancedOAuth2Api');
14
- const version = credentials.mauticVersion || 'v6';
15
- return version === 'v7' ? 'v7' : 'v6';
16
- }
17
- exports.getMauticVersion = getMauticVersion;
6
+ const GenericFunctions_1 = require("../GenericFunctions");
7
+ Object.defineProperty(exports, "getMauticVersion", { enumerable: true, get: function () { return GenericFunctions_1.getMauticVersion; } });
18
8
  // -----------------------------
19
9
  // v1 tag helpers (legacy API)
20
10
  // -----------------------------
@@ -33,7 +33,12 @@ function processContactFields(responseData, options, fieldsToReturn) {
33
33
  }
34
34
  return sourceData;
35
35
  }
36
- const processedData = sourceData.map((item) => item.fields?.all || item);
36
+ const processedData = sourceData.map((item) => {
37
+ const all = item.fields?.all;
38
+ if (!all)
39
+ return item;
40
+ return { id: item.id, owner: item.owner ?? null, ...all };
41
+ });
37
42
  if (Array.isArray(filterFields) && filterFields.length > 0) {
38
43
  return processedData.map((item, index) => filterContactFields(item, sourceData[index], filterFields));
39
44
  }
@@ -30,9 +30,6 @@ function normalizeCredentialUrl(value) {
30
30
  return withoutTrailingSlashes(trimmed);
31
31
  }
32
32
  }
33
- function getMauticVersion(credentials) {
34
- return String(credentials.mauticVersion || 'v6');
35
- }
36
33
  function credentialRefPart(value) {
37
34
  if (typeof value === 'string' && value) {
38
35
  return value;
@@ -64,7 +61,6 @@ function getCacheKey(authenticationMethod, credentialType, credentialReference,
64
61
  credentialType,
65
62
  credentialReference,
66
63
  normalizeCredentialUrl(credentials.url),
67
- getMauticVersion(credentials),
68
64
  datasetKey,
69
65
  ]);
70
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-mautic-advanced",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Enhanced n8n node for Mautic with comprehensive API coverage including tags, campaigns, categories, and advanced contact management",
5
5
  "keywords": [
6
6
  "n8n",