コンテンツにスキップ

2026-03 Storefront 価格表示拡張仕様(通常価格併記 + 価格内訳)

目的

商品ページおよび商品カード等の カート投入前 の価格表示では、仕入れ価格に近い標準単価・顧客別価格・掛率を露出しないため、原則として上代単価(定価)のみを表示する。

価格内訳(hover / click / i 詳細)は、カート投入後の購入文脈だけに限定する。campaign 側で明示的に catalog 割引表示を許可した場合でも、pre-cart で許可されるのは %OFF と元価格打ち消し線までで、価格内訳 i は出さない。

本仕様の対象コンポーネントは apps/storefront/src/components/product/product-price.tsxProductPrice。価格内訳の表示モデルは apps/storefront/src/lib/product-price-display.ts、商流 action のユーザー向け整形は apps/storefront/src/lib/product-pricing.ts を正本とする。

適用範囲

  • ProductPrice を利用する表示箇所。ただし、表示モードで扱いを分ける。
  • 商品カード
  • 商品詳細ページ
  • お気に入り
  • compact product card
  • その他 ProductPrice 利用画面

表示仕様

0. カート投入前の既定表示

  • 商品一覧、商品詳細、検索、お気に入り、関連商品、カルーセルなどの回遊面では上代単価(定価)の税込表示だけを主表示にする。
  • 標準単価、顧客別価格、掛率、価格内訳 hover / click / i 詳細、通常の %OFF バッジ、元価格打ち消し線は出さない。
  • pre-cart 表示では、価格表示コンポーネント自身から activeOrderCommercialState(s) を取得しない。

1. 明示許可 campaign の割引表示

  • 税込の割引後価格を主表示(大きいフォント)
  • 通常価格(税込)を併記(打ち消し線)
  • %OFF バッジを表示
  • 表示条件は、適用 action の catalogDiscountDisplayEnabled === true かつ最終価格が上代より低い場合に限る
  • isDefaultRate、SMILE 単価マスタ、顧客別価格、標準掛率だけでは pre-cart の割引表示を許可しない
  • pre-cart ではこの例外が成立しても価格内訳 hover / click / i 詳細は表示しない。詳細内訳はカート以降だけに出す。

2. 割引なし

  • 既存表示を維持(1価格表示)
  • 税込価格
  • 税抜価格

3. 内訳表示(カート以降の購入文脈の価格エリア)

  • 対象はカート、checkout、注文確認、注文履歴、Quick Order 等のカート投入後・注文文脈に限る。
  • PC: 購入文脈の価格行にマウスオーバーすると内訳ポップアップを表示する。
  • モバイル / キーボード: 購入文脈の価格行のタップまたは Enter / Space で内訳ポップアップを固定表示する。Escape で閉じる。
  • trigger 範囲は、主価格、税込ラベル、情報アイコン、割引 %OFF バッジを含む。情報アイコン単体だけを hover 対象にしない。
  • 内訳内容(ユーザー向け)
  • 適用税率
  • 購入単位(例: 10個ごと
  • 1 個単価
  • 通常価格(税込)
  • 割引額または価格調整額(税込)
  • 表示価格(税込)
  • 適用された価格ルール

4. 適用された価格ルールの表示

価格内訳では、商流 rule / campaign / 直送加算の appliedActions をユーザーが読める粒度で表示する。これは debug 専用情報ではなく、通常表示の一部とする。

action kind 表示名 補足表示
set_unit_price 固定単価 単価 N円
multiply_unit_price 掛率 掛率 N% と、割引時は M%OFF
add_unit_amount 単価調整 +N円 / -N円
direct_shipping_surcharge 直送手数料 商品単価の10%加算
  • backend の descriptionruleCode:tierName:kind 形式の場合は、末尾の kind を除き ruleCode / tierName として表示する。
  • raw internal state や GraphQL type 名をそのまま出さない。
  • 金額欄は税込換算した増減額を表示する。掛率など金額差分を直接持たない action では、割合を補助表示する。
  • 直送手数料は固定額ではなく 商品単価の 10% 加算 として説明する。画面上の amount は計算済みの結果であり、仕様説明の正本は「商品単価の 10%」である。

データ取得仕様

  • Shop API の activeOrderCommercialState(productVariantId, shippingMode) を使用する。
  • 商品詳細では campaign 状態を activeOrderCommercialState で取得してよいが、pre-cart 価格表示は catalogDiscountDisplayEnabled の判定にだけ使う。価格内訳 i は商品詳細では出さない。
  • ProductPriceprefetchedBreakdown がある場合、価格内訳のために同じ Shop API query を二重発火しない。
  • 商品カード、商品一覧、検索結果などの pre-cart UI では商流シミュレーション fetch を行わない。
  • 価格内訳はログイン中ユーザーを対象にサーバー側で計算する。
  • customerId をクライアントから受け取らない(RequestContext の認証情報を使用)
  • 非認証時は取得不可(エラー)

GraphQL 仕様(Shop API)

query ActiveOrderCommercialState($productVariantId: ID, $shippingMode: String) {
  activeOrderCommercialState(productVariantId: $productVariantId, shippingMode: $shippingMode) {
    focusLineResult {
      productVariantId
      originalUnitPrice
      finalUnitPrice
      discountAmount
      appliedActions {
        kind
        description
        amount
        value
      }
    }
    matchedRules {
      ruleId
      code
      name
    }
  }
}

セキュリティ・公開ルール

  • activeOrderCommercialState は認証済み context を前提に、クライアントから customerId を受け取らない。
  • Storefront の購入文脈の表示では action kind を直接ラベルにせず、ユーザー向け表示名へ正規化する。
  • pre-cart の割引表示は catalogDiscountDisplayEnabled を正本にし、価格差や action kind から推測しない。
  • rule code / tier name は価格内訳の根拠として表示してよいが、raw internal state や GraphQL の型名・内部 decision state は通常表示に出さない。

テスト / スクリーンショット

  • Component Test: apps/storefront/tests/e2e/ct/product/product-price.ct.spec.tsx
  • 固定する操作:
  • displayMode="orderContext" の購入文脈では価格 hover で内訳 dialog が開く
  • displayMode="orderContext" の購入文脈では割引 %OFF バッジ hover で内訳 dialog が開く
  • displayMode="preCart" の pre-cart 表示では上代単価だけを表示し、明示許可 campaign の %OFF 表示時も内訳 dialog / i を出さない
  • click / Enter / Space で固定表示できる
  • Escape で閉じる
  • 盛り込み fixture で固定単価、掛率、単価調整、直送手数料、購入単位が表示される
  • 盛り込みスクリーンショット:
  • output/playwright/product-price-rich-breakdown.png
  • CT 実行時の package cwd でも repo root の output/playwright/ に生成される

更新日: 2026-05-26