資料定義
商品
定義如下:
ts
/** 商品
*
* key 與 price 會影響計算結果,其他欄位隨意。
*
* 同一商品、不同規格,也必須使用不同 key。
*/
export interface Commodity<Data = undefined> {
/** 唯一值 */
key: string;
price: number;
/** 方便識別,不影響計算 */
name: string;
/** 規格。參考用 */
specifications?: string[];
/** 自定義額外資料 */
metadata?: Data;
}ts
/** 項目,表示商品與其數量 */
export interface Item<Data = undefined> {
/** 商品 */
commodity: Commodity<Data>;
quantity: number;
}贈品
列出候選商品,需要讓使用者選擇
ts
/** 贈品,表示可選商品與最大數量 */
export interface SelectableGiveaway<Data = undefined> {
/** 候選商品。可以加入 undefined 表示有「不選擇」選項 */
commodities: (Commodity<Data> | undefined)[];
/** 選擇數量。最後選擇總數必須等於此值 */
quantity: number;
}優惠類別
優惠基本結構為
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;
}💡 不計入滿額優惠之條件計算
細節請見文件
其中 type 有三種類別:
ts
export enum PromotionType {
/** 商品優惠
*
* 條件與商品直接相關,過程會取出被套用的商品,不能重複套用商品。
*
* 例:
* - 指定商品滿件折扣、折價、贈送等等。
*/
COMMODITY_OFFER = 'commodity-offer',
/** 訂單優惠
*
* 條件與商品無直接關連,只與整筆訂單相關。
*
* 例:
* - 整筆訂單 8 折。
*
*/
ORDER_OFFER = 'order-offer',
/** 滿額優惠
*
* 依照前兩種優惠的結果,計算其優惠條件。
*
* 例:
* - 滿千送 A、每滿千折 200。
*/
MINIMUM_SPEND_OFFER = 'minimum-spend-offer',
}contents 則對應 type 定義其細節:
商品優惠
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; }>訂單優惠
ts/** 訂單優惠 * * 條件與商品無直接關連,只與整筆訂單相關。 * * - 整筆訂單 8 折。 */ export type PromotionOrderOffer<Data = undefined> = PromotionBase<'order-offer', { result: SelectableGiveaway<Data> | Arithmetic; }>滿額優惠
ts/** 滿額優惠 * * 依照前兩種優惠的結果,計算其優惠條件。 * * - 單筆消費滿 3 萬元,送 A 商品 * - 任意消費送 A 商品 */ export type PromotionMinimumSpendOffer<Data = undefined> = PromotionBase<'minimum-spend-offer', { condition: Comparison; /** 結果 */ result: SelectableGiveaway<Data> | Arithmetic; }>
處理邏輯
實際處理邏輯為從 1 到 3 依序帶入優惠:
- 將所有商品依照「商品優惠」條件取出並分組
- 套入「訂單優惠」
- 依照條件判斷是否可使用「滿額優惠」
「商品優惠」與「訂單優惠」可以設定其消費金額是否累積至「滿額累計」。
「不計入滿額優惠之條件計算」具體邏輯如下:
商品優惠:套用商品優惠後的商品價格不列入滿額計算,假設 A 商品原價 100,套用過該商品優惠後,則不列入滿額計算,故滿額累計 0 元
訂單優惠:使用訂單優惠前的價格來判斷是否滿額,假設訂單優惠前是 1000,優惠後是 800,啟用該選項後,滿額累計為 1000 元