ヘッドレス側で実装すること
Shopify側の設定が完了したら、ヘッドレス(Next.js)側で以下を実装します。
- ログイン時にタグを取得
- タグから割引率を算出
- 会員価格を表示
- 決済時にクーポンを自動適用
- 請求書払いの処理(オプション)
ステップ1: ログイン時にタグを取得
お客様がログインしたら、Storefront APIを使ってタグ一覧を取得します。
GraphQLクエリ
query getCustomer($customerAccessToken: String!) {
customer(customerAccessToken: $customerAccessToken) {
id
email
tags
}
}
レスポンス例
{
"data": {
"customer": {
"id": "gid://shopify/Customer/12345",
"email": "dealer@example.com",
"tags": ["standard-35", "premium-25", "b2b-account"]
}
}
}
この顧客は standard-35 と premium-25 のタグを持っているので、2種類の割引が適用されます。
ステップ2: タグから割引率を算出
タグ名から割引率を抽出するロジックを実装します。
基本的な考え方
// タグ名: "standard-35"
// 抽出したい値: 35(割引率)
function getDiscountRateFromTag(tag: string): number | null {
// タグ名の形式: カテゴリ-割引率
const match = tag.match(/^(.+)-(\d+)$/);
if (!match) return null;
const discountRate = parseInt(match[2], 10);
return discountRate;
}
// 使用例
getDiscountRateFromTag("standard-35"); // → 35
getDiscountRateFromTag("premium-25"); // → 25
カテゴリと割引率のマッピング
どのタグがどのコレクション(商品カテゴリ)に対応するかを設定ファイルで管理します。
// config/b2b-discounts.ts
export const B2B_DISCOUNT_CONFIG = [
{
tagPrefix: "standard",
collectionHandle: "b2b-standard-products",
// 割引率はタグ名から動的に取得
},
{
tagPrefix: "premium",
collectionHandle: "b2b-premium-products",
},
{
tagPrefix: "elite",
collectionHandle: "b2b-elite-products",
},
{
tagPrefix: "special",
collectionHandle: "b2b-special-products",
},
];
ステップ3: 会員価格を表示
タグ情報をもとに、商品の会員価格を計算・表示します。
価格計算ロジック
function calculateMemberPrice(
originalPrice: number,
customerTags: string[],
productCollections: string[]
): { memberPrice: number; discountRate: number } | null {
for (const config of B2B_DISCOUNT_CONFIG) {
// この商品が対象コレクションに含まれているか
if (!productCollections.includes(config.collectionHandle)) {
continue;
}
// 顧客がこのカテゴリの割引タグを持っているか
const matchingTag = customerTags.find(tag =>
tag.startsWith(`${config.tagPrefix}-`)
);
if (matchingTag) {
const discountRate = getDiscountRateFromTag(matchingTag);
if (discountRate) {
const memberPrice = originalPrice * (1 - discountRate / 100);
return { memberPrice, discountRate };
}
}
}
return null; // 割引対象外
}
カート画面での表示例
| 商品 | 通常価格 | 会員価格 |
|---|---|---|
| 商品A(標準カテゴリ) | ¥10,000 | ¥6,500(35%OFF) |
| 商品B(プレミアムカテゴリ) | ¥20,000 | ¥15,000(25%OFF) |
| 項目 | 金額 |
|---|---|
| 元の合計 | ¥30,000 |
| 会員割引 | -¥8,500 |
| お支払い額 | ¥21,500 |
ステップ4: クーポンを自動適用
「購入手続きへ」ボタンを押したとき、タグ名と同名のクーポンを自動でカートに適用します。
処理の流れ
カート内の商品を確認・各商品のコレクションを取得
適用すべきタグを特定
タグ名=クーポン名でカートに適用
割引が適用された状態
実装例(概念)
async function proceedToCheckout(
cartId: string,
customerTags: string[],
cartItems: CartItem[]
) {
// 適用すべきクーポン(タグ名)を特定
const applicableCoupons = getApplicableCoupons(customerTags, cartItems);
// 各クーポンをカートに適用
for (const couponCode of applicableCoupons) {
await applyDiscountCode(cartId, couponCode);
}
// チェックアウトURLを取得して遷移
const checkoutUrl = await getCheckoutUrl(cartId);
window.location.href = checkoutUrl;
}
function getApplicableCoupons(
customerTags: string[],
cartItems: CartItem[]
): string[] {
const coupons: string[] = [];
for (const item of cartItems) {
for (const config of B2B_DISCOUNT_CONFIG) {
// 商品が対象コレクションに含まれているか
if (!item.collections.includes(config.collectionHandle)) {
continue;
}
// 顧客がこのカテゴリの割引タグを持っているか
const matchingTag = customerTags.find(tag =>
tag.startsWith(`${config.tagPrefix}-`)
);
if (matchingTag && !coupons.includes(matchingTag)) {
coupons.push(matchingTag); // タグ名 = クーポン名
}
}
}
return coupons;
}
お客様はコード入力不要
この仕組みにより、お客様はクーポンコードを知る必要も、入力する必要もありません。ログインしているだけで、自動的に割引が適用されます。
ステップ5: 請求書払い(掛け売り)機能
B2Bでは、クレジットカード払いではなく請求書払いのニーズがあります。
ドラフトオーダーを使った実装
Shopifyの「ドラフトオーダー(下書き注文)」機能を使って、請求書払いを実現します。
処理の流れ:
- お客様が「請求書払いで注文」を選択
- Admin APIでドラフトオーダーを作成
- ドラフトオーダーには以下の情報を記録:
- 商品情報(会員価格適用後)
- 割引率と節約額
- 顧客情報
- 販売担当にメールで通知
- 確認後、請求書を発行
ドラフトオーダー作成の実装例
async function createInvoiceOrder(
customer: Customer,
cartItems: CartItemWithDiscount[]
) {
const lineItems = cartItems.map(item => ({
variantId: item.variantId,
quantity: item.quantity,
// 会員価格を適用
appliedDiscount: {
value: item.discountRate,
valueType: "PERCENTAGE",
title: `B2B割引(${item.discountRate}%OFF)`,
},
}));
const draftOrder = await adminApi.draftOrderCreate({
input: {
lineItems,
customerId: customer.id,
note: `請求書払い注文\n割引タグ: ${customer.tags.join(", ")}`,
tags: ["invoice-payment", "b2b-order"],
},
});
// 担当者に通知
await sendNotificationEmail({
to: "sales@example.com",
subject: `新規B2B注文(請求書払い): ${customer.email}`,
body: `
顧客: ${customer.email}
合計金額: ¥${draftOrder.totalPrice}
元の金額: ¥${draftOrder.subtotalPrice}
割引額: ¥${draftOrder.totalDiscounts}
`,
});
return draftOrder;
}
請求書払いのUI
| お支払い方法 | 説明 |
|---|---|
| クレジットカードで購入 | Shopify決済へ進む |
| 請求書払いで注文 | 後日請求書をお送りします(月末締め翌月末払い) |
優先順位の管理
同じ商品に複数のルールが適用可能な場合の制御方法です。
設定例
export const B2B_DISCOUNT_CONFIG = [
// 優先順位が高いものを先に定義
{
tagPrefix: "vip",
collectionHandle: "b2b-vip-products",
priority: 1, // 最優先
},
{
tagPrefix: "standard",
collectionHandle: "b2b-standard-products",
priority: 2,
},
// ...
];
優先順位が高いルールが先にマッチしたら、それを適用して終了します。
まとめ
ヘッドレス側の実装ポイントを整理します。
| 機能 | 実装内容 |
|---|---|
| タグ取得 | Storefront API でログイン顧客のタグを取得 |
| 価格計算 | タグから割引率を抽出し、会員価格を算出 |
| 価格表示 | カート画面で通常価格と会員価格を並べて表示 |
| クーポン適用 | 決済時にタグ名と同名のクーポンを自動適用 |
| 請求書払い | Admin API でドラフトオーダーを作成 |
この仕組みの最大のメリット:
- コード変更不要: 新しいB2B顧客やカテゴリを追加しても、Shopify設定だけで対応
- お客様体験: ログインするだけで自動的に会員価格が適用される
- 運用効率: 設定ファイル1箇所の編集でカテゴリ追加可能
Shopify Plus不要で、通常プランでも本格的なB2B機能を実現できる設計です。