促銷是電商拉業績的武器,也是帳務的災難現場。折扣碼、紅利點數、會員折扣、免運門檻——這些單獨看都簡單,但客人會同時用。四種疊在一起,如果沒有規則約束,很快就會疊出一個你不想看到的結果:負毛利,賣一件倒賠一件。

這篇拆一個真實電商的促銷疊加引擎,重點講一件我太常遇到、所以知道非做不可的事:毛利保護。

疊加的兩條基本規則

促銷引擎的核心,是回答「這一堆促銷怎麼一起算」。基本上兩條規則:

  1. 不同 scope 的可以疊:商品層的折扣、訂單層的滿額折、運費層的免運——它們作用在不同層次,可以一層層疊上去。
  2. 同 scope 的取最優:同一個商品上有兩個折扣活動,不是兩個都給,是取對客人最有利的那一個(或按規則取其一),不能重複折。

光這兩條就擋掉一堆「同一筆折兩次」的漏洞。但擋不住最危險的那個——疊到負毛利。

為什麼一定要有毛利保護:因為負毛利太常遇到

這一段是我最想強調的,因為負毛利真的太常遇到了

想像一件成本 80、售價 100 的商品。客人用了會員 9 折(-10)、又用了滿額折抵(-15)、再折抵 20 點紅利(-20)——算下來售價變 55,低於成本 80,這一單直接倒賠 25。而這種組合不是刻意鑽漏洞,是促銷疊加下自然就會發生的:每個活動單獨看都合理,疊在一起就破底。

所以促銷引擎一定要有一條毛利保護上限:不管促銷怎麼疊,最終售價不能低於某個底線(成本、或成本加一個最低毛利)。疊到觸底就停,不再往下折。這條線不是「加分項」,是防止促銷把你賣到破產的保命閥

(這套系統甚至有「負毛利商品」要走審核才能上架的機制——因為有時候你確實想用賠本品引流,但那要是刻意的決定,不能是促銷疊出來的意外。)

優惠券的併發問題:樂觀鎖

促銷還有一個容易忽略的並發坑:限量優惠券

「前 100 名結帳送折扣券」——這種限量的東西,跟庫存超賣是同一類問題:一堆人同時搶最後幾張,怎麼保證不會發超過 100 張?

這套系統用的是樂觀鎖:發券的時候,用一個帶條件的更新(UPDATE ... WHERE 剩餘數量 > 0),如果更新影響的筆數是 0,代表券已經被搶光了,直接拋錯拒絕。這比悲觀的行鎖輕量——不用先鎖再判斷,而是「先搶、搶不到才知道沒了」。適合優惠券這種「大部分時候搶得到、偶爾撞上搶光」的場景。

點數也是類似的邏輯:發放(earn)、折抵(burn)都要防併發,而且點數折抵一樣要吃毛利保護——不能讓客人用點數把價格折到負毛利。退貨的時候,點數還要按比例退還(呼應退款那篇的逆向計算)。

收:促銷設計的三個要點

  1. 疊加規則:不同 scope 可疊、同 scope 取優,先擋掉重複折。
  2. 毛利保護是保命閥:負毛利會自然疊出來(不是漏洞),一定要有底線,觸底就停。
  3. 限量優惠券用樂觀鎖:跟超賣同類,UPDATE WHERE 剩餘>0、影響 0 筆就拒絕。

接下來往哪走

  • 退款與對帳 — 促銷「正向疊」了,退款就要「逆向拆」,這裡最容易算錯
  • 庫存預佔 — 限量券的併發,跟限量商品的超賣是同一類問題
  • 訂單狀態機 — 回到起點:這八篇的商業邏輯,最後都掛在一張訂單上