discount-engine について
EC事業者や開発者向けに、標準機能や拡張ツールを使ったカート販促の設定方法を解説します。クーポン、BOGO、段階割引、併用ルールに加え、独自ストアでのサーバー側検証も扱います。
主な機能
- 01割合割引と定額割引の設定
- 02BOGOと数量別割引の設定
- 03カート条件に応じた販促の適用
- 04割引の優先順位と併用ルールの管理
- 05注文作成時のサーバー側再検証
活用シーン
- 01新規ストアの販促ルール設定
- 02既存チェックアウトへのクーポン追加
- 03購入数量に応じた段階価格の提供
- 04カート条件を使った自動割引の作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ finsilabs/ awesome-ecommerce-skills --skill discount-engineインストール後、Claude Code で/discount-engineを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
tile.jsonevals/coupon-code-api-validation/criteria.jsontask.mdevals/discount-data-model-and-schema/criteria.jsontask.mdevals/discount-evaluation-pipeline/criteria.jsontask.md詳細
割引エンジン
概要
割引エンジンはカートに対してプロモーションを評価し、適切な割引を適切な順序で適用します。主要な e コマースプラットフォームにはすべて割引エンジンが組み込まれています。カスタムコードを検討する前に、まずプラットフォーム標準のシステムを設定してください。このスキルでは、各プラットフォームで複雑な割引ロジック(割引率、固定額、BOGO、段階的な購入条件、条件付きルール)を設定する方法と、標準機能を拡張するためにアプリやプラグインを使うタイミングを説明します。
このスキルを使用するタイミング
- 新しい e コマースストア向けにプロモーションシステムを構築するとき
- 既存のチェックアウトフローにクーポンコードのサポートを追加するとき
- 段階的な価格設定(例:3 個以上購入で 10%オフ、10 個以上購入で 20%オフ)を実装するとき
- カートの条件に基づいて適用される自動割引を作成するとき
- BOGO、バンドル、または購入特典のプロモーションが必要なとき
基本手順
ステップ 1:販売事業者のプラットフォームを特定し、適切なツールを選ぶ
| プラットフォーム | 組み込みの割引機能 | アプリ/プラグインを追加するタイミング |
|---|---|---|
| Shopify | 自動割引、コードベースの割引、BOGO、段階的な「X を購入すると Y を獲得」— すべて Discounts 管理画面にあります | 高度な割引の併用やカスタムロジックには Shopify Plus Scripts、視覚的なルール構築には Bold Discounts |
| WooCommerce | クーポン(コア機能)で基本的なケースに対応できます | BOGO、段階的な数量価格設定、またはルールベースの自動割引には、YITH WooCommerce Dynamic Pricing & Discounts(約 $70/年)または WooCommerce の Dynamic Pricing 拡張機能(約 $99/年) |
| BigCommerce | プロモーションエンジンはカート単位および商品単位の割引、無料商品、BOGO に対応しています | BigCommerce の組み込み Promotions は高機能です。特殊なケースにはカスタムスクリプトを使用してください |
| カスタム/ヘッドレス | 構築が必要です — 以下を参照 | 該当なし |
ステップ 2:プラットフォームで自動割引と BOGO を設定する
Shopify
自動割引(コード不要):
- Discounts → Create discount → Amount off products(または Amount off order)に移動します
- No discount code を切り替えます(自動割引になり、コードなしで適用されます)
- 割引額と条件を設定します
- Minimum purchase requirements で、割引適用の条件となる最低数量または小計を設定します
- Active dates を設定します。この期間中、対象となるすべてのカートに自動割引が適用されます
BOGO(X を購入すると Y を獲得):
- Discounts → Create discount → Buy X get Y に移動します
- Customer buys セクションで、数量と対象となる商品/コレクションを設定します
- Customer gets セクションで、無料または割引対象となる商品の数量と商品を設定します
- 割引率を設定します(100%=無料)
- 必要に応じて Maximum uses の上限を設定します
段階的な数量割引(Shopify): Shopify 標準機能では、アプリなしで段階的な数量割引(例:1~4 個は通常価格、5~9 個は 10%オフ、10 個以上は 20%オフ)に対応していません。選択肢は次のとおりです。
- Bold Discounts(App Store、約 $20/月):段階的な価格設定ルールを視覚的に操作できるインターフェース
- Wholesale Club(App Store):B2B 向けの卸売/段階的な価格設定を追加します
- Shopify Plus + Shopify Functions:カート内の明細数量に基づいて適切な段階の割引を適用する Discount Function を JavaScript で記述します
割引の併用ルール: Shopify では、各割引をほかの割引と併用できるよう設定できます。
- 割引を編集し、Combinations までスクロールします
- 併用できる割引の種類(商品割引、注文割引、配送割引)を切り替えます
WooCommerce
WooCommerce のコアクーポンでは、単一コード、割合割引、定額割引に対応しています。自動割引、ルールベースの割引、BOGO 割引には、Dynamic Pricing & Discounts プラグインを使用します。
Dynamic Pricing のインストール:
- YITH WooCommerce Dynamic Pricing & Discounts または WooCommerce ブランドの Dynamic Pricing 拡張機能を購入してインストールします
- WooCommerce → Dynamic Pricing → Add Rule に移動します
段階的な数量ルールの作成:
- ルールの種類を Product Pricing または Category Pricing に設定します
- 価格帯を追加します:
- 数量 1〜4:0%割引(通常価格)
- 5〜9:10%割引
- 10〜24:20%割引
- 25 以上:30%割引
- 適用する商品またはカテゴリーを設定します
- 保存して公開します
WooCommerce での BOGO:
- Dynamic Pricing で、種類を Cart Pricing にした新しいルールを作成します
- 条件を設定します:「カートに [商品] が X 個含まれている場合」
- アクションを設定します:「[商品] を Y 個、[通常価格の 0%] で追加する」
- または、購入特典として商品を付けるには WooCommerce Smart Coupons を使用します
意図しない割引の併用を防ぐ: WooCommerce のコアクーポンでは、Individual use only にチェックを入れると、クーポンがほかのクーポンと併用されなくなります。Dynamic Pricing の自動ルールには「Stops further rules」オプションがあり、優先度の低いルールが適用されないようにできます。
BigCommerce
BigCommerce には、ほとんどの割引シナリオに対応する標準の Promotions システムがあります。
- Marketing → Promotions → Create promotion に移動します
- Promotion type を設定します:カート単位の割引、商品単位の割引、送料無料、無料商品、BOGO
- Conditions を設定します:
- カートの最低小計
- 対象または対象外にする特定の商品やカテゴリー
- 顧客グループ(B2B またはセグメント別の価格設定向け)
- Actions を設定します:割引額と適用対象の商品
- Coupon(任意)を設定します:手動適用を必須にする場合はコードを設定し、自動適用にする場合は空欄にします
- 併用ルールを設定します:BigCommerce では、プロモーションをほかのプロモーションと併用できるかどうかを定義できます
BigCommerce での段階的な数量価格設定: Price Lists 機能(Plus プラン以上)を使用します:
- Products → Price Lists に移動します
- 数量のしきい値ごとに、1 個あたりの価格を明示した価格リストを作成します
- 価格リストを顧客グループに割り当てます
- そのグループの顧客には、段階的な価格が自動的に表示されます
カスタム/ヘッドレス
カスタムストアフロントでは、割引エンジンが適用可能な割引を評価し、カート内の商品行に割り当てます。重要な原則は、サーバー側で評価すること、優先順位に従って適用すること、併用ルールを適用することです。
interface Discount {
id: string;
type: 'percentage' | 'fixed_amount' | 'bogo' | 'free_shipping';
value: number; // percentage (0-100) or cents
target: 'order' | 'line_item' | 'shipping';
isStackable: boolean;
minCartCents?: number;
minQuantity?: number;
entitledProductIds?: string[];
excludedProductIds?: string[];
startsAt: Date;
endsAt?: Date;
}
interface CartLine {
id: string;
productId: string;
quantity: number;
unitPriceCents: number;
}
function evaluateDiscounts(
cart: { lines: CartLine[]; subtotalCents: number },
discounts: Discount[]
): { discountId: string; amountCents: number; affectedLineIds: string[] }[] {
const now = new Date();
const eligible = discounts.filter(d =>
d.startsAt <= now && (!d.endsAt || d.endsAt > now)
);
// Sort: non-stackable first, then higher-value
const sorted = [...eligible].sort((a, b) => (a.isStackable ? 1 : -1) - (b.isStackable ? 1 : -1));
const applications: { discountId: string; amountCents: number; affectedLineIds: string[] }[] = [];
let nonStackableApplied = false;
for (const discount of sorted) {
if (!discount.isStackable && nonStackableApplied) continue;
// Check minimum cart value
if (discount.minCartCents && cart.subtotalCents < discount.minCartCents) continue;
const eligibleLines = cart.lines.filter(line =>
(!discount.entitledProductIds || discount.entitledProductIds.includes(line.productId)) &&
(!discount.excludedProductIds || !discount.excludedProductIds.includes(line.productId))
);
if (eligibleLines.length === 0) continue;
let amountCents = 0;
if (discount.type === 'percentage') {
amountCents = Math.round(
eligibleLines.reduce((s, l) => s + l.unitPriceCents * l.quantity, 0) * discount.value / 100
);
} else if (discount.type === 'fixed_amount') {
amountCents = Math.min(discount.value, cart.subtotalCents);
} else if (discount.type === 'bogo') {
const buyQty = discount.minQuantity ?? 1;
for (const line of eligibleLines) {
const freeItems = Math.floor(line.quantity / (buyQty + discount.value)) * discount.value;
amountCents += freeItems * line.unitPriceCents;
}
}
if (amountCents > 0) {
applications.push({ discountId: discount.id, amountCents, affectedLineIds: eligibleLines.map(l => l.id) });
if (!discount.isStackable) nonStackableApplied = true;
}
}
return applications;
}
競合状態や期限切れの割引を検出するため、この評価はカートへの追加時だけでなく、注文作成時にも必ず再実行してください。
ベストプラクティス
- 割引は必ずサーバー側で計算する — クライアントから送信された割引額を信用せず、チェックアウト時に再計算してください
- 併用ルールを明確に定義する — 複数の割引を併用できるかどうかを事前に決め、マーチャンダイジングチーム向けのポリシーを文書化してください
- 割引額の上限を設定する — 割合割引には、プロモーションが過剰にならないよう最大金額の上限を設定してください
- 追加プロモーションの対象からセール商品を除外する — 割引の重複によって利益率が損なわれるのを防ぎます。Shopify と WooCommerce はどちらも「セール商品を除外」するルールに対応しています
- 有効化する前にステージング環境でルールをテストする — コード不要で対象となるすべての顧客に適用される自動割引では、特に重要です
- 割引の適用をすべて記録する — 監査証跡やプロモーションの ROI レポート用に、割引 ID、顧客、注文、金額を記録してください
- 終了日を明確に設定する — 終了日が設定されていない自動割引は無期限に適用されます。必ず有効期限を設定してください
よくある問題
| 問題 | 解決策 |
|---|---|
| 注文確定後に割引が適用される(カートが古い状態のまま) | 注文作成時にすべての割引を再検証し、期限切れまたは無効な割引を決済前に削除します |
| 1点だけのカートにBOGOが適用される | BOGOが適用される前に、購入数量以上のカート数量を必須にします |
| 割引によって注文合計がマイナスになる | 割引合計の上限をカート小計に設定し、注文合計が0を下回らないようにします |
| 自動割引とコードベースの割引が予期せず併用される | Shopifyでは各割引の「組み合わせ」設定を確認し、WooCommerceのクーポンでは「個別使用のみ」を選択します |
| 数量を更新すると段階割引の適用段階が誤って表示される | チェックアウト時だけでなく、カート数量が変更されるたびに適用する段階を再計算します |
関連するスキル
- @stripe-integration
- @checkout-flow-optimization
- @coupon-management
- @price-rules-engine
- @volume-pricing