商品ページ統合

商品ページからprotegerを表示・購入できるようにしましょう。

shopserveではPCサイトとスマートフォンサイトでデザインが大きく異なるため、それぞれで異なる商品ページ統合処理が必要になります。事業者様のご利用環境に合わせて、導入を進めてください。

PCサイトへの統合

🚧

テーマについて

ここでは、「レスポンシブデザイン対応テーマ」を基準に紹介しています。

お使いのテーマに合わせて適宜変更して下さい。

概要

このセクションでは、次の手順について説明します。

  • プランの表示とモーダルの表示
  • [カートに入れる]ボタンとフォーム要素を見つけます
  • proteger-product-integrationパーツの追加

所要時間:約1時間


設定

  1. [カートに入れる]ボタンのタイプ名を見つけます。
    1. 商品ページで[カートに入れる]ボタンを見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で<input>が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    4. タイプ属性を見つけます。これは、ステートメント type= の後の属性名になります。
    5. タイプ属性をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。

🚧

複数カートに入れるボタンがある場合

shopserveはバリエーション毎に[カートに入れる]ボタンが表示されている場合があります。

バリエーションが無い([カートに入れる]ボタンが1つの)場合にも動作する様に、適切なクラス名を設定する必要があります。

  1. カートエリアのクラス名を見つけます。
    1. 商品ページで[カートに入れる]ボタンを見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <div id="pi_cart"> が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    4. id名を見つけます。これは、ステートメント id= の後の属性名になります。
    5. id名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. フォームのクラス名を見つけます。
    1. 商品ページで[カートに入れる]ボタンを見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <form> が見つかるまで要素の上にカーソルを置きます。
    4. クラス名を見つけます。これは、ステートメント class= の後の属性名になります。
    5. クラス名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. protegerを表示する[上の要素]を見つけます。
    *この例では商品数量の下に表示する事を想定しています。
    1. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    2. 要素上で、 <table class="spec"> が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    3. クラス名を見つけます。これは、ステートメント class= の後の属性名になります。
    4. クラス名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. [商品番号]を見つけます。
    1. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    2. 要素上で、 <input type="hidden" name="ITEM_NO"> の値が見つかるまで要素の上にカーソルを置きます。
    3. 要素の中に商品番号が含まれていることを確認します。もしも存在しない場合は、商品番号を含む別の要素を指定してください。
    4. name属性を見つけます。これは、ステートメント name= の後の属性名になります。
    5. name属性をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. [商品名]を見つけます。
    1. 商品ページで[商品名]欄を見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <title> が見つかるまで要素の上にカーソルを置きます。
    4. タグ名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. [商品数量]を見つけます。
    1. 商品ページで[数量]入力欄を見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <input> が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    4. name属性を見つけます。これは、ステートメント name= の後の属性名になります。
    5. name属性をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. shopserveの管理画面を開き、「デザイン設定」->「テーマ」->「HTMLのカスタマイズ」から「商品ページ」->「メイン紹介文」->「HTMLを編集」をクリックします。
  1. 画像の赤枠の部分にprotegerを表示するためのHTMLを記述します。
  • HTMLテンプレートはこちらです。
<script src="https://sdk.helloproteger.com/proteger-sdk-min.js"></script>
<script src="https://sdk.helloproteger.com/shopserve/v1/plan.min.js"></script>
<script>
  window.addEventListener("DOMContentLoaded", function () {
    Proteger.config({
      storeId: "protegerが発行した店舗ID",
      logoUrl: "店舗のロゴのURL",
      protegerEnv: "prd",
    });
  });
</script>

<script>
  // DOMContentLoadedでスクリプトを実行し、サイトのロード時間に影響を与えないようにします。
  window.addEventListener("DOMContentLoaded", function () {
    // protegerのオファーを表示する前に、Proteger変数がウィンドウ内に存在するかどうかをチェックします。
    if (window.Proteger && window.ProtegerShopserve) {
      /************************/
      /* Initial Variables */
      /************************/
      const cartFormSelector = "CHANGE_HERE"; // フォーム要素のセレクタに変更(例: .shopping_form )
      const cartAreaSelector = "CHANGE_HERE"; // カートエリアのセレクタに変更(例: #pi_cart )
      const addToCartButtonsSelector = "CHANGE_HERE"; // [カートに追加する]ボタンのセレクタに変更(例: input[type=image] )
      const protegerOfferSymbolSelector = "CHANGE_HERE"; // protegerを表示する[上の要素]のセレクタに変更(例: .spec )
      const productIdSelector = "CHANGE_HERE"; // 商品番号のセレクタに変更(例: input[name=ITEM_NO] )
      const productQuantitySelector = "CHANGE_HERE"; // 商品数量のセレクタに変更(例: input[type=text][name=CNT-1] )
      const productTitleSelector = "CHANGE_HERE"; // 商品名のセレクタに変更(例: title )

      const ProtegerOfferId = "proteger-offer";

      const cartForm = document.querySelector(cartFormSelector);
      const cartUrl = cartForm && cartForm.action;
      const cartArea = document.querySelector(cartAreaSelector);
      const addToCartButtons = cartArea && cartArea.querySelectorAll(addToCartButtonsSelector);
      const productTitle = document.querySelector(productTitleSelector);
      const protegerOfferSymbol = cartArea && cartArea.querySelector(protegerOfferSymbolSelector);
      const protegerOffer = document.createElement("div"); // プランを表示するシンボルエレメント
      protegerOffer.id = ProtegerOfferId;
      if (protegerOfferSymbol)
        protegerOfferSymbol.parentElement.insertBefore(protegerOffer, protegerOfferSymbol.nextSibling);

      /************************/
      /* initProductOffer */
      /************************/
      // プランの初期化、PDP ATCボタン機能の処理
      function initProductOffer() {
        // safe機能
        if (!cartUrl || !addToCartButtons || !productTitle || !protegerOffer) return;

        // 商品がproteger保証かどうかを確認し、保証の場合はATCを無効化します。
        function isProteger() {
          if (productTitle.textContent.includes("proteger")) {
            addToCartButtons.forEach(function (button) {
              button.disabled = true;
            });
          }
        }

        isProteger();

        // cartForm から productId を取得し、初期プランをレンダリングします。
        const productId = cartForm.querySelector(productIdSelector).value;
        Proteger.buttons.render(ProtegerOfferId, {
          productId: productId,
        });

        //[カートに追加]ボタンのハンドラー
        function handleAddToCart(e) {
          e.preventDefault();
          e.stopImmediatePropagation();

          const quantityEl = cartArea.querySelector(productQuantitySelector);
          const quantity = quantityEl && quantityEl.value;

          // 保証プランコンポーネントを取得
          const component = Proteger.buttons.instance(ProtegerOfferId);

          // 選択された保証プランを取得
          const plan = component.getPlanSelection();

          let index = Array.from(addToCartButtons).indexOf(e.target);

          ProtegerShopserve.addPlanToCart(
            {
              cartUrl: cartUrl,
              productId: productId,
              plan: plan,
              quantity: quantity,
              modal: true,
            },
            function () {
              addToCartButtons[index].removeEventListener("click", handleAddToCart, true);
              addToCartButtons[index].click();
              addToCartButtons[index].addEventListener("click", handleAddToCart, true);
            }
          );
        }

        //ATCをクリックするとhandleAddToCartが実行され、イベントをキャプチャ
        addToCartButtons.forEach((button, index) => {
          button.addEventListener("click", handleAddToCart, true);
        });
      }

      // 初期レンダリング
      initProductOffer();
    }
  });
</script>

  • "protegerが発行した店舗ID" : protger管理画面を開き、「右上の歯車マーク」->「店舗設定」から確認できます。
  • "店舗のロゴのURL" :店舗のロゴ画像リンクを設定してください。
  • "CHANGE_HERE" : 任意の要素で上書きしてください。
    _NOTE:店舗のデザインテーマを大幅にカスタマイズしていない場合は、 "例" の後に記載しているタグをそのまま利用できる可能性があります。
    • cartFormSelectorCHANGE_HERE を、上記で取得したフォームのクラス名に置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に .ピリオドを付けてください。
    • cartAreaSelectorCHANGE_HERE を、上記で取得したカートエリアのクラス名に置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に #シャープを付けてください。
    • addToCartButtonsSelectorCHANGE_HERE を、上記で取得した[カートに追加]ボタンに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。 type属性の場合はinput[type=Name]としてください。Name部分は保存した値で上書きしてください。
    • protegerOfferSymbolSelectorCHANGE_HERE を、上記で取得したprotegerを表示する[上の要素]のクラスに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に .ピリオドを付けてください。
    • productIdSelectorCHANGE_HERE を、上記で取得した[商品番号]のクラスに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。name属性の場合はinput[name=Name]としてください。Name部分は保存した値で上書きしてください。
    • productQuantitySelectorCHANGE_HERE を、上記で取得した[商品番号]のクラスに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。name属性の場合はinput[name=Name]としてください。Name部分は保存した値で上書きしてください。
    • productTitleSelectorCHANGE_HERE を、上記で取得した[商品名]のタグに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。
  1. 更新したHTMLを貼り付けて「保存」をクリックします。
    _NOTE:shopserveの仕様上「保存した内容でプレビューする」を実行しても、protegerは表示されません。
  1. 上部の「お店ページの更新へ」をクリックし、「編集中のテーマでお店を更新」をクリックします。

❗️

Warn

テーマの更新を行うと本番のサイトに反映されるため、慎重に行ってください。万が一、サイトに不具合が生じた場合は、追記したHTMLを削除してテーマの更新を行ってください。

  1. 設定は完了です。このまま次の確認セクションに進んでください。

確認

  1. 店舗サイトに移動します。
  2. 保証対象製品ページに移動します。
  3. プランが表示されている事を確認します。
  1. モーダルが表示される事を確認します。
  1. 両方のパターンで商品と保証がカートに追加される事を確認します。
  1. 完了です 🎉

📘

NOTE

お困りの際は担当者または下記のメールアドレスにいつでもご連絡下さい。
[email protected]


スマートフォンサイトへの統合

🚧

テーマについて

ここでは、「S-ホワイトテーマ」を基準に紹介しています。

お使いのテーマに合わせて適宜変更して下さい。

概要

このセクションでは、次の手順について説明します。

  • プランの表示とモーダルの表示
  • [カートに入れる]ボタンとフォーム要素を見つけます
  • proteger-product-integrationパーツの追加

所要時間:約1時間


設定

  1. [カートに入れる]ボタンのタイプ名を見つけます。
    1. 商品ページで[カートに入れる]ボタンを見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で<input>が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    4. クラス名を見つけます。これは、ステートメント class= の後の属性名になります。
    5. クラス名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。

🚧

複数カートに入れるボタンがある場合

shopserveはバリエーション毎に[カートに入れる]ボタンが表示されている場合があります。

バリエーションが無い([カートに入れる]ボタンが1つの)場合にも動作する様に、適切なクラス名を設定する必要があります。

  1. カートエリアのクラス名を見つけます。
    1. 商品ページで[カートに入れる]ボタンを見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <section> が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    4. id名を見つけます。これは、ステートメント id= の後の属性名になります。
    5. id名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. フォームのクラス名を見つけます。
    1. 商品ページで[カートに入れる]ボタンを見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <form> が見つかるまで要素の上にカーソルを置きます。
    4. クラス名を見つけます。これは、ステートメント class= の後の属性名になります。
    5. クラス名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. protegerを表示する[上の要素]を見つけます。
    *この例では商品数量の下に表示する事を想定しています。
    1. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    2. 要素上で、 <table class="remark"> が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    3. クラス名を見つけます。これは、ステートメント class= の後の属性名になります。
    4. クラス名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. [商品番号]を見つけます。
    1. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    2. 要素上で、 <input type="hidden" name="ITM"> の値が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    3. 要素の中に商品番号が含まれていることを確認します。もしも存在しない場合は、商品番号を含む別の要素を指定してください。
    4. name属性を見つけます。これは、ステートメント name= の後の属性名になります。
    5. name属性をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. [商品名]を見つけます。
    1. 商品ページで[商品名]欄を見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <title> が見つかるまで要素の上にカーソルを置きます。
    4. タグ名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. [商品数量]を見つけます。
    1. 商品ページで[数量]入力欄を見つけます。
    2. 右クリックしてから、右クリックメニューの[検証]をクリックします。
    3. 要素上で、 <input> が見つかるまで要素の上にカーソルを置きます。
      _Note: タブの要素にカーソルを合わせると、ページ上で強調表示されていることがわかります。
    4. クラス名を見つけます。これは、ステートメント class= の後の属性名になります。
    5. クラス名をコピーして、後で使用するために別の場所に貼り付ける等保存しておきます。
  1. shopserveのスマートフォンサイト設定管理画面を開き、「各種設定」->「ヘッダ・フッタ設定」->「フッタ設定」->「共通フッタ設定」から「編集」をクリックします。
  1. HTMLエディタがONになっている場合は、「⇒HTMLエディタ OFF/ON 切替」をクリックし、HTMLエディタをOFFにします。
    _Note: 普段はHTMLエディタをONの状態にしておきたい場合は、全ての統合作業が終了後にHTMLエディタの設定を戻すことができます。
  1. フッタ設定画面に戻り、フッタのフリーエリアの「表示する」にチェックを入れます。
  1. 画像の赤枠の部分にprotegerを表示するためのHTMLを記述します。
  • HTMLテンプレートはこちらです。
<script src="https://sdk.helloproteger.com/proteger-sdk-min.js"></script>
<script src="https://sdk.helloproteger.com/shopserve/v1/plan.min.js"></script>
<script>
  window.addEventListener("DOMContentLoaded", function () {
    Proteger.config({
      storeId: "protegerが発行した店舗ID",
      logoUrl: "店舗のロゴのURL",
      protegerEnv: "prd",
    });
  });
</script>

<script>
  // DOMContentLoadedでスクリプトを実行し、サイトのロード時間に影響を与えないようにします。
  window.addEventListener("DOMContentLoaded", function () {
    // protegerのオファーを表示する前に、Proteger変数がウィンドウ内に存在するかどうかをチェックします。
    if (window.Proteger && window.ProtegerShopserve) {
      /************************/
      /* Initial Variables */
      /************************/
      const cartFormSelector = "CHANGE_HERE"; // フォーム要素のセレクタに変更(例: .shopping_form )
      const cartAreaSelector = "CHANGE_HERE"; // カートエリアのセレクタに変更(例: #pi_cart )
      const addToCartButtonsSelector = "CHANGE_HERE"; // [カートに追加する]ボタンのセレクタに変更(例: .block_submit_btn )
      const protegerOfferSymbolSelector = "CHANGE_HERE"; // protegerを表示する[上の要素]のセレクタに変更(例: div > .remark, aside > * > .remark )
      const productIdSelector = "CHANGE_HERE"; // 商品番号のセレクタに変更(例: input[name=ITM] )
      const productQuantitySelector = "CHANGE_HERE"; // 商品数量のセレクタに変更(例: .input10 )
      const productTitleSelector = "CHANGE_HERE"; // 商品名のセレクタに変更(e.g. title )

      const ProtegerOfferId = "proteger-offer";

      const cartForm = document.querySelector(cartFormSelector);
      const cartUrl = cartForm && cartForm.action;
      const cartArea = document.querySelector(cartAreaSelector);
      const addToCartButtons = cartArea && cartArea.querySelectorAll(addToCartButtonsSelector);
      const productTitle = document.querySelector(productTitleSelector);
      const protegerOfferSymbol = cartArea && cartArea.querySelector(protegerOfferSymbolSelector);
      const protegerOffer = document.createElement("div"); // プランを表示するシンボルエレメント
      protegerOffer.id = ProtegerOfferId;
      if (protegerOfferSymbol)
        protegerOfferSymbol.parentElement.insertBefore(protegerOffer, protegerOfferSymbol.nextSibling);

      /************************/
      /* initProductOffer */
      /************************/
      // プランの初期化、PDP ATCボタン機能の処理
      function initProductOffer() {
        // safe機能
        if (!cartUrl || !addToCartButtons || !productTitle || !protegerOffer) return;

        // 商品がproteger保証かどうかを確認し、保証の場合はATCを無効化します。
        function isProteger() {
          if (productTitle.textContent.includes("proteger")) {
            addToCartButtons.forEach(function (button) {
              button.disabled = true;
            });
          }
        }

        isProteger();

        // cartForm から productId を取得し、初期プランをレンダリングします。
        const productId = cartForm.querySelector(productIdSelector).value;
        Proteger.buttons.render(ProtegerOfferId, {
          productId: productId,
        });

        //[カートに追加]ボタンのハンドラー
        function handleAddToCart(e) {
          e.preventDefault();
          e.stopImmediatePropagation();

          const quantityEl = cartArea.querySelector(productQuantitySelector);
          const quantity = quantityEl && quantityEl.value;

          // 保証プランコンポーネントを取得
          const component = Proteger.buttons.instance(ProtegerOfferId);

          // 選択された保証プランを取得
          const plan = component.getPlanSelection();

          let index = Array.from(addToCartButtons).indexOf(e.target);

          ProtegerShopserve.addPlanToCart(
            {
              cartUrl: cartUrl,
              productId: productId,
              plan: plan,
              quantity: quantity,
              modal: true,
            },
            function () {
              addToCartButtons[index].removeEventListener("click", handleAddToCart, true);
              addToCartButtons[index].click();
              addToCartButtons[index].addEventListener("click", handleAddToCart, true);
            }
          );
        }

        //ATCをクリックするとhandleAddToCartが実行され、イベントをキャプチャ
        addToCartButtons.forEach((button, index) => {
          button.addEventListener("click", handleAddToCart, true);
        });
      }

      // 初期レンダリング
      initProductOffer();
    }
  });
</script>

  • "protegerが発行した店舗ID" : protger管理画面を開き、「右上の歯車マーク」->「店舗設定」から確認できます。
  • "店舗のロゴのURL" :店舗のロゴ画像リンクを設定してください。
  • "CHANGE_HERE" : 任意の要素で上書きしてください。
    _NOTE:店舗のデザインテーマを大幅にカスタマイズしていない場合は、 "例" の後に記載しているタグをそのまま利用できる可能性があります。
    • cartFormSelectorCHANGE_HERE を、上記で取得したフォームのクラス名に置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に .ピリオドを付けてください。
    • cartAreaSelectorCHANGE_HERE を、上記で取得したカートエリアのクラス名に置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に #シャープを付けてください。
    • addToCartButtonsSelectorCHANGE_HERE を、上記で取得した[カートに追加]ボタンに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に .ピリオドを付けてください。
    • protegerOfferSymbolSelectorCHANGE_HERE を、上記で取得したprotegerを表示する[上の要素]のクラスに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に .ピリオドを付けてください。
    • productIdSelectorCHANGE_HERE を、上記で取得した[商品番号]のクラスに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。name属性の場合はinput[name=Name]としてください。Name部分は保存した値で上書きしてください。
    • productQuantitySelectorCHANGE_HERE を、上記で取得した[商品番号]のクラスに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。前方に .を付けてください。
    • productTitleSelectorCHANGE_HERE を、上記で取得した[商品名]のタグに置き換えます。
      _NOTE: クラス名には css セレクターを使用する必要があります。取得したクラスを適切な構文に変換してください。
  1. 更新したHTMLを貼り付けて 「閉じる」をクリックします。
    _NOTE: shopserveの仕様上「プレビューに反映する」を実行しても、protegerは表示されません。
  1. 「お店ページに反映する」をクリックします。

    ❗️

    Warn

    テーマの反映を行うと本番のサイトに反映されるため、慎重に行ってください。万が一、サイトに不具合が生じた場合は、追記したHTMLを削除してテーマの反映を行ってください。

  1. 設定は完了です。このまま次の確認セクションに進んでください。

確認

  1. 店舗サイトに移動します。
  2. 保証対象製品ページに移動します。
  3. プランが表示されている事を確認します。
  1. モーダルが表示される事を確認します。
  1. 両方のパターンで商品と保証がカートに追加される事を確認します。
  1. 完了です 🎉

📘

NOTE

お困りの際は担当者または下記のメールアドレスにいつでもご連絡下さい。
[email protected]