Skip to content

優惠結果說明

讓我們用 2 個簡單的例子說明。

假設商品資料為:

ts
const a30: Commodity = {
  key: '1',
  name: 'A-30ml',
  price: 6000
}

const a50: Commodity = {
  key: '2',
  name: 'A-50ml',
  price: 9000
}

優惠為「A 商品 30ml、50ml,任兩件 85 折」

ts
const promotionAnyTwoA15Off: Promotion = {
  key: '5',
  type: 'commodity-offer',
  name: 'A 商品優惠',
  description: '30ml、50ml,任兩件 85 折',
  contents: [
    {
      condition: [
        {
          list: [ a50, a30 ],
          comparison: {
            logic: 'equal',
            target: 'purchase-quantity',
            value: 2
          }
        }
      ],
      result: {
        operator: 'mul',
        value: 0.85
      }
    }
  ]
}

一般結果

2 個 A 30ml

可以預期一定符合優惠,這時候得到的結果為:

ts
const result = [
  {
    "giveawayList": [],
    "offsetList": [],
    "originalItems": [
      {
        "commodity": a30,
        "quantity": 2
      }
    ],
    "remainingItems": [],
    "promotedList": [
      {
        "appliedList": [
          {
            "item": {
              "commodity": a30,
              "quantity": 2
            }
          }
        ],
        "promotedContent": {
          "condition": [
            {
              "list": [
                {
                  "key": "1",
                  "name": "A",
                  "specifications": [
                    "30ml"
                  ],
                  "price": 6000
                },
                {
                  "key": "2",
                  "name": "A",
                  "specifications": [
                    "50ml"
                  ],
                  "price": 9000
                }
              ],
              "comparison": {
                "logic": "equal",
                "target": "purchase-quantity",
                "value": 2
              }
            }
          ],
          "result": {
            "operator": "mul",
            "value": 0.85
          }
        },
        "promotion": {
          "key": "5",
          "type": "commodity-offer",
          "name": "A 商品優惠",
          "description": "30ml、50ml,任兩件 85 折",
          "contents": [
            {
              "condition": [
                {
                  "list": [
                    {
                      "key": "1",
                      "name": "A",
                      "specifications": [
                        "30ml"
                      ],
                      "price": 6000
                    },
                    {
                      "key": "2",
                      "name": "A",
                      "specifications": [
                        "50ml"
                      ],
                      "price": 9000
                    }
                  ],
                  "comparison": {
                    "logic": "equal",
                    "target": "purchase-quantity",
                    "value": 2
                  }
                }
              ],
              "result": {
                "operator": "mul",
                "value": 0.85
              }
            }
          ]
        }
      }
    ]
  }
]

很長很長,讓我們一項一項看。

由於沒有贈品,所以 giveawayList 和 offsetList 都是空矩陣,所以這兩者先跳過不看。

originalItems

此欄位等於原始購買內容,所以就是 2 個 A 30ml。

json
"originalItems": [
  {
    "commodity": a30,
    "quantity": 2
  }
],

remainingItems

此欄位表示沒有套用優惠,被剩下來的商品。

由於 2 個 A 30ml 都被加入優惠,沒有剩下任何商品,所以會得到空矩陣。

json
"remainingItems": [],

promotedList

此欄位表示被套用優惠的商品與詳細商品細節。

其中 appliedList 為被套用的商品,也就是 2 個 A 30ml。

json
{
  "appliedList": [
    {
      "item": {
        "commodity": a30,
        "quantity": 2
      }
    }
  ],
  ...
}

剩下的欄位其實很單純:

  • promotedContent 表示實際上符合的 contents
  • promotion 則是優惠本體

所以那個很長的結果其實完全效於以下內容:

json
{
  "promotedContent": promotionAnyTwoA15Off.contents[0],
  "promotion": promotionAnyTwoA15Off
}

3 個 A 30ml

和剛剛的例子只差在多了 1 個 A,可以預期 2 個 A 有套用優惠,最後剩下 1 個 A。

讓我們來看看結果:

ts
const result = [
  {
    "giveawayList": [],
    "offsetList": [],
    "originalItems": [
      {
        "commodity": a30,
        "quantity": 3
      }
    ],
    "remainingItems": [
      {
        "commodity": a30,
        "quantity": 1
      }
    ],
    "promotedList": [
      {
        "appliedList": [
          {
            "item": {
              "commodity": a30,
              "quantity": 2
            }
          }
        ],
        "promotedContent": promotionAnyTwoA15Off.contents[0],
        "promotion": promotionAnyTwoA15Off
      }
    ]
  }
]

originalItems

3 個 A 30ml 沒錯。

json
"originalItems": [
  {
    "commodity": a30,
    "quantity": 3
  }
],

remainingItems

由於 2 個 A 30ml 都被加入優惠,剩下 1 個 A

json
"remainingItems": [
  {
    "commodity": a30,
    "quantity": 1
  }
],

promotedList

一樣套用了 2 個 A,所以會與上一個例子相同。

json
{
  "appliedList": [
    {
      "item": {
        "commodity": a30,
        "quantity": 2
      }
    }
  ],
  "promotedContent": promotionAnyTwoA15Off.contents[0],
  "promotion": promotionAnyTwoA15Off
}

贈品自動抵銷

autoOffsetMode 有以下模式:

  • single-type:

    贈品種類只有一種時,自動抵銷商品。超過一種則不抵銷,同一般贈品。

  • multiple-types-from-highest:

    不管種類多寡,都從價值最高的贈品開始抵銷。

使用範例

ts
const offsetPromotions = getPromotionsRanking({ 
  items,
  promotions,         
  autoOffsetMode: 'multiple-types-from-highest',
});

假設有以下優惠:

ts
const promotion01: Promotion = {
  key: '5',
  type: 'commodity-offer',
  name: 'A 商品優惠',
  description: '買 A 系列 50ml 2 瓶,送 1 瓶 30ml',
  contents: [
    {
      condition: [
        {
          list: [ a50 ],
          comparison: {
            logic: 'equal',
            target: 'purchase-quantity',
            value: 2
          }
        }
      ],
      result: {
        commodities: [ a30 ],
        quantity: 1,
      }
    }
  ]
}

const promotion02: Promotion = {
  key: '6',
  type: 'commodity-offer',
  name: 'A 商品優惠',
  description: '買 A 系列任 5 瓶,送 A 系列任選 1 瓶',
  contents: [
    {
      condition: [
        {
          list: [ a50, a30 ],
          comparison: {
            logic: 'equal',
            target: 'purchase-quantity',
            value: 5
          }
        }
      ],
      result: {
        commodities: [ a30, a50 ],
        quantity: 1,
      }
    }
  ]
}

2 瓶 A 50ml、1 瓶 A 30ml

這裡使用 promotion01 優惠,不難看出 1 瓶 A 30ml 會被自動抵銷。

由於贈品只有 1 種,所以不管是哪一種模式結果都會相同。

ts
const result: PromotionResult = {
  giveawayList: [],
  offsetList: [
    {
      item: { commodity: a30, quantity: 1 },
      promotedContent: promotion01.contents[0],
      promotion: promotion01,
    },
  ],
  originalItems: [
    { commodity: a50, quantity: 2 },
    { commodity: a30, quantity: 1 },
  ],
  remainingItems: [],
  promotedList: [
    {
      appliedList: [
        { item: { commodity: a50, quantity: 2 } }
      ],
      promotedContent: promotion01.contents[0],
      promotion: promotion01,
    }
  ]
}

可以看到 a30 跑到 offsetList 裡面去了。ლ(╹◡╹ლ)

6 瓶 A 50ml、1 瓶 A 30ml

這裡使用 promotion02 優惠,由於贈品有 2 種,所以這次不同模式結果會不同。

single-type

由於贈品有 2 種,所以不會自動抵銷。

ts
const result: PromotionResult = {
  giveawayList: [
    {
      item: {
        commodities: [ a30, a50 ], quantity: 1,
      },
      promotedContent: promotion01.contents[0],
      promotion: promotion01,
    },
  ],
  offsetList: [],
  originalItems: [
    { commodity: a50, quantity: 6 },
    { commodity: a30, quantity: 1 },
  ],
  remainingItems: [
    { commodity: a50, quantity: 1 },
    { commodity: a30, quantity: 1 },
  ],
  promotedList: [
    {
      appliedList: [
        {
          item: { commodity: a50, quantity: 5 }
        }
      ],
      promotedContent: promotion02.contents[0],
      promotion: promotion02,
    }
  ]
}

可以看到 giveawayList 裡有東西了。(。・∀・)ノ゙

multiple-types-from-highest

此模式會從最貴的商品開始抵銷,所以會抵銷 a50,而非 a30。

ts
const result: PromotionResult = {
  giveawayList: [],
  offsetList: [
    {
      item: { commodity: a50, quantity: 1 },
      promotedContent: promotion02.contents[0],
      promotion: promotion02,
    }
  ],
  originalItems: [
    { commodity: a50, quantity: 6 },
    { commodity: a30, quantity: 1 },
  ],
  remainingItems: [
    { commodity: a30, quantity: 1 },
  ],
  promotedList: [
    {
      appliedList: [
        {
          item: { commodity: a50, quantity: 5 }
        }
      ],
      promotedContent: promotion02.contents[0],
      promotion: promotion02,
    }
  ]
}

可以看到剩下的那一個 a50 跑到 offsetList 了。