@redonvn/zalo-ads-sdk 0.2.20 → 0.2.29
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/dist/index.d.mts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +382 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +380 -31
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1774,11 +1774,15 @@ var ZaloAdsActionType = {
|
|
|
1774
1774
|
MUA_NGAY: 2,
|
|
1775
1775
|
THU_NGAY: 3,
|
|
1776
1776
|
TAI_NGAY: 4,
|
|
1777
|
+
/** Nút "Xem thêm" trên Quảng cáo Form (Type 18) gửi mã 4 */
|
|
1778
|
+
XEM_THEM_FORM: 4,
|
|
1777
1779
|
XEM_THEM: 5,
|
|
1778
1780
|
NGHE_NGAY: 6,
|
|
1779
1781
|
CHOI_NGAY: 7,
|
|
1780
1782
|
DANG_KY: 8,
|
|
1781
1783
|
GOI_DIEN: 9,
|
|
1784
|
+
/** Nút bấm "Gửi tin nhắn" / "Nhắn tin" dành cho Quảng cáo Tin nhắn (Type 19/30) */
|
|
1785
|
+
NHAN_TIN: 10,
|
|
1782
1786
|
/** Dành riêng cho Quảng cáo Official Account (Type 2) */
|
|
1783
1787
|
QUAN_TAM_OA: 6
|
|
1784
1788
|
};
|
|
@@ -1789,6 +1793,12 @@ var ZaloAdsVideoSrc = {
|
|
|
1789
1793
|
/** Tự tải video lên hoặc chọn từ Thư viện Media */
|
|
1790
1794
|
SELF_UPLOAD: 2
|
|
1791
1795
|
};
|
|
1796
|
+
var ZaloAdsVideoPlatform = {
|
|
1797
|
+
/** Nền tảng Video (toàn màn hình như ZVideo, Báo Mới; sàn CPM 7,300đ) */
|
|
1798
|
+
VIDEO_NETWORK: 1,
|
|
1799
|
+
/** Nhật ký Zalo (Feed xen giữa tin bạn bè; sàn CPM 6,000đ) */
|
|
1800
|
+
ZALO_FEED: 2
|
|
1801
|
+
};
|
|
1792
1802
|
var ZaloAdsBudgetScheduleType = {
|
|
1793
1803
|
/** Toàn lịch chạy */
|
|
1794
1804
|
TOTAL_SCHEDULE: 1,
|
|
@@ -2042,13 +2052,33 @@ var VALID_CAMPAIGN_TYPES = {
|
|
|
2042
2052
|
var VALID_AD_TYPES = {
|
|
2043
2053
|
WEBSITE: 5,
|
|
2044
2054
|
FORM: 18,
|
|
2045
|
-
MESSAGE:
|
|
2055
|
+
MESSAGE: 19,
|
|
2056
|
+
// Mã chuẩn của máy chủ Zalo Ads khi UpdateAd
|
|
2057
|
+
MESSAGE_LEGACY: 30,
|
|
2058
|
+
// Hỗ trợ tương thích ngược
|
|
2046
2059
|
OA: 2,
|
|
2047
2060
|
VIDEO: 11,
|
|
2048
2061
|
COMMERCE: 28,
|
|
2049
2062
|
// Server trả về 28 (không phải 23)
|
|
2050
2063
|
ARTICLE: 3,
|
|
2051
|
-
DISPLAY: 21
|
|
2064
|
+
DISPLAY: 21,
|
|
2065
|
+
// Masthead Mobile (Format 1) & Masthead Desktop (Format 2)
|
|
2066
|
+
DISPLAY_HALFPAGE: 26,
|
|
2067
|
+
// Halfpage Mobile (Format 13) & Halfpage PC (Format 14)
|
|
2068
|
+
DISPLAY_MEDIUM_RECTANGLE: 23
|
|
2069
|
+
// Medium Rectangle 300x250 (Format 6)
|
|
2070
|
+
};
|
|
2071
|
+
var ZALO_DISPLAY_AD_FORMAT = {
|
|
2072
|
+
MASTHEAD_MOBILE: 1,
|
|
2073
|
+
// Kích thước 640x360, Os: [0, 1]
|
|
2074
|
+
MASTHEAD_DESKTOP: 2,
|
|
2075
|
+
// Kích thước 970x250, Os: [3]
|
|
2076
|
+
MEDIUM_RECTANGLE: 6,
|
|
2077
|
+
// Kích thước 300x250, Os: [0, 1]
|
|
2078
|
+
HALFPAGE_MOBILE: 13,
|
|
2079
|
+
// Kích thước 300x600, Os: [0, 1]
|
|
2080
|
+
HALFPAGE_PC: 14
|
|
2081
|
+
// Kích thước 300x600, Os: [3]
|
|
2052
2082
|
};
|
|
2053
2083
|
var ALLOWED_CTAS_PER_AD_TYPE = {
|
|
2054
2084
|
// Website (Type 5): 9 CTAs
|
|
@@ -2084,22 +2114,71 @@ var ALLOWED_CTAS_PER_AD_TYPE = {
|
|
|
2084
2114
|
ZaloAdsActionType.CHOI_NGAY,
|
|
2085
2115
|
ZaloAdsActionType.DANG_KY
|
|
2086
2116
|
],
|
|
2087
|
-
// Form (Type 18): 5 CTAs
|
|
2117
|
+
// Form (Type 18): 5 CTAs (Đặt ngay: 1, Mua ngay: 2, Thử ngay: 3, Xem thêm: 4/5, Đăng ký: 8)
|
|
2088
2118
|
[VALID_AD_TYPES.FORM]: [
|
|
2089
2119
|
ZaloAdsActionType.DAT_NGAY,
|
|
2090
2120
|
ZaloAdsActionType.MUA_NGAY,
|
|
2091
2121
|
ZaloAdsActionType.THU_NGAY,
|
|
2122
|
+
4,
|
|
2092
2123
|
ZaloAdsActionType.XEM_THEM,
|
|
2093
2124
|
ZaloAdsActionType.DANG_KY
|
|
2094
2125
|
],
|
|
2095
|
-
// Commerce (Type 28): 3 CTAs
|
|
2126
|
+
// Commerce (Type 28): 3 CTAs (Đặt ngay: 1, Mua ngay: 2, Xem thêm: 4/5)
|
|
2096
2127
|
[VALID_AD_TYPES.COMMERCE]: [
|
|
2097
2128
|
ZaloAdsActionType.DAT_NGAY,
|
|
2098
2129
|
ZaloAdsActionType.MUA_NGAY,
|
|
2130
|
+
4,
|
|
2099
2131
|
ZaloAdsActionType.XEM_THEM
|
|
2100
2132
|
],
|
|
2101
2133
|
// OA (Type 2): Cố định Quan tâm OA (6)
|
|
2102
|
-
[VALID_AD_TYPES.OA]: [ZaloAdsActionType.QUAN_TAM_OA]
|
|
2134
|
+
[VALID_AD_TYPES.OA]: [ZaloAdsActionType.QUAN_TAM_OA],
|
|
2135
|
+
// Message (Type 19 & Type 30 legacy):
|
|
2136
|
+
[VALID_AD_TYPES.MESSAGE]: [
|
|
2137
|
+
ZaloAdsActionType.NHAN_TIN,
|
|
2138
|
+
ZaloAdsActionType.XEM_THEM,
|
|
2139
|
+
ZaloAdsActionType.DANG_KY,
|
|
2140
|
+
ZaloAdsActionType.GOI_DIEN
|
|
2141
|
+
],
|
|
2142
|
+
[VALID_AD_TYPES.MESSAGE_LEGACY]: [
|
|
2143
|
+
ZaloAdsActionType.NHAN_TIN,
|
|
2144
|
+
ZaloAdsActionType.XEM_THEM,
|
|
2145
|
+
ZaloAdsActionType.DANG_KY,
|
|
2146
|
+
ZaloAdsActionType.GOI_DIEN
|
|
2147
|
+
],
|
|
2148
|
+
// Display (Type 21) & Display Halfpage (Type 26): Hỗ trợ các hành động cơ bản
|
|
2149
|
+
[VALID_AD_TYPES.DISPLAY]: [
|
|
2150
|
+
ZaloAdsActionType.DAT_NGAY,
|
|
2151
|
+
ZaloAdsActionType.MUA_NGAY,
|
|
2152
|
+
ZaloAdsActionType.THU_NGAY,
|
|
2153
|
+
ZaloAdsActionType.TAI_NGAY,
|
|
2154
|
+
ZaloAdsActionType.XEM_THEM,
|
|
2155
|
+
ZaloAdsActionType.NGHE_NGAY,
|
|
2156
|
+
ZaloAdsActionType.CHOI_NGAY,
|
|
2157
|
+
ZaloAdsActionType.DANG_KY,
|
|
2158
|
+
ZaloAdsActionType.GOI_DIEN
|
|
2159
|
+
],
|
|
2160
|
+
[VALID_AD_TYPES.DISPLAY_HALFPAGE]: [
|
|
2161
|
+
ZaloAdsActionType.DAT_NGAY,
|
|
2162
|
+
ZaloAdsActionType.MUA_NGAY,
|
|
2163
|
+
ZaloAdsActionType.THU_NGAY,
|
|
2164
|
+
ZaloAdsActionType.TAI_NGAY,
|
|
2165
|
+
ZaloAdsActionType.XEM_THEM,
|
|
2166
|
+
ZaloAdsActionType.NGHE_NGAY,
|
|
2167
|
+
ZaloAdsActionType.CHOI_NGAY,
|
|
2168
|
+
ZaloAdsActionType.DANG_KY,
|
|
2169
|
+
ZaloAdsActionType.GOI_DIEN
|
|
2170
|
+
],
|
|
2171
|
+
[VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE]: [
|
|
2172
|
+
ZaloAdsActionType.DAT_NGAY,
|
|
2173
|
+
ZaloAdsActionType.MUA_NGAY,
|
|
2174
|
+
ZaloAdsActionType.THU_NGAY,
|
|
2175
|
+
ZaloAdsActionType.TAI_NGAY,
|
|
2176
|
+
ZaloAdsActionType.XEM_THEM,
|
|
2177
|
+
ZaloAdsActionType.NGHE_NGAY,
|
|
2178
|
+
ZaloAdsActionType.CHOI_NGAY,
|
|
2179
|
+
ZaloAdsActionType.DANG_KY,
|
|
2180
|
+
ZaloAdsActionType.GOI_DIEN
|
|
2181
|
+
]
|
|
2103
2182
|
};
|
|
2104
2183
|
function validateCreateCampaignPayload(payload, options = {}) {
|
|
2105
2184
|
const errors = [];
|
|
@@ -2135,8 +2214,9 @@ function validateCreateCampaignPayload(payload, options = {}) {
|
|
|
2135
2214
|
}
|
|
2136
2215
|
switch (payload.campaignType) {
|
|
2137
2216
|
case VALID_CAMPAIGN_TYPES.WEBSITE:
|
|
2217
|
+
case VALID_CAMPAIGN_TYPES.VIDEO:
|
|
2138
2218
|
if (!payload.targetUrl || typeof payload.targetUrl !== "string" || !payload.targetUrl.trim()) {
|
|
2139
|
-
errors.push("targetUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Website.");
|
|
2219
|
+
errors.push("targetUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Website / Video.");
|
|
2140
2220
|
} else if (!/^https?:\/\/.+/i.test(payload.targetUrl)) {
|
|
2141
2221
|
errors.push("targetUrl ph\u1EA3i l\xE0 m\u1ED9t \u0111\u01B0\u1EDDng link h\u1EE3p l\u1EC7 b\u1EAFt \u0111\u1EA7u b\u1EB1ng http:// ho\u1EB7c https://.");
|
|
2142
2222
|
}
|
|
@@ -2195,11 +2275,15 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2195
2275
|
if (!adInfo) {
|
|
2196
2276
|
errors.push("Settings.AdInfo l\xE0 b\u1EAFt bu\u1ED9c.");
|
|
2197
2277
|
} else {
|
|
2278
|
+
const rawTypeNum = Number(payload.Type);
|
|
2279
|
+
const isDisplayAd = rawTypeNum === 21 || rawTypeNum === 23 || rawTypeNum === 26 || adInfo.AdFormat === 1 || adInfo.AdFormat === 2 || adInfo.AdFormat === 6 || adInfo.AdFormat === 13 || adInfo.AdFormat === 14;
|
|
2198
2280
|
if (!adInfo.Caption || !adInfo.Caption.trim()) {
|
|
2199
|
-
|
|
2281
|
+
if (!isDisplayAd) {
|
|
2282
|
+
errors.push("Settings.AdInfo.Caption l\xE0 b\u1EAFt bu\u1ED9c.");
|
|
2283
|
+
}
|
|
2200
2284
|
} else {
|
|
2201
2285
|
const captionLen = adInfo.Caption.trim().length;
|
|
2202
|
-
if (captionLen < 35) {
|
|
2286
|
+
if (!isDisplayAd && captionLen < 35) {
|
|
2203
2287
|
errors.push(`Settings.AdInfo.Caption qu\xE1 ng\u1EAFn (${captionLen}/35 k\xFD t\u1EF1 t\u1ED1i thi\u1EC3u).`);
|
|
2204
2288
|
} else if (captionLen > 90) {
|
|
2205
2289
|
errors.push(`Settings.AdInfo.Caption qu\xE1 d\xE0i (${captionLen}/90 k\xFD t\u1EF1 t\u1ED1i \u0111a).`);
|
|
@@ -2223,6 +2307,14 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2223
2307
|
);
|
|
2224
2308
|
}
|
|
2225
2309
|
}
|
|
2310
|
+
if (isDisplayAd) {
|
|
2311
|
+
const targetUrl = typeof adInfo.TargetUrl === "object" ? adInfo.TargetUrl?.Url : adInfo.TargetUrl;
|
|
2312
|
+
if (!targetUrl || typeof targetUrl !== "string" || !targetUrl.trim()) {
|
|
2313
|
+
errors.push("Settings.AdInfo.TargetUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Display.");
|
|
2314
|
+
} else if (!/^https?:\/\//i.test(targetUrl.trim())) {
|
|
2315
|
+
errors.push("Settings.AdInfo.TargetUrl ph\u1EA3i l\xE0 m\u1ED9t \u0111\u01B0\u1EDDng d\u1EABn h\u1EE3p l\u1EC7 (b\u1EAFt \u0111\u1EA7u b\u1EB1ng http:// ho\u1EB7c https://).");
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2226
2318
|
if (adInfo.Action !== void 0 && payload.Type) {
|
|
2227
2319
|
const allowedCtas = ALLOWED_CTAS_PER_AD_TYPE[payload.Type];
|
|
2228
2320
|
if (allowedCtas && !allowedCtas.includes(adInfo.Action)) {
|
|
@@ -2250,20 +2342,149 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2250
2342
|
} else if (payload.Type === VALID_AD_TYPES.VIDEO) {
|
|
2251
2343
|
if (price.Type !== 1 && price.Type !== 7) {
|
|
2252
2344
|
errors.push(
|
|
2253
|
-
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Video (Type 11)
|
|
2345
|
+
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Video (Type 11), Price.Type b\u1EAFt bu\u1ED9c l\xE0 1 (CPM - L\u01B0\u1EE3t hi\u1EC3n th\u1ECB) ho\u1EB7c 7 (CPV - L\u01B0\u1EE3t xem). N\u1EBFu truy\u1EC1n 2 (CPC), form ch\u1EC9nh s\u1EEDa c\u1EE7a Zalo Ads s\u1EBD kh\xF4ng hi\u1EC3n th\u1ECB \u0111\u01B0\u1EE3c gi\xE1 v\xE0 s\u1ED1 l\u01B0\u1EE3ng."
|
|
2254
2346
|
);
|
|
2255
2347
|
}
|
|
2256
|
-
if (price.Type === 1
|
|
2348
|
+
if (price.Type === 1) {
|
|
2349
|
+
if ((price.Limit ?? 0) < 50) {
|
|
2350
|
+
errors.push(
|
|
2351
|
+
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Video CPM, s\u1ED1 l\u01B0\u1EE3ng hi\u1EC3n th\u1ECB t\u1ED1i thi\u1EC3u (Price.Limit) l\xE0 50 (t\u01B0\u01A1ng \u1EE9ng 50,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB)."
|
|
2352
|
+
);
|
|
2353
|
+
}
|
|
2354
|
+
const videoPlatform = payload.Settings?.VideoPlatform;
|
|
2355
|
+
if (videoPlatform === ZaloAdsVideoPlatform.VIDEO_NETWORK) {
|
|
2356
|
+
if (price.Bid !== void 0 && price.Bid < 7300) {
|
|
2357
|
+
errors.push(
|
|
2358
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho N\u1EC1n t\u1EA3ng Video (ZVideo, B\xE1o M\u1EDBi) t\u1ED1i thi\u1EC3u l\xE0 7,300 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2359
|
+
);
|
|
2360
|
+
}
|
|
2361
|
+
} else if (videoPlatform === ZaloAdsVideoPlatform.ZALO_FEED) {
|
|
2362
|
+
if (price.Bid !== void 0 && price.Bid < 6e3) {
|
|
2363
|
+
errors.push(
|
|
2364
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Video tr\xEAn Nh\u1EADt k\xFD Zalo t\u1ED1i thi\u1EC3u l\xE0 6,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
} else {
|
|
2368
|
+
if (price.Bid !== void 0 && price.Bid < 6e3) {
|
|
2369
|
+
errors.push(
|
|
2370
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Video t\u1ED1i thi\u1EC3u l\xE0 6,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2371
|
+
);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
} else if (payload.Type === VALID_AD_TYPES.COMMERCE) {
|
|
2376
|
+
if (price.Type !== 2 && price.Type !== 5) {
|
|
2257
2377
|
errors.push(
|
|
2258
|
-
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o
|
|
2378
|
+
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Commerce (Type 28), Price.Type ch\u1EC9 h\u1ED7 tr\u1EE3 2 (CPC - L\u01B0\u1EE3t nh\u1EA5n) ho\u1EB7c 5 (CPA - L\u01B0\u1EE3t \u0111\u1EB7t h\xE0ng)."
|
|
2259
2379
|
);
|
|
2260
2380
|
}
|
|
2261
|
-
|
|
2381
|
+
if (price.Type === 2) {
|
|
2382
|
+
if (price.SpendingMethod === 1) {
|
|
2383
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 6e5) {
|
|
2384
|
+
errors.push(
|
|
2385
|
+
`T\u1ED5ng ng\xE2n s\xE1ch cho Qu\u1EA3ng c\xE1o Commerce CPC t\u1ED1i thi\u1EC3u l\xE0 600,000 VN\u0110 (Price.Limit >= 600000). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}\u0111.`
|
|
2386
|
+
);
|
|
2387
|
+
}
|
|
2388
|
+
} else if (price.SpendingMethod === 0) {
|
|
2389
|
+
if (price.Bid !== void 0 && price.Bid < 650) {
|
|
2390
|
+
errors.push(
|
|
2391
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i l\u01B0\u1EE3t nh\u1EA5n (Price.Bid) t\u1ED1i thi\u1EC3u l\xE0 650 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
if (price.Limit !== void 0 && price.Limit < 50) {
|
|
2395
|
+
errors.push(
|
|
2396
|
+
`S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t nh\u1EA5n t\u1ED1i thi\u1EC3u (Price.Limit) m\u1ED7i ng\xE0y l\xE0 50 l\u01B0\u1EE3t. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}.`
|
|
2397
|
+
);
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
} else if (price.Type === 5) {
|
|
2401
|
+
if (price.SpendingMethod === 1) {
|
|
2402
|
+
if (price.Bid !== void 0 && price.Bid !== 0) {
|
|
2403
|
+
errors.push(
|
|
2404
|
+
"Khi ch\u1ECDn 'T\u1ED5ng ng\xE2n s\xE1ch qu\u1EA3ng c\xE1o' (SpendingMethod = 1) cho L\u01B0\u1EE3t \u0111\u1EB7t h\xE0ng (CPA), tr\u01B0\u1EDDng Bid b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 0 (h\u1EC7 th\u1ED1ng t\u1EF1 \u0111\u1ED9ng \u0111\u1EA5u th\u1EA7u)."
|
|
2405
|
+
);
|
|
2406
|
+
}
|
|
2407
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 15e5) {
|
|
2408
|
+
errors.push(
|
|
2409
|
+
`T\u1ED5ng ng\xE2n s\xE1ch cho Qu\u1EA3ng c\xE1o Commerce CPA (L\u01B0\u1EE3t \u0111\u1EB7t h\xE0ng t\u1EF1 \u0111\u1ED9ng) t\u1ED1i thi\u1EC3u l\xE0 1,500,000 VN\u0110 (Price.Limit >= 1500000). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}\u0111.`
|
|
2410
|
+
);
|
|
2411
|
+
}
|
|
2412
|
+
} else if (price.SpendingMethod === 0) {
|
|
2413
|
+
if (price.Bid !== void 0 && price.Bid < 6e4) {
|
|
2414
|
+
errors.push(
|
|
2415
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i l\u01B0\u1EE3t \u0111\u1EB7t h\xE0ng (Price.Bid) t\u1ED1i thi\u1EC3u l\xE0 60,000 VN\u0110 / l\u01B0\u1EE3t \u0111\u1EB7t h\xE0ng. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2416
|
+
);
|
|
2417
|
+
}
|
|
2418
|
+
if (price.Limit !== void 0 && price.Limit < 10) {
|
|
2419
|
+
errors.push(
|
|
2420
|
+
`S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t \u0111\u1EB7t h\xE0ng t\u1ED1i thi\u1EC3u (Price.Limit) l\xE0 10 \u0111\u01A1n h\xE0ng (Limit >= 10). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}.`
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
2423
|
+
} else if (price.SpendingMethod !== void 0) {
|
|
2424
|
+
errors.push(
|
|
2425
|
+
"C\xE1ch \u0111\u1EB7t gi\xE1 SpendingMethod cho Qu\u1EA3ng c\xE1o Commerce CPA ch\u1EC9 ch\u1EA5p nh\u1EADn 1 (T\u1ED5ng ng\xE2n s\xE1ch qu\u1EA3ng c\xE1o) ho\u1EB7c 0 (T\u1EF1 \u0111\u1EB7t gi\xE1)."
|
|
2426
|
+
);
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
} else if (payload.Type === VALID_AD_TYPES.ARTICLE) {
|
|
2262
2430
|
if (price.Type !== 2) {
|
|
2263
2431
|
errors.push(
|
|
2264
2432
|
`\u0110\u1ED1i v\u1EDBi Ad Type ${payload.Type}, Price.Type b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 2 (CPC).`
|
|
2265
2433
|
);
|
|
2266
2434
|
}
|
|
2435
|
+
} else if (payload.Type === VALID_AD_TYPES.FORM) {
|
|
2436
|
+
if (price.Type !== 1 && price.Type !== 2 && price.Type !== 5) {
|
|
2437
|
+
errors.push(
|
|
2438
|
+
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Form (Type 18), Price.Type ch\u1EC9 h\u1ED7 tr\u1EE3 1 (CPM - L\u01B0\u1EE3t hi\u1EC3n th\u1ECB), 2 (CPC - L\u01B0\u1EE3t nh\u1EA5n) ho\u1EB7c 5 (CPA - L\u01B0\u1EE3t li\xEAn h\u1EC7)."
|
|
2439
|
+
);
|
|
2440
|
+
}
|
|
2441
|
+
if (price.Type === 1) {
|
|
2442
|
+
if (price.Bid !== void 0 && price.Bid < 7300) {
|
|
2443
|
+
errors.push(
|
|
2444
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Form t\u1ED1i thi\u1EC3u l\xE0 7,300 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
if (price.Limit !== void 0 && price.Limit < 50) {
|
|
2448
|
+
errors.push(
|
|
2449
|
+
`S\u1ED1 l\u01B0\u1EE3ng hi\u1EC3n th\u1ECB t\u1ED1i thi\u1EC3u (Price.Limit) cho Qu\u1EA3ng c\xE1o Form CPM l\xE0 50 (t\u01B0\u01A1ng \u1EE9ng 50,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}.`
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
} else if (price.Type === 2) {
|
|
2453
|
+
if (price.SpendingMethod === 1) {
|
|
2454
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 2e5) {
|
|
2455
|
+
errors.push(
|
|
2456
|
+
`Ng\xE2n s\xE1ch m\u1ED7i ng\xE0y cho Qu\u1EA3ng c\xE1o Form CPC t\u1ED1i thi\u1EC3u l\xE0 200,000 VN\u0110 (Price.Limit >= 200000). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}\u0111.`
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
} else if (price.SpendingMethod === 0) {
|
|
2460
|
+
if (price.Bid !== void 0 && price.Bid < 650) {
|
|
2461
|
+
errors.push(
|
|
2462
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i l\u01B0\u1EE3t nh\u1EA5n (Price.Bid) t\u1ED1i thi\u1EC3u l\xE0 650 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2463
|
+
);
|
|
2464
|
+
}
|
|
2465
|
+
if (price.Limit !== void 0 && price.Limit < 50) {
|
|
2466
|
+
errors.push(
|
|
2467
|
+
`S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t nh\u1EA5n t\u1ED1i thi\u1EC3u (Price.Limit) m\u1ED7i ng\xE0y l\xE0 50 l\u01B0\u1EE3t. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}.`
|
|
2468
|
+
);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
} else if (price.Type === 5) {
|
|
2472
|
+
if (price.SpendingMethod !== 1) {
|
|
2473
|
+
errors.push(
|
|
2474
|
+
"Khi t\xEDnh ti\u1EC1n theo L\u01B0\u1EE3t li\xEAn h\u1EC7 (Price.Type = 5 / CPA), SpendingMethod b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 1 (T\u1ED1i \u01B0u t\u1EF1 \u0111\u1ED9ng theo ng\xE2n s\xE1ch)."
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
if (price.Bid !== void 0 && price.Bid !== 0) {
|
|
2478
|
+
errors.push(
|
|
2479
|
+
"Khi t\xEDnh ti\u1EC1n theo L\u01B0\u1EE3t li\xEAn h\u1EC7 (Price.Type = 5 / CPA), tr\u01B0\u1EDDng Bid b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 0 (Zalo Ads t\u1EF1 \u0111\u1ED9ng t\u1ED1i \u01B0u gi\xE1 th\u1EA7u, n\u1EBFu truy\u1EC1n > 0 m\xE1y ch\u1EE7 s\u1EBD b\xE1o l\u1ED7i code 13: Gi\xE1 \u0111\u1EB7t kh\xF4ng h\u1EE3p l\u1EC7)."
|
|
2480
|
+
);
|
|
2481
|
+
}
|
|
2482
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 5e5) {
|
|
2483
|
+
errors.push(
|
|
2484
|
+
`Ng\xE2n s\xE1ch m\u1ED7i ng\xE0y cho Qu\u1EA3ng c\xE1o Form CPA (L\u01B0\u1EE3t li\xEAn h\u1EC7) t\u1ED1i thi\u1EC3u l\xE0 500,000 VN\u0110 (Price.Limit >= 500000). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}\u0111.`
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2267
2488
|
} else if (payload.Type === VALID_AD_TYPES.OA) {
|
|
2268
2489
|
if (price.Type !== 2 && price.Type !== 5) {
|
|
2269
2490
|
errors.push(
|
|
@@ -2323,13 +2544,43 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2323
2544
|
);
|
|
2324
2545
|
}
|
|
2325
2546
|
}
|
|
2326
|
-
} else if (payload.Type === VALID_AD_TYPES.MESSAGE) {
|
|
2327
|
-
if (price.Type !== 2 && price.Type !== 5) {
|
|
2547
|
+
} else if (payload.Type === VALID_AD_TYPES.MESSAGE || payload.Type === VALID_AD_TYPES.MESSAGE_LEGACY || Number(payload.Type) === 19 || Number(payload.Type) === 30) {
|
|
2548
|
+
if (price.Type !== 1 && price.Type !== 2 && price.Type !== 5) {
|
|
2328
2549
|
errors.push(
|
|
2329
|
-
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Tin nh\u1EAFn (Type
|
|
2550
|
+
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Tin nh\u1EAFn (Type 19), Price.Type ch\u1EC9 h\u1ED7 tr\u1EE3 1 (CPM - L\u01B0\u1EE3t hi\u1EC3n th\u1ECB), 2 (CPC - L\u01B0\u1EE3t nh\u1EA5n) ho\u1EB7c 5 (CPA - L\u01B0\u1EE3t li\xEAn h\u1EC7)."
|
|
2330
2551
|
);
|
|
2331
2552
|
}
|
|
2332
|
-
if (price.Type ===
|
|
2553
|
+
if (price.Type === 1) {
|
|
2554
|
+
if (price.Bid !== void 0 && price.Bid < 7300) {
|
|
2555
|
+
errors.push(
|
|
2556
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Tin nh\u1EAFn t\u1ED1i thi\u1EC3u l\xE0 7,300 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
if (price.Limit !== void 0 && price.Limit < 50) {
|
|
2560
|
+
errors.push(
|
|
2561
|
+
`S\u1ED1 l\u01B0\u1EE3ng hi\u1EC3n th\u1ECB t\u1ED1i thi\u1EC3u (Price.Limit) cho Qu\u1EA3ng c\xE1o Tin nh\u1EAFn CPM l\xE0 50 (t\u01B0\u01A1ng \u1EE9ng 50,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}.`
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
} else if (price.Type === 2) {
|
|
2565
|
+
if (price.SpendingMethod === 1) {
|
|
2566
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 2e5) {
|
|
2567
|
+
errors.push(
|
|
2568
|
+
`Ng\xE2n s\xE1ch m\u1ED7i ng\xE0y cho Qu\u1EA3ng c\xE1o Tin nh\u1EAFn CPC t\u1ED1i thi\u1EC3u l\xE0 200,000 VN\u0110 (Price.Limit >= 200000). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}\u0111.`
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2571
|
+
} else if (price.SpendingMethod === 0) {
|
|
2572
|
+
if (price.Bid !== void 0 && price.Bid < 650) {
|
|
2573
|
+
errors.push(
|
|
2574
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i l\u01B0\u1EE3t nh\u1EA5n (Price.Bid) t\u1ED1i thi\u1EC3u l\xE0 650 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
if (price.Limit !== void 0 && price.Limit < 50) {
|
|
2578
|
+
errors.push(
|
|
2579
|
+
`S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t nh\u1EA5n t\u1ED1i thi\u1EC3u (Price.Limit) m\u1ED7i ng\xE0y l\xE0 50 l\u01B0\u1EE3t. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}.`
|
|
2580
|
+
);
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
} else if (price.Type === 5) {
|
|
2333
2584
|
if (price.SpendingMethod !== 1) {
|
|
2334
2585
|
errors.push(
|
|
2335
2586
|
"Khi t\xEDnh ti\u1EC1n theo L\u01B0\u1EE3t li\xEAn h\u1EC7 (Price.Type = 5 / CPA), SpendingMethod b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 1 (T\u1ED1i \u01B0u t\u1EF1 \u0111\u1ED9ng theo ng\xE2n s\xE1ch)."
|
|
@@ -2340,12 +2591,71 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2340
2591
|
"Khi t\xEDnh ti\u1EC1n theo L\u01B0\u1EE3t li\xEAn h\u1EC7 (Price.Type = 5 / CPA), tr\u01B0\u1EDDng Bid b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 0 (Zalo Ads t\u1EF1 \u0111\u1ED9ng t\u1ED1i \u01B0u gi\xE1 th\u1EA7u, n\u1EBFu truy\u1EC1n > 0 m\xE1y ch\u1EE7 s\u1EBD b\xE1o l\u1ED7i code 13: Gi\xE1 \u0111\u1EB7t kh\xF4ng h\u1EE3p l\u1EC7)."
|
|
2341
2592
|
);
|
|
2342
2593
|
}
|
|
2594
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 5e5) {
|
|
2595
|
+
errors.push(
|
|
2596
|
+
`Ng\xE2n s\xE1ch m\u1ED7i ng\xE0y cho Qu\u1EA3ng c\xE1o Tin nh\u1EAFn CPA (L\u01B0\u1EE3t li\xEAn h\u1EC7) t\u1ED1i thi\u1EC3u l\xE0 500,000 VN\u0110 (Price.Limit >= 500000). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}\u0111.`
|
|
2597
|
+
);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
} else if (Number(payload.Type) === 21 || Number(payload.Type) === 23 || Number(payload.Type) === 26 || payload.Type === VALID_AD_TYPES.DISPLAY || payload.Type === VALID_AD_TYPES.DISPLAY_HALFPAGE || payload.Type === VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE) {
|
|
2601
|
+
const adFormat = payload.Settings?.AdInfo?.AdFormat;
|
|
2602
|
+
const typeNum = Number(payload.Type);
|
|
2603
|
+
const isHalfpage = typeNum === 26 || adFormat === 13 || adFormat === 14 || (payload.AdName || "").toLowerCase().includes("halfpage");
|
|
2604
|
+
const isMediumRectangle = typeNum === 23 || adFormat === 6 || (payload.AdName || "").toLowerCase().includes("medium rectangle") || (payload.AdName || "").toLowerCase().includes("300x250");
|
|
2605
|
+
const adNameLower = (payload.AdName || "").toLowerCase();
|
|
2606
|
+
const isWelcome = adNameLower.includes("welcome");
|
|
2607
|
+
const isMasthead = (adNameLower.includes("masthead") || typeNum === 21 || adFormat === 1 || adFormat === 2) && !isWelcome && !isMediumRectangle;
|
|
2608
|
+
if (price.Type !== 1 && price.Type !== 2) {
|
|
2609
|
+
errors.push(
|
|
2610
|
+
"\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Display, Price.Type ch\u1EC9 ch\u1EA5p nh\u1EADn 1 (CPM - L\u01B0\u1EE3t hi\u1EC3n th\u1ECB) ho\u1EB7c 2 (CPC - L\u01B0\u1EE3t nh\u1EA5n)."
|
|
2611
|
+
);
|
|
2343
2612
|
}
|
|
2344
|
-
if (
|
|
2613
|
+
if ((isHalfpage || isMasthead) && price.Type === 2) {
|
|
2345
2614
|
errors.push(
|
|
2346
|
-
|
|
2615
|
+
`Qu\u1EA3ng c\xE1o ${isHalfpage ? "Halfpage (Type 26 / AdFormat 13, 14)" : "Masthead (Type 21)"} ch\u1EC9 h\u1ED7 tr\u1EE3 t\xEDnh ti\u1EC1n theo l\u01B0\u1EE3t hi\u1EC3n th\u1ECB CPM (Price.Type = 1), kh\xF4ng h\u1ED7 tr\u1EE3 CPC.`
|
|
2347
2616
|
);
|
|
2348
2617
|
}
|
|
2618
|
+
if (price.Type === 1) {
|
|
2619
|
+
if (price.Bid !== void 0) {
|
|
2620
|
+
if (isWelcome && price.Bid < 3e4) {
|
|
2621
|
+
errors.push(
|
|
2622
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Welcome Mobile t\u1ED1i thi\u1EC3u l\xE0 30,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2623
|
+
);
|
|
2624
|
+
} else if (isHalfpage && price.Bid < 16e3) {
|
|
2625
|
+
errors.push(
|
|
2626
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Halfpage t\u1ED1i thi\u1EC3u l\xE0 16,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2627
|
+
);
|
|
2628
|
+
} else if (isMasthead && price.Bid < 13e3) {
|
|
2629
|
+
errors.push(
|
|
2630
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Masthead t\u1ED1i thi\u1EC3u l\xE0 13,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2631
|
+
);
|
|
2632
|
+
} else if (isMediumRectangle && price.Bid < 8e3) {
|
|
2633
|
+
errors.push(
|
|
2634
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Medium Rectangle CPM t\u1ED1i thi\u1EC3u l\xE0 8,000 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2635
|
+
);
|
|
2636
|
+
} else if (price.Bid < 8e3) {
|
|
2637
|
+
errors.push(
|
|
2638
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i 1,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB (Price.Bid) cho Qu\u1EA3ng c\xE1o Display CPM t\u1ED1i thi\u1EC3u l\xE0 8,000 VN\u0110 (s\xE0n h\u1EC7 th\u1ED1ng). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2639
|
+
);
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 50) {
|
|
2643
|
+
errors.push(
|
|
2644
|
+
"S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t hi\u1EC3n th\u1ECB t\u1ED1i thi\u1EC3u (Price.Limit) cho Qu\u1EA3ng c\xE1o Display CPM l\xE0 50 (t\u01B0\u01A1ng \u1EE9ng 50,000 l\u01B0\u1EE3t hi\u1EC3n th\u1ECB)."
|
|
2645
|
+
);
|
|
2646
|
+
}
|
|
2647
|
+
} else if (price.Type === 2) {
|
|
2648
|
+
if (price.Bid !== void 0 && price.Bid < 1800) {
|
|
2649
|
+
errors.push(
|
|
2650
|
+
`Gi\xE1 \u0111\u1EB7t m\u1ED7i l\u01B0\u1EE3t nh\u1EA5n (Price.Bid) cho Qu\u1EA3ng c\xE1o Display CPC t\u1ED1i thi\u1EC3u l\xE0 1,800 VN\u0110. Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
|
|
2651
|
+
);
|
|
2652
|
+
}
|
|
2653
|
+
if (price.Limit !== void 0 && price.Limit > 0 && price.Limit < 50) {
|
|
2654
|
+
errors.push(
|
|
2655
|
+
"S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t nh\u1EA5n t\u1ED1i thi\u1EC3u (Price.Limit) cho Qu\u1EA3ng c\xE1o Display CPC l\xE0 50 l\u01B0\u1EE3t nh\u1EA5n."
|
|
2656
|
+
);
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2349
2659
|
}
|
|
2350
2660
|
if (payload.Settings && payload.Settings.DeliveryType !== void 0) {
|
|
2351
2661
|
const deliveryType = payload.Settings.DeliveryType;
|
|
@@ -2362,6 +2672,21 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2362
2672
|
}
|
|
2363
2673
|
const targeting = payload.Settings?.Targeting;
|
|
2364
2674
|
if (targeting) {
|
|
2675
|
+
if (targeting.Gender !== void 0 && targeting.Gender !== null) {
|
|
2676
|
+
if (![0, 1, 2].includes(Number(targeting.Gender))) {
|
|
2677
|
+
errors.push(`M\xE3 gi\u1EDBi t\xEDnh 'Gender' (${targeting.Gender}) kh\xF4ng h\u1EE3p l\u1EC7. H\u1EE3p l\u1EC7: 0 (T\u1EA5t c\u1EA3), 1 (Nam), 2 (N\u1EEF).`);
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
if (targeting.CustomAudienceId !== void 0 && targeting.CustomAudienceId !== null) {
|
|
2681
|
+
if (typeof targeting.CustomAudienceId !== "number" || targeting.CustomAudienceId < 0) {
|
|
2682
|
+
errors.push("CustomAudienceId ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (>= 0).");
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
if (targeting.ExcludedAudienceId !== void 0 && targeting.ExcludedAudienceId !== null) {
|
|
2686
|
+
if (typeof targeting.ExcludedAudienceId !== "number" || targeting.ExcludedAudienceId < 0) {
|
|
2687
|
+
errors.push("ExcludedAudienceId ph\u1EA3i l\xE0 s\u1ED1 nguy\xEAn kh\xF4ng \xE2m (>= 0).");
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2365
2690
|
const newAges = targeting.NewAgeRanges;
|
|
2366
2691
|
const oldAges = targeting.AgeRanges;
|
|
2367
2692
|
if (newAges && newAges.length > 0) {
|
|
@@ -2385,6 +2710,14 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2385
2710
|
errors.push(`M\xE3 h\u1EC7 \u0111i\u1EC1u h\xE0nh kh\xF4ng h\u1EE3p l\u1EC7: ${invalidOs.join(", ")}. H\u1EE3p l\u1EC7: 0 (Android), 1 (iOS), 3 (PC).`);
|
|
2386
2711
|
}
|
|
2387
2712
|
}
|
|
2713
|
+
const videoPlatform = payload.Settings?.VideoPlatform;
|
|
2714
|
+
if (videoPlatform !== void 0 && videoPlatform !== null) {
|
|
2715
|
+
if (![1, 2].includes(Number(videoPlatform))) {
|
|
2716
|
+
warnings.push(
|
|
2717
|
+
`VideoPlatform (${videoPlatform}) kh\xF4ng h\u1EE3p l\u1EC7. Gi\xE1 tr\u1ECB chu\u1EA9n: 1 (N\u1EC1n t\u1EA3ng Video - ZVideo, B\xE1o M\u1EDBi) ho\u1EB7c 2 (Nh\u1EADt k\xFD Zalo - Feed).`
|
|
2718
|
+
);
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2388
2721
|
const deliveryType = payload.Settings?.DeliveryType;
|
|
2389
2722
|
if (deliveryType !== void 0 && deliveryType !== ZaloAdsDeliveryType.STANDARD && deliveryType !== ZaloAdsDeliveryType.SPEED_UP) {
|
|
2390
2723
|
warnings.push(
|
|
@@ -2452,21 +2785,15 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2452
2785
|
if (!payload.ZaloFormId || !payload.ZaloFormId.trim()) {
|
|
2453
2786
|
errors.push("ZaloFormId l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Form (Ad Type 18).");
|
|
2454
2787
|
}
|
|
2455
|
-
} else if (payload.Type === VALID_AD_TYPES.MESSAGE) {
|
|
2788
|
+
} else if (payload.Type === VALID_AD_TYPES.MESSAGE || payload.Type === VALID_AD_TYPES.MESSAGE_LEGACY || Number(payload.Type) === 19 || Number(payload.Type) === 30) {
|
|
2456
2789
|
if (!payload.Settings?.Image?.LogoUrl) {
|
|
2457
|
-
errors.push("Settings.Image.LogoUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Tin Nh\u1EAFn (Ad Type 30).");
|
|
2458
|
-
}
|
|
2459
|
-
if (!payload.MiniPageId || payload.MiniPageId <= 0) {
|
|
2460
|
-
errors.push(
|
|
2461
|
-
"MiniPageId l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Tin Nh\u1EAFn (Ad Type 30, Template 4 - K\u1ECBch b\u1EA3n gi\u1EDBi thi\u1EC7u th\u01B0\u01A1ng hi\u1EC7u / Tin nh\u1EAFn). N\u1EBFu thi\u1EBFu ho\u1EB7c = 0, m\xE1y ch\u1EE7 Zalo Ads s\u1EBD t\u1EEB ch\u1ED1i v\u1EDBi l\u1ED7i: 'Mini Page kh\xF4ng h\u1EE3p l\u1EC7.'."
|
|
2462
|
-
);
|
|
2790
|
+
errors.push("Settings.Image.LogoUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Tin Nh\u1EAFn (Ad Type 19/30).");
|
|
2463
2791
|
}
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
if (payload.Settings?.Image?.ExtraImgs && payload.Settings?.Image?.ExtraImgs.length > 0) {
|
|
2792
|
+
const hasFlow = payload.ZaloFlowId && Number(payload.ZaloFlowId) > 0;
|
|
2793
|
+
const hasMiniPage = payload.MiniPageId && Number(payload.MiniPageId) > 0;
|
|
2794
|
+
if (!hasFlow && !hasMiniPage) {
|
|
2468
2795
|
errors.push(
|
|
2469
|
-
"Qu\u1EA3ng c\xE1o Tin Nh\u1EAFn \
|
|
2796
|
+
"Qu\u1EA3ng c\xE1o Tin Nh\u1EAFn y\xEAu c\u1EA7u ph\u1EA3i ch\u1ECDn K\u1ECBch b\u1EA3n tin nh\u1EAFn (ZaloFlowId > 0) ho\u1EB7c Trang gi\u1EDBi thi\u1EC7u th\u01B0\u01A1ng hi\u1EC7u (MiniPageId > 0)."
|
|
2470
2797
|
);
|
|
2471
2798
|
}
|
|
2472
2799
|
} else if (payload.Type === VALID_AD_TYPES.COMMERCE) {
|
|
@@ -2484,6 +2811,14 @@ function validateUpdateAdPayload(payload, options = {}) {
|
|
|
2484
2811
|
if (!payload.ZaloFeedId && !payload.articleId) {
|
|
2485
2812
|
errors.push("ZaloFeedId ho\u1EB7c articleId l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o B\xE0i Vi\u1EBFt (Ad Type 3).");
|
|
2486
2813
|
}
|
|
2814
|
+
} else if (Number(payload.Type) === 21 || Number(payload.Type) === 23 || Number(payload.Type) === 26 || payload.Type === VALID_AD_TYPES.DISPLAY || payload.Type === VALID_AD_TYPES.DISPLAY_HALFPAGE || payload.Type === VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE) {
|
|
2815
|
+
const img = payload.Settings?.Image;
|
|
2816
|
+
const hasImage = img?.LandscapeCoverUrl || img?.BaseLandscapeCoverUrl || img?.PortraitCoverUrl || img?.SquareCoverUrl;
|
|
2817
|
+
if (!hasImage) {
|
|
2818
|
+
errors.push(
|
|
2819
|
+
"Qu\u1EA3ng c\xE1o Display b\u1EAFt bu\u1ED9c ph\u1EA3i c\xF3 \xEDt nh\u1EA5t m\u1ED9t banner h\xECnh \u1EA3nh (Settings.Image.LandscapeCoverUrl ho\u1EB7c BaseLandscapeCoverUrl)."
|
|
2820
|
+
);
|
|
2821
|
+
}
|
|
2487
2822
|
}
|
|
2488
2823
|
return {
|
|
2489
2824
|
isValid: errors.length === 0,
|
|
@@ -2725,7 +3060,19 @@ function validateUpdateWebsiteAd(payload, options = {}) {
|
|
|
2725
3060
|
return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.WEBSITE }, options);
|
|
2726
3061
|
}
|
|
2727
3062
|
function validateUpdateDisplayAd(payload, options = {}) {
|
|
2728
|
-
|
|
3063
|
+
const adFormat = payload.Settings?.AdInfo?.AdFormat;
|
|
3064
|
+
const rawType = Number(payload.Type);
|
|
3065
|
+
const isHalfpage = rawType === 26 || adFormat === 13 || adFormat === 14;
|
|
3066
|
+
const isMediumRectangle = rawType === 23 || adFormat === 6;
|
|
3067
|
+
let effectiveType;
|
|
3068
|
+
if (isHalfpage) {
|
|
3069
|
+
effectiveType = VALID_AD_TYPES.DISPLAY_HALFPAGE;
|
|
3070
|
+
} else if (isMediumRectangle) {
|
|
3071
|
+
effectiveType = VALID_AD_TYPES.DISPLAY_MEDIUM_RECTANGLE;
|
|
3072
|
+
} else {
|
|
3073
|
+
effectiveType = payload.Type ?? VALID_AD_TYPES.DISPLAY;
|
|
3074
|
+
}
|
|
3075
|
+
return validateUpdateAdPayload({ ...payload, Type: effectiveType }, options);
|
|
2729
3076
|
}
|
|
2730
3077
|
function validateUpdateVideoAd(payload, options = {}) {
|
|
2731
3078
|
return validateUpdateAdPayload({ ...payload, Type: VALID_AD_TYPES.VIDEO }, options);
|
|
@@ -8871,6 +9218,7 @@ export {
|
|
|
8871
9218
|
VALID_AD_TYPES,
|
|
8872
9219
|
VALID_CAMPAIGN_TYPES,
|
|
8873
9220
|
VIETNAM_PHONE_REGEX,
|
|
9221
|
+
ZALO_DISPLAY_AD_FORMAT,
|
|
8874
9222
|
ZALO_NEW_REGION_PROVINCE_CODES,
|
|
8875
9223
|
ZALO_PROFILE_ADS_PROVINCES,
|
|
8876
9224
|
ZALO_PROFILE_ADS_SUB_CATEGORIES,
|
|
@@ -8906,6 +9254,7 @@ export {
|
|
|
8906
9254
|
ZaloAdsUpdateVideoAdRequest,
|
|
8907
9255
|
ZaloAdsUpdateVideoAdResponse,
|
|
8908
9256
|
ZaloAdsUseConversion,
|
|
9257
|
+
ZaloAdsVideoPlatform,
|
|
8909
9258
|
ZaloAdsVideoSrc,
|
|
8910
9259
|
ZaloAdsXTemplates,
|
|
8911
9260
|
ZaloAudiencesService,
|