キャンペーンと価格ルールの責務分離(補足仕様)¶
目的¶
キャンペーン.xlsx の運用と、Vendure 実装(Campaign / Policy /
Pricing)の責務を明確化する。
本書は元資料を改変せず、実装上の解釈を補足する。
参照元¶
docs/specifications/キャンペーン.xlsxdocs/specifications/BtoB発注システム要件 (最新).xlsxdocs/specifications/2026-05-campaign-target-product-selection.md
設計方針(決定)¶
- 恒常的な価格制御は
pricing ruleで扱う - 期間付き販促は
campaignで扱う - 可視性/決済の許可制御は
access policy(visibility/payment)で扱う
責務定義¶
価格ルール(pricing rule)¶
- 顧客・顧客グループ・グローバルに対する恒常価格制御
- 商品/バンドル商品/コレクション単位の恒常的な割引率設定
- 期間限定販促、特典選択、購入上限リセットは担当しない
キャンペーン(campaign)¶
- 期間付きの販促ルール
- 金額・数量しきい値での適用判定
- 無償特典(固定/変動/選択式)と割引の付与
- 仮想商品を使ったマイナス価格相当の注文調整
- 達成までの進捗表示(残額/残数)
- 顧客単位上限と手動リセット
campaignは販促施策の概念であり、価格変更はその実現手段の一つに過ぎない
用語整理(2026-03)¶
業務概念¶
pricing rule: 恒常価格・得意先別価格・常設の価格置換を扱うcampaign: 期間販促・特典・おまけ・注文調整を扱うcampaign page: 顧客向けの特設ページ・一覧導線・専用URLを扱うaccess policy: 可視性・決済の許可/拒否を扱う
実装概念¶
CommercialRulesPluginはpricing ruleとcampaignを 共通エンジン で評価するcampaign pageはcampaigns親配下の Vendure Collection を正本にし、WordPress は本文の任意ソースとして連携するPolicyはaccess policyを評価する- Admin API / Shop API の内部名称は
commercialRule(s)のまま維持する - React Dashboard の内部パスは
/commercial-rulesを維持し、業務上の導線は「価格・販促 > 価格・販促ルール」とする - React Dashboard の
ポリシー管理には、表示制御ルールと表示ロジックプレビューを置く campaign pageの運用導線は専用画面を増やさず、Collection 管理を使う
業務概念と実装概念の対応¶
| 業務概念 | 業務上の意味 | 実装上の扱い | React Dashboard 上の扱い |
|---|---|---|---|
| Pricing Rule | 恒常価格・得意先別価格・常設の価格置換 | CommercialRulesPlugin の価格系 action で評価する |
「価格・販促 > 価格・販促ルール」で Campaign と共通管理 |
| Campaign | 期間販促、特典ギフト、仮想商品による注文調整、進捗/上限管理 | CommercialRulesPlugin の販促系 action と条件で評価する |
「価格・販促 > 価格・販促ルール」から操作する |
| Campaign Page | 顧客向けのキャンペーンページ、一覧導線、専用URL | campaigns 親配下の Collection + WordPress 本文任意連携 |
Collection 管理から操作する |
| Access Policy | 可視性・決済方法の許可/拒否 | 表示制御ルール / PMCA で評価する | /policies / /payment-methods/collection-mapping で管理する |
実装ルール(2026-02)¶
キャンペーン対象の指定¶
- 商品単位: ProductVariant(SKU)
- バンドル商品:
customFields.setComponentsが設定された親 ProductVariant - バンドル商品も 独立キーではなく ProductVariant として指定する
- 対象商品の選定・除外判断・変更管理は
2026-05-campaign-target-product-selection.mdを正本にする
Campaign conditions 拡張キー¶
targets.productVariantIds: string[]targets.productVariantIdsには通常 SKU とバンドル親 ProductVariant の両方を含めてよい。- 旧
targetBundleProductVariantIdsは過去 migration でtargets.productVariantIdsへ統合済みであり、保存・更新・評価のいずれにも使用しない。
Campaign conditions 汎用 DSL¶
- Campaign の
conditionsは固定キーに加えて、次の条件ツリーを持てる。 all: CampaignConditions[]any: CampaignConditions[]not: CampaignConditions- MVP で React Dashboard から編集できる条件は次の通り。
order.quantity.min/maxorder.subtotal.min/maxcustomer.customerGroupIdscustomer.fields[]shipping.modes- 旧互換のトップレベル条件キー(
minAmount,maxAmount,minQuantity,maxQuantity)は保存・更新・評価のいずれにも使用しない。 customer.fields[]は次の演算子を許可する。eq,neq,gt,gte,lt,lte,in,not_in,contains- MVP の顧客フィールド対象は次の通り。
customerStatuscollectionMethoddiscountRatebillingCustomerCodesalesRateClassCode- 対象商品の絞り込みは
targets.productVariantIdsを正本とし、通常 SKU とバンドル親 ProductVariant を同じ配列で扱う。 - 旧互換入力として
targetBundleProductVariantIdsが渡されても runtime では読替しない。必要な場合は migration / repair でtargets.productVariantIdsに正規化する。
Campaign benefits 拡張キー¶
priceRanges: CampaignPriceRange[]basis: "quantity" | "subtotal"unitPrice: numberminQuantity?,maxQuantity?minSubtotal?,maxSubtotal?description?priceRangesは期間限定販促における「このレンジならこの単価」を表す。- 同時に通常の
discountType/discountValueを持ってよいが、固定単価レンジを優先して割引額を計算する。 - ギフト特典は
giftItems[]を正本とし、旧互換のgiftProductCodes/giftQuantityは保存・更新・評価のいずれにも使用しない。 giftItems[]で付与するおまけ商品はOrderLineとして明細追加する。- 付与されたおまけ商品の販売単価・明細価格は、商品マスタ価格に関わらず 0円 とする。
- おまけ商品の無償化は注文行価格を正本とし、注文全体を相殺するための別値引きサーチャージを正本にしない。
Catalog 割引表示フラグ(2026-06)¶
- カート投入前の商品一覧・商品詳細・検索などでは、既定で上代単価(定価)のみを表示する。
- campaign の割引を回遊面でも明示したい場合だけ、
CommercialRule.catalogDiscountDisplayEnabledを有効にする。 - このフラグが有効な campaign action が適用され、かつ最終価格が上代より低い場合のみ、Storefront の pre-cart 面で
%OFFと元価格打ち消し線を表示する。 - pre-cart 面では、このフラグが有効でも価格内訳 hover / click /
i詳細は表示しない。価格内訳はカート、checkout、注文確認、注文履歴などのカート以降に限定する。 - pricing rule、SMILE 単価マスタ、顧客別価格、標準掛率はこのフラグの対象外。仕入れ価格に近い標準単価・顧客別単価を回遊中に露出しないため、価格差から割引表示を推測しない。
レンジ価格の責務分離¶
- 期間限定の特売・販促単価は
campaign.priceRangesで扱う。 - 恒常価格・得意先別価格・常設の価格置換は
pricing ruleのreplace_price系アクションで扱う。 - したがって「価格レンジ」という表現でも、期間付き販促かどうかで責務を分ける。
決済許可制御(collectionMethod)の扱い¶
collectionMethodの決済可否はPaymentMethodCollectionAssignment(PMCA) を正本に表現する。PMCA は「回収方法コード × 許可 PaymentMethod codes」を直接保持 するエンティティで、AccessPolicy や表示制御ルールは経由しない。- 顧客の
collectionMethodはCustomer.customFields.collectionMethodを正本入力 とし、SMILE CSV 上の回収方法ヘッダー(コード側)を SMILE 取込が書き込む。 Dashboard 表示項目は回収方法(SMILE)/回収方法名(SMILE)を正とする。 - 決済方法(paymentMethod)は PMCA の
allowedPaymentMethodCodesで指定し、 Dashboard/payment-methods/collection-mappingで編集する。 - 判定は
paymentCollectionMethodEligibilityCheckerがpaymentOptions.paymentMethodEligibilityCheckers経由で行う。 - 将来要件の追加は、原則として PMCA のエンティティ更新(コード追加・許可決済方法 の差し替え)で対応する。
旧仕様(廃止): 以前は
policyType = paymentの AccessPolicy にallow_payment_methods/deny_payment_methodsaction を持たせ、subject 側で[決済ポリシー:回収方法]:1〜4CustomerGroup を使っていたが、PMCA 移行で削除。 移行 migration はapps/vendure-server/src/migrations/1779800400000_migrate_payment_policies_to_collection_assignments.ts参照。
クーポン(Promotion)とキャンペーン(campaign)の使い分け(2026-05)¶
決定¶
要件『BtoB発注システム要件』#59 のキャンペーンコードは、適用トリガで 2 系統に分離する。
- 手入力クーポンは Vendure 標準 Promotion を正本にする。
- 顧客/営業がコードを入力して適用する割引。
- 使用上限・有効期限・「注文検索」でのコード抽出は Vendure 標準機能を使う。
- 自動適用の販促(コード不要)は
campaign(CommercialRulesPlugin)を正本にする。 - 期間販促・数量/金額しきい値・おまけ(
giftItems)・進捗/上限・仮想商品による注文調整。 - 「顧客にコードを見せず自動適用し、注文へキャンペーンコードを登録」(#94-95) は
campaign側の責務とする。Order の customField にキャンペーンコードを記録し、成果抽出に使う。 Vendure 標準 Promotion の coupon code では代替しない。
Promotion の再有効化(最小範囲)¶
promotionOptions.promotionConditions/promotionActionsの空殻化([])を解除する。- 登録するのは手入力クーポン割引に必要な標準アクションのみに限定する。
orderPercentageDiscount/orderFixedDiscount/productsPercentageDiscount- 数量割引・おまけ等、
campaignと責務が重複するアクションは Promotion 側に登録しない。 - Dashboard 標準 Promotion ナビは、専任責務(手入力クーポン)を持つため表示する(非表示化しない)。
併用と重ね順¶
- クーポンと
campaignは基本併用可能とする。 - 重ね順:
campaign(価格エンジン)で行価格を確定した後に、クーポン(Promotion)を最後に適用する。 - 下限: クーポン+
campaign割引+おまけの重複適用後も、注文行・注文合計が負値にならない floor を必須とする。 - 個別排他: 既定は併用可。例外として併用を排他にしたい場合の precedence は「クーポン優先(
campaignが譲る)」を既定とする。 - 排他指定が有効なクーポンが注文に適用されている間は、
campaignの割引・おまけ(surcharge / giftItems)を withhold する。 - 顧客が入力したクーポンを checkout で剥がす/拒否することは UX 事故になるため行わない。silently 抑制してよいのは自動適用の
campaign側のみ。 - 排他フラグ自体の保存先(
CommercialRuleEntity新カラム or Promotion customField)・Admin API・Dashboard UI は、最初の具体的な排他ケースが発生した時点で実装する。 既定が併用可で機能するため、例外要件が未確定の段階でスキーマ/UI を先行実装しない(YAGNI)。
別概念(混同注意)¶
- クーポン割引用仮想商品
80000088(2026-03-virtual-product-assignment-settings.md)は、 SMILE 注文 CSV のクーポン割引行を取り込むためのデータ連携であり、上記ランタイム 2 機構とは別レイヤー。
未確定(クライアント確認)¶
- 手入力クーポンの割引種別(注文%引き/固定額引き/対象商品%引き 等)は要件未記載。 確定までは標準アクション 3 種を登録し、クーポン作成時に Dashboard で選択する運用とする。
残課題の解消状況(2026-05-29)¶
実装・staging 実機検証(floor)完了後の残課題を、投機実装を避けて以下のとおり確定する。
- 併用排他フラグ(フェーズ3): precedence は「クーポン優先(campaign が譲る)」で確定済み。 実カラム/Admin API/Dashboard UI の実装は、最初の具体的な排他ケースが発生した時点で行う(YAGNI)。 既定の併用可で運用上問題は出ないため、投機的なスキーマ/UI 追加はしない。
- クーポン割引種別: クライアント確認待ち。標準 3 アクション+Dashboard 選択の暫定運用で機能するため、 コード対応は不要。確定後に登録アクションを絞るかは運用判断。
- floor の厳密ゼロ化: floor は「合計を負にしない」契約を満たす(staging 実機で確認)。 割引が注文額を大きく超える極端ケースでのみ厳密 0 でなく小さい正値へ補正されるが、常に非負(安全側)。 realistic な割引額では floor 自体が発火しない。反復収束は決済計算の安定性リスクがあるため、 現挙動を accepted とする。
- キャンペーンコードの注文記録(#94-95)= SMILE 受注CSV へ出力(2026-05-29 マッピング確定):
- SMILE 受注取込CSV の
摘要 / 摘要1 / 摘要2列(位置 32-34)にキャンペーン情報を行ごとに出力する。 SMILE 取込は位置ベースのためヘッダー名は摘要/摘要1/摘要2のまま保持し、値のみを変更する (運用上は「適用 / 適用1 / 適用2」と呼ぶ=同音異字。ヘッダーは改名しない=既存フォーマット非破壊)。摘要(適用) = 業務キャンペーンコード(適用された campaign のCommercialRule.code)摘要1(適用1) = キャンペーン内容の説明文字列(その1)摘要2(適用2) = キャンペーン内容の説明文字列(その2)
- 行ごと(OrderLine 単位)に、その行へ適用された campaign の code / 説明を出力する。
キャンペーン未適用の行は空文字(旧 placeholder の
"0"は廃止)。 - 出所の整理:
appliedCampaigns(#803 削除済み)は rule ID(UUID) の dead field でこれとは別物。 本要件は CommercialRule.code(業務コード) を行ごとに出力するもので、surcharge の ruleId(UUID) や 仮想商品コードとは別軸。 - 手入力クーポン(Promotion)の couponCode はここには出さない(
摘要/適用 は適用された campaign(CommercialRule) の業務コードを正とする。クーポン単独適用行の扱いは別途追補)。
判断基準(運用)¶
次の条件に 1 つでも当てはまる場合は campaign を優先する。
- 期間限定である
- しきい値(数量/金額)達成が必要
- 無償特典や選択式特典がある
- 上限管理・例外管理が必要
次の条件に当てはまる場合は pricing rule を優先する。
- 常時適用される価格調整
- 顧客属性に応じた恒常割引
- 監査可能な権限制御として保持したい価格上書き
備考¶
- 元資料(xlsx/pdf)は編集禁止。要件変更は本補足仕様に追記し、必要に応じて実装仕様へ反映する。