@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.
- package/CHANGELOG.md +131 -0
- package/ZNS-TYPE-IMPROVEMENTS.md +220 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/services/consultation.service.d.ts +114 -147
- package/dist/services/consultation.service.d.ts.map +1 -1
- package/dist/services/consultation.service.js +370 -0
- package/dist/services/consultation.service.js.map +1 -1
- package/dist/services/zns.service.d.ts.map +1 -1
- package/dist/services/zns.service.js +142 -141
- package/dist/services/zns.service.js.map +1 -1
- package/dist/types/consultation.d.ts +253 -0
- package/dist/types/consultation.d.ts.map +1 -0
- package/dist/types/consultation.js +13 -0
- package/dist/types/consultation.js.map +1 -0
- package/dist/types/zns.d.ts +95 -0
- package/dist/types/zns.d.ts.map +1 -1
- package/examples/consultation-template-example.ts +324 -0
- package/examples/zns-validation-example.ts +362 -0
- package/package.json +10 -4
|
@@ -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
|
+
};
|