rez_core 2.2.190 → 2.2.191

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.
Files changed (36) hide show
  1. package/dist/module/communication/communication.module.js +4 -1
  2. package/dist/module/communication/communication.module.js.map +1 -1
  3. package/dist/module/communication/controller/calender-event.controller.d.ts +31 -0
  4. package/dist/module/communication/controller/calender-event.controller.js +51 -0
  5. package/dist/module/communication/controller/calender-event.controller.js.map +1 -0
  6. package/dist/module/communication/controller/communication.controller.d.ts +8 -1
  7. package/dist/module/communication/controller/communication.controller.js +27 -0
  8. package/dist/module/communication/controller/communication.controller.js.map +1 -1
  9. package/dist/module/communication/dto/create-config.dto.d.ts +40 -0
  10. package/dist/module/communication/dto/create-config.dto.js +24 -1
  11. package/dist/module/communication/dto/create-config.dto.js.map +1 -1
  12. package/dist/module/communication/factories/whatsapp.factory.d.ts +3 -1
  13. package/dist/module/communication/factories/whatsapp.factory.js +13 -3
  14. package/dist/module/communication/factories/whatsapp.factory.js.map +1 -1
  15. package/dist/module/communication/service/calendar-event.service.d.ts +32 -0
  16. package/dist/module/communication/service/calendar-event.service.js +115 -0
  17. package/dist/module/communication/service/calendar-event.service.js.map +1 -0
  18. package/dist/module/communication/service/communication.service.d.ts +8 -0
  19. package/dist/module/communication/service/communication.service.js +56 -1
  20. package/dist/module/communication/service/communication.service.js.map +1 -1
  21. package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.d.ts +15 -0
  22. package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.js +233 -16
  23. package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.js.map +1 -1
  24. package/dist/module/workflow/service/task.service.js +0 -1
  25. package/dist/module/workflow/service/task.service.js.map +1 -1
  26. package/dist/tsconfig.build.tsbuildinfo +1 -1
  27. package/package.json +1 -1
  28. package/src/module/communication/communication.module.ts +5 -1
  29. package/src/module/communication/controller/calender-event.controller.ts +31 -0
  30. package/src/module/communication/controller/communication.controller.ts +29 -0
  31. package/src/module/communication/dto/create-config.dto.ts +71 -0
  32. package/src/module/communication/factories/whatsapp.factory.ts +13 -2
  33. package/src/module/communication/service/calendar-event.service.ts +123 -0
  34. package/src/module/communication/service/communication.service.ts +91 -2
  35. package/src/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.ts +373 -19
  36. package/src/module/workflow/service/task.service.ts +1 -1
@@ -1,11 +1,83 @@
1
- import { Injectable } from '@nestjs/common';
1
+ import { Injectable, Logger } from '@nestjs/common';
2
+ import axios, { AxiosResponse } from 'axios';
2
3
  import {
3
4
  CommunicationStrategy,
4
5
  CommunicationResult,
5
6
  } from '../communication.strategy';
6
7
 
8
+ interface WhatsAppConfig {
9
+ accessToken: string;
10
+ phoneNumberId: string;
11
+ apiVersion?: string;
12
+ businessAccountId?: string;
13
+ }
14
+
15
+ interface WhatsAppMessage {
16
+ messaging_product: string;
17
+ to: string;
18
+ type: string;
19
+ text?: {
20
+ body: string;
21
+ preview_url?: boolean;
22
+ };
23
+ template?: {
24
+ name: string;
25
+ language: {
26
+ code: string;
27
+ };
28
+ components?: any[];
29
+ };
30
+ image?: {
31
+ link?: string;
32
+ caption?: string;
33
+ };
34
+ document?: {
35
+ link?: string;
36
+ caption?: string;
37
+ filename?: string;
38
+ };
39
+ audio?: {
40
+ link: string;
41
+ };
42
+ video?: {
43
+ link?: string;
44
+ caption?: string;
45
+ };
46
+ location?: {
47
+ latitude: number;
48
+ longitude: number;
49
+ name?: string;
50
+ address?: string;
51
+ };
52
+ interactive?: {
53
+ type: string;
54
+ body?: {
55
+ text: string;
56
+ };
57
+ footer?: {
58
+ text: string;
59
+ };
60
+ action: any;
61
+ };
62
+ }
63
+
64
+ interface WhatsAppApiResponse {
65
+ messaging_product: string;
66
+ contacts: Array<{
67
+ input: string;
68
+ wa_id: string;
69
+ }>;
70
+ messages: Array<{
71
+ id: string;
72
+ message_status?: string;
73
+ }>;
74
+ }
75
+
7
76
  @Injectable()
8
77
  export class WhatsAppCloudStrategy implements CommunicationStrategy {
78
+ private readonly logger = new Logger(WhatsAppCloudStrategy.name);
79
+ private readonly baseUrl = 'https://graph.facebook.com';
80
+
9
81
  async sendMessage(
10
82
  to: string,
11
83
  message: string,
@@ -16,34 +88,316 @@ export class WhatsAppCloudStrategy implements CommunicationStrategy {
16
88
  throw new Error('Invalid WhatsApp Cloud API configuration');
17
89
  }
18
90
 
19
- // WhatsApp Cloud API implementation would go here
20
- // This is a placeholder for actual WhatsApp integration
21
- console.log('Sending WhatsApp message via Cloud API to:', to);
91
+ const whatsappConfig = config as WhatsAppConfig;
92
+ const apiVersion = whatsappConfig.apiVersion || 'v18.0';
93
+ const url = `${this.baseUrl}/${apiVersion}/${whatsappConfig.phoneNumberId}/messages`;
22
94
 
23
- return {
24
- success: true,
25
- messageId: `whatsapp-${Date.now()}`,
26
- provider: 'whatsapp',
27
- service: 'API',
28
- timestamp: new Date(),
29
- };
95
+ // Determine message type and prepare payload
96
+ const payload = this.prepareMessagePayload(to, message, config);
97
+
98
+ const response: AxiosResponse<WhatsAppApiResponse> = await axios.post(
99
+ url,
100
+ payload,
101
+ {
102
+ headers: {
103
+ Authorization: `Bearer ${whatsappConfig.accessToken}`,
104
+ 'Content-Type': 'application/json',
105
+ },
106
+ timeout: 30000,
107
+ },
108
+ );
109
+
110
+ if (response.data?.messages?.[0]?.id) {
111
+ this.logger.log(
112
+ `WhatsApp message sent successfully to ${to}, messageId: ${response.data.messages[0].id}`,
113
+ );
114
+
115
+ return {
116
+ success: true,
117
+ messageId: response.data.messages[0].id,
118
+ provider: 'whatsapp-cloud',
119
+ service: 'API',
120
+ timestamp: new Date(),
121
+ };
122
+ } else {
123
+ throw new Error('Invalid response from WhatsApp API');
124
+ }
30
125
  } catch (error) {
126
+ this.logger.error(
127
+ `Failed to send WhatsApp message to ${to}`,
128
+ error.response?.data || error.message,
129
+ );
130
+
31
131
  return {
32
132
  success: false,
33
- provider: 'whatsapp',
133
+ provider: 'whatsapp-cloud',
34
134
  service: 'API',
35
- error: error.message,
135
+ error: this.extractErrorMessage(error),
36
136
  timestamp: new Date(),
37
137
  };
38
138
  }
39
139
  }
40
140
 
141
+ private prepareMessagePayload(
142
+ to: string,
143
+ message: string,
144
+ config: any,
145
+ ): WhatsAppMessage {
146
+ const basePayload: WhatsAppMessage = {
147
+ messaging_product: 'whatsapp',
148
+ to: this.formatPhoneNumber(to),
149
+ type: 'text',
150
+ };
151
+
152
+ // Handle different message types based on config
153
+ if (config.messageType) {
154
+ switch (config.messageType) {
155
+ case 'template':
156
+ return {
157
+ ...basePayload,
158
+ type: 'template',
159
+ template: {
160
+ name: config.templateName || 'hello_world',
161
+ language: {
162
+ code: config.languageCode || 'en_US',
163
+ },
164
+ components: config.templateComponents || [],
165
+ },
166
+ };
167
+
168
+ case 'image':
169
+ return {
170
+ ...basePayload,
171
+ type: 'image',
172
+ image: {
173
+ link: config.mediaUrl,
174
+ caption: message || config.caption,
175
+ },
176
+ };
177
+
178
+ case 'document':
179
+ return {
180
+ ...basePayload,
181
+ type: 'document',
182
+ document: {
183
+ link: config.mediaUrl,
184
+ caption: message || config.caption,
185
+ filename: config.filename,
186
+ },
187
+ };
188
+
189
+ case 'audio':
190
+ return {
191
+ ...basePayload,
192
+ type: 'audio',
193
+ audio: {
194
+ link: config.mediaUrl,
195
+ },
196
+ };
197
+
198
+ case 'video':
199
+ return {
200
+ ...basePayload,
201
+ type: 'video',
202
+ video: {
203
+ link: config.mediaUrl,
204
+ caption: message || config.caption,
205
+ },
206
+ };
207
+
208
+ case 'location':
209
+ return {
210
+ ...basePayload,
211
+ type: 'location',
212
+ location: {
213
+ latitude: config.latitude,
214
+ longitude: config.longitude,
215
+ name: config.locationName,
216
+ address: config.locationAddress,
217
+ },
218
+ };
219
+
220
+ case 'interactive':
221
+ return {
222
+ ...basePayload,
223
+ type: 'interactive',
224
+ interactive: {
225
+ type: config.interactiveType || 'button',
226
+ body: {
227
+ text: message,
228
+ },
229
+ footer: config.footer ? { text: config.footer } : undefined,
230
+ action: config.interactiveAction,
231
+ },
232
+ };
233
+
234
+ default:
235
+ // Fall back to text message
236
+ break;
237
+ }
238
+ }
239
+
240
+ // Default text message
241
+ return {
242
+ ...basePayload,
243
+ text: {
244
+ body: message,
245
+ preview_url: config.previewUrl !== false, // Default true
246
+ },
247
+ };
248
+ }
249
+
250
+ private formatPhoneNumber(phoneNumber: string): string {
251
+ // Remove any non-digit characters except +
252
+ let formatted = phoneNumber.replace(/[^\d+]/g, '');
253
+
254
+ // If it doesn't start with +, add country code if provided
255
+ if (!formatted.startsWith('+')) {
256
+ formatted = `+${formatted}`;
257
+ }
258
+
259
+ // Remove + for WhatsApp API (it expects numbers without +)
260
+ return formatted.substring(1);
261
+ }
262
+
263
+ private extractErrorMessage(error: any): string {
264
+ if (error.response?.data?.error?.message) {
265
+ return error.response.data.error.message;
266
+ }
267
+
268
+ if (error.response?.data?.error?.error_user_msg) {
269
+ return error.response.data.error.error_user_msg;
270
+ }
271
+
272
+ if (error.response?.data?.message) {
273
+ return error.response.data.message;
274
+ }
275
+
276
+ if (error.message) {
277
+ return error.message;
278
+ }
279
+
280
+ return 'Unknown WhatsApp API error';
281
+ }
282
+
41
283
  validateConfig(config: any): boolean {
42
- return (
43
- config &&
44
- config.accessToken &&
45
- config.phoneNumberId &&
46
- config.businessAccountId
47
- );
284
+ if (!config || typeof config !== 'object') {
285
+ return false;
286
+ }
287
+
288
+ // Required fields
289
+ if (!config.accessToken || !config.phoneNumberId) {
290
+ return false;
291
+ }
292
+
293
+ // Validate message type specific requirements
294
+ if (config.messageType) {
295
+ switch (config.messageType) {
296
+ case 'template':
297
+ if (!config.templateName) {
298
+ return false;
299
+ }
300
+ break;
301
+
302
+ case 'image':
303
+ case 'document':
304
+ case 'audio':
305
+ case 'video':
306
+ if (!config.mediaUrl) {
307
+ return false;
308
+ }
309
+ break;
310
+
311
+ case 'location':
312
+ if (
313
+ typeof config.latitude !== 'number' ||
314
+ typeof config.longitude !== 'number'
315
+ ) {
316
+ return false;
317
+ }
318
+ break;
319
+
320
+ case 'interactive':
321
+ if (!config.interactiveAction) {
322
+ return false;
323
+ }
324
+ break;
325
+ }
326
+ }
327
+
328
+ return true;
329
+ }
330
+
331
+ async getPhoneNumberInfo(config: WhatsAppConfig): Promise<any> {
332
+ try {
333
+ const apiVersion = config.apiVersion || 'v18.0';
334
+ const url = `${this.baseUrl}/${apiVersion}/${config.phoneNumberId}`;
335
+
336
+ const response = await axios.get(url, {
337
+ headers: {
338
+ Authorization: `Bearer ${config.accessToken}`,
339
+ },
340
+ });
341
+
342
+ return response.data;
343
+ } catch (error) {
344
+ this.logger.error(
345
+ 'Failed to get phone number info',
346
+ error.response?.data || error.message,
347
+ );
348
+ throw new Error(
349
+ `Failed to get phone number info: ${this.extractErrorMessage(error)}`,
350
+ );
351
+ }
352
+ }
353
+
354
+ async getBusinessProfile(config: WhatsAppConfig): Promise<any> {
355
+ try {
356
+ const apiVersion = config.apiVersion || 'v18.0';
357
+ const url = `${this.baseUrl}/${apiVersion}/${config.phoneNumberId}/whatsapp_business_profile`;
358
+
359
+ const response = await axios.get(url, {
360
+ headers: {
361
+ Authorization: `Bearer ${config.accessToken}`,
362
+ },
363
+ });
364
+
365
+ return response.data;
366
+ } catch (error) {
367
+ this.logger.error(
368
+ 'Failed to get business profile',
369
+ error.response?.data || error.message,
370
+ );
371
+ throw new Error(
372
+ `Failed to get business profile: ${this.extractErrorMessage(error)}`,
373
+ );
374
+ }
375
+ }
376
+
377
+ async updateBusinessProfile(
378
+ config: WhatsAppConfig,
379
+ profileData: any,
380
+ ): Promise<any> {
381
+ try {
382
+ const apiVersion = config.apiVersion || 'v18.0';
383
+ const url = `${this.baseUrl}/${apiVersion}/${config.phoneNumberId}/whatsapp_business_profile`;
384
+
385
+ const response = await axios.post(url, profileData, {
386
+ headers: {
387
+ Authorization: `Bearer ${config.accessToken}`,
388
+ 'Content-Type': 'application/json',
389
+ },
390
+ });
391
+
392
+ return response.data;
393
+ } catch (error) {
394
+ this.logger.error(
395
+ 'Failed to update business profile',
396
+ error.response?.data || error.message,
397
+ );
398
+ throw new Error(
399
+ `Failed to update business profile: ${this.extractErrorMessage(error)}`,
400
+ );
401
+ }
48
402
  }
49
403
  }
@@ -463,7 +463,7 @@ export class TaskService extends EntityServiceImpl {
463
463
  );
464
464
 
465
465
  if (!tasks.length) {
466
- console.log('No tasks due in 30 mins');
466
+ // console.log('No tasks due in 30 mins');
467
467
  return;
468
468
  }
469
469