2026-03 Storefront 価格表示拡張仕様(通常価格併記 + 価格内訳)¶
目的¶
商品ページおよび商品カード等の カート投入前 の価格表示では、仕入れ価格に近い標準単価・顧客別価格・掛率を露出しないため、原則として上代単価(定価)のみを表示する。
価格内訳(hover / click / i 詳細)は、カート投入後の購入文脈だけに限定する。campaign 側で明示的に catalog 割引表示を許可した場合でも、pre-cart で許可されるのは %OFF と元価格打ち消し線までで、価格内訳 i は出さない。
本仕様の対象コンポーネントは apps/storefront/src/components/product/product-price.tsx の ProductPrice。価格内訳の表示モデルは 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 の
descriptionがruleCode: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は商品詳細では出さない。 ProductPriceはprefetchedBreakdownがある場合、価格内訳のために同じ 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