@warriorteam/redai-zalo-sdk 1.28.1 → 1.30.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.
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Ví dụ sử dụng ConsultationService.sendTemplateMessage()
3
+ * Gửi tin nhắn template tổng quát với elements và buttons
4
+ *
5
+ * API Endpoint: https://openapi.zalo.me/v3.0/oa/message/cs
6
+ * Method: POST
7
+ * Content-Type: application/json
8
+ */
9
+
10
+ import {
11
+ ConsultationService,
12
+ TemplateElement,
13
+ TemplateButton,
14
+ TemplateAction
15
+ } from '../src/services/consultation.service';
16
+ import { ZaloClient } from '../src/clients/zalo-client';
17
+
18
+ // Khởi tạo service
19
+ const zaloClient = new ZaloClient();
20
+ const consultationService = new ConsultationService(zaloClient);
21
+
22
+ const ACCESS_TOKEN = "your_access_token_here";
23
+ const USER_ID = "2468458835296117922";
24
+
25
+ /**
26
+ * Ví dụ 1: Template request_user_info cơ bản
27
+ */
28
+ async function example1_BasicRequestUserInfo() {
29
+ try {
30
+ // Tạo elements (tối đa 5 phần tử)
31
+ const elements: TemplateElement[] = [
32
+ // Element đầu tiên PHẢI có subtitle
33
+ consultationService.createTemplateElement(
34
+ "OA Chatbot (Testing)",
35
+ "Đang yêu cầu thông tin từ bạn",
36
+ "https://developers.zalo.me/web/static/zalo.png",
37
+ consultationService.createUrlAction("https://developers.zalo.me/")
38
+ ),
39
+ // Các element sau có thể không có subtitle
40
+ consultationService.createTemplateElement(
41
+ "Liên hệ hỗ trợ",
42
+ undefined, // không có subtitle
43
+ "https://developers.zalo.me/web/static/zalo.png",
44
+ consultationService.createPhoneAction("84919018791")
45
+ )
46
+ ];
47
+
48
+ // Tạo buttons (tối đa 5 phần tử)
49
+ const buttons: TemplateButton[] = [
50
+ consultationService.createUrlButton("OPEN URL", "https://developers.zalo.me/"),
51
+ consultationService.createQueryShowButton("QUERY SHOW", "#callback_data"),
52
+ consultationService.createQueryHideButton("QUERY HIDE", "#callback_data"),
53
+ consultationService.createSmsButton("OPEN SMS", "84919018791", "alo"),
54
+ consultationService.createPhoneButton("OPEN PHONE", "84919018791")
55
+ ];
56
+
57
+ // Gửi template message
58
+ const result = await consultationService.sendTemplateMessage(
59
+ ACCESS_TOKEN,
60
+ USER_ID,
61
+ "request_user_info",
62
+ elements,
63
+ buttons
64
+ );
65
+
66
+ console.log("✅ Template message sent successfully:", result);
67
+ return result;
68
+
69
+ } catch (error) {
70
+ console.error("❌ Error sending template message:", error);
71
+ throw error;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Ví dụ 2: Template đơn giản chỉ có 1 element và 2 buttons
77
+ */
78
+ async function example2_SimpleTemplate() {
79
+ try {
80
+ // Chỉ 1 element
81
+ const elements: TemplateElement[] = [
82
+ {
83
+ title: "Chào mừng bạn đến với dịch vụ của chúng tôi!",
84
+ subtitle: "Chúng tôi có thể hỗ trợ gì cho bạn?",
85
+ image_url: "https://example.com/welcome.png"
86
+ }
87
+ ];
88
+
89
+ // 2 buttons đơn giản
90
+ const buttons: TemplateButton[] = [
91
+ consultationService.createQueryShowButton("Tư vấn sản phẩm", "product_consultation"),
92
+ consultationService.createPhoneButton("Gọi hotline", "84919018791")
93
+ ];
94
+
95
+ const result = await consultationService.sendTemplateMessage(
96
+ ACCESS_TOKEN,
97
+ USER_ID,
98
+ "request_user_info",
99
+ elements,
100
+ buttons
101
+ );
102
+
103
+ console.log("✅ Simple template sent successfully:", result);
104
+ return result;
105
+
106
+ } catch (error) {
107
+ console.error("❌ Error sending simple template:", error);
108
+ throw error;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Ví dụ 3: Template không có buttons (chỉ elements)
114
+ */
115
+ async function example3_ElementsOnly() {
116
+ try {
117
+ const elements: TemplateElement[] = [
118
+ {
119
+ title: "Thông báo quan trọng",
120
+ subtitle: "Hệ thống sẽ bảo trì từ 2:00 - 4:00 sáng ngày mai",
121
+ image_url: "https://example.com/maintenance.png",
122
+ default_action: {
123
+ type: "oa.open.url",
124
+ url: "https://example.com/maintenance-info"
125
+ }
126
+ },
127
+ {
128
+ title: "Liên hệ hỗ trợ khẩn cấp",
129
+ // Không có subtitle cho element thứ 2
130
+ default_action: {
131
+ type: "oa.open.phone",
132
+ payload: { phone_code: "84919018791" }
133
+ }
134
+ }
135
+ ];
136
+
137
+ // Không có buttons
138
+ const result = await consultationService.sendTemplateMessage(
139
+ ACCESS_TOKEN,
140
+ USER_ID,
141
+ "request_user_info",
142
+ elements
143
+ // buttons parameter bỏ qua
144
+ );
145
+
146
+ console.log("✅ Elements-only template sent successfully:", result);
147
+ return result;
148
+
149
+ } catch (error) {
150
+ console.error("❌ Error sending elements-only template:", error);
151
+ throw error;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Ví dụ 4: Template với tất cả loại buttons
157
+ */
158
+ async function example4_AllButtonTypes() {
159
+ try {
160
+ const elements: TemplateElement[] = [
161
+ {
162
+ title: "Trung tâm hỗ trợ khách hàng",
163
+ subtitle: "Chọn hình thức liên hệ phù hợp với bạn",
164
+ image_url: "https://example.com/support.png"
165
+ }
166
+ ];
167
+
168
+ const buttons: TemplateButton[] = [
169
+ // URL button
170
+ {
171
+ title: "Xem FAQ",
172
+ type: "oa.open.url",
173
+ payload: { url: "https://example.com/faq" }
174
+ },
175
+ // Query show button
176
+ {
177
+ title: "Chat với tư vấn viên",
178
+ type: "oa.query.show",
179
+ payload: "start_chat_with_agent"
180
+ },
181
+ // Query hide button
182
+ {
183
+ title: "Gửi phản hồi",
184
+ type: "oa.query.hide",
185
+ payload: "send_feedback"
186
+ },
187
+ // SMS button
188
+ {
189
+ title: "Gửi SMS hỗ trợ",
190
+ type: "oa.open.sms",
191
+ payload: {
192
+ phone_code: "84919018791",
193
+ content: "Tôi cần hỗ trợ"
194
+ }
195
+ },
196
+ // Phone button
197
+ {
198
+ title: "Gọi hotline",
199
+ type: "oa.open.phone",
200
+ payload: { phone_code: "84919018791" }
201
+ }
202
+ ];
203
+
204
+ const result = await consultationService.sendTemplateMessage(
205
+ ACCESS_TOKEN,
206
+ USER_ID,
207
+ "request_user_info",
208
+ elements,
209
+ buttons
210
+ );
211
+
212
+ console.log("✅ All button types template sent successfully:", result);
213
+ return result;
214
+
215
+ } catch (error) {
216
+ console.error("❌ Error sending all button types template:", error);
217
+ throw error;
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Ví dụ 5: Template với validation errors (để test)
223
+ */
224
+ async function example5_ValidationErrors() {
225
+ try {
226
+ // Element với title quá dài (> 100 ký tự)
227
+ const invalidElements: TemplateElement[] = [
228
+ {
229
+ title: "A".repeat(101), // 101 ký tự - sẽ báo lỗi
230
+ subtitle: "This will cause validation error"
231
+ }
232
+ ];
233
+
234
+ await consultationService.sendTemplateMessage(
235
+ ACCESS_TOKEN,
236
+ USER_ID,
237
+ "request_user_info",
238
+ invalidElements
239
+ );
240
+
241
+ } catch (error) {
242
+ console.log("✅ Expected validation error caught:", error.message);
243
+ }
244
+
245
+ try {
246
+ // Element đầu tiên không có subtitle
247
+ const invalidElements2: TemplateElement[] = [
248
+ {
249
+ title: "Valid title",
250
+ // Thiếu subtitle cho element đầu tiên - sẽ báo lỗi
251
+ }
252
+ ];
253
+
254
+ await consultationService.sendTemplateMessage(
255
+ ACCESS_TOKEN,
256
+ USER_ID,
257
+ "request_user_info",
258
+ invalidElements2
259
+ );
260
+
261
+ } catch (error) {
262
+ console.log("✅ Expected validation error caught:", error.message);
263
+ }
264
+
265
+ try {
266
+ // Quá nhiều elements (> 5)
267
+ const tooManyElements: TemplateElement[] = Array(6).fill(null).map((_, i) => ({
268
+ title: `Element ${i + 1}`,
269
+ subtitle: i === 0 ? "Required subtitle for first element" : undefined
270
+ }));
271
+
272
+ await consultationService.sendTemplateMessage(
273
+ ACCESS_TOKEN,
274
+ USER_ID,
275
+ "request_user_info",
276
+ tooManyElements
277
+ );
278
+
279
+ } catch (error) {
280
+ console.log("✅ Expected validation error caught:", error.message);
281
+ }
282
+ }
283
+
284
+ // Chạy các ví dụ
285
+ async function runExamples() {
286
+ console.log("🚀 Running Consultation Template Examples...\n");
287
+
288
+ try {
289
+ await example1_BasicRequestUserInfo();
290
+ console.log("\n");
291
+
292
+ await example2_SimpleTemplate();
293
+ console.log("\n");
294
+
295
+ await example3_ElementsOnly();
296
+ console.log("\n");
297
+
298
+ await example4_AllButtonTypes();
299
+ console.log("\n");
300
+
301
+ await example5_ValidationErrors();
302
+ console.log("\n");
303
+
304
+ console.log("✅ All examples completed!");
305
+
306
+ } catch (error) {
307
+ console.error("❌ Example failed:", error);
308
+ }
309
+ }
310
+
311
+ // Export để có thể import và sử dụng
312
+ export {
313
+ example1_BasicRequestUserInfo,
314
+ example2_SimpleTemplate,
315
+ example3_ElementsOnly,
316
+ example4_AllButtonTypes,
317
+ example5_ValidationErrors,
318
+ runExamples
319
+ };
320
+
321
+ // Chạy nếu file được execute trực tiếp
322
+ if (require.main === module) {
323
+ runExamples();
324
+ }
@@ -0,0 +1,362 @@
1
+ /**
2
+ * Ví dụ sử dụng ZNS Service với type validation rõ ràng
3
+ *
4
+ * File này minh họa cách sử dụng các type cụ thể thay vì `any`
5
+ * trong ZNS Service để có type safety tốt hơn.
6
+ */
7
+
8
+ import { ZNSService } from "../src/services/zns.service";
9
+ import { ZaloClient } from "../src/clients/zalo-client";
10
+ import {
11
+ ZNSCreateTemplateRequest,
12
+ ZNSValidationComponent,
13
+ ZNSTitleComponent,
14
+ ZNSParagraphComponent,
15
+ ZNSLogoComponent,
16
+ ZNSButtonsComponent,
17
+ ZNSPaymentComponent,
18
+ ZNSVoucherComponent,
19
+ ZNSRatingComponent,
20
+ ZNSAttachment,
21
+ } from "../src/types/zns";
22
+
23
+ // Khởi tạo service
24
+ const zaloClient = new ZaloClient("your-app-id", "your-app-secret");
25
+ const znsService = new ZNSService(zaloClient);
26
+
27
+ // ===== VÍ DỤ 1: ZNS TÙY CHỈNH (Type 1) =====
28
+ async function createCustomTemplate() {
29
+ // Định nghĩa các component với type cụ thể
30
+ const logoComponent: ZNSValidationComponent = {
31
+ LOGO: {
32
+ light: {
33
+ type: "IMAGE",
34
+ media_id: "logo-light-media-id"
35
+ },
36
+ dark: {
37
+ type: "IMAGE",
38
+ media_id: "logo-dark-media-id"
39
+ }
40
+ }
41
+ };
42
+
43
+ const titleComponent: ZNSValidationComponent = {
44
+ TITLE: {
45
+ value: "Xin chào {{customer_name}}, đơn hàng của bạn đã được xác nhận!"
46
+ }
47
+ };
48
+
49
+ const paragraphComponent: ZNSValidationComponent = {
50
+ PARAGRAPH: {
51
+ value: "Cảm ơn bạn đã đặt hàng tại {{shop_name}}. Đơn hàng {{order_id}} sẽ được giao trong {{delivery_time}}."
52
+ }
53
+ };
54
+
55
+ const buttonsComponent: ZNSValidationComponent = {
56
+ BUTTONS: {
57
+ items: [
58
+ {
59
+ type: 1, // URL
60
+ title: "Xem đơn hàng",
61
+ content: "https://shop.com/orders/{{order_id}}"
62
+ },
63
+ {
64
+ type: 2, // Phone
65
+ title: "Liên hệ",
66
+ content: "0123456789"
67
+ }
68
+ ]
69
+ }
70
+ };
71
+
72
+ // Layout với type safety
73
+ const layout: ZNSValidationComponent[] = [
74
+ logoComponent,
75
+ titleComponent,
76
+ paragraphComponent,
77
+ buttonsComponent
78
+ ];
79
+
80
+ // Template request với type cụ thể
81
+ const templateRequest: ZNSCreateTemplateRequest = {
82
+ template_name: "Thông báo xác nhận đơn hàng",
83
+ template_type: 1, // ZNS tùy chỉnh
84
+ tag: "1", // Transaction
85
+ layout: layout,
86
+ params: [
87
+ {
88
+ name: "customer_name",
89
+ type: "1", // Tên khách hàng
90
+ sample_value: "Nguyễn Văn A"
91
+ },
92
+ {
93
+ name: "shop_name",
94
+ type: "5", // Nhãn tùy chỉnh
95
+ sample_value: "Shop ABC"
96
+ },
97
+ {
98
+ name: "order_id",
99
+ type: "4", // Mã số
100
+ sample_value: "ORD123456"
101
+ },
102
+ {
103
+ name: "delivery_time",
104
+ type: "11", // Thời gian
105
+ sample_value: "2-3 ngày"
106
+ }
107
+ ],
108
+ note: "Template thông báo xác nhận đơn hàng cho khách hàng",
109
+ tracking_id: "custom-template-001"
110
+ };
111
+
112
+ try {
113
+ const result = await znsService.createTemplate("access-token", templateRequest);
114
+ console.log("Template created successfully:", result);
115
+ } catch (error) {
116
+ console.error("Error creating template:", error);
117
+ }
118
+ }
119
+
120
+ // ===== VÍ DỤ 2: ZNS PAYMENT (Type 3) =====
121
+ async function createPaymentTemplate() {
122
+ const logoComponent: ZNSValidationComponent = {
123
+ LOGO: {
124
+ light: { type: "IMAGE", media_id: "logo-light" },
125
+ dark: { type: "IMAGE", media_id: "logo-dark" }
126
+ }
127
+ };
128
+
129
+ const titleComponent: ZNSValidationComponent = {
130
+ TITLE: {
131
+ value: "Thông báo thanh toán hóa đơn {{invoice_id}}"
132
+ }
133
+ };
134
+
135
+ const paymentComponent: ZNSValidationComponent = {
136
+ PAYMENT: {
137
+ bank_code: "970425", // VietinBank
138
+ account_name: "CÔNG TY ABC",
139
+ bank_account: "1234567890",
140
+ amount: "{{amount}}",
141
+ note: "Thanh toan hoa don {{invoice_id}}"
142
+ }
143
+ };
144
+
145
+ const layout: ZNSValidationComponent[] = [
146
+ logoComponent,
147
+ titleComponent,
148
+ paymentComponent
149
+ ];
150
+
151
+ const templateRequest: ZNSCreateTemplateRequest = {
152
+ template_name: "Thông báo yêu cầu thanh toán",
153
+ template_type: 3, // ZNS yêu cầu thanh toán
154
+ tag: "1", // Transaction
155
+ layout: layout,
156
+ params: [
157
+ {
158
+ name: "invoice_id",
159
+ type: "4", // Mã số
160
+ sample_value: "INV001"
161
+ },
162
+ {
163
+ name: "amount",
164
+ type: "14", // Tiền tệ VNĐ
165
+ sample_value: "500000"
166
+ }
167
+ ],
168
+ tracking_id: "payment-template-001"
169
+ };
170
+
171
+ try {
172
+ const result = await znsService.createTemplate("access-token", templateRequest);
173
+ console.log("Payment template created:", result);
174
+ } catch (error) {
175
+ console.error("Error creating payment template:", error);
176
+ }
177
+ }
178
+
179
+ // ===== VÍ DỤ 3: ZNS VOUCHER (Type 4) =====
180
+ async function createVoucherTemplate() {
181
+ const imageComponent: ZNSValidationComponent = {
182
+ IMAGES: {
183
+ items: [
184
+ {
185
+ type: "IMAGE",
186
+ media_id: "voucher-image-media-id"
187
+ }
188
+ ]
189
+ }
190
+ };
191
+
192
+ const titleComponent: ZNSValidationComponent = {
193
+ TITLE: {
194
+ value: "🎉 Voucher giảm giá {{discount_percent}}% dành cho bạn!"
195
+ }
196
+ };
197
+
198
+ const voucherComponent: ZNSValidationComponent = {
199
+ VOUCHER: {
200
+ name: "Voucher giảm giá {{discount_percent}}%",
201
+ condition: "Áp dụng cho đơn hàng từ {{min_order}}đ",
202
+ end_date: "{{expiry_date}}",
203
+ voucher_code: "{{voucher_code}}",
204
+ display_code: 1 // QR code
205
+ }
206
+ };
207
+
208
+ const buttonsComponent: ZNSValidationComponent = {
209
+ BUTTONS: {
210
+ items: [
211
+ {
212
+ type: 1, // URL
213
+ title: "Sử dụng ngay",
214
+ content: "https://shop.com/voucher/{{voucher_code}}"
215
+ }
216
+ ]
217
+ }
218
+ };
219
+
220
+ const layout: ZNSValidationComponent[] = [
221
+ imageComponent,
222
+ titleComponent,
223
+ voucherComponent,
224
+ buttonsComponent
225
+ ];
226
+
227
+ const templateRequest: ZNSCreateTemplateRequest = {
228
+ template_name: "Thông báo voucher giảm giá",
229
+ template_type: 4, // ZNS voucher
230
+ tag: "3", // Promotion
231
+ layout: layout,
232
+ params: [
233
+ {
234
+ name: "discount_percent",
235
+ type: "10", // Số lượng/Số tiền
236
+ sample_value: "20"
237
+ },
238
+ {
239
+ name: "min_order",
240
+ type: "14", // Tiền tệ VNĐ
241
+ sample_value: "200000"
242
+ },
243
+ {
244
+ name: "expiry_date",
245
+ type: "11", // Thời gian
246
+ sample_value: "31/12/2024"
247
+ },
248
+ {
249
+ name: "voucher_code",
250
+ type: "4", // Mã số
251
+ sample_value: "SAVE20"
252
+ }
253
+ ],
254
+ tracking_id: "voucher-template-001"
255
+ };
256
+
257
+ try {
258
+ const result = await znsService.createTemplate("access-token", templateRequest);
259
+ console.log("Voucher template created:", result);
260
+ } catch (error) {
261
+ console.error("Error creating voucher template:", error);
262
+ }
263
+ }
264
+
265
+ // ===== VÍ DỤ 4: ZNS RATING (Type 5) =====
266
+ async function createRatingTemplate() {
267
+ const logoComponent: ZNSValidationComponent = {
268
+ LOGO: {
269
+ light: { type: "IMAGE", media_id: "logo-light" },
270
+ dark: { type: "IMAGE", media_id: "logo-dark" }
271
+ }
272
+ };
273
+
274
+ const titleComponent: ZNSValidationComponent = {
275
+ TITLE: {
276
+ value: "Đánh giá trải nghiệm dịch vụ của {{service_name}}"
277
+ }
278
+ };
279
+
280
+ const ratingComponent: ZNSValidationComponent = {
281
+ RATING: {
282
+ items: [
283
+ {
284
+ star: 1,
285
+ title: "Rất không hài lòng",
286
+ question: "Chúng tôi có thể cải thiện điều gì?",
287
+ answers: ["Chất lượng dịch vụ", "Thái độ nhân viên", "Thời gian phục vụ"],
288
+ thanks: "Cảm ơn bạn đã góp ý!",
289
+ description: "Chúng tôi sẽ cải thiện dịch vụ tốt hơn"
290
+ },
291
+ {
292
+ star: 2,
293
+ title: "Không hài lòng",
294
+ question: "Điều gì khiến bạn chưa hài lòng?",
295
+ answers: ["Chất lượng dịch vụ", "Giá cả", "Thời gian chờ"],
296
+ thanks: "Cảm ơn phản hồi của bạn!",
297
+ description: "Chúng tôi sẽ khắc phục những vấn đề này"
298
+ },
299
+ {
300
+ star: 3,
301
+ title: "Bình thường",
302
+ question: "Bạn mong muốn điều gì tốt hơn?",
303
+ answers: ["Dịch vụ nhanh hơn", "Chất lượng tốt hơn", "Giá cả hợp lý hơn"],
304
+ thanks: "Cảm ơn bạn đã đánh giá!",
305
+ description: "Chúng tôi sẽ nỗ lực cải thiện"
306
+ },
307
+ {
308
+ star: 4,
309
+ title: "Hài lòng",
310
+ question: "Điều gì bạn thích nhất?",
311
+ answers: ["Dịch vụ tốt", "Nhân viên thân thiện", "Chất lượng ổn"],
312
+ thanks: "Cảm ơn bạn đã tin tưởng!",
313
+ description: "Chúng tôi sẽ duy trì chất lượng này"
314
+ },
315
+ {
316
+ star: 5,
317
+ title: "Rất hài lòng",
318
+ question: "Bạn có muốn giới thiệu cho bạn bè?",
319
+ answers: ["Có, chắc chắn", "Có thể", "Sẽ suy nghĩ"],
320
+ thanks: "Cảm ơn bạn rất nhiều!",
321
+ description: "Chúng tôi rất vui khi được phục vụ bạn"
322
+ }
323
+ ]
324
+ }
325
+ };
326
+
327
+ const layout: ZNSValidationComponent[] = [
328
+ logoComponent,
329
+ titleComponent,
330
+ ratingComponent
331
+ ];
332
+
333
+ const templateRequest: ZNSCreateTemplateRequest = {
334
+ template_name: "Đánh giá dịch vụ khách hàng",
335
+ template_type: 5, // ZNS đánh giá dịch vụ
336
+ tag: "2", // Customer care
337
+ layout: layout,
338
+ params: [
339
+ {
340
+ name: "service_name",
341
+ type: "5", // Nhãn tùy chỉnh
342
+ sample_value: "Dịch vụ giao hàng"
343
+ }
344
+ ],
345
+ tracking_id: "rating-template-001"
346
+ };
347
+
348
+ try {
349
+ const result = await znsService.createTemplate("access-token", templateRequest);
350
+ console.log("Rating template created:", result);
351
+ } catch (error) {
352
+ console.error("Error creating rating template:", error);
353
+ }
354
+ }
355
+
356
+ // Export các function để sử dụng
357
+ export {
358
+ createCustomTemplate,
359
+ createPaymentTemplate,
360
+ createVoucherTemplate,
361
+ createRatingTemplate
362
+ };