ProductVariant の購入不可在庫しきい値¶
背景¶
在庫数が 0 になる直前まで販売すると、注文確定時の在庫引当てで不足が発生しうる。 そのため、ProductVariant ごとに安全余裕を持たせた「購入不可しきい値」を設定できることを正とする。
要件¶
- ProductVariant ごとの購入不可しきい値は、Vendure 標準の
outOfStockThresholdを正本とする。独自 custom field は追加しない。 - Variant ごとに個別値を使う場合は
useGlobalOutOfStockThreshold = falseとし、その variant のoutOfStockThresholdを設定する。 - Shop API では、saleable stock がその variant の
outOfStockThreshold以下になった時点でstockLevel = OUT_OF_STOCKとして扱う。 - Storefront の商品カード・商品詳細・クイックオーダーは
stockLevel = OUT_OF_STOCKを購入不可条件として共通利用し、 threshold 到達時点で同じ基準で購入不可にする。 - 商品カード・商品詳細のカート投入 CTA は
apps/storefront/src/lib/cart-eligibility.tsのresolveVariantCartEligibility()を共通入口にする。個別 component がstockLevelや配送モード、購入可能期間、数量制限をそれぞれ独自順序で判定してはならない。 - Storefront の購入可否判定では、
stockLevelは常に ProductVariant の 状態を正本とする。bundle variant であってもOUT_OF_STOCKの場合は 通常 variant と同じく購入不可にし、商品カード・商品詳細・クイックオーダーで 個別の例外分岐を作らない。 - 実装上の在庫切れメッセージ・ボタンラベル・低在庫停止メッセージの解決は
apps/storefront/src/lib/out-of-stock-message.tsを共通入口とする。 UI コンポーネントや Quick Order 側でisBundleProductを見て在庫切れを 上書きしてはならない。 stockLevel(OUT_OF_STOCK/LOW_STOCK/IN_STOCK)の粗いラベルでは 「あと何個買えるか」が分からないため、Shop API はProductVariant.saleableStockLevel(予約差引後の販売可能在庫数,Int!)も返す。正本はpackages/plugins/src/standard-extensions/inventory/saleable-stock.shop-resolver.ts(ProductVariantService.getSaleableStockLevelに委譲)とし、storefront は この実在庫数を事前のカート投入判定に使う。- 事前(クリック前)の数量上限は、購入上限(
maxPerOrder/ 期間ルール)に加えてsaleableStockLevel(カート内既存数量を差引いた残数)でも丸める。残数が最低購入 数量に満たない場合はresolveVariantCartEligibility()が事前に購入不可へ倒す。saleableStockLevelを取得しない surface(= 値がnull)では事前在庫判定を スキップし、従来どおりサーバ拒否で吸収する。 addItemToOrder/adjustOrderLineがInsufficientStockErrorを返した場合は サーバが返すquantityAvailable(実際に追加できた/できる数量)を使い、数量ステッパー 上限を実在庫に丸めて再試行可能にする(CTA を恒久 disable しない)。残数が 0 なら 在庫切れとして購入不可へ倒す。quantityAvailableを返さないレスポンスは従来どおりresolveAddItemToOrderRejectionReason()で不可理由へ変換し、CTA を再クリックできない 状態へ倒す(安全側 fallback)。いずれも Shop API の最終判定を UI に反映するための fail-closed UX であり、server-side 在庫検証は引き続き必須とする。- threshold を上回っていても、stock display strategy により
LOW_STOCK表示になることは許容する。購入不可の境界はOUT_OF_STOCKへの遷移点とし、LOW_STOCK/IN_STOCKの範囲内ではsaleableStockLevelで 数量上限を丸めて要求超過を事前に防ぐ。
受け入れ観点¶
- Vendure Dashboard の Product Variant 編集で
outOfStockThresholdを設定できる。 - 在庫数と同じ値を threshold に設定すると、Shop API の
stockLevelがOUT_OF_STOCKになる。 - Storefront では該当 variant をカート追加できず、クイックオーダーでもエラーになる。
- bundle variant でも
stockLevel = OUT_OF_STOCKなら、商品カード・商品詳細・クイックオーダーで同じ在庫切れ扱いになる。 - 在庫が
LOW_STOCK/IN_STOCKでも、数量ステッパーの上限がsaleableStockLevel(カート内既存数量を差引)に丸められ、実在庫を超える数量は選べない。 - 実在庫を超える数量で
addItemToOrderがInsufficientStockError(quantityAvailable付き)を返した場合、CTA は恒久 disable されず、数量上限が実在庫数に丸められて再試行できる(残数 0 のときのみ在庫切れ表示)。