@friggframework/api-module-zoho-crm 2.0.0-next.0 → 2.0.0-next.2
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 +183 -197
- package/dist/api.d.ts +101 -0
- package/dist/api.js +521 -0
- package/dist/defaultConfig.json +13 -0
- package/dist/definition.d.ts +22 -0
- package/dist/definition.js +75 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +32 -0
- package/dist/types.d.ts +356 -0
- package/dist/types.js +2 -0
- package/package.json +21 -10
- package/.env.example +0 -4
- package/CHANGELOG.md +0 -50
- package/api.js +0 -169
- package/defaultConfig.json +0 -13
- package/definition.js +0 -51
- package/images/image-1.jpg +0 -0
- package/images/image-10.jpg +0 -0
- package/images/image-11.jpg +0 -0
- package/images/image-12.jpg +0 -0
- package/images/image-2.jpg +0 -0
- package/images/image-3.jpg +0 -0
- package/images/image-5.jpg +0 -0
- package/images/image-6.jpg +0 -0
- package/images/image-7.jpg +0 -0
- package/images/image-9.jpg +0 -0
- package/images/image.jpg +0 -0
- package/index.js +0 -9
- package/jest-setup.js +0 -3
- package/jest-teardown.js +0 -2
- package/jest.config.js +0 -22
- package/tests/api.test.js +0 -195
package/dist/api.js
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Api = void 0;
|
|
4
|
+
const FormData = require("form-data");
|
|
5
|
+
const core_1 = require("@friggframework/core");
|
|
6
|
+
class Api extends core_1.OAuth2Requester {
|
|
7
|
+
constructor(params) {
|
|
8
|
+
super(params);
|
|
9
|
+
this.baseUrl = 'https://www.zohoapis.com/crm/v8';
|
|
10
|
+
this.authorizationUri = encodeURI(`https://accounts.zoho.com/oauth/v2/auth?scope=${this.scope}&client_id=${this.client_id}&redirect_uri=${this.redirect_uri}&response_type=code&access_type=offline`);
|
|
11
|
+
this.tokenUri = 'https://accounts.zoho.com/oauth/v2/token';
|
|
12
|
+
this.access_token = (0, core_1.get)(params, 'access_token', null);
|
|
13
|
+
this.refresh_token = (0, core_1.get)(params, 'refresh_token', null);
|
|
14
|
+
this.URLs = {
|
|
15
|
+
users: '/users',
|
|
16
|
+
user: (userId) => `/users/${userId}`,
|
|
17
|
+
roles: '/settings/roles',
|
|
18
|
+
role: (roleId) => `/settings/roles/${roleId}`,
|
|
19
|
+
profiles: '/settings/profiles',
|
|
20
|
+
contacts: '/Contacts',
|
|
21
|
+
contact: (contactId) => `/Contacts/${contactId}`,
|
|
22
|
+
contactSearch: '/Contacts/search',
|
|
23
|
+
leads: '/Leads',
|
|
24
|
+
lead: (leadId) => `/Leads/${leadId}`,
|
|
25
|
+
leadSearch: '/Leads/search',
|
|
26
|
+
accounts: '/Accounts',
|
|
27
|
+
account: (accountId) => `/Accounts/${accountId}`,
|
|
28
|
+
accountSearch: '/Accounts/search',
|
|
29
|
+
notificationsWatch: '/actions/watch',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
getAuthUri() {
|
|
33
|
+
return this.authorizationUri;
|
|
34
|
+
}
|
|
35
|
+
async getTokenFromCode(code) {
|
|
36
|
+
const formData = new FormData();
|
|
37
|
+
formData.append('grant_type', 'authorization_code');
|
|
38
|
+
formData.append('client_id', this.client_id);
|
|
39
|
+
formData.append('client_secret', this.client_secret);
|
|
40
|
+
formData.append('redirect_uri', this.redirect_uri);
|
|
41
|
+
formData.append('scope', this.scope);
|
|
42
|
+
formData.append('code', code);
|
|
43
|
+
const options = {
|
|
44
|
+
body: formData,
|
|
45
|
+
headers: formData.getHeaders(),
|
|
46
|
+
url: this.tokenUri,
|
|
47
|
+
};
|
|
48
|
+
const response = await this._post(options, false);
|
|
49
|
+
await this.setTokens(response);
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
async _delete(options) {
|
|
53
|
+
const response = await super._delete(options);
|
|
54
|
+
return await this.parsedBody(response);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build URL for notes endpoints with proper encoding
|
|
58
|
+
* @param module - Module API name (e.g., 'Contacts', 'Leads')
|
|
59
|
+
* @param recordId - Record ID
|
|
60
|
+
* @param noteId - Optional note ID for specific note operations
|
|
61
|
+
* @returns Encoded URL path for notes endpoint
|
|
62
|
+
*/
|
|
63
|
+
buildNotesUrl(module, recordId, noteId) {
|
|
64
|
+
const segments = [module, recordId, 'Notes'];
|
|
65
|
+
if (noteId)
|
|
66
|
+
segments.push(noteId);
|
|
67
|
+
const encodedPath = segments.map(encodeURIComponent).join('/');
|
|
68
|
+
return `${this.baseUrl}/${encodedPath}`;
|
|
69
|
+
}
|
|
70
|
+
async listUsers(queryParams = {}) {
|
|
71
|
+
return this._get({
|
|
72
|
+
url: this.baseUrl + this.URLs.users,
|
|
73
|
+
query: { ...queryParams },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async getUser(userId) {
|
|
77
|
+
if (!userId) {
|
|
78
|
+
throw new Error('userId is required');
|
|
79
|
+
}
|
|
80
|
+
return this._get({
|
|
81
|
+
url: this.baseUrl + this.URLs.user(userId),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async createUser(body = {}) {
|
|
85
|
+
if (!body || Object.keys(body).length === 0) {
|
|
86
|
+
throw new Error('Request body is required');
|
|
87
|
+
}
|
|
88
|
+
return this._post({
|
|
89
|
+
url: this.baseUrl + this.URLs.users,
|
|
90
|
+
body: body
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async updateUser(userId, body = {}) {
|
|
94
|
+
if (!userId) {
|
|
95
|
+
throw new Error('userId is required');
|
|
96
|
+
}
|
|
97
|
+
if (!body || Object.keys(body).length === 0) {
|
|
98
|
+
throw new Error('Request body is required');
|
|
99
|
+
}
|
|
100
|
+
return this._put({
|
|
101
|
+
url: this.baseUrl + this.URLs.user(userId),
|
|
102
|
+
body: body,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async deleteUser(userId) {
|
|
106
|
+
if (!userId) {
|
|
107
|
+
throw new Error('userId is required');
|
|
108
|
+
}
|
|
109
|
+
return this._delete({
|
|
110
|
+
url: this.baseUrl + this.URLs.user(userId),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async listRoles() {
|
|
114
|
+
return this._get({
|
|
115
|
+
url: this.baseUrl + this.URLs.roles
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async getRole(roleId) {
|
|
119
|
+
if (!roleId) {
|
|
120
|
+
throw new Error('roleId is required');
|
|
121
|
+
}
|
|
122
|
+
return this._get({
|
|
123
|
+
url: this.baseUrl + this.URLs.role(roleId)
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async createRole(body = {}) {
|
|
127
|
+
if (!body || Object.keys(body).length === 0) {
|
|
128
|
+
throw new Error('Request body is required');
|
|
129
|
+
}
|
|
130
|
+
return this._post({
|
|
131
|
+
url: this.baseUrl + this.URLs.roles,
|
|
132
|
+
body: body
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async updateRole(roleId, body = {}) {
|
|
136
|
+
if (!roleId) {
|
|
137
|
+
throw new Error('roleId is required');
|
|
138
|
+
}
|
|
139
|
+
if (!body || Object.keys(body).length === 0) {
|
|
140
|
+
throw new Error('Request body is required');
|
|
141
|
+
}
|
|
142
|
+
return this._put({
|
|
143
|
+
url: this.baseUrl + this.URLs.role(roleId),
|
|
144
|
+
body: body,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async deleteRole(roleId, queryParams = {}) {
|
|
148
|
+
if (!roleId) {
|
|
149
|
+
throw new Error('roleId is required');
|
|
150
|
+
}
|
|
151
|
+
return this._delete({
|
|
152
|
+
url: this.baseUrl + this.URLs.role(roleId),
|
|
153
|
+
query: { ...queryParams },
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async listProfiles() {
|
|
157
|
+
return this._get({
|
|
158
|
+
url: this.baseUrl + this.URLs.profiles
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
async listContacts(queryParams = {}) {
|
|
162
|
+
const params = {
|
|
163
|
+
fields: Api.CONTACTS_DEFAULT_FIELDS,
|
|
164
|
+
...queryParams,
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
return await this._get({
|
|
168
|
+
url: this.baseUrl + this.URLs.contacts,
|
|
169
|
+
query: params,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async getContact(contactId) {
|
|
177
|
+
if (!contactId) {
|
|
178
|
+
throw new Error('contactId is required');
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
return await this._get({
|
|
182
|
+
url: this.baseUrl + this.URLs.contact(contactId),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async searchContacts(searchParams = {}) {
|
|
190
|
+
if (!searchParams || Object.keys(searchParams).length === 0) {
|
|
191
|
+
throw new Error('At least one search parameter is required (email, phone, criteria, or word)');
|
|
192
|
+
}
|
|
193
|
+
const params = {
|
|
194
|
+
fields: Api.CONTACTS_DEFAULT_FIELDS,
|
|
195
|
+
...searchParams,
|
|
196
|
+
};
|
|
197
|
+
try {
|
|
198
|
+
return await this._get({
|
|
199
|
+
url: this.baseUrl + this.URLs.contactSearch,
|
|
200
|
+
query: params,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async listLeads(queryParams = {}) {
|
|
208
|
+
const params = {
|
|
209
|
+
fields: Api.LEADS_DEFAULT_FIELDS,
|
|
210
|
+
...queryParams,
|
|
211
|
+
};
|
|
212
|
+
try {
|
|
213
|
+
return await this._get({
|
|
214
|
+
url: this.baseUrl + this.URLs.leads,
|
|
215
|
+
query: params,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async getLead(leadId) {
|
|
223
|
+
if (!leadId) {
|
|
224
|
+
throw new Error('leadId is required');
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
return await this._get({
|
|
228
|
+
url: this.baseUrl + this.URLs.lead(leadId),
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async searchLeads(searchParams = {}) {
|
|
236
|
+
if (!searchParams || Object.keys(searchParams).length === 0) {
|
|
237
|
+
throw new Error('At least one search parameter is required (email, phone, criteria, or word)');
|
|
238
|
+
}
|
|
239
|
+
const params = {
|
|
240
|
+
fields: Api.LEADS_DEFAULT_FIELDS,
|
|
241
|
+
...searchParams,
|
|
242
|
+
};
|
|
243
|
+
try {
|
|
244
|
+
return await this._get({
|
|
245
|
+
url: this.baseUrl + this.URLs.leadSearch,
|
|
246
|
+
query: params,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async listAccounts(queryParams = {}) {
|
|
254
|
+
const params = {
|
|
255
|
+
fields: Api.ACCOUNTS_DEFAULT_FIELDS,
|
|
256
|
+
...queryParams,
|
|
257
|
+
};
|
|
258
|
+
try {
|
|
259
|
+
return await this._get({
|
|
260
|
+
url: this.baseUrl + this.URLs.accounts,
|
|
261
|
+
query: params,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async getAccount(accountId) {
|
|
269
|
+
if (!accountId) {
|
|
270
|
+
throw new Error('accountId is required');
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
return await this._get({
|
|
274
|
+
url: this.baseUrl + this.URLs.account(accountId),
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async searchAccounts(searchParams = {}) {
|
|
282
|
+
if (!searchParams || Object.keys(searchParams).length === 0) {
|
|
283
|
+
throw new Error('At least one search parameter is required (email, phone, criteria, or word)');
|
|
284
|
+
}
|
|
285
|
+
const params = {
|
|
286
|
+
fields: Api.ACCOUNTS_DEFAULT_FIELDS,
|
|
287
|
+
...searchParams,
|
|
288
|
+
};
|
|
289
|
+
try {
|
|
290
|
+
return await this._get({
|
|
291
|
+
url: this.baseUrl + this.URLs.accountSearch,
|
|
292
|
+
query: params,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* List all notes for a specific record
|
|
301
|
+
* @param module - Module API name (Contacts, Leads, Accounts, etc.)
|
|
302
|
+
* @param recordId - Record ID to get notes for
|
|
303
|
+
* @param queryParams - Optional query parameters (per_page, page, etc.)
|
|
304
|
+
* @returns Promise<NoteListResponse> Notes list response
|
|
305
|
+
*/
|
|
306
|
+
async listNotes(module, recordId, queryParams = {}) {
|
|
307
|
+
if (!module) {
|
|
308
|
+
throw new Error('module is required');
|
|
309
|
+
}
|
|
310
|
+
if (!recordId) {
|
|
311
|
+
throw new Error('recordId is required');
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
return await this._get({
|
|
315
|
+
url: this.buildNotesUrl(module, recordId),
|
|
316
|
+
query: queryParams,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Get a specific note by ID
|
|
325
|
+
* @param module - Module API name (Contacts, Leads, Accounts, etc.)
|
|
326
|
+
* @param recordId - Record ID the note is attached to
|
|
327
|
+
* @param noteId - Note ID to retrieve
|
|
328
|
+
* @returns Promise<NotesResponse> Note details
|
|
329
|
+
*/
|
|
330
|
+
async getNote(module, recordId, noteId) {
|
|
331
|
+
if (!module) {
|
|
332
|
+
throw new Error('module is required');
|
|
333
|
+
}
|
|
334
|
+
if (!recordId) {
|
|
335
|
+
throw new Error('recordId is required');
|
|
336
|
+
}
|
|
337
|
+
if (!noteId) {
|
|
338
|
+
throw new Error('noteId is required');
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
return await this._get({
|
|
342
|
+
url: this.buildNotesUrl(module, recordId, noteId),
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Create a note for a specific record
|
|
351
|
+
* @param module - Module API name (Contacts, Leads, Accounts, etc.)
|
|
352
|
+
* @param recordId - Record ID to attach note to
|
|
353
|
+
* @param noteData - Note data with Note_Content (required) and optional Note_Title
|
|
354
|
+
* @returns Promise<NotesResponse> Created note response
|
|
355
|
+
*/
|
|
356
|
+
async createNote(module, recordId, noteData) {
|
|
357
|
+
if (!module) {
|
|
358
|
+
throw new Error('module is required');
|
|
359
|
+
}
|
|
360
|
+
if (!recordId) {
|
|
361
|
+
throw new Error('recordId is required');
|
|
362
|
+
}
|
|
363
|
+
if (!noteData || !noteData.Note_Content) {
|
|
364
|
+
throw new Error('noteData.Note_Content is required');
|
|
365
|
+
}
|
|
366
|
+
const body = {
|
|
367
|
+
data: [{
|
|
368
|
+
Note_Content: noteData.Note_Content,
|
|
369
|
+
...(noteData.Note_Title && { Note_Title: noteData.Note_Title }),
|
|
370
|
+
}]
|
|
371
|
+
};
|
|
372
|
+
try {
|
|
373
|
+
return await this._post({
|
|
374
|
+
url: this.buildNotesUrl(module, recordId),
|
|
375
|
+
body: body,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Update an existing note
|
|
384
|
+
* @param module - Module API name (Contacts, Leads, Accounts, etc.)
|
|
385
|
+
* @param recordId - Record ID the note is attached to
|
|
386
|
+
* @param noteId - Note ID to update
|
|
387
|
+
* @param noteData - Updated note data. At least one of Note_Content or Note_Title must be provided.
|
|
388
|
+
* @returns Promise<NotesResponse> Updated note response
|
|
389
|
+
*/
|
|
390
|
+
async updateNote(module, recordId, noteId, noteData) {
|
|
391
|
+
if (!module) {
|
|
392
|
+
throw new Error('module is required');
|
|
393
|
+
}
|
|
394
|
+
if (!recordId) {
|
|
395
|
+
throw new Error('recordId is required');
|
|
396
|
+
}
|
|
397
|
+
if (!noteId) {
|
|
398
|
+
throw new Error('noteId is required');
|
|
399
|
+
}
|
|
400
|
+
if (!noteData || (!noteData.Note_Content && !noteData.Note_Title)) {
|
|
401
|
+
throw new Error('noteData must contain Note_Content or Note_Title');
|
|
402
|
+
}
|
|
403
|
+
const body = {
|
|
404
|
+
data: [{
|
|
405
|
+
...(noteData.Note_Content && { Note_Content: noteData.Note_Content }),
|
|
406
|
+
...(noteData.Note_Title && { Note_Title: noteData.Note_Title }),
|
|
407
|
+
}]
|
|
408
|
+
};
|
|
409
|
+
try {
|
|
410
|
+
return await this._put({
|
|
411
|
+
url: this.buildNotesUrl(module, recordId, noteId),
|
|
412
|
+
body: body,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Delete a note
|
|
421
|
+
* @param module - Module API name (Contacts, Leads, Accounts, etc.)
|
|
422
|
+
* @param recordId - Record ID the note is attached to
|
|
423
|
+
* @param noteId - Note ID to delete
|
|
424
|
+
* @returns Promise<NotesResponse> Deletion response
|
|
425
|
+
*/
|
|
426
|
+
async deleteNote(module, recordId, noteId) {
|
|
427
|
+
if (!module) {
|
|
428
|
+
throw new Error('module is required');
|
|
429
|
+
}
|
|
430
|
+
if (!recordId) {
|
|
431
|
+
throw new Error('recordId is required');
|
|
432
|
+
}
|
|
433
|
+
if (!noteId) {
|
|
434
|
+
throw new Error('noteId is required');
|
|
435
|
+
}
|
|
436
|
+
try {
|
|
437
|
+
return await this._delete({
|
|
438
|
+
url: this.buildNotesUrl(module, recordId, noteId),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
throw error;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Enable notification channel to receive real-time events
|
|
447
|
+
* @param body - Notification configuration with watch items
|
|
448
|
+
* @returns Promise<NotificationResponse> Response with channel details
|
|
449
|
+
* @see https://www.zoho.com/crm/developer/docs/api/v8/notifications/enable.html
|
|
450
|
+
*/
|
|
451
|
+
async enableNotification(body) {
|
|
452
|
+
if (!body || !body.watch || !Array.isArray(body.watch)) {
|
|
453
|
+
throw new Error('Body must contain watch array');
|
|
454
|
+
}
|
|
455
|
+
// Validate each watch item
|
|
456
|
+
body.watch.forEach((item, index) => {
|
|
457
|
+
if (!item.channel_id) {
|
|
458
|
+
throw new Error(`watch[${index}].channel_id is required`);
|
|
459
|
+
}
|
|
460
|
+
if (!item.events || !Array.isArray(item.events) || item.events.length === 0) {
|
|
461
|
+
throw new Error(`watch[${index}].events must be a non-empty array`);
|
|
462
|
+
}
|
|
463
|
+
if (!item.notify_url) {
|
|
464
|
+
throw new Error(`watch[${index}].notify_url is required`);
|
|
465
|
+
}
|
|
466
|
+
if (item.token && item.token.length > 50) {
|
|
467
|
+
throw new Error(`watch[${index}].token must be 50 characters or less`);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
try {
|
|
471
|
+
return await this._post({
|
|
472
|
+
url: this.baseUrl + this.URLs.notificationsWatch,
|
|
473
|
+
body: body,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
throw error;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Disable notification channels
|
|
482
|
+
* @param channelIds - Array of channel IDs to disable
|
|
483
|
+
* @returns Promise<NotificationResponse> Response confirming deletion
|
|
484
|
+
* @see https://www.zoho.com/crm/developer/docs/api/v8/notifications/disable.html
|
|
485
|
+
*/
|
|
486
|
+
async disableNotification(channelIds) {
|
|
487
|
+
if (!channelIds || !Array.isArray(channelIds) || channelIds.length === 0) {
|
|
488
|
+
throw new Error('channelIds must be a non-empty array');
|
|
489
|
+
}
|
|
490
|
+
try {
|
|
491
|
+
return await this._delete({
|
|
492
|
+
url: this.baseUrl + this.URLs.notificationsWatch,
|
|
493
|
+
query: {
|
|
494
|
+
channel_ids: channelIds.join(',')
|
|
495
|
+
},
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Get details of all active notification channels
|
|
504
|
+
* @returns Promise<NotificationDetailsResponse> Details of all active channels
|
|
505
|
+
* @see https://www.zoho.com/crm/developer/docs/api/v8/notifications/get-details.html
|
|
506
|
+
*/
|
|
507
|
+
async getNotificationDetails() {
|
|
508
|
+
try {
|
|
509
|
+
return await this._get({
|
|
510
|
+
url: this.baseUrl + this.URLs.notificationsWatch,
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
throw error;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
exports.Api = Api;
|
|
519
|
+
Api.CONTACTS_DEFAULT_FIELDS = 'id,First_Name,Last_Name,Email,Phone,Mobile,Account_Name,Company,Owner,Lead_Source,Created_Time,Modified_Time';
|
|
520
|
+
Api.LEADS_DEFAULT_FIELDS = 'id,First_Name,Last_Name,Email,Phone,Mobile,Company,Industry,Lead_Source,Lead_Status,Owner,Created_Time,Modified_Time,Converted__s,Converted_Date_Time';
|
|
521
|
+
Api.ACCOUNTS_DEFAULT_FIELDS = 'id,Account_Name,Account_Number,Account_Type,Industry,Annual_Revenue,Rating,Phone,Fax,Website,Parent_Account,Owner,Billing_City,Billing_State,Billing_Country,Shipping_City,Shipping_State,Shipping_Country,Created_Time,Modified_Time';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zohoCrm",
|
|
3
|
+
"label": "Zoho CRM",
|
|
4
|
+
"productUrl": "https://www.zoho.com/crm/",
|
|
5
|
+
"apiDocs": "https://www.zoho.com/crm/developer/docs/",
|
|
6
|
+
"logoUrl": "https://friggframework.org/assets/img/zoho-icon.png",
|
|
7
|
+
"categories": [
|
|
8
|
+
"Sales",
|
|
9
|
+
"Marketing",
|
|
10
|
+
"CRM"
|
|
11
|
+
],
|
|
12
|
+
"description": "Zoho CRM acts as a single repository to bring your sales, marketing, and customer support activities together, and streamline your process, policy, and people in one platform."
|
|
13
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Api } from './api';
|
|
2
|
+
export declare const Definition: {
|
|
3
|
+
API: typeof Api;
|
|
4
|
+
getName: () => string;
|
|
5
|
+
moduleName: string;
|
|
6
|
+
requiredAuthMethods: {
|
|
7
|
+
getToken: (api: Api, params: any) => Promise<void>;
|
|
8
|
+
apiPropertiesToPersist: {
|
|
9
|
+
credential: string[];
|
|
10
|
+
entity: never[];
|
|
11
|
+
};
|
|
12
|
+
getCredentialDetails: (api: Api, userId: string) => Promise<any>;
|
|
13
|
+
getEntityDetails: (api: Api, callbackParams: any, tokenResponse: any, userId: string) => Promise<any>;
|
|
14
|
+
testAuthRequest: (api: Api) => Promise<any>;
|
|
15
|
+
};
|
|
16
|
+
env: {
|
|
17
|
+
client_id: string | undefined;
|
|
18
|
+
client_secret: string | undefined;
|
|
19
|
+
scope: string | undefined;
|
|
20
|
+
redirect_uri: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Definition = void 0;
|
|
27
|
+
const dotenv = __importStar(require("dotenv"));
|
|
28
|
+
dotenv.config();
|
|
29
|
+
const api_1 = require("./api");
|
|
30
|
+
const core_1 = require("@friggframework/core");
|
|
31
|
+
const config = __importStar(require("./defaultConfig.json"));
|
|
32
|
+
exports.Definition = {
|
|
33
|
+
API: api_1.Api,
|
|
34
|
+
getName: function () {
|
|
35
|
+
return config.name;
|
|
36
|
+
},
|
|
37
|
+
moduleName: config.name,
|
|
38
|
+
requiredAuthMethods: {
|
|
39
|
+
getToken: async function (api, params) {
|
|
40
|
+
const code = (0, core_1.get)(params, 'code');
|
|
41
|
+
await api.getTokenFromCode(code);
|
|
42
|
+
},
|
|
43
|
+
apiPropertiesToPersist: {
|
|
44
|
+
credential: ['access_token', 'refresh_token'],
|
|
45
|
+
entity: [],
|
|
46
|
+
},
|
|
47
|
+
getCredentialDetails: async function (api, userId) {
|
|
48
|
+
const response = await api.listUsers({ type: 'CurrentUser' });
|
|
49
|
+
const currentUser = response.users[0];
|
|
50
|
+
return {
|
|
51
|
+
identifiers: { externalId: currentUser.id, user: userId },
|
|
52
|
+
details: {},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
getEntityDetails: async function (api, callbackParams, tokenResponse, userId) {
|
|
56
|
+
const response = await api.listUsers({ type: 'CurrentUser' });
|
|
57
|
+
const currentUser = response.users[0];
|
|
58
|
+
return {
|
|
59
|
+
identifiers: { externalId: currentUser.id, user: userId },
|
|
60
|
+
details: {
|
|
61
|
+
name: currentUser.email
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
testAuthRequest: async function (api) {
|
|
66
|
+
return await api.listUsers();
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
env: {
|
|
70
|
+
client_id: process.env.ZOHO_CRM_CLIENT_ID,
|
|
71
|
+
client_secret: process.env.ZOHO_CRM_CLIENT_SECRET,
|
|
72
|
+
scope: process.env.ZOHO_CRM_SCOPE,
|
|
73
|
+
redirect_uri: `${process.env.REDIRECT_URI}/zohoCrm`,
|
|
74
|
+
}
|
|
75
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Definition = exports.Config = exports.Api = void 0;
|
|
27
|
+
const api_1 = require("./api");
|
|
28
|
+
Object.defineProperty(exports, "Api", { enumerable: true, get: function () { return api_1.Api; } });
|
|
29
|
+
const Config = __importStar(require("./defaultConfig.json"));
|
|
30
|
+
exports.Config = Config;
|
|
31
|
+
const definition_1 = require("./definition");
|
|
32
|
+
Object.defineProperty(exports, "Definition", { enumerable: true, get: function () { return definition_1.Definition; } });
|