Hydrogen店の設定ガイド

【SAKU領収書】Hydrogen(ヘッドレス)ストアでの設定ガイド

  • インボイス対応

  • Hydrogen対応

  • $4.99/月〜

【SAKU領収書】Hydrogen(ヘッドレス)ストアでの設定ガイド

アプリの特徴

  • お客様がサンクスページ・注文状況ページ・メールから自分で発行
  • インボイス登録番号と、8%・10%の税率ごとの内訳に対応
  • 会社のロゴ・印鑑・テーマカラーを設定できる
  • 管理画面から1件ずつでも、まとめてでも印刷
  • 帳票は日本語と英語に対応
  • Proプラン:備考の出し分け・発行済みタグ・発行回数の制限
  • Hydrogenプラン:ヘッドレス(Hydrogen)ストアでも発行

※注意
「新しいお客様アカウント」対応。
「従来のお客様アカウント」には一部対応。(テーマ「Dawn/Rise/Studio」対応済み)

SAKU領収書を、Hydrogen(Shopify のヘッドレスストア)で使うための設定ガイドです。Hydrogen ストアでお客様に領収書・請求書・納品書を発行してもらうには、Hydrogen プランが必要です(開発ストアでは無料でお試しいただけます)。


全体の流れ

通常のストアでは、帳票はストアの URL の下(/apps/saku-print)で開きます。Hydrogen ストアではこの仕組み(アプリプロキシ)が使えません。そのため、Hydrogen プランのストアには、帳票専用の入口(https://receipt.saku-apps.com/document)を用意しています。お客様は、注文ID と確認番号の組み合わせで帳票を開きます。

  1. ストアを Hydrogen プランにします。
  2. サンクスページと注文状況ページの「領収書」などのボタンは、行き先が自動で Hydrogen 用の入口に切り替わります。ボタンを置く作業は、通常のストアと同じです。
  3. 注文確認メールには、アプリの設定ページから Hydrogen 用のリンクをコピーして、メールのコードに貼り付けます。
  4. Hydrogen のマイページ(注文一覧・注文詳細)には、ストアを作った会社(開発者)が、ボタン部品(React コンポーネント「SakuReceiptButtons」)を組み込みます(任意)。

場所ごとに必要な作業は、次のとおりです。

場所 必要な作業
サンクスページ ボタンを置きます(切り替えは自動です)
注文状況ページ(お客様アカウント) ボタンを置きます(切り替えは自動です)
注文確認メール メールのコードのリンクを、Hydrogen 用のリンクに置き換えます
Hydrogen のマイページ 制作会社がボタン部品を組み込みます(任意)

この記事では、次の3つのステップで説明します。

  1. サンクスページ・注文状況ページにボタンを置く
  2. 注文確認メールに Hydrogen 用のリンクを入れる
  3. Hydrogen のマイページにボタンを置く(制作会社向け)


始める前に用意するもの

  • SAKU領収書(インストール済みで、帳票の設定が終わっていること)
  • Hydrogen プラン(アプリの料金プランで Hydrogen プランを選んでいること。開発ストアでは無料でお試しいただけます)
  • マイページにボタンを置くときは、ストアを作った会社(開発者)。React と Hydrogen の知識が必要です。

テーマの「アプリブロック」(従来のカスタマーアカウント用)は、Hydrogen ストアでは使えません。


1️⃣ サンクスページ・注文状況ページにボタンを置く

Hydrogen ストアでも、サンクスページと注文状況ページは Shopify の標準ページです。通常のストアと同じアプリブロックを、チェックアウトエディターで追加します。Hydrogen プランのストアでは、ボタンの行き先が自動で専用の入口に切り替わります。

① チェックアウトエディターを開きます。
Shopify管理画面の「設定」→「チェックアウト」を開き、「編集」を押します。

② 「サンクスページ」を開き、アプリブロック「SAKU buttons - Thanks page」を追加します。
画面の上のページ切り替えで「サンキュー」(サンクスページ)を選び、左側の「メイン」の「ブロックを追加」から「SAKU buttons - Thanks page」を追加します。注文状況ページには、同じ手順で「SAKU buttons - Order page」を追加します。

チェックアウトエディターのサンクスページに、SAKUのボタンのブロックを追加する画面

赤枠のように、SAKUのボタンのブロックを追加します。Hydrogen ストアでも同じブロックを使います。

③ 「保存」を押せば、ステップ1は完了です。
Hydrogen プランのストアでは、ボタンのリンクが自動で Hydrogen 用に切り替わるので、リンクの書き換えは要りません。ブロックの追加方法の詳しい説明は設定ガイドをご覧ください。


2️⃣ 注文確認メールに Hydrogen 用のリンクを入れる

① アプリの「設定」ページを開き、一番下までスクロールします。
「Hydrogen ストア(Hydrogen プラン)」の欄の「注文確認メールのリンク」にある「リンクをコピー」を押します。

SAKU領収書の設定ページの一番下。「Hydrogen ストア(Hydrogen プラン)」の欄と「リンクをコピー」ボタンを赤枠で囲んだ画面

設定ページの一番下の「Hydrogen ストア(Hydrogen プラン)」。リンクはストアごとに異なります。

② メールにコードを追加します。
メール設定ガイドの手順で、注文確認メールにコードを追加します。

③ コードの中のリンクを、コピーしたリンクに置き換えます。
置き換えるのは、コードの中の {{ shop.url }}/apps/saku-print?… の部分です。ここを、①でコピーしたリンクに貼り替えます。

④ 書類の種類を変えたいときは、リンクの最後の type=receipt を書き換えます。
type=receipt の receipt の部分(= のうしろ)だけを、次の言葉に書き換えます。

開きたい書類 type= のうしろに入れる言葉 書き換えたあとの例
領収書 receipt(最初のまま) type=receipt
請求書 invoice type=invoice
納品書 delivery_note type=delivery_note
見積書 quotation type=quotation

たとえば請求書のリンクにする場合は、次のようになります(変えたのは type= のうしろだけです。リンクの前半はストアごとに異なります)。

(コピーしたリンクの前半)…&type=invoice

⑤ メールを保存すれば、ステップ2は完了です。
テスト注文をして、メールのリンクから書類が開くことを確かめてください。


3️⃣ Hydrogen のマイページにボタンを置く(制作会社向け)

Hydrogen のマイページ(注文一覧・注文詳細)はストアごとに作られているため、ストアを制作した会社に、次のボタン部品を組み込んでいただきます。

組み込んだときのイメージです(見た目は制作会社がストアのデザインに合わせて変えられます)。

Hydrogen のマイページの注文詳細に置いた領収書・請求書・納品書のボタン

注文詳細:「領収書・請求書・納品書」のまとまりとボタン

Hydrogen のマイページの注文履歴に置いた領収書ボタン

注文履歴:注文ごとの「領収書」ボタン

ボタンから開いた領収書

ボタンを押すと、別のタブで領収書が開きます(印刷・PDF 保存・宛名の変更ができます)

手順

① ボタン部品のコードを保存します。
下の「ボタン部品のコード」を app/components/SakuReceiptButtons.tsx として保存します。

② 注文のクエリを確認します。
注文のクエリ(Customer Account API の Order)に id と confirmationNumber が含まれていることを確認します(最近の Hydrogen のテンプレートには含まれています)。

③ ストアのドメインを loader から渡します。
ストアの myshopify ドメイン(例 example.myshopify.com)を loader から渡します。Oxygen では環境変数 PUBLIC_STORE_DOMAIN に myshopify ドメインが自動で入っています。

④ 注文詳細や注文一覧に部品を置けば、ステップ3は完了です。
次のコードが置き方の例です。

import {SakuReceiptButtons} from '~/components/SakuReceiptButtons';

export async function loader({context}) {
  // …注文の取得
  return {order, receiptShop: context.env.PUBLIC_STORE_DOMAIN};
}

export default function OrderRoute() {
  const {order, receiptShop} = useLoaderData<typeof loader>();
  return (
    <section>
      <h3>領収書・請求書・納品書</h3>
      <p>別のタブで書類が開きます。印刷するか、印刷画面から PDF として保存できます。</p>
      <SakuReceiptButtons
        order={order}
        shop={receiptShop}
        types={['receipt', 'invoice', 'delivery_note']}
        fallback={<p>この注文の書類は、ストアまでお問い合わせください。</p>}
      />
    </section>
  );
}

注文一覧では、注文ごとに「領収書」ボタンだけを置くのがおすすめです(types を省略すると領収書だけになります)。ボタンは別のタブで開き、マイページの URL を送らない設定(rel="noopener noreferrer")になっています。


ボタン部品のコード(SakuReceiptButtons.tsx)

すべてコピーして、app/components/SakuReceiptButtons.tsx に貼り付けてください。見た目は自由に変えられます。

// SAKU領収書:Hydrogen のマイページ(注文一覧・注文詳細)に置く帳票ボタンのサンプル。
//
// Customer Account API の Order.id(gid://shopify/Order/123…)と Order.confirmationNumber から、
// 帳票の直接の入口 https://receipt.saku-apps.com/document へのリンクを作る。
// 使い方はこの記事を参照。ストアのデザインに合わせて見た目は自由に変えてよい。
//
// 本人確認は「注文ID+確認番号の一致」だけで行うため、確認番号が無い注文(2024年より前の注文など)では
// ボタンを出さない(fallback を渡せば代わりにそれを出す)。

import type {ReactNode} from 'react';

export const SAKU_RECEIPT_ENTRY_URL = 'https://receipt.saku-apps.com/document';

export type SakuDocumentType = 'receipt' | 'invoice' | 'delivery_note' | 'quotation';

/** Customer Account API の Order から使うフィールドだけ */
export type SakuReceiptOrder = {
  id: string;
  confirmationNumber?: string | null;
};

const DEFAULT_LABELS: Record<'ja' | 'en', Record<SakuDocumentType, string>> = {
  ja: {
    receipt: '領収書',
    invoice: '請求書',
    delivery_note: '納品書',
    quotation: '見積書',
  },
  en: {
    receipt: 'Receipt',
    invoice: 'Invoice',
    delivery_note: 'Delivery note',
    quotation: 'Quotation',
  },
};

const MYSHOPIFY_DOMAIN = /^[a-z0-9][a-z0-9-]*\.myshopify\.com$/;

/** gid://shopify/Order/1234567890 → "1234567890"。数字だけの ID はそのまま使う */
export function toNumericOrderId(id: string | null | undefined): string | null {
  const value = String(id ?? '').trim();
  const match = /^gid:\/\/shopify\/Order\/(\d+)(?:\?.*)?$/.exec(value);
  if (match) return match[1];
  return /^\d+$/.test(value) ? value : null;
}

/** 帳票の URL を作る。作れないとき(ID・確認番号・shop が不正)は null */
export function buildSakuReceiptUrl({
  order,
  shop,
  type = 'receipt',
  lang,
  entryUrl = SAKU_RECEIPT_ENTRY_URL,
}: {
  order: SakuReceiptOrder;
  /** ストアの myshopify ドメイン(例 example.myshopify.com)。独自ドメインは不可 */
  shop: string;
  type?: SakuDocumentType;
  /** 帳票の言語。省略すると購入時のお客様の言語→ストアの言語の順で決まる */
  lang?: string;
  entryUrl?: string;
}): string | null {
  const orderId = toNumericOrderId(order?.id);
  const confirmationNo = String(order?.confirmationNumber ?? '').trim();
  const shopDomain = String(shop ?? '').trim().toLowerCase();
  if (!orderId || !confirmationNo || !MYSHOPIFY_DOMAIN.test(shopDomain)) return null;

  const url = new URL(entryUrl);
  url.searchParams.set('shop', shopDomain);
  url.searchParams.set('orderId', orderId);
  url.searchParams.set('confirmationNo', confirmationNo);
  url.searchParams.set('type', type);
  if (lang) url.searchParams.set('lang', lang);
  return url.toString();
}

export function SakuReceiptButtons({
  order,
  shop,
  types = ['receipt'],
  lang,
  labels,
  entryUrl,
  className,
  fallback = null,
}: {
  order: SakuReceiptOrder;
  shop: string;
  /** 出す帳票の種類と並び順 */
  types?: SakuDocumentType[];
  lang?: 'ja' | 'en' | string;
  /** ボタンの文言を変えたいときだけ渡す */
  labels?: Partial<Record<SakuDocumentType, string>>;
  entryUrl?: string;
  className?: string;
  /** ボタンを出せない注文(確認番号が無いなど)で代わりに出すもの */
  fallback?: ReactNode;
}) {
  const baseLabels = DEFAULT_LABELS[lang === 'en' ? 'en' : 'ja'];
  const links = types
    .map((type) => ({
      type,
      href: buildSakuReceiptUrl({order, shop, type, lang, entryUrl}),
      label: labels?.[type] ?? baseLabels[type],
    }))
    .filter((link): link is {type: SakuDocumentType; href: string; label: string} =>
      Boolean(link.href),
    );

  if (links.length === 0) return <>{fallback}</>;

  return (
    <div className={className ?? 'saku-receipt-buttons'}>
      {links.map((link) => (
        // 帳票は別タブで開く。参照元(マイページのURL)を送らない
        <a
          key={link.type}
          href={link.href}
          target="_blank"
          rel="noopener noreferrer"
          className="saku-receipt-button"
        >
          {link.label}
        </a>
      ))}
    </div>
  );
}

export default SakuReceiptButtons;


見た目の例(CSS)

部品が出す要素(.saku-receipt-buttons の中の .saku-receipt-button)に、ストアのデザインに合わせて CSS を当ててください。次は、最初のボタン(領収書)を塗りつぶし、ほかを枠線にした例です。

/*
 * SAKU領収書:マイページの帳票ボタンの見た目の例(制作会社向けサンプル)
 *
 * SakuReceiptButtons は次の要素を出します。色や形はストアのデザインに合わせて自由に変えてください。
 *   <div class="saku-receipt-buttons">
 *     <a class="saku-receipt-button" …>領収書</a>
 *     <a class="saku-receipt-button" …>請求書</a> …
 *   </div>
 *
 * この例では、最初のボタン(ふつうは領収書)を塗りつぶしにして目立たせ、残りを枠線だけにしています。
 * 色は下の変数を書き換えるだけで変えられます。
 */

.saku-receipt-buttons {
  --saku-accent: #1f3a5f;        /* ボタンの色 */
  --saku-accent-hover: #162a46;  /* 塗りつぶしボタンに重ねたときの色 */
  --saku-accent-soft: #e8edf4;   /* 枠線ボタンに重ねたときの背景 */
  --saku-on-accent: #ffffff;     /* 塗りつぶしボタンの文字色 */

  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.saku-receipt-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px; /* 指で押しやすい高さ */
  padding: 0 22px;
  border: 1px solid var(--saku-accent);
  border-radius: 999px;
  background: transparent;
  color: var(--saku-accent);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 160ms ease-out, color 160ms ease-out;
}
.saku-receipt-button:hover {
  background: var(--saku-accent-soft);
}
.saku-receipt-button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px #ffffff, 0 0 0 5px var(--saku-accent);
}
.saku-receipt-button:first-child {
  background: var(--saku-accent);
  color: var(--saku-on-accent);
}
.saku-receipt-button:first-child:hover {
  background: var(--saku-accent-hover);
}

/* 注文詳細に置く「書類」のまとまり(記事の例のマークアップ用) */
.saku-documents {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px 32px;
  align-items: center;
  padding: 24px;
  border: 1px solid #e4dfd7;
  border-radius: 10px;
  background: #ffffff;
}
.saku-documents__title {
  margin: 0 0 4px;
  font-size: 1.0625rem;
}
.saku-documents__lead {
  margin: 0;
  max-width: 46ch;
  color: #5c574f;
  font-size: 0.9375rem;
}

/* スマートフォンでは縦に並べ、ボタンを横幅いっぱいにする */
@media (max-width: 640px) {
  .saku-documents {
    grid-template-columns: 1fr;
    padding: 20px;
  }
  .saku-receipt-buttons {
    width: 100%;
  }
  .saku-receipt-button {
    flex: 1 1 auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .saku-receipt-button {
    transition: none;
  }
}


注意事項

  • 帳票は注文ID と確認番号の組み合わせで開きます。ログイン中のお客様を自動で本人とみなす仕組みはありません。リンクを知っている人は開けるため、リンクを第三者に共有しないようお客様にご案内ください。
  • 2024年より前の注文には確認番号が無いことがあり、その場合は帳票を開けません(部品は fallback を表示します)。
  • B2B で同じ会社の他の担当者の注文を開けるかどうかは、マイページの作り(その注文を一覧に出すかどうか)によります。
  • 短時間に何度も確認番号を間違えると、同じ回線(IP アドレス)からは一時的に帳票を開けなくなります(いたずら防止のため)。
  • Hydrogen プランから Basic・Pro プランに変更すると、ボタンは通常の帳票ページ(/apps/saku-print)に戻ります。Hydrogen ストアでは開けない場合があるため、Hydrogen ストアでは Hydrogen プランをご利用ください。


うまくいかないとき

  • Hydrogen ストアで、ボタンやメールのリンクから書類が開かない
    リンクが /apps/saku-print のままになっていないか確認してください。サンクスページと注文状況ページのボタンは、Hydrogen プランであれば自動で切り替わります。プランが Hydrogen プランになっているか、アプリの「設定」ページで確認してください。メールは、ステップ2のとおりにリンクを置き換えます。
  • マイページにボタンが出ない
    その注文に確認番号が無いか、ストアのドメインが正しくない可能性があります。shop には、独自ドメインではなく、myshopify ドメイン(例 example.myshopify.com)を渡してください。2024年より前の注文には確認番号が無いことがあり、その場合は fallback が表示されます。
  • 何度も試すと書類が開けなくなった
    確認番号を短時間に何度も間違えると、同じ回線(IP アドレス)から一時的に開けなくなります。しばらく待ってから、正しい確認番号で試してください。


関連記事


お問い合わせ

ご不明な点は info@saku-apps.com までお問い合わせください。