@warriorteam/redai-zalo-sdk 1.2.0 → 1.4.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.
Files changed (77) hide show
  1. package/README.md +563 -550
  2. package/dist/index.d.ts +0 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -5
  5. package/dist/index.js.map +1 -1
  6. package/dist/services/article.service.d.ts +1 -1
  7. package/dist/services/article.service.d.ts.map +1 -1
  8. package/dist/services/article.service.js +24 -16
  9. package/dist/services/article.service.js.map +1 -1
  10. package/dist/services/auth.service.d.ts +1 -0
  11. package/dist/services/auth.service.d.ts.map +1 -1
  12. package/dist/services/auth.service.js +23 -9
  13. package/dist/services/auth.service.js.map +1 -1
  14. package/dist/services/consultation.service.d.ts +63 -16
  15. package/dist/services/consultation.service.d.ts.map +1 -1
  16. package/dist/services/consultation.service.js +264 -49
  17. package/dist/services/consultation.service.js.map +1 -1
  18. package/dist/services/general-message.service.d.ts +2 -25
  19. package/dist/services/general-message.service.d.ts.map +1 -1
  20. package/dist/services/general-message.service.js +11 -112
  21. package/dist/services/general-message.service.js.map +1 -1
  22. package/dist/services/group-management.service.d.ts +1 -1
  23. package/dist/services/group-management.service.d.ts.map +1 -1
  24. package/dist/services/group-management.service.js +59 -27
  25. package/dist/services/group-management.service.js.map +1 -1
  26. package/dist/services/group-message.service.d.ts +1 -1
  27. package/dist/services/group-message.service.d.ts.map +1 -1
  28. package/dist/services/group-message.service.js +49 -23
  29. package/dist/services/group-message.service.js.map +1 -1
  30. package/dist/services/message-management.service.d.ts +21 -2
  31. package/dist/services/message-management.service.d.ts.map +1 -1
  32. package/dist/services/message-management.service.js +83 -7
  33. package/dist/services/message-management.service.js.map +1 -1
  34. package/dist/services/oa.service.d.ts +1 -0
  35. package/dist/services/oa.service.d.ts.map +1 -1
  36. package/dist/services/oa.service.js +23 -5
  37. package/dist/services/oa.service.js.map +1 -1
  38. package/dist/services/user.service.d.ts +108 -18
  39. package/dist/services/user.service.d.ts.map +1 -1
  40. package/dist/services/user.service.js +260 -59
  41. package/dist/services/user.service.js.map +1 -1
  42. package/dist/services/video-upload.service.d.ts +1 -1
  43. package/dist/services/video-upload.service.d.ts.map +1 -1
  44. package/dist/services/video-upload.service.js +11 -8
  45. package/dist/services/video-upload.service.js.map +1 -1
  46. package/dist/services/zns.service.d.ts +88 -21
  47. package/dist/services/zns.service.d.ts.map +1 -1
  48. package/dist/services/zns.service.js +157 -42
  49. package/dist/services/zns.service.js.map +1 -1
  50. package/dist/types/group.d.ts +5 -5
  51. package/dist/types/group.d.ts.map +1 -1
  52. package/dist/types/user.d.ts +155 -12
  53. package/dist/types/user.d.ts.map +1 -1
  54. package/dist/types/user.js.map +1 -1
  55. package/dist/types/zns.d.ts +67 -33
  56. package/dist/types/zns.d.ts.map +1 -1
  57. package/dist/zalo-sdk.d.ts +3 -11
  58. package/dist/zalo-sdk.d.ts.map +1 -1
  59. package/dist/zalo-sdk.js +0 -10
  60. package/dist/zalo-sdk.js.map +1 -1
  61. package/docs/API_REFERENCE.md +680 -0
  62. package/docs/AUTHENTICATION.md +709 -0
  63. package/docs/CONSULTATION_SERVICE.md +512 -330
  64. package/docs/GROUP_MANAGEMENT.md +2 -2
  65. package/docs/MESSAGE_SERVICES.md +1224 -0
  66. package/docs/TAG_MANAGEMENT.md +1462 -0
  67. package/docs/USER_MANAGEMENT.md +481 -0
  68. package/docs/ZNS_SERVICE.md +985 -0
  69. package/package.json +1 -1
  70. package/dist/services/tag.service.d.ts +0 -144
  71. package/dist/services/tag.service.d.ts.map +0 -1
  72. package/dist/services/tag.service.js +0 -184
  73. package/dist/services/tag.service.js.map +0 -1
  74. package/dist/services/user-management.service.d.ts +0 -117
  75. package/dist/services/user-management.service.d.ts.map +0 -1
  76. package/dist/services/user-management.service.js +0 -239
  77. package/dist/services/user-management.service.js.map +0 -1
@@ -0,0 +1,1224 @@
1
+ # RedAI Zalo SDK - Message Services Guide
2
+
3
+ ## Tổng quan
4
+
5
+ RedAI Zalo SDK cung cấp các Message Services chuyên biệt để gửi các loại tin nhắn khác nhau qua Zalo Official Account. Mỗi loại tin nhắn có mục đích, quy tắc và giới hạn riêng.
6
+
7
+ ## Các loại Message Services
8
+
9
+ | Service | Mục đích | Thời gian gửi | Giới hạn |
10
+ |---------|----------|---------------|----------|
11
+ | **ConsultationService** | Hỗ trợ khách hàng | Trong 48h sau tương tác | Không giới hạn |
12
+ | **TransactionService** | Thông báo giao dịch | Bất cứ lúc nào | Theo quota |
13
+ | **PromotionService** | Tin nhắn khuyến mại | Theo quy định | Giới hạn theo gói |
14
+ | **GeneralMessageService** | Tin nhắn chung | Phản hồi user | Theo quota |
15
+ | **MessageManagementService** | Quản lý tin nhắn | N/A | N/A |
16
+
17
+ ---
18
+
19
+ ## ConsultationService
20
+
21
+ Dùng để **hỗ trợ khách hàng** trong vòng 48 giờ sau khi user tương tác với OA.
22
+
23
+ ### Khởi tạo
24
+
25
+ ```typescript
26
+ import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";
27
+
28
+ const zalo = new ZaloSDK({
29
+ appId: "your-app-id",
30
+ appSecret: "your-app-secret"
31
+ });
32
+
33
+ // Access consultation service
34
+ const consultationService = zalo.consultation;
35
+ ```
36
+
37
+ ### 1. Gửi tin nhắn text
38
+
39
+ ```typescript
40
+ // Gửi text consultation message
41
+ await zalo.consultation.sendTextMessage(
42
+ accessToken,
43
+ { user_id: "user-zalo-id" },
44
+ {
45
+ type: "text",
46
+ text: "Xin chào! Tôi có thể hỗ trợ gì cho bạn không?"
47
+ }
48
+ );
49
+ ```
50
+
51
+ ### 2. Gửi hình ảnh
52
+
53
+ ```typescript
54
+ // Gửi hình ảnh hướng dẫn
55
+ await zalo.consultation.sendImageMessage(
56
+ accessToken,
57
+ { user_id: "user-zalo-id" },
58
+ {
59
+ type: "image",
60
+ attachment_id: "image-attachment-id", // ID sau khi upload
61
+ // hoặc sử dụng URL
62
+ attachment: {
63
+ type: "image",
64
+ payload: {
65
+ url: "https://example.com/support-image.jpg"
66
+ }
67
+ }
68
+ }
69
+ );
70
+ ```
71
+
72
+ ### 3. Gửi file đính kèm
73
+
74
+ ```typescript
75
+ // Gửi file hướng dẫn, catalog
76
+ await zalo.consultation.sendFileMessage(
77
+ accessToken,
78
+ { user_id: "user-zalo-id" },
79
+ {
80
+ type: "file",
81
+ url: "https://example.com/user-manual.pdf",
82
+ filename: "Hướng dẫn sử dụng.pdf",
83
+ attachment: {
84
+ type: "file",
85
+ payload: {
86
+ url: "https://example.com/user-manual.pdf"
87
+ }
88
+ }
89
+ }
90
+ );
91
+ ```
92
+
93
+ ### 4. Gửi sticker
94
+
95
+ ```typescript
96
+ // Gửi sticker để tạo không khí thân thiện
97
+ await zalo.consultation.sendStickerMessage(
98
+ accessToken,
99
+ { user_id: "user-zalo-id" },
100
+ {
101
+ type: "sticker",
102
+ attachment: {
103
+ type: "sticker",
104
+ payload: {
105
+ sticker_id: "sticker-id"
106
+ }
107
+ }
108
+ }
109
+ );
110
+ ```
111
+
112
+ ### 5. Gửi tin nhắn quote (trích dẫn)
113
+
114
+ ```typescript
115
+ // Quote tin nhắn trước đó của user
116
+ await zalo.consultation.sendQuoteMessage(
117
+ accessToken,
118
+ { user_id: "user-zalo-id" },
119
+ {
120
+ type: "quote",
121
+ text: "Cảm ơn bạn đã hỏi về sản phẩm này",
122
+ quote_msg_id: "original-message-id"
123
+ }
124
+ );
125
+ ```
126
+
127
+ ### 6. Yêu cầu thông tin user
128
+
129
+ ```typescript
130
+ // Yêu cầu user cung cấp thông tin
131
+ await zalo.consultation.sendRequestInfoMessage(
132
+ accessToken,
133
+ { user_id: "user-zalo-id" },
134
+ {
135
+ type: "request_user_info",
136
+ title: "Thông tin liên hệ",
137
+ subtitle: "Vui lòng cung cấp thông tin để chúng tôi hỗ trợ tốt hơn",
138
+ image_url: "https://example.com/contact-form.jpg"
139
+ }
140
+ );
141
+ ```
142
+
143
+ ### Consultation Use Cases
144
+
145
+ ```typescript
146
+ class CustomerSupportService {
147
+ constructor(private zalo: ZaloSDK, private accessToken: string) {}
148
+
149
+ // Phản hồi câu hỏi về sản phẩm
150
+ async respondToProductInquiry(userId: string, productId: string) {
151
+ const product = await this.getProductInfo(productId);
152
+
153
+ // Gửi thông tin sản phẩm
154
+ await this.zalo.consultation.sendTextMessage(
155
+ this.accessToken,
156
+ { user_id: userId },
157
+ {
158
+ type: "text",
159
+ text: `Thông tin sản phẩm ${product.name}:
160
+
161
+ 💰 Giá: ${product.price.toLocaleString('vi-VN')} VNĐ
162
+ 📦 Tình trạng: ${product.stock > 0 ? 'Còn hàng' : 'Hết hàng'}
163
+ 🚚 Giao hàng: ${product.deliveryTime}
164
+
165
+ Bạn có muốn đặt hàng không?`
166
+ }
167
+ );
168
+
169
+ // Gửi hình ảnh sản phẩm
170
+ if (product.imageUrl) {
171
+ await this.zalo.consultation.sendImageMessage(
172
+ this.accessToken,
173
+ { user_id: userId },
174
+ {
175
+ type: "image",
176
+ attachment: {
177
+ type: "image",
178
+ payload: { url: product.imageUrl }
179
+ }
180
+ }
181
+ );
182
+ }
183
+ }
184
+
185
+ // Hỗ trợ khiếu nại
186
+ async handleComplaint(userId: string, complaintText: string) {
187
+ // Quote lại tin nhắn khiếu nại
188
+ await this.zalo.consultation.sendQuoteMessage(
189
+ this.accessToken,
190
+ { user_id: userId },
191
+ {
192
+ type: "quote",
193
+ text: "Chúng tôi đã nhận được phản hồi của bạn và sẽ xử lý trong 24h. Cảm ơn bạn đã góp ý!",
194
+ quote_msg_id: complaintText // ID của tin nhắn khiếu nại
195
+ }
196
+ );
197
+
198
+ // Yêu cầu thêm thông tin nếu cần
199
+ await this.zalo.consultation.sendRequestInfoMessage(
200
+ this.accessToken,
201
+ { user_id: userId },
202
+ {
203
+ type: "request_user_info",
204
+ title: "Thông tin bổ sung",
205
+ subtitle: "Để xử lý khiếu nại hiệu quả, vui lòng cung cấp thêm thông tin liên hệ"
206
+ }
207
+ );
208
+ }
209
+ }
210
+ ```
211
+
212
+ ---
213
+
214
+ ## TransactionService
215
+
216
+ Gửi tin nhắn **thông báo giao dịch** như đơn hàng, thanh toán, vận chuyển.
217
+
218
+ ### Khởi tạo
219
+
220
+ ```typescript
221
+ const transactionService = zalo.transaction;
222
+ ```
223
+
224
+ ### Gửi transaction message
225
+
226
+ ```typescript
227
+ // Thông báo đơn hàng
228
+ await zalo.transaction.sendTransactionMessage(
229
+ accessToken,
230
+ { user_id: "user-zalo-id" },
231
+ {
232
+ type: "transaction",
233
+ template_type: "order_update",
234
+ template_data: {
235
+ order_id: "DH001234",
236
+ status: "Đã xác nhận",
237
+ total_amount: "299,000 VNĐ",
238
+ items: "Áo thun x2, Quần jean x1",
239
+ delivery_date: "25/12/2024"
240
+ },
241
+ attachment: {
242
+ type: "template",
243
+ payload: {
244
+ template_type: "receipt",
245
+ elements: [{
246
+ title: "Đơn hàng #DH001234",
247
+ subtitle: "Tổng tiền: 299,000 VNĐ",
248
+ image_url: "https://example.com/order-receipt.jpg",
249
+ buttons: [{
250
+ type: "web_url",
251
+ title: "Xem chi tiết",
252
+ url: "https://mystore.com/order/DH001234"
253
+ }]
254
+ }]
255
+ }
256
+ }
257
+ }
258
+ );
259
+ ```
260
+
261
+ ### Transaction Use Cases
262
+
263
+ ```typescript
264
+ class TransactionNotificationService {
265
+ constructor(private zalo: ZaloSDK, private accessToken: string) {}
266
+
267
+ // Thông báo xác nhận đơn hàng
268
+ async sendOrderConfirmation(order: Order) {
269
+ await this.zalo.transaction.sendTransactionMessage(
270
+ this.accessToken,
271
+ { user_id: order.customerId },
272
+ {
273
+ type: "transaction",
274
+ template_type: "order_confirmation",
275
+ template_data: {
276
+ customer_name: order.customerName,
277
+ order_id: order.id,
278
+ order_date: this.formatDate(order.createdAt),
279
+ total_amount: this.formatCurrency(order.totalAmount),
280
+ payment_method: order.paymentMethod,
281
+ delivery_address: order.deliveryAddress,
282
+ estimated_delivery: this.formatDate(order.estimatedDelivery)
283
+ }
284
+ }
285
+ );
286
+ }
287
+
288
+ // Cập nhật trạng thái vận chuyển
289
+ async sendShippingUpdate(order: Order, trackingInfo: TrackingInfo) {
290
+ await this.zalo.transaction.sendTransactionMessage(
291
+ this.accessToken,
292
+ { user_id: order.customerId },
293
+ {
294
+ type: "transaction",
295
+ template_type: "shipping_update",
296
+ template_data: {
297
+ order_id: order.id,
298
+ status: trackingInfo.status,
299
+ tracking_code: trackingInfo.trackingCode,
300
+ current_location: trackingInfo.currentLocation,
301
+ estimated_delivery: this.formatDate(trackingInfo.estimatedDelivery)
302
+ },
303
+ attachment: {
304
+ type: "template",
305
+ payload: {
306
+ template_type: "generic",
307
+ elements: [{
308
+ title: `Đơn hàng ${order.id}`,
309
+ subtitle: `Trạng thái: ${trackingInfo.status}`,
310
+ buttons: [{
311
+ type: "web_url",
312
+ title: "Tra cứu vận đơn",
313
+ url: `https://tracking.com/${trackingInfo.trackingCode}`
314
+ }]
315
+ }]
316
+ }
317
+ }
318
+ }
319
+ );
320
+ }
321
+
322
+ // Thông báo thanh toán
323
+ async sendPaymentNotification(payment: Payment) {
324
+ await this.zalo.transaction.sendTransactionMessage(
325
+ this.accessToken,
326
+ { user_id: payment.customerId },
327
+ {
328
+ type: "transaction",
329
+ template_type: "payment_confirmation",
330
+ template_data: {
331
+ transaction_id: payment.transactionId,
332
+ amount: this.formatCurrency(payment.amount),
333
+ payment_method: payment.method,
334
+ payment_date: this.formatDateTime(payment.createdAt),
335
+ merchant_name: payment.merchantName
336
+ }
337
+ }
338
+ );
339
+ }
340
+
341
+ private formatCurrency(amount: number): string {
342
+ return new Intl.NumberFormat('vi-VN').format(amount) + ' VNĐ';
343
+ }
344
+
345
+ private formatDate(date: Date): string {
346
+ return date.toLocaleDateString('vi-VN');
347
+ }
348
+
349
+ private formatDateTime(date: Date): string {
350
+ return date.toLocaleString('vi-VN');
351
+ }
352
+ }
353
+ ```
354
+
355
+ ---
356
+
357
+ ## PromotionService
358
+
359
+ Gửi tin nhắn **khuyến mại và marketing** theo quy định của Zalo.
360
+
361
+ ### Khởi tạo
362
+
363
+ ```typescript
364
+ const promotionService = zalo.promotion;
365
+ ```
366
+
367
+ ### Gửi promotion message
368
+
369
+ ```typescript
370
+ // Thông báo khuyến mại
371
+ await zalo.promotion.sendPromotionMessage(
372
+ accessToken,
373
+ { user_id: "user-zalo-id" },
374
+ {
375
+ type: "promotion",
376
+ template_type: "sale_announcement",
377
+ template_data: {
378
+ promotion_title: "FLASH SALE - Giảm 50%",
379
+ discount_percentage: "50%",
380
+ original_price: "500,000 VNĐ",
381
+ discounted_price: "250,000 VNĐ",
382
+ valid_until: "31/12/2024 23:59",
383
+ terms_conditions: "Áp dụng cho đơn hàng từ 200,000 VNĐ"
384
+ },
385
+ attachment: {
386
+ type: "template",
387
+ payload: {
388
+ template_type: "generic",
389
+ elements: [{
390
+ title: "🔥 FLASH SALE - Giảm 50%",
391
+ subtitle: "Chỉ còn 2 ngày! Đừng bỏ lỡ cơ hội tiết kiệm lớn",
392
+ image_url: "https://example.com/flash-sale-banner.jpg",
393
+ buttons: [
394
+ {
395
+ type: "web_url",
396
+ title: "Mua ngay",
397
+ url: "https://mystore.com/flash-sale"
398
+ },
399
+ {
400
+ type: "postback",
401
+ title: "Xem thêm",
402
+ payload: "VIEW_MORE_PROMOTIONS"
403
+ }
404
+ ]
405
+ }]
406
+ }
407
+ }
408
+ }
409
+ );
410
+ ```
411
+
412
+ ### Promotion Use Cases
413
+
414
+ ```typescript
415
+ class MarketingCampaignService {
416
+ constructor(private zalo: ZaloSDK, private accessToken: string) {}
417
+
418
+ // Campaign sale sự kiện
419
+ async sendEventSaleCampaign(userSegment: string[], campaign: Campaign) {
420
+ const results = [];
421
+
422
+ for (const userId of userSegment) {
423
+ try {
424
+ await this.zalo.promotion.sendPromotionMessage(
425
+ this.accessToken,
426
+ { user_id: userId },
427
+ {
428
+ type: "promotion",
429
+ template_type: "event_sale",
430
+ template_data: {
431
+ customer_name: await this.getUserName(userId),
432
+ event_name: campaign.eventName,
433
+ discount_code: this.generatePersonalizedCode(userId),
434
+ discount_value: campaign.discountValue,
435
+ min_order_value: campaign.minOrderValue,
436
+ valid_until: this.formatDate(campaign.endDate)
437
+ }
438
+ }
439
+ );
440
+
441
+ results.push({ userId, success: true });
442
+ } catch (error) {
443
+ results.push({ userId, success: false, error: error.message });
444
+ }
445
+ }
446
+
447
+ return results;
448
+ }
449
+
450
+ // Thông báo sản phẩm mới
451
+ async sendNewProductAnnouncement(product: Product, targetUsers: string[]) {
452
+ for (const userId of targetUsers) {
453
+ await this.zalo.promotion.sendPromotionMessage(
454
+ this.accessToken,
455
+ { user_id: userId },
456
+ {
457
+ type: "promotion",
458
+ template_type: "new_product",
459
+ template_data: {
460
+ product_name: product.name,
461
+ product_description: product.description,
462
+ launch_price: this.formatCurrency(product.launchPrice),
463
+ regular_price: this.formatCurrency(product.regularPrice),
464
+ availability_date: this.formatDate(product.launchDate)
465
+ },
466
+ attachment: {
467
+ type: "template",
468
+ payload: {
469
+ template_type: "generic",
470
+ elements: [{
471
+ title: `🆕 ${product.name}`,
472
+ subtitle: product.description,
473
+ image_url: product.imageUrl,
474
+ buttons: [{
475
+ type: "web_url",
476
+ title: "Đặt hàng ngay",
477
+ url: `https://mystore.com/product/${product.id}`
478
+ }]
479
+ }]
480
+ }
481
+ }
482
+ }
483
+ );
484
+ }
485
+ }
486
+
487
+ // Nhắc nhở giỏ hàng bỏ dở
488
+ async sendAbandonedCartReminder(userId: string, cart: Cart) {
489
+ await this.zalo.promotion.sendPromotionMessage(
490
+ this.accessToken,
491
+ { user_id: userId },
492
+ {
493
+ type: "promotion",
494
+ template_type: "cart_abandonment",
495
+ template_data: {
496
+ customer_name: cart.customerName,
497
+ cart_total: this.formatCurrency(cart.totalValue),
498
+ items_count: cart.items.length.toString(),
499
+ special_offer: "Giảm thêm 10% nếu hoàn tất đơn hàng trong 24h",
500
+ discount_code: this.generateCartRecoveryCode(userId)
501
+ }
502
+ }
503
+ );
504
+ }
505
+
506
+ private generatePersonalizedCode(userId: string): string {
507
+ return `PERSONAL${userId.slice(-6).toUpperCase()}`;
508
+ }
509
+
510
+ private generateCartRecoveryCode(userId: string): string {
511
+ return `RECOVERY${Date.now().toString().slice(-6)}`;
512
+ }
513
+ }
514
+ ```
515
+
516
+ ---
517
+
518
+ ## GeneralMessageService
519
+
520
+ Gửi tin nhắn **phản hồi chung** và **anonymous messages**.
521
+
522
+ ### Khởi tạo
523
+
524
+ ```typescript
525
+ const generalService = zalo.generalMessage;
526
+ ```
527
+
528
+ ### 1. Gửi response message
529
+
530
+ ```typescript
531
+ // Phản hồi tin nhắn của user
532
+ await zalo.generalMessage.sendResponseMessage(
533
+ accessToken,
534
+ { user_id: "user-zalo-id" },
535
+ {
536
+ type: "text",
537
+ text: "Cảm ơn bạn đã liên hệ với chúng tôi!"
538
+ }
539
+ );
540
+ ```
541
+
542
+ ### 2. Gửi anonymous message
543
+
544
+ ```typescript
545
+ // Gửi tin nhắn anonymous (không hiện tên OA)
546
+ await zalo.generalMessage.sendAnonymousMessage(
547
+ accessToken,
548
+ { user_id: "user-zalo-id" },
549
+ {
550
+ type: "text",
551
+ text: "Đây là tin nhắn anonymous từ hệ thống",
552
+ is_anonymous: true
553
+ }
554
+ );
555
+ ```
556
+
557
+ ### General Message Use Cases
558
+
559
+ ```typescript
560
+ class AutoResponseService {
561
+ constructor(private zalo: ZaloSDK, private accessToken: string) {}
562
+
563
+ // Auto response cho các câu hỏi thường gặp
564
+ async handleAutoResponse(userId: string, messageText: string) {
565
+ const responses = this.getAutoResponses();
566
+
567
+ for (const [keyword, response] of responses) {
568
+ if (messageText.toLowerCase().includes(keyword)) {
569
+ await this.zalo.generalMessage.sendResponseMessage(
570
+ this.accessToken,
571
+ { user_id: userId },
572
+ {
573
+ type: "text",
574
+ text: response
575
+ }
576
+ );
577
+ break;
578
+ }
579
+ }
580
+ }
581
+
582
+ // Gửi thông báo hệ thống
583
+ async sendSystemNotification(userId: string, notificationType: string) {
584
+ let message = "";
585
+
586
+ switch (notificationType) {
587
+ case "maintenance":
588
+ message = "🔧 Hệ thống đang bảo trì từ 2:00 - 4:00 sáng ngày mai. Xin lỗi vì sự bất tiện!";
589
+ break;
590
+ case "service_update":
591
+ message = "🆙 Chúng tôi vừa cập nhật tính năng mới! Hãy trải nghiệm nhé.";
592
+ break;
593
+ default:
594
+ message = "📢 Thông báo từ hệ thống";
595
+ }
596
+
597
+ await this.zalo.generalMessage.sendAnonymousMessage(
598
+ this.accessToken,
599
+ { user_id: userId },
600
+ {
601
+ type: "text",
602
+ text: message,
603
+ is_anonymous: true
604
+ }
605
+ );
606
+ }
607
+
608
+ private getAutoResponses(): Map<string, string> {
609
+ return new Map([
610
+ ["giờ mở cửa", "🕒 Giờ mở cửa: 8:00 - 22:00 hàng ngày"],
611
+ ["địa chỉ", "📍 Địa chỉ: 123 Nguyễn Văn A, Q.1, TP.HCM"],
612
+ ["liên hệ", "📞 Hotline: 1800-xxx-xxx\n📧 Email: support@example.com"],
613
+ ["giao hàng", "🚚 Giao hàng: 1-3 ngày làm việc trong nội thành"],
614
+ ["thanh toán", "💳 Hình thức thanh toán: Tiền mặt, chuyển khoản, thẻ tín dụng"]
615
+ ]);
616
+ }
617
+ }
618
+ ```
619
+
620
+ ---
621
+
622
+ ## MessageManagementService
623
+
624
+ Quản lý và phân tích tin nhắn đã gửi.
625
+
626
+ ### Khởi tạo
627
+
628
+ ```typescript
629
+ const messageManagement = zalo.messageManagement;
630
+ ```
631
+
632
+ ### 1. Lấy lịch sử tin nhắn
633
+
634
+ ```typescript
635
+ // Lấy lịch sử tin nhắn với user
636
+ const messageHistory = await zalo.messageManagement.getMessageHistory(
637
+ accessToken,
638
+ {
639
+ user_id: "user-zalo-id",
640
+ from_time: Date.now() - (7 * 24 * 60 * 60 * 1000), // 7 days ago
641
+ to_time: Date.now(),
642
+ offset: 0,
643
+ limit: 50
644
+ }
645
+ );
646
+
647
+ messageHistory.data.forEach(message => {
648
+ console.log(`${message.time}: ${message.message}`);
649
+ });
650
+ ```
651
+
652
+ ### 2. Thống kê tin nhắn
653
+
654
+ ```typescript
655
+ // Lấy analytics tin nhắn
656
+ const analytics = await zalo.messageManagement.getMessageAnalytics(
657
+ accessToken,
658
+ {
659
+ from_date: "2024-12-01",
660
+ to_date: "2024-12-31",
661
+ message_type: "all" // consultation, transaction, promotion
662
+ }
663
+ );
664
+
665
+ console.log("Tổng tin nhắn gửi:", analytics.total_sent);
666
+ console.log("Tỷ lệ đọc:", analytics.read_rate);
667
+ console.log("Tỷ lệ phản hồi:", analytics.response_rate);
668
+ ```
669
+
670
+ ### 3. Kiểm tra trạng thái tin nhắn
671
+
672
+ ```typescript
673
+ // Kiểm tra tin nhắn đã được gửi thành công chưa
674
+ const messageStatus = await zalo.messageManagement.getMessageStatus(
675
+ accessToken,
676
+ "message-id"
677
+ );
678
+
679
+ console.log("Status:", messageStatus.status); // sent, delivered, read, failed
680
+ console.log("Sent time:", messageStatus.sent_time);
681
+ console.log("Delivered time:", messageStatus.delivered_time);
682
+ ```
683
+
684
+ ### Message Management Use Cases
685
+
686
+ ```typescript
687
+ class MessageAnalyticsService {
688
+ constructor(private zalo: ZaloSDK, private accessToken: string) {}
689
+
690
+ // Báo cáo hiệu quả campaign
691
+ async getCampaignReport(campaignId: string, dateRange: DateRange) {
692
+ const analytics = await this.zalo.messageManagement.getMessageAnalytics(
693
+ this.accessToken,
694
+ {
695
+ from_date: this.formatDate(dateRange.start),
696
+ to_date: this.formatDate(dateRange.end),
697
+ campaign_id: campaignId
698
+ }
699
+ );
700
+
701
+ return {
702
+ campaignId,
703
+ totalSent: analytics.total_sent,
704
+ deliveryRate: (analytics.delivered / analytics.total_sent * 100).toFixed(2) + '%',
705
+ readRate: (analytics.read / analytics.delivered * 100).toFixed(2) + '%',
706
+ responseRate: (analytics.responses / analytics.read * 100).toFixed(2) + '%',
707
+ conversionRate: analytics.conversion_rate || '0%'
708
+ };
709
+ }
710
+
711
+ // Phân tích tương tác của user
712
+ async getUserEngagementAnalysis(userId: string) {
713
+ const history = await this.zalo.messageManagement.getMessageHistory(
714
+ this.accessToken,
715
+ {
716
+ user_id: userId,
717
+ from_time: Date.now() - (30 * 24 * 60 * 60 * 1000), // 30 days
718
+ to_time: Date.now(),
719
+ limit: 1000
720
+ }
721
+ );
722
+
723
+ const sentMessages = history.data.filter(msg => msg.from_oa);
724
+ const receivedMessages = history.data.filter(msg => !msg.from_oa);
725
+
726
+ return {
727
+ userId,
728
+ messagesSent: sentMessages.length,
729
+ messagesReceived: receivedMessages.length,
730
+ avgResponseTime: this.calculateAvgResponseTime(history.data),
731
+ lastInteraction: history.data[0]?.time,
732
+ engagementLevel: this.calculateEngagementLevel(sentMessages, receivedMessages)
733
+ };
734
+ }
735
+
736
+ // Tìm tin nhắn chưa được phản hồi
737
+ async findUnrespondedMessages(timeWindow: number = 24 * 60 * 60 * 1000) {
738
+ // Lấy tất cả conversations trong khoảng thời gian
739
+ const cutoffTime = Date.now() - timeWindow;
740
+
741
+ const conversations = await this.getAllActiveConversations();
742
+ const unresponded = [];
743
+
744
+ for (const conv of conversations) {
745
+ const history = await this.zalo.messageManagement.getMessageHistory(
746
+ this.accessToken,
747
+ {
748
+ user_id: conv.user_id,
749
+ from_time: cutoffTime,
750
+ to_time: Date.now(),
751
+ limit: 10
752
+ }
753
+ );
754
+
755
+ const lastMessage = history.data[0];
756
+ if (lastMessage && !lastMessage.from_oa && lastMessage.time > cutoffTime) {
757
+ unresponded.push({
758
+ userId: conv.user_id,
759
+ lastMessage: lastMessage.message,
760
+ waitingTime: Date.now() - lastMessage.time
761
+ });
762
+ }
763
+ }
764
+
765
+ return unresponded;
766
+ }
767
+
768
+ private calculateAvgResponseTime(messages: any[]): number {
769
+ let totalResponseTime = 0;
770
+ let responseCount = 0;
771
+
772
+ for (let i = 1; i < messages.length; i++) {
773
+ const current = messages[i];
774
+ const previous = messages[i - 1];
775
+
776
+ if (current.from_oa && !previous.from_oa) {
777
+ totalResponseTime += (previous.time - current.time);
778
+ responseCount++;
779
+ }
780
+ }
781
+
782
+ return responseCount > 0 ? totalResponseTime / responseCount : 0;
783
+ }
784
+
785
+ private calculateEngagementLevel(sentMessages: any[], receivedMessages: any[]): string {
786
+ const ratio = receivedMessages.length / (sentMessages.length || 1);
787
+
788
+ if (ratio > 2) return "Very High";
789
+ if (ratio > 1.5) return "High";
790
+ if (ratio > 1) return "Medium";
791
+ if (ratio > 0.5) return "Low";
792
+ return "Very Low";
793
+ }
794
+ }
795
+ ```
796
+
797
+ ---
798
+
799
+ ## Message Templates & Rich Content
800
+
801
+ ### 1. Template Messages
802
+
803
+ ```typescript
804
+ // Generic template với buttons
805
+ const genericTemplate = {
806
+ type: "template",
807
+ attachment: {
808
+ type: "template",
809
+ payload: {
810
+ template_type: "generic",
811
+ elements: [{
812
+ title: "Sản phẩm mới ra mắt",
813
+ subtitle: "iPhone 15 Pro Max - Titanium mới",
814
+ image_url: "https://example.com/iphone15.jpg",
815
+ buttons: [
816
+ {
817
+ type: "web_url",
818
+ title: "Xem chi tiết",
819
+ url: "https://store.com/iphone15"
820
+ },
821
+ {
822
+ type: "postback",
823
+ title: "Đặt hàng",
824
+ payload: "ORDER_IPHONE15"
825
+ }
826
+ ]
827
+ }]
828
+ }
829
+ }
830
+ };
831
+
832
+ await zalo.consultation.sendMessage(accessToken, recipient, genericTemplate);
833
+ ```
834
+
835
+ ### 2. List Template
836
+
837
+ ```typescript
838
+ // List template cho menu hoặc catalog
839
+ const listTemplate = {
840
+ type: "template",
841
+ attachment: {
842
+ type: "template",
843
+ payload: {
844
+ template_type: "list",
845
+ top_element_style: "compact", // hoặc "large"
846
+ elements: [
847
+ {
848
+ title: "iPhone 15 Pro",
849
+ subtitle: "From $999",
850
+ image_url: "https://example.com/iphone15pro.jpg",
851
+ buttons: [{
852
+ type: "web_url",
853
+ title: "Buy",
854
+ url: "https://store.com/iphone15pro"
855
+ }]
856
+ },
857
+ {
858
+ title: "iPhone 15",
859
+ subtitle: "From $799",
860
+ image_url: "https://example.com/iphone15.jpg",
861
+ buttons: [{
862
+ type: "web_url",
863
+ title: "Buy",
864
+ url: "https://store.com/iphone15"
865
+ }]
866
+ }
867
+ ]
868
+ }
869
+ }
870
+ };
871
+ ```
872
+
873
+ ### 3. Button Template
874
+
875
+ ```typescript
876
+ // Button template cho quick actions
877
+ const buttonTemplate = {
878
+ type: "template",
879
+ attachment: {
880
+ type: "template",
881
+ payload: {
882
+ template_type: "button",
883
+ text: "Bạn muốn làm gì tiếp theo?",
884
+ buttons: [
885
+ {
886
+ type: "web_url",
887
+ title: "Xem sản phẩm",
888
+ url: "https://store.com/products"
889
+ },
890
+ {
891
+ type: "postback",
892
+ title: "Liên hệ hỗ trợ",
893
+ payload: "CONTACT_SUPPORT"
894
+ },
895
+ {
896
+ type: "phone_number",
897
+ title: "Gọi hotline",
898
+ payload: "+84123456789"
899
+ }
900
+ ]
901
+ }
902
+ }
903
+ };
904
+ ```
905
+
906
+ ---
907
+
908
+ ## Best Practices
909
+
910
+ ### 1. Message Timing
911
+
912
+ ```typescript
913
+ // Kiểm tra thời gian thích hợp để gửi tin nhắn
914
+ function isAppropriateTime(): boolean {
915
+ const now = new Date();
916
+ const hour = now.getHours();
917
+
918
+ // Tránh gửi tin nhắn quá sớm (trước 8h) hoặc quá muộn (sau 22h)
919
+ return hour >= 8 && hour <= 22;
920
+ }
921
+
922
+ async function sendMessageAtAppropriateTime(
923
+ messageFunc: () => Promise<any>
924
+ ): Promise<void> {
925
+ if (isAppropriateTime()) {
926
+ await messageFunc();
927
+ } else {
928
+ // Schedule message for later
929
+ console.log("Message scheduled for appropriate time");
930
+ // Implement scheduling logic
931
+ }
932
+ }
933
+ ```
934
+
935
+ ### 2. Message Personalization
936
+
937
+ ```typescript
938
+ class MessagePersonalizer {
939
+ static personalizeMessage(template: string, userData: UserData): string {
940
+ return template
941
+ .replace(/\{name\}/g, userData.name || "bạn")
942
+ .replace(/\{first_name\}/g, userData.firstName || "bạn")
943
+ .replace(/\{last_purchase\}/g, userData.lastPurchase || "gần đây")
944
+ .replace(/\{city\}/g, userData.city || "");
945
+ }
946
+
947
+ static getPersonalizedGreeting(userData: UserData): string {
948
+ const hour = new Date().getHours();
949
+ let greeting;
950
+
951
+ if (hour < 12) greeting = "Chào buổi sáng";
952
+ else if (hour < 18) greeting = "Chào buổi chiều";
953
+ else greeting = "Chào buổi tối";
954
+
955
+ const name = userData.name || "bạn";
956
+ return `${greeting} ${name}! `;
957
+ }
958
+ }
959
+ ```
960
+
961
+ ### 3. Rate Limiting & Queue Management
962
+
963
+ ```typescript
964
+ class MessageQueue {
965
+ private queue: Array<MessageTask> = [];
966
+ private processing = false;
967
+ private readonly maxConcurrent = 5;
968
+ private readonly delayBetweenMessages = 1000; // 1 second
969
+
970
+ async addMessage(task: MessageTask): Promise<void> {
971
+ this.queue.push(task);
972
+
973
+ if (!this.processing) {
974
+ this.processQueue();
975
+ }
976
+ }
977
+
978
+ private async processQueue(): Promise<void> {
979
+ this.processing = true;
980
+
981
+ while (this.queue.length > 0) {
982
+ const batch = this.queue.splice(0, this.maxConcurrent);
983
+
984
+ const promises = batch.map(async (task) => {
985
+ try {
986
+ await task.execute();
987
+ console.log(`✅ Message sent to ${task.userId}`);
988
+ } catch (error) {
989
+ console.error(`❌ Failed to send to ${task.userId}:`, error);
990
+ }
991
+ });
992
+
993
+ await Promise.all(promises);
994
+
995
+ // Delay between batches
996
+ if (this.queue.length > 0) {
997
+ await this.delay(this.delayBetweenMessages);
998
+ }
999
+ }
1000
+
1001
+ this.processing = false;
1002
+ }
1003
+
1004
+ private delay(ms: number): Promise<void> {
1005
+ return new Promise(resolve => setTimeout(resolve, ms));
1006
+ }
1007
+ }
1008
+
1009
+ interface MessageTask {
1010
+ userId: string;
1011
+ execute: () => Promise<any>;
1012
+ }
1013
+ ```
1014
+
1015
+ ---
1016
+
1017
+ ## Error Handling & Retry Logic
1018
+
1019
+ ### 1. Message-specific Error Handling
1020
+
1021
+ ```typescript
1022
+ async function sendMessageWithErrorHandling(
1023
+ messageFunc: () => Promise<any>,
1024
+ messageType: string
1025
+ ): Promise<boolean> {
1026
+ try {
1027
+ await messageFunc();
1028
+ return true;
1029
+ } catch (error) {
1030
+ console.error(`Failed to send ${messageType} message:`, error);
1031
+
1032
+ switch (error.code) {
1033
+ case -216:
1034
+ console.error("Access token invalid - need to refresh");
1035
+ break;
1036
+ case -201:
1037
+ console.error("Invalid message parameters");
1038
+ break;
1039
+ case -223:
1040
+ console.error(`${messageType} quota exceeded`);
1041
+ break;
1042
+ case -232:
1043
+ console.error("User has blocked the OA");
1044
+ break;
1045
+ case -233:
1046
+ console.error("User not found");
1047
+ break;
1048
+ default:
1049
+ console.error("Unexpected error occurred");
1050
+ }
1051
+
1052
+ return false;
1053
+ }
1054
+ }
1055
+ ```
1056
+
1057
+ ### 2. Comprehensive Message Service Wrapper
1058
+
1059
+ ```typescript
1060
+ class MessageServiceWrapper {
1061
+ constructor(private zalo: ZaloSDK, private accessToken: string) {}
1062
+
1063
+ async sendConsultation(userId: string, message: any): Promise<boolean> {
1064
+ return sendMessageWithErrorHandling(
1065
+ () => this.zalo.consultation.sendTextMessage(this.accessToken, { user_id: userId }, message),
1066
+ 'consultation'
1067
+ );
1068
+ }
1069
+
1070
+ async sendTransaction(userId: string, message: any): Promise<boolean> {
1071
+ return sendMessageWithErrorHandling(
1072
+ () => this.zalo.transaction.sendTransactionMessage(this.accessToken, { user_id: userId }, message),
1073
+ 'transaction'
1074
+ );
1075
+ }
1076
+
1077
+ async sendPromotion(userId: string, message: any): Promise<boolean> {
1078
+ return sendMessageWithErrorHandling(
1079
+ () => this.zalo.promotion.sendPromotionMessage(this.accessToken, { user_id: userId }, message),
1080
+ 'promotion'
1081
+ );
1082
+ }
1083
+ }
1084
+ ```
1085
+
1086
+ ---
1087
+
1088
+ ## Testing Message Services
1089
+
1090
+ ### 1. Unit Tests
1091
+
1092
+ ```typescript
1093
+ // message-services.test.ts
1094
+ import { ZaloSDK } from '@warriorteam/redai-zalo-sdk';
1095
+
1096
+ describe('Message Services', () => {
1097
+ const zalo = new ZaloSDK({
1098
+ appId: 'test_app_id',
1099
+ appSecret: 'test_app_secret'
1100
+ });
1101
+
1102
+ it('should send consultation message', async () => {
1103
+ const mockResponse = { error: 0, message: "Success" };
1104
+ jest.spyOn(zalo.consultation, 'sendTextMessage').mockResolvedValue(mockResponse);
1105
+
1106
+ const result = await zalo.consultation.sendTextMessage(
1107
+ 'test_token',
1108
+ { user_id: 'test_user' },
1109
+ { type: 'text', text: 'Test message' }
1110
+ );
1111
+
1112
+ expect(result.error).toBe(0);
1113
+ });
1114
+
1115
+ it('should handle different message types', async () => {
1116
+ const messageTypes = ['consultation', 'transaction', 'promotion'];
1117
+
1118
+ for (const type of messageTypes) {
1119
+ const service = zalo[type];
1120
+ expect(service).toBeDefined();
1121
+ }
1122
+ });
1123
+ });
1124
+ ```
1125
+
1126
+ ---
1127
+
1128
+ ## Performance Optimization
1129
+
1130
+ ### 1. Message Caching
1131
+
1132
+ ```typescript
1133
+ class MessageCache {
1134
+ private cache = new Map<string, any>();
1135
+ private readonly ttl = 5 * 60 * 1000; // 5 minutes
1136
+
1137
+ set(key: string, value: any): void {
1138
+ this.cache.set(key, {
1139
+ value,
1140
+ timestamp: Date.now()
1141
+ });
1142
+ }
1143
+
1144
+ get(key: string): any | null {
1145
+ const item = this.cache.get(key);
1146
+
1147
+ if (!item) return null;
1148
+
1149
+ if (Date.now() - item.timestamp > this.ttl) {
1150
+ this.cache.delete(key);
1151
+ return null;
1152
+ }
1153
+
1154
+ return item.value;
1155
+ }
1156
+
1157
+ // Cache user info để tránh gọi API nhiều lần
1158
+ async getUserInfo(userId: string): Promise<UserInfo> {
1159
+ const cached = this.get(`user_${userId}`);
1160
+ if (cached) return cached;
1161
+
1162
+ const userInfo = await this.fetchUserInfo(userId);
1163
+ this.set(`user_${userId}`, userInfo);
1164
+
1165
+ return userInfo;
1166
+ }
1167
+ }
1168
+ ```
1169
+
1170
+ ### 2. Batch Message Processing
1171
+
1172
+ ```typescript
1173
+ class BatchMessageProcessor {
1174
+ async processBatchMessages(
1175
+ messages: Array<{userId: string, messageType: string, content: any}>
1176
+ ): Promise<BatchResult> {
1177
+ const results = {
1178
+ successful: 0,
1179
+ failed: 0,
1180
+ errors: [] as Array<{userId: string, error: string}>
1181
+ };
1182
+
1183
+ // Group messages by type for better processing
1184
+ const groupedMessages = this.groupMessagesByType(messages);
1185
+
1186
+ for (const [messageType, messageGroup] of groupedMessages) {
1187
+ const batchResults = await this.processSameTypeMessages(messageType, messageGroup);
1188
+
1189
+ results.successful += batchResults.successful;
1190
+ results.failed += batchResults.failed;
1191
+ results.errors.push(...batchResults.errors);
1192
+ }
1193
+
1194
+ return results;
1195
+ }
1196
+
1197
+ private groupMessagesByType(messages: any[]): Map<string, any[]> {
1198
+ const groups = new Map();
1199
+
1200
+ for (const message of messages) {
1201
+ if (!groups.has(message.messageType)) {
1202
+ groups.set(message.messageType, []);
1203
+ }
1204
+ groups.get(message.messageType).push(message);
1205
+ }
1206
+
1207
+ return groups;
1208
+ }
1209
+ }
1210
+ ```
1211
+
1212
+ ---
1213
+
1214
+ ## Next Steps
1215
+
1216
+ Sau khi nắm vững Message Services:
1217
+
1218
+ 1. **[User Management](./USER_MANAGEMENT.md)** - Quản lý danh sách người dùng
1219
+ 2. **[Tag Management](./TAG_MANAGEMENT.md)** - Phân đoạn và tag users
1220
+ 3. **[Webhook Events](./WEBHOOK_EVENTS.md)** - Xử lý events thời gian thực
1221
+ 4. **[Error Handling](./ERROR_HANDLING.md)** - Xử lý lỗi toàn diện
1222
+ 5. **[Group Management](./GROUP_MANAGEMENT.md)** - Quản lý Zalo groups
1223
+
1224
+ Tham khảo **[API Reference](./API_REFERENCE.md)** để biết chi tiết về tất cả message methods có sẵn.