Skip to content

API 參考

主要 API

取得優惠結果排名(getPromotionsRanking)

ts
export interface GetPromotionRankingParam<Data> {
  /** 商品與其數量。通常是購物車內商品 */
  items: Item<Data>[];

  /** 可用優惠 */
  promotions: Promotion<Data>[];

  /** 取得前幾名。預設 3。數量不足時,則以實際數量為主 */
  topN?: number;

  /** 贈品自動抵銷模式 */
  autoOffsetMode?: AutoOffsetMode;

  /** 重現性,即相同的輸入保證得到相同的輸出。
   *
   * @default true
   */
  reproducibility?: boolean;
}
ts
export function getPromotionsRanking<Data = undefined>(
  param: GetPromotionRankingParam<Data>
): PromotionResult<Data>[]

取得優惠結果之統計資料(getAnalyticalData)

總金額、訂單優惠金額等等

ts
/** 取得優惠結果的統計資料 */
export function getAnalyticalData(
  promotionResult: PromotionResult
): AnalyticalData

取得每個商品使用的優惠與其優惠價格(getItemizedResult)

ts
/** 取得每個商品使用的優惠與其優惠價格 */
export function getItemizedResult(
  promotionResult: PromotionResult
): ItemizedResult

取得推薦優惠(getRecommendResults)

根據目前商品推薦優惠並提示達成條件

ts
/** 取得推薦結果 */
export function getRecommendResults(
  param: GetRecommendResultsParam
): RecommendResult[]

檢查優惠結果有效性(checkPromotionResult)

回傳錯誤訊息,空字串表示沒有問題

ts
export function checkPromotionResult(
  promotionResult: PromotionResult
): string

檢查優惠結果重現性(checkParamsAndRankedResult)

檢查優惠結果是否與指定參數結果一致,可以讓 server 用來檢查結果是否被竄改。

ts
interface CheckParamsAndRankedResultParam<Data> {
  /** 商品與其數量。通常是購物車內商品 */
  items: Item<Data>[];
  /** 可用優惠 */
  promotions: Promotion<Data>[];
  /** 取得前幾名。預設 3。數量不足時,則以實際數量為主 */
  topN?: number;
  /** 贈品自動抵銷模式 */
  autoOffsetMode?: AutoOffsetMode;
  results: RankedPromotionResult<Data>[];
}

export function checkParamsAndRankedResult(
  param: CheckParamsAndRankedResultParam
): boolean

utils API

處理計算邏輯(operation)

ts
/** 處理 Arithmetic 邏輯
 *
 * 根據 arithmetic 定義計算 value 結果。
 */
export function operation(
  arithmetic: Arithmetic, value: number | Decimal
): number

型別定義

優惠基本結構(PromotionBase)

ts
/** 優惠規則 */
interface PromotionBase<Type extends `${PromotionType}`, Content> {
  /** 唯一值 */
  key: string;
  type: Type;
  name: string;
  description: string;
  /** 優惠內容。條件與實際結果在此定義。
   *
   * 任一個 content 符合條件,即可套用此優惠。
   */
  contents: Content[];
  /** 優惠群組名稱。分類優惠,可用於限制不可與某 group 一起使用 */
  group?: string;
  /** 限制。例如一筆訂單只能使用一次,或是排除某優惠(不會同時存在) */
  constraints?: Constraint[];
  /** 不計入滿額優惠之條件計算 */
  notIncludedInSpendTotalPrice?: boolean;
}

優惠決策(PromotionDecision)

ts
/** 優惠決策。
 *
 * 定義候選商品、條件、結果。
 */
export interface PromotionDecision<Data = undefined> {
  /** 候選商品 */
  list: Commodity<Data>[];
  /** 優惠結果 */
  result?: SelectableGiveaway<Data> | Arithmetic;
  /** 條件 */
  comparison: Comparison;
}

優惠結果(PromotionResult)

ts
/** 優惠結果 */
export interface PromotionResult<Data = undefined> {
  /** 原始購物清單 */
  originalItems: Item<Data>[];
  /** 剩餘的商品。沒有商品優惠可用,剩下來的商品 */
  remainingItems: Item<Data>[];
  /** 套用優惠的商品 */
  promotedList: PromotedListItem<Data>[];
  /** 可用贈品。 */
  giveawayList: GiveawayListItem<Data>[];
  /** 被贈品抵銷的商品。此區商品要被視為 0 元 */
  offsetList: OffsetListItem<Data>[];
  /** 所有已使用的優惠,彙整自 promotedList.promotion */
  usedPromotions: Promotion[];
}

/** 已套用優惠結果的商品 */
export interface PromotedListItem<Data = undefined> {
  /** 符合條件之商品與優惠結果 */
  appliedList: Array<{
    item: Item<Data>;
    /** 優惠結果 */
    result?: SelectableGiveaway<Data> | Arithmetic;
  }>;
  /** 原始優惠 */
  promotion: Promotion;
  /** 套用的優惠內容 */
  promotedContent: Promotion['contents'][number];
  /** 匹配的 Decision */
  matchedDecision?: PromotionDecision<Data>;
}

/** 可用贈品。
 *
 * 集結 promotedList.appliedList.result 中的 SelectableGiveaway 資料。
 *
 * 不包含以自動抵銷的贈品,自動抵銷的贈品在 offsetList 中。
 */
export interface GiveawayListItem<Data = undefined> {
  /** 贈品 */
  item: SelectableGiveaway<Data>;
  /** 原始優惠 */
  promotion: Promotion;
  /** 套用的優惠內容 */
  promotedContent: Promotion['contents'][number];
  /** 匹配的 Decision */
  matchedDecision?: PromotionDecision<Data>;
}
/** 被贈品抵銷的商品 */
export interface OffsetListItem<Data = undefined> {
  /** 商品 */
  item: Item<Data>;
  /** 原始優惠 */
  promotion: Promotion;
  /** 套用的優惠內容 */
  promotedContent: Promotion['contents'][number];
  /** 匹配的 Decision */
  matchedDecision?: PromotionDecision<Data>;
}

/** 已排名後的優惠結果 */
export interface RankedPromotionResult<Data> extends PromotionResult<Data> {
  /** 統計資料 */
  analyticalData: AnalyticalData;
}

優惠限制(Constraint)

ts
/** 限制種類 */
export enum ConstraintType {
  /** 一筆訂單中指定優惠套用次數,value 為可套用次數 */
  USE_TIMES_FOR_ONE_ORDER = 'use-times-for-one-order',

  // TODO: 實作全部的 ConstraintType
  // /** 不可以一起使用的 promotion,value 為 Promotion ID */
  // EXCLUDE_PROMOTION = 'exclude-promotion',

  // /** 不可以一起使用的 promotion group,value 為 PromotionBase.group  */
  // EXCLUDE_PROMOTION_GROUP = 'exclude-promotion-group',
}
/** 限制。value 依照 type 有不同意義 */
export interface Constraint {
  type: `${ConstraintType}`;
  value: number | string;
}

優惠種類細節

  1. 商品優惠

    ts
    /** 商品優惠
     *
     * 條件與商品直接相關,過程會取出被套用的商品,不能重複套用商品。
     *
     * - A + B 只要 50 元
     * - A + B,A 打折、B 打折
     * - 買 A 區送 B 區
     * - 任選 10 個 A 系列,打折
     * - 任 3 件 84 折
     * - 2 件 5000 元
     * - 3 件折 500 元
     * - 同品項買 2 送 1
     */
    export type PromotionCommodityOffer<Data = undefined> = PromotionBase<'commodity-offer', {
      /** 候選商品群組。
       *
       * condition.comparison.target 只能是 `purchase-quantity`,因為滿額邏輯只能定義於滿額優惠中。
       *
       * 必須所有 condition 皆相符,才能套用目前 content。
       */
      condition: PromotionDecision<Data>[];
    
      /** 整體結果。
       *
       * 優惠結果可以在 condition 分別定義,也可用此值全部帶入。
       */
      result?: SelectableGiveaway | Arithmetic;
    }>
  2. 訂單優惠

    ts
    /** 訂單優惠
     *
     * 條件與商品無直接關連,只與整筆訂單相關。
     *
     * - 整筆訂單 8 折。
     */
    export type PromotionOrderOffer<Data = undefined> = PromotionBase<'order-offer', {
      result: SelectableGiveaway<Data> | Arithmetic;
    }>
  3. 滿額優惠

    ts
    /** 滿額優惠
     *
     * 依照前兩種優惠的結果,計算其優惠條件。
     *
     * - 單筆消費滿 3 萬元,送 A 商品
     * - 任意消費送 A 商品
     */
    export type PromotionMinimumSpendOffer<Data = undefined> = PromotionBase<'minimum-spend-offer', {
      condition: Comparison;
      /** 結果 */
      result: SelectableGiveaway<Data> | Arithmetic;
    }>

計算(Arithmetic )

ts
export enum ArithmeticOperator {
  /** 加 */
  PLUS = 'plus',
  /** 減 */
  SUB = 'sub',
  /** 乘 */
  MUL = 'mul',
  /** 設為 */
  SET = 'set',
}

/** 計算目標 */
export enum ArithmeticTarget {
  /** 每一個商品,而不是全部商品
   *
   * 通常用於以下優惠:
   * - 任選 10 個以上,每個 100 元
   * - 任選 A 系列 2 個,每件減 10 元
   */
  EVERY = 'every',
}

/** 計算 */
export interface Arithmetic {
  operator: `${ArithmeticOperator}`;
  /** 為空表示針對全部商品
   *
   * 只對商品優惠(commodity-offer)有效
   */
  target?: `${ArithmeticTarget}`;
  value: number;
}

比較(Comparison)

ts
export enum ComparisonLogic {
  /** 大於 */
  GREATER_THAN = 'greater-than',

  /** 大於等於 */
  GREATER_THAN_EQUAL_TO = 'greater-than-equal-to',

  /** 小於 */
  LESS_THAN = 'less-than',

  /** 小於等於 */
  LESS_THAN_EQUAL_TO = 'less-than-equal-to',

  /** 等於 */
  EQUAL = 'equal',

  /** 每次。用於滿額優惠,表示每多少。例:每千送百
   *
   * 其邏輯等同 greater-than-equal-to
   */
  EVERY = 'every',
}

/** 目標對象。此比較條件判斷依據 */
export enum ComparisonTarget {
  /** 總金額 */
  TOTAL_PRICE = 'total-price',

  /** 購買數量 */
  PURCHASE_QUANTITY = 'purchase-quantity',
}

/** 比較 */
export interface Comparison {
  target: `${ComparisonTarget}`;
  logic: `${ComparisonLogic}`;
  value: number;
}