@trg-admin/n8n-nodes-zoho-desk 0.1.17 → 0.1.20
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.
|
@@ -85,17 +85,25 @@ async function zohoDeskApiRequest(method, endpoint, body = {}, qs = {}, itemInde
|
|
|
85
85
|
async function zohoDeskApiRequestAllItems(method, endpoint, body = {}, qs = {}, itemIndex = 0) {
|
|
86
86
|
const returnData = [];
|
|
87
87
|
let responseData;
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const query = {
|
|
89
|
+
...qs,
|
|
90
|
+
limit: qs.limit || 100,
|
|
91
|
+
from: qs.from || 0,
|
|
92
|
+
};
|
|
90
93
|
do {
|
|
91
|
-
responseData = await zohoDeskApiRequest.call(this, method, endpoint, body,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
responseData = await zohoDeskApiRequest.call(this, method, endpoint, body, query, itemIndex);
|
|
95
|
+
const items = Array.isArray(responseData?.data)
|
|
96
|
+
? responseData.data
|
|
97
|
+
: Array.isArray(responseData)
|
|
98
|
+
? responseData
|
|
99
|
+
: [];
|
|
100
|
+
if (items.length > 0) {
|
|
101
|
+
returnData.push(...items);
|
|
102
|
+
if (items.length < query.limit) {
|
|
95
103
|
// Last page
|
|
96
104
|
break;
|
|
97
105
|
}
|
|
98
|
-
|
|
106
|
+
query.from = query.from + items.length;
|
|
99
107
|
}
|
|
100
108
|
else {
|
|
101
109
|
break;
|
|
@@ -7,6 +7,10 @@ export declare class ZohoDesk implements INodeType {
|
|
|
7
7
|
name: string;
|
|
8
8
|
value: string;
|
|
9
9
|
}[]>;
|
|
10
|
+
getChannels(this: ILoadOptionsFunctions): Promise<{
|
|
11
|
+
name: string;
|
|
12
|
+
value: string;
|
|
13
|
+
}[]>;
|
|
10
14
|
};
|
|
11
15
|
};
|
|
12
16
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
@@ -154,6 +154,17 @@ class ZohoDesk {
|
|
|
154
154
|
default: '',
|
|
155
155
|
description: 'Agent ID to assign the ticket to',
|
|
156
156
|
},
|
|
157
|
+
{
|
|
158
|
+
displayName: 'Channel',
|
|
159
|
+
name: 'channel',
|
|
160
|
+
type: 'options',
|
|
161
|
+
typeOptions: {
|
|
162
|
+
loadOptionsMethod: 'getChannels',
|
|
163
|
+
loadOptionsDependsOn: ['organizationId'],
|
|
164
|
+
},
|
|
165
|
+
default: 'Email',
|
|
166
|
+
description: 'Channel through which the ticket was received or created. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
|
|
167
|
+
},
|
|
157
168
|
{
|
|
158
169
|
displayName: 'Contact ID',
|
|
159
170
|
name: 'contactId',
|
|
@@ -448,13 +459,9 @@ class ZohoDesk {
|
|
|
448
459
|
loadOptions: {
|
|
449
460
|
async getDepartments() {
|
|
450
461
|
try {
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
: Array.isArray(responseData)
|
|
455
|
-
? responseData
|
|
456
|
-
: [];
|
|
457
|
-
return departments.map((department) => {
|
|
462
|
+
const departments = (await GenericFunctions_1.zohoDeskApiRequestAllItems.call(this, 'GET', '/departments', {}, {}, 0));
|
|
463
|
+
return departments
|
|
464
|
+
.map((department) => {
|
|
458
465
|
const name = department.name ||
|
|
459
466
|
department.departmentName ||
|
|
460
467
|
String(department.id);
|
|
@@ -462,12 +469,98 @@ class ZohoDesk {
|
|
|
462
469
|
name,
|
|
463
470
|
value: department.id,
|
|
464
471
|
};
|
|
465
|
-
})
|
|
472
|
+
})
|
|
473
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
466
474
|
}
|
|
467
475
|
catch (error) {
|
|
468
476
|
throw new Error(`Failed to load departments. Error: ${error.message}. Ensure Organization ID is correct and Desk API Base URL matches your region.`);
|
|
469
477
|
}
|
|
470
478
|
},
|
|
479
|
+
async getChannels() {
|
|
480
|
+
const fallbackChannels = [
|
|
481
|
+
{ name: 'Chat', value: 'Chat' },
|
|
482
|
+
{ name: 'Email', value: 'Email' },
|
|
483
|
+
{ name: 'Facebook', value: 'Facebook' },
|
|
484
|
+
{ name: 'Feedback Widget', value: 'Feedback Widget' },
|
|
485
|
+
{ name: 'Forums', value: 'Forums' },
|
|
486
|
+
{ name: 'Help Center', value: 'Help Center' },
|
|
487
|
+
{ name: 'Phone', value: 'Phone' },
|
|
488
|
+
{ name: 'Twitter', value: 'Twitter' },
|
|
489
|
+
{ name: 'Web', value: 'Web' },
|
|
490
|
+
];
|
|
491
|
+
try {
|
|
492
|
+
const responseData = await GenericFunctions_1.zohoDeskApiRequest.call(this, 'GET', '/channels', {}, {}, 0);
|
|
493
|
+
const channels = Array.isArray(responseData.data)
|
|
494
|
+
? responseData.data
|
|
495
|
+
: Array.isArray(responseData)
|
|
496
|
+
? responseData
|
|
497
|
+
: [];
|
|
498
|
+
if (channels.length > 0) {
|
|
499
|
+
const channelMap = new Map();
|
|
500
|
+
for (const c of channels) {
|
|
501
|
+
const name = c.channelName ||
|
|
502
|
+
c.name ||
|
|
503
|
+
c.channelCode ||
|
|
504
|
+
String(c.id);
|
|
505
|
+
const value = c.channelCode ||
|
|
506
|
+
c.name ||
|
|
507
|
+
c.channelName ||
|
|
508
|
+
String(c.id);
|
|
509
|
+
if (value) {
|
|
510
|
+
channelMap.set(value, name || value);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
for (const fb of fallbackChannels) {
|
|
514
|
+
if (!channelMap.has(fb.value)) {
|
|
515
|
+
channelMap.set(fb.value, fb.name);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return Array.from(channelMap.entries())
|
|
519
|
+
.map(([value, name]) => ({ name, value }))
|
|
520
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
try {
|
|
525
|
+
const fieldsResponse = await GenericFunctions_1.zohoDeskApiRequest.call(this, 'GET', '/organizationFields', {}, { module: 'tickets' }, 0);
|
|
526
|
+
const fields = Array.isArray(fieldsResponse.data)
|
|
527
|
+
? fieldsResponse.data
|
|
528
|
+
: Array.isArray(fieldsResponse)
|
|
529
|
+
? fieldsResponse
|
|
530
|
+
: [];
|
|
531
|
+
const channelField = fields.find((f) => String(f.apiName || '').toLowerCase() === 'channel');
|
|
532
|
+
if (channelField && Array.isArray(channelField.allowedValues)) {
|
|
533
|
+
const channelMap = new Map();
|
|
534
|
+
for (const val of channelField.allowedValues) {
|
|
535
|
+
if (typeof val === 'string') {
|
|
536
|
+
channelMap.set(val, val);
|
|
537
|
+
}
|
|
538
|
+
else if (val && typeof val === 'object') {
|
|
539
|
+
const name = val.displayValue ||
|
|
540
|
+
val.label ||
|
|
541
|
+
val.value;
|
|
542
|
+
const value = val.value || val.displayValue;
|
|
543
|
+
if (value) {
|
|
544
|
+
channelMap.set(value, name || value);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
for (const fb of fallbackChannels) {
|
|
549
|
+
if (!channelMap.has(fb.value)) {
|
|
550
|
+
channelMap.set(fb.value, fb.name);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return Array.from(channelMap.entries())
|
|
554
|
+
.map(([value, name]) => ({ name, value }))
|
|
555
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
catch {
|
|
559
|
+
// Fall back to predefined list
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return fallbackChannels;
|
|
563
|
+
},
|
|
471
564
|
},
|
|
472
565
|
};
|
|
473
566
|
}
|
|
@@ -27,7 +27,7 @@ function getDeskBaseUrl(tokenUrl = '', apiDomain = '', overrideBaseUrl = '') {
|
|
|
27
27
|
return 'https://desk.zoho.com.cn';
|
|
28
28
|
return 'https://desk.zoho.com';
|
|
29
29
|
}
|
|
30
|
-
async function deskRequest(context, method, endpoint, organizationId, body = {}) {
|
|
30
|
+
async function deskRequest(context, method, endpoint, organizationId, body = {}, qs = {}) {
|
|
31
31
|
const credentials = (await context.getCredentials('zohoCRMDeskOAuth2Api'));
|
|
32
32
|
const { oauthTokenData, accessTokenUrl, authUrl, deskBaseUrl } = credentials;
|
|
33
33
|
const baseUrl = getDeskBaseUrl(accessTokenUrl || authUrl || '', oauthTokenData?.api_domain || '', deskBaseUrl || '');
|
|
@@ -40,6 +40,9 @@ async function deskRequest(context, method, endpoint, organizationId, body = {})
|
|
|
40
40
|
},
|
|
41
41
|
json: true,
|
|
42
42
|
};
|
|
43
|
+
if (Object.keys(qs).length) {
|
|
44
|
+
options.qs = qs;
|
|
45
|
+
}
|
|
43
46
|
if (method !== 'GET' && method !== 'DELETE' && Object.keys(body).length) {
|
|
44
47
|
options.body = body;
|
|
45
48
|
}
|
|
@@ -50,6 +53,34 @@ async function deskRequest(context, method, endpoint, organizationId, body = {})
|
|
|
50
53
|
throw new n8n_workflow_1.NodeApiError(context.getNode(), error);
|
|
51
54
|
}
|
|
52
55
|
}
|
|
56
|
+
async function deskRequestAllItems(context, method, endpoint, organizationId, body = {}, qs = {}) {
|
|
57
|
+
const returnData = [];
|
|
58
|
+
let responseData;
|
|
59
|
+
const query = {
|
|
60
|
+
...qs,
|
|
61
|
+
limit: qs.limit || 100,
|
|
62
|
+
from: qs.from || 0,
|
|
63
|
+
};
|
|
64
|
+
do {
|
|
65
|
+
responseData = await deskRequest(context, method, endpoint, organizationId, body, query);
|
|
66
|
+
const items = Array.isArray(responseData?.data)
|
|
67
|
+
? responseData.data
|
|
68
|
+
: Array.isArray(responseData)
|
|
69
|
+
? responseData
|
|
70
|
+
: [];
|
|
71
|
+
if (items.length > 0) {
|
|
72
|
+
returnData.push(...items);
|
|
73
|
+
if (items.length < query.limit) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
query.from = query.from + items.length;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
} while (true);
|
|
82
|
+
return returnData;
|
|
83
|
+
}
|
|
53
84
|
async function deskWebhookRequest(context, method, endpoint, body = {}) {
|
|
54
85
|
const organizationId = context.getNodeParameter('organizationId');
|
|
55
86
|
return deskRequest(context, method, endpoint, organizationId, body);
|
|
@@ -208,16 +239,13 @@ class ZohoDeskTrigger {
|
|
|
208
239
|
async getDepartments() {
|
|
209
240
|
const organizationId = this.getNodeParameter('organizationId', 0, '');
|
|
210
241
|
try {
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
: Array.isArray(responseData)
|
|
215
|
-
? responseData
|
|
216
|
-
: [];
|
|
217
|
-
return departments.map((dept) => ({
|
|
242
|
+
const departments = await deskRequestAllItems(this, 'GET', '/departments', organizationId);
|
|
243
|
+
return departments
|
|
244
|
+
.map((dept) => ({
|
|
218
245
|
name: dept.name || dept.departmentName || String(dept.id),
|
|
219
246
|
value: dept.id,
|
|
220
|
-
}))
|
|
247
|
+
}))
|
|
248
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
221
249
|
}
|
|
222
250
|
catch (error) {
|
|
223
251
|
throw new Error(`Failed to load departments: ${error.message}. Ensure Organization ID is set correctly.`);
|