@redonvn/zalo-ads-sdk 0.2.30 → 0.2.33

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.js CHANGED
@@ -2247,7 +2247,7 @@ var VALID_AD_TYPES = {
2247
2247
  OA: 2,
2248
2248
  VIDEO: 11,
2249
2249
  COMMERCE: 28,
2250
- // Server trả về 28 (không phải 23)
2250
+ // Mã chuẩn cho Commerce Ad
2251
2251
  ARTICLE: 3,
2252
2252
  DISPLAY: 21,
2253
2253
  // Masthead Mobile (Format 1) & Masthead Desktop (Format 2)
@@ -2517,15 +2517,46 @@ function validateUpdateAdPayload(payload, options = {}) {
2517
2517
  errors.push("Settings.Price l\xE0 b\u1EAFt bu\u1ED9c.");
2518
2518
  } else {
2519
2519
  if (payload.Type === VALID_AD_TYPES.WEBSITE) {
2520
- if (price.Type !== 1) {
2520
+ if (price.Type !== 2 && price.Type !== 1) {
2521
2521
  errors.push(
2522
- "\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Website (Type 5), Price.Type b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 1 (CPC). N\u1EBFu truy\u1EC1n 2 s\u1EBD b\u1ECB m\xE1y ch\u1EE7 l\u1ED7i."
2522
+ "\u0110\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Website (Type 5), Price.Type b\u1EAFt bu\u1ED9c ph\u1EA3i b\u1EB1ng 2 (L\u01B0\u1EE3t nh\u1EA5n - CPC)."
2523
2523
  );
2524
2524
  }
2525
- if (price.LimitType === 1) {
2526
- errors.push(
2527
- "Qu\u1EA3ng c\xE1o Website kh\xF4ng h\u1ED7 tr\u1EE3 LimitType: 1 (t\u1ED5ng ng\xE2n s\xE1ch). B\u1EAFt bu\u1ED9c ph\u1EA3i d\xF9ng LimitType: 0 (ng\xE2n s\xE1ch ng\xE0y)."
2528
- );
2525
+ if (price.SpendingMethod === 1) {
2526
+ if (price.Bid !== void 0 && price.Bid !== 0) {
2527
+ warnings.push(
2528
+ "Khi ch\u1ECDn 'T\u1ED5ng ng\xE2n s\xE1ch qu\u1EA3ng c\xE1o' (SpendingMethod = 1) cho Qu\u1EA3ng c\xE1o Website, tr\u01B0\u1EDDng Price.Bid n\xEAn \u0111\u1EC3 b\u1EB1ng 0 (h\u1EC7 th\u1ED1ng t\u1EF1 \u0111\u1ED9ng \u0111\u1EA5u th\u1EA7u)."
2529
+ );
2530
+ }
2531
+ if (price.LimitType === 1) {
2532
+ let days = 1;
2533
+ if (payload.StartDate && payload.EndDate && payload.EndDate > payload.StartDate) {
2534
+ days = Math.max(1, Math.ceil((payload.EndDate - payload.StartDate) / 86400));
2535
+ }
2536
+ const minTotalBudget = days * 2e5;
2537
+ if (price.Limit !== void 0 && price.Limit < minTotalBudget) {
2538
+ errors.push(
2539
+ `Ng\xE2n s\xE1ch To\xE0n l\u1ECBch ch\u1EA1y cho Qu\u1EA3ng c\xE1o Website (${days} ng\xE0y) t\u1ED1i thi\u1EC3u l\xE0 ${minTotalBudget.toLocaleString("vi-VN")} VN\u0110 (${days} ng\xE0y x 200,000\u0111/ng\xE0y). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit.toLocaleString("vi-VN")}\u0111.`
2540
+ );
2541
+ }
2542
+ } else if (price.LimitType === 2 || price.LimitType === 0) {
2543
+ if (price.Limit !== void 0 && price.Limit < 2e5) {
2544
+ errors.push(
2545
+ `Ng\xE2n s\xE1ch M\u1ED7i ng\xE0y cho Qu\u1EA3ng c\xE1o Website (SpendingMethod = 1) t\u1ED1i thi\u1EC3u l\xE0 200,000 VN\u0110 (Price.Limit >= 200000). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit.toLocaleString("vi-VN")}\u0111.`
2546
+ );
2547
+ }
2548
+ }
2549
+ } else if (price.SpendingMethod === 0) {
2550
+ if (price.Bid !== void 0 && price.Bid < 650) {
2551
+ errors.push(
2552
+ `Gi\xE1 \u0111\u1EB7t m\u1ED7i l\u01B0\u1EE3t nh\u1EA5n (Price.Bid) cho Qu\u1EA3ng c\xE1o Website t\u1ED1i thi\u1EC3u l\xE0 650 VN\u0110 (s\xE0n h\u1EC7 th\u1ED1ng Zalo Ads). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Bid}\u0111.`
2553
+ );
2554
+ }
2555
+ if (price.Limit !== void 0 && price.Limit < 50) {
2556
+ errors.push(
2557
+ `S\u1ED1 l\u01B0\u1EE3ng l\u01B0\u1EE3t nh\u1EA5n (Price.Limit) cho Qu\u1EA3ng c\xE1o Website t\u1ED1i thi\u1EC3u l\xE0 50 l\u01B0\u1EE3t (minCTA = 50). Hi\u1EC7n t\u1EA1i \u0111ang truy\u1EC1n: ${price.Limit}.`
2558
+ );
2559
+ }
2529
2560
  }
2530
2561
  } else if (payload.Type === VALID_AD_TYPES.VIDEO) {
2531
2562
  if (price.Type !== 1 && price.Type !== 7) {
@@ -2969,14 +3000,31 @@ function validateUpdateAdPayload(payload, options = {}) {
2969
3000
  );
2970
3001
  }
2971
3002
  }
2972
- if (payload.Type === VALID_AD_TYPES.FORM) {
3003
+ const isNonEmptyStr = (val) => typeof val === "string" && val.trim().length > 0;
3004
+ if (payload.Type === VALID_AD_TYPES.WEBSITE || Number(payload.Type) === 5) {
3005
+ if (!isNonEmptyStr(payload.Settings?.Image?.LandscapeCoverUrl)) {
3006
+ errors.push(
3007
+ "Settings.Image.LandscapeCoverUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Website (Ad Type 5). Vui l\xF2ng upload \u1EA3nh b\xECa t\u1EC9 l\u1EC7 16:9 (1024x533 px) l\xEAn CDN Zalo Ads tr\u01B0\u1EDBc khi l\u01B0u."
3008
+ );
3009
+ }
3010
+ } else if (payload.Type === VALID_AD_TYPES.FORM || Number(payload.Type) === 18) {
2973
3011
  if (!payload.ZaloFormId || !payload.ZaloFormId.trim()) {
2974
3012
  errors.push("ZaloFormId l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Form (Ad Type 18).");
2975
3013
  }
3014
+ if (!isNonEmptyStr(payload.Settings?.Image?.LandscapeCoverUrl)) {
3015
+ errors.push(
3016
+ "Settings.Image.LandscapeCoverUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Form (Ad Type 18). Vui l\xF2ng upload \u1EA3nh b\xECa t\u1EC9 l\u1EC7 16:9 (1024x533 px) l\xEAn CDN Zalo Ads tr\u01B0\u1EDBc khi l\u01B0u."
3017
+ );
3018
+ }
2976
3019
  } else if (payload.Type === VALID_AD_TYPES.MESSAGE || payload.Type === VALID_AD_TYPES.MESSAGE_LEGACY || Number(payload.Type) === 19 || Number(payload.Type) === 30) {
2977
- if (!payload.Settings?.Image?.LogoUrl) {
3020
+ if (!isNonEmptyStr(payload.Settings?.Image?.LogoUrl)) {
2978
3021
  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).");
2979
3022
  }
3023
+ if (!isNonEmptyStr(payload.Settings?.Image?.LandscapeCoverUrl)) {
3024
+ errors.push(
3025
+ "Settings.Image.LandscapeCoverUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Tin Nh\u1EAFn (Ad Type 19/30). Vui l\xF2ng upload \u1EA3nh b\xECa t\u1EC9 l\u1EC7 16:9 (1024x533 px) l\xEAn CDN Zalo Ads tr\u01B0\u1EDBc khi l\u01B0u."
3026
+ );
3027
+ }
2980
3028
  const hasFlow = payload.ZaloFlowId && Number(payload.ZaloFlowId) > 0;
2981
3029
  const hasMiniPage = payload.MiniPageId && Number(payload.MiniPageId) > 0;
2982
3030
  if (!hasFlow && !hasMiniPage) {
@@ -2984,30 +3032,58 @@ function validateUpdateAdPayload(payload, options = {}) {
2984
3032
  "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)."
2985
3033
  );
2986
3034
  }
2987
- } else if (payload.Type === VALID_AD_TYPES.COMMERCE) {
3035
+ } else if (payload.Type === VALID_AD_TYPES.COMMERCE || Number(payload.Type) === 28) {
2988
3036
  if (!payload.MiniPageId || payload.MiniPageId <= 0) {
2989
3037
  errors.push("MiniPageId l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Commerce (Ad Type 28, Template 1/2/3).");
2990
3038
  }
2991
- } else if (payload.Type === VALID_AD_TYPES.VIDEO) {
3039
+ const hasSquare = isNonEmptyStr(payload.Settings?.Image?.SquareCoverUrl);
3040
+ const hasLandscape = isNonEmptyStr(payload.Settings?.Image?.LandscapeCoverUrl);
3041
+ if (!hasSquare && !hasLandscape) {
3042
+ errors.push(
3043
+ "Settings.Image.SquareCoverUrl (ho\u1EB7c LandscapeCoverUrl) l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Commerce (Ad Type 28). Vui l\xF2ng upload \u1EA3nh s\u1EA3n ph\u1EA9m (1024x1024 px) l\xEAn CDN Zalo Ads tr\u01B0\u1EDBc khi l\u01B0u."
3044
+ );
3045
+ }
3046
+ } else if (payload.Type === VALID_AD_TYPES.OA || Number(payload.Type) === 2) {
3047
+ if (!isNonEmptyStr(payload.Settings?.Image?.LandscapeCoverUrl)) {
3048
+ errors.push(
3049
+ "Settings.Image.LandscapeCoverUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o OA (Ad Type 2). Vui l\xF2ng upload \u1EA3nh b\xECa (1024x533 px) l\xEAn CDN Zalo Ads tr\u01B0\u1EDBc khi l\u01B0u."
3050
+ );
3051
+ }
3052
+ if (payload.Settings?.AdInfo?.Action !== void 0 && Number(payload.Settings.AdInfo.Action) !== 6) {
3053
+ warnings.push("Qu\u1EA3ng c\xE1o OA ch\u1EC9 ch\u1EA5p nh\u1EADn Action = 6 (Quan t\xE2m OA).");
3054
+ }
3055
+ } else if (payload.Type === VALID_AD_TYPES.ARTICLE || Number(payload.Type) === 3) {
3056
+ if (!payload.ZaloFeedId && !payload.articleId) {
3057
+ 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).");
3058
+ }
3059
+ if (!isNonEmptyStr(payload.Settings?.Image?.LandscapeCoverUrl)) {
3060
+ errors.push(
3061
+ "Settings.Image.LandscapeCoverUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o B\xE0i Vi\u1EBFt (Ad Type 3). Vui l\xF2ng upload \u1EA3nh \u0111\u1EA1i di\u1EC7n b\xE0i vi\u1EBFt (1024x533 px) l\xEAn CDN Zalo Ads tr\u01B0\u1EDBc khi l\u01B0u."
3062
+ );
3063
+ }
3064
+ } else if (payload.Type === VALID_AD_TYPES.VIDEO || Number(payload.Type) === 11) {
2992
3065
  if (!payload.ZaloVideoId && !payload.Settings?.Image?.VideoUrl) {
2993
3066
  errors.push("ZaloVideoId ho\u1EB7c Settings.Image.VideoUrl l\xE0 b\u1EAFt bu\u1ED9c \u0111\u1ED1i v\u1EDBi Qu\u1EA3ng c\xE1o Video (Ad Type 11).");
2994
3067
  }
2995
3068
  if (payload.Settings?.Image?.VideoUrl && !payload.Settings.Image.VideoUrl.includes("zascdn.me")) {
2996
3069
  warnings.push("VideoUrl n\xEAn l\xE0 \u0111\u01B0\u1EDDng d\u1EABn CDN ch\xEDnh th\u1EE9c c\u1EE7a Zalo Ads (*.zascdn.me).");
2997
3070
  }
2998
- } else if (payload.Type === VALID_AD_TYPES.ARTICLE) {
2999
- if (!payload.ZaloFeedId && !payload.articleId) {
3000
- 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).");
3071
+ if (!isNonEmptyStr(payload.Settings?.Image?.LandscapeCoverUrl)) {
3072
+ warnings.push("N\xEAn b\u1ED5 sung Settings.Image.LandscapeCoverUrl l\xE0m \u1EA3nh poster \u0111\u1EA1i di\u1EC7n khi video ch\u01B0a t\u1EF1 \u0111\u1ED9ng ph\xE1t.");
3001
3073
  }
3002
3074
  } 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) {
3003
3075
  const img = payload.Settings?.Image;
3004
- const hasImage = img?.LandscapeCoverUrl || img?.BaseLandscapeCoverUrl || img?.PortraitCoverUrl || img?.SquareCoverUrl;
3076
+ const hasImage = isNonEmptyStr(img?.LandscapeCoverUrl) || isNonEmptyStr(img?.BaseLandscapeCoverUrl) || isNonEmptyStr(img?.PortraitCoverUrl) || isNonEmptyStr(img?.SquareCoverUrl);
3005
3077
  if (!hasImage) {
3006
3078
  errors.push(
3007
3079
  "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)."
3008
3080
  );
3009
3081
  }
3010
3082
  }
3083
+ const coverUrl = payload.Settings?.Image?.LandscapeCoverUrl;
3084
+ if (coverUrl && typeof coverUrl === "string" && !coverUrl.includes("zascdn.me") && !coverUrl.includes("zadn.vn") && !coverUrl.includes("zdn.vn") && !coverUrl.includes("zalo.me")) {
3085
+ warnings.push("\u1EA2nh b\xECa (LandscapeCoverUrl) n\xEAn \u0111\u01B0\u1EE3c t\u1EA3i l\xEAn CDN Zalo Ads (*.zascdn.me) \u0111\u1EC3 \u0111\u1EA3m b\u1EA3o duy\u1EC7t.");
3086
+ }
3011
3087
  return {
3012
3088
  isValid: errors.length === 0,
3013
3089
  errors,