🫥

[Shopify Flowの可能性を探る#1]ノベルティ付与の自動化

2024/12/16に公開

こんにちは。

(ちょっと前ですが、)Admin APIを実行できるようになったり
そろそろ Run Code アクションで fetch が許可されそうみたいな発表も出ていますので!
Shopify Flowの可能性を探る旅にでたいと思います🗿

第1回:Flowでノベルティ付与の自動化をしよう

結論どんな自動化かというと、

  1. 注文が作成される
  2. Flowが発火
  3. どんな注文か条件をチェック
  4. 条件が満たせていたらノベルティ商品を追加
  5. ノベルティ商品が追加されたメールを送付

です。

ポイントになるのは、このノベルティ付与は注文完了後に行われる、ということです。
この方法を選ぶに至って遭遇したIssueは、
某ノベルティを追加するShopifyアプリでは、カート追加がトリガーとなっているため、カート追加時のコンディションしか判別できない。
つまり、カート追加後に発火するFunctionsやCheckout時の変更が反映されないのです。

簡単な具体例を挙げると、

5000円以上10000円未満ならノベルティAを付与
10000円以上ならノベルティBを付与

というキャンペーンがあった時に、1万円以上カートに追加すると当たり前にノベルティBがカートに追加されますが、
チェックアウト時に割引を適用して1万円以下になってもノベルティAに変更が適用されないのです。

その他にもカート追加時トリガーは他の重要なFunctionsとの競合が起きることがあります。(聞いた話で経験はしてませんが、、)

重要なワークフローとの競合から起きるインシデントを避けるため、機能・ビジネス的重要性が比較的高くないノベルティ追加については、注文完了後に追加するという安全策を取りました。

ワークフロー

早速お店するとこんな感じです。
Send Admin API の orderEditBegin => orderEditSetQuantity => orderEditCommit をする必要があるのかと思っていたのですが、Line Itemの追加はデフォルトのアクションでサポートされているようでした🙌🙌

このワークフローはさほど難しいものではなく、解説なんているのかと思っていますが、
Run Code の中身はこのような形で、条件をチェックし、どのノベルティが付与されるのかを返しています。
現状は1キャンペーンでノベルティ自体も二つしかないですが、今後増えることを考えると condition より Run Code でチェックする方が拡張性があると思ってます。
(conditionをGUIで選択していくのがめんどくさい)

次に product object を取得して、実際に Line Itemに追加できるようにするのと、その前段で、在庫が存在しているかをチェックします。
在庫がなければ、単純に在庫が無かったよとインナーでわかるログを出しているだけですが、必要であれば、利用のマーケティングツールでお客様通知の Action を追加すると良いかもです

Add order line item アクションで望みのノベルティを追加し、同時にメール送付も行います。
メールの送付ができたり、重複を許可するかとか、注文のタイムラインを残せたり機能がリッチで驚き🤩

最後にちょっと wait time で休憩してからノベルティが追加されたよ~というタグを注文に付与します(🤔)

所感

シンプルなワークフローでしたね、皆さんの要件に合わせてカスタマイズしてください。
.flowファイルなんて添付できるわけないと分かってたけど、ドラッグ&ドロップしてみたら中身を出力してくれたので添付しときます。
コピーして、.flowの拡張子でファイル保存して、インポートすればできる?のかな?

.flowの中身
ノベルティを付与する.flow
ceba1fc55bf0fec32a59fee3ecc7c024f3095b8e8b379cd304dccba179a37c45:{"__metadata":{"version":0.1},"root":{"steps":[{"step_id":"51cc3f80-ac61-11ef-b6f8-cbafa6e7af7e","step_position":[900,1160],"config_field_values":[],"task_id":"shopify::admin::order_created","task_version":"0.1","task_type":"TRIGGER","description":null,"note":null,"name":null},{"step_id":"b05636a0-ac61-11ef-b6f8-cbafa6e7af7e","step_position":[1260,1160],"config_field_values":[{"config_field_id":"input","value":"query{\n  order{\n    subtotalPriceSet {\n      presentmentMoney {\n        amount\n      }\n    }\n  }\n}"},{"config_field_id":"script","value":"export default function main(input) {\n  // Make sure that the data you return matches the\n  // shape & types defined in the output schema.\n  let subtotalPriceExTax = input.order.subtotalPriceSet.presentmentMoney.amount;\n  console.log(\"subtotalPriceExTax\", subtotalPriceExTax);\n  let novelty = '';\n\n  if (subtotalPriceExTax > 0 && subtotalPriceExTax < 10000) {\n    novelty = 'noveltyA';\n  } else if (subtotalPriceExTax >= 10000) {\n    novelty = 'noveltyB';\n  }\n  \n  return {\n    novelty: novelty,\n  }\n}"},{"config_field_id":"output_schema","value":"\"The output of Run Code\"\ntype Output {\n  \"The message returned by the script\"\n  novelty: String!\n}"}],"task_id":"shopify::flow::run_code","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":"Run code"},{"step_id":"8e013130-ac62-11ef-b6f8-cbafa6e7af7e","step_position":[1620,1160],"config_field_values":[{"config_field_id":"condition","value":"{\"uuid\":\"92b913f2-ac62-11ef-b6f8-cbafa6e7af7e\",\"lhs\":{\"uuid\":\"9035c470-ac62-11ef-b6f8-cbafa6e7af7e\",\"parent_uuid\":\"92b913f2-ac62-11ef-b6f8-cbafa6e7af7e\",\"lhs\":{\"uuid\":\"92b913f0-ac62-11ef-b6f8-cbafa6e7af7e\",\"parent_uuid\":\"9035c470-ac62-11ef-b6f8-cbafa6e7af7e\",\"value\":\"runCode.novelty\",\"comparison_value_type\":\"EnvironmentValue\",\"full_environment_path\":\"runCode.novelty\"},\"rhs\":{\"uuid\":\"ac52ab60-bae9-11ef-a270-077b7c644f68\",\"parent_uuid\":\"9035c470-ac62-11ef-b6f8-cbafa6e7af7e\",\"value\":\"noveltyA\",\"comparison_value_type\":\"LiteralValue\"},\"value_type\":\"EnvironmentScalarDefinition:String\",\"operator\":\"==\",\"operation_type\":\"Comparison\"},\"operator\":\"AND\",\"operation_type\":\"LogicalExpression\"}"}],"task_id":"shopify::flow::condition","task_version":"0.1","task_type":"CONDITION","description":null,"note":null,"name":null},{"step_id":"a0d6d120-ac62-11ef-b6f8-cbafa6e7af7e","step_position":[2740,1220],"config_field_values":[{"config_field_id":"order_id","value":"order.id"},{"config_field_id":"variant_id","value":"gid://shopify/ProductVariant/49600603259197"},{"config_field_id":"quantity","value":"1"},{"config_field_id":"allow_duplicates","value":"false"},{"config_field_id":"notify_customer","value":"true"},{"config_field_id":"staff_note","value":"ノベルティの付与"}],"task_id":"shopify::admin::add_order_line_item","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":null},{"step_id":"b8ff8260-ac62-11ef-b6f8-cbafa6e7af7e","step_position":[2740,1540],"config_field_values":[{"config_field_id":"order_id","value":"order.id"},{"config_field_id":"variant_id","value":"gid://shopify/ProductVariant/49600603259197"},{"config_field_id":"quantity","value":"1"},{"config_field_id":"allow_duplicates","value":"false"},{"config_field_id":"notify_customer","value":"true"},{"config_field_id":"staff_note","value":""}],"task_id":"shopify::admin::add_order_line_item","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":null},{"step_id":"9d9a3500-ac68-11ef-b043-d38bcc3eadc6","step_position":[1980,1160],"config_field_values":[{"config_field_id":"sort_by","value":"{\"sortKey\":\"CREATED_AT\",\"order\":\"ASCENDING\"}"},{"config_field_id":"max_root_records","value":"1"},{"config_field_id":"query","value":"id:\"\""}],"task_id":"shopify::flow::fetch::products","task_version":"v1","task_type":"ACTION","description":null,"note":null,"name":"Get product data"},{"step_id":"c25b6300-ac68-11ef-b043-d38bcc3eadc6","step_position":[2340,1160],"config_field_values":[{"config_field_id":"condition","value":"{\"uuid\":\"d734c234-ac68-11ef-b043-d38bcc3eadc6\",\"lhs\":{\"uuid\":\"d7349b20-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d734c234-ac68-11ef-b043-d38bcc3eadc6\",\"array_path\":{\"uuid\":\"d7349b21-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d7349b20-ac68-11ef-b043-d38bcc3eadc6\",\"value\":\"getProductData\",\"comparison_value_type\":\"EnvironmentValue\"},\"array_item_key\":{\"uuid\":\"d7349b22-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d7349b20-ac68-11ef-b043-d38bcc3eadc6\",\"value\":\"getProductData_item\",\"comparison_value_type\":\"EnvironmentValue\"},\"operation\":{\"uuid\":\"d7349b23-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d7349b20-ac68-11ef-b043-d38bcc3eadc6\",\"array_path\":{\"uuid\":\"d7349b24-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d7349b23-ac68-11ef-b043-d38bcc3eadc6\",\"value\":\"getProductData_item.variants\",\"comparison_value_type\":\"EnvironmentValue\"},\"array_item_key\":{\"uuid\":\"d7349b25-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d7349b23-ac68-11ef-b043-d38bcc3eadc6\",\"value\":\"variants_item\",\"comparison_value_type\":\"EnvironmentValue\"},\"operation\":{\"uuid\":\"d734c230-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d7349b23-ac68-11ef-b043-d38bcc3eadc6\",\"lhs\":{\"uuid\":\"d734c231-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d734c230-ac68-11ef-b043-d38bcc3eadc6\",\"lhs\":{\"uuid\":\"d734c232-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d734c231-ac68-11ef-b043-d38bcc3eadc6\",\"value\":\"variants_item.inventoryQuantity\",\"comparison_value_type\":\"EnvironmentValue\",\"full_environment_path\":\"variants_item.inventoryQuantity\"},\"rhs\":{\"uuid\":\"db3c40b0-ac68-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"d734c231-ac68-11ef-b043-d38bcc3eadc6\",\"value\":\"0\",\"comparison_value_type\":\"LiteralValue\"},\"value_type\":\"EnvironmentScalarDefinition:Int\",\"operator\":\">\",\"operation_type\":\"Comparison\"},\"operator\":\"AND\",\"operation_type\":\"LogicalExpression\"},\"operator\":\"ANY\",\"operation_type\":\"ArrayExpression\"},\"operator\":\"ANY\",\"operation_type\":\"ArrayExpression\"},\"operator\":\"AND\",\"operation_type\":\"LogicalExpression\"}"}],"task_id":"shopify::flow::condition","task_version":"0.1","task_type":"CONDITION","description":null,"note":null,"name":null},{"step_id":"e6289410-ac68-11ef-b043-d38bcc3eadc6","step_position":[2780,1360],"config_field_values":[{"config_field_id":"message","value":"在庫切れのため追加できません"}],"task_id":"shopify::flow::print","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":null},{"step_id":"f3ad6ca0-ac68-11ef-b043-d38bcc3eadc6","step_position":[1980,1400],"config_field_values":[{"config_field_id":"sort_by","value":"{\"sortKey\":\"CREATED_AT\",\"order\":\"ASCENDING\"}"},{"config_field_id":"max_root_records","value":"1"},{"config_field_id":"query","value":"id:\"\""}],"task_id":"shopify::flow::fetch::products","task_version":"v1","task_type":"ACTION","description":null,"note":null,"name":"Get product data (1)"},{"step_id":"26b5d8d0-ac69-11ef-b043-d38bcc3eadc6","step_position":[2340,1400],"config_field_values":[{"config_field_id":"condition","value":"{\"uuid\":\"300df7a7-ac69-11ef-b043-d38bcc3eadc6\",\"lhs\":{\"uuid\":\"300dd090-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300df7a7-ac69-11ef-b043-d38bcc3eadc6\",\"array_path\":{\"uuid\":\"300dd091-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300dd090-ac69-11ef-b043-d38bcc3eadc6\",\"value\":\"getProductData1\",\"comparison_value_type\":\"EnvironmentValue\"},\"array_item_key\":{\"uuid\":\"300dd092-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300dd090-ac69-11ef-b043-d38bcc3eadc6\",\"value\":\"getProductData1_item\",\"comparison_value_type\":\"EnvironmentValue\"},\"operation\":{\"uuid\":\"300df7a0-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300dd090-ac69-11ef-b043-d38bcc3eadc6\",\"array_path\":{\"uuid\":\"300df7a1-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300df7a0-ac69-11ef-b043-d38bcc3eadc6\",\"value\":\"getProductData1_item.variants\",\"comparison_value_type\":\"EnvironmentValue\"},\"array_item_key\":{\"uuid\":\"300df7a2-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300df7a0-ac69-11ef-b043-d38bcc3eadc6\",\"value\":\"variants_item\",\"comparison_value_type\":\"EnvironmentValue\"},\"operation\":{\"uuid\":\"300df7a3-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300df7a0-ac69-11ef-b043-d38bcc3eadc6\",\"lhs\":{\"uuid\":\"300df7a4-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300df7a3-ac69-11ef-b043-d38bcc3eadc6\",\"lhs\":{\"uuid\":\"300df7a5-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300df7a4-ac69-11ef-b043-d38bcc3eadc6\",\"value\":\"variants_item.inventoryQuantity\",\"comparison_value_type\":\"EnvironmentValue\",\"full_environment_path\":\"variants_item.inventoryQuantity\"},\"rhs\":{\"uuid\":\"32d63f60-ac69-11ef-b043-d38bcc3eadc6\",\"parent_uuid\":\"300df7a4-ac69-11ef-b043-d38bcc3eadc6\",\"value\":\"0\",\"comparison_value_type\":\"LiteralValue\"},\"value_type\":\"EnvironmentScalarDefinition:Int\",\"operator\":\">\",\"operation_type\":\"Comparison\"},\"operator\":\"AND\",\"operation_type\":\"LogicalExpression\"},\"operator\":\"ANY\",\"operation_type\":\"ArrayExpression\"},\"operator\":\"ANY\",\"operation_type\":\"ArrayExpression\"},\"operator\":\"AND\",\"operation_type\":\"LogicalExpression\"}"}],"task_id":"shopify::flow::condition","task_version":"0.1","task_type":"CONDITION","description":null,"note":null,"name":null},{"step_id":"3b8c2ac0-ac69-11ef-b043-d38bcc3eadc6","step_position":[2780,1680],"config_field_values":[{"config_field_id":"message","value":"在庫切れのため追加できません"}],"task_id":"shopify::flow::print","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":null},{"step_id":"89914120-ad58-11ef-b44a-674c2546ad17","step_position":[3460,1220],"config_field_values":[{"config_field_id":"order_id","value":"order.id"},{"config_field_id":"tags","value":"[\"ノベルティ追加済\"]"}],"task_id":"shopify::admin::add_order_tags","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":null},{"step_id":"967e1f70-ad58-11ef-b44a-674c2546ad17","step_position":[3460,1540],"config_field_values":[{"config_field_id":"order_id","value":"order.id"},{"config_field_id":"tags","value":"[\"ノベルティ追加済\"]"}],"task_id":"shopify::admin::add_order_tags","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":null},{"step_id":"9dbbc2b0-ad58-11ef-b44a-674c2546ad17","step_position":[3100,1220],"config_field_values":[{"config_field_id":"wait_duration","value":"{\"amount\":\"2\",\"unit\":\"seconds\"}"}],"task_id":"shopify::flow::wait","task_version":"0.1","task_type":"WAIT","description":"メール送信時とのバッテイングを防ぐため","note":null,"name":null},{"step_id":"b51982d0-ad58-11ef-b44a-674c2546ad17","step_position":[3100,1540],"config_field_values":[{"config_field_id":"wait_duration","value":"{\"amount\":\"2\",\"unit\":\"seconds\"}"}],"task_id":"shopify::flow::wait","task_version":"0.1","task_type":"WAIT","description":"メール送信時とのバッテイングを防ぐため","note":null,"name":null}],"links":[{"from_step_id":"51cc3f80-ac61-11ef-b6f8-cbafa6e7af7e","from_port_id":"output","to_step_id":"b05636a0-ac61-11ef-b6f8-cbafa6e7af7e","to_port_id":"input"},{"from_step_id":"b05636a0-ac61-11ef-b6f8-cbafa6e7af7e","from_port_id":"output","to_step_id":"8e013130-ac62-11ef-b6f8-cbafa6e7af7e","to_port_id":"input"},{"from_step_id":"8e013130-ac62-11ef-b6f8-cbafa6e7af7e","from_port_id":"true","to_step_id":"9d9a3500-ac68-11ef-b043-d38bcc3eadc6","to_port_id":"input"},{"from_step_id":"9d9a3500-ac68-11ef-b043-d38bcc3eadc6","from_port_id":"output","to_step_id":"c25b6300-ac68-11ef-b043-d38bcc3eadc6","to_port_id":"input"},{"from_step_id":"c25b6300-ac68-11ef-b043-d38bcc3eadc6","from_port_id":"true","to_step_id":"a0d6d120-ac62-11ef-b6f8-cbafa6e7af7e","to_port_id":"input"},{"from_step_id":"c25b6300-ac68-11ef-b043-d38bcc3eadc6","from_port_id":"false","to_step_id":"e6289410-ac68-11ef-b043-d38bcc3eadc6","to_port_id":"input"},{"from_step_id":"8e013130-ac62-11ef-b6f8-cbafa6e7af7e","from_port_id":"false","to_step_id":"f3ad6ca0-ac68-11ef-b043-d38bcc3eadc6","to_port_id":"input"},{"from_step_id":"f3ad6ca0-ac68-11ef-b043-d38bcc3eadc6","from_port_id":"output","to_step_id":"26b5d8d0-ac69-11ef-b043-d38bcc3eadc6","to_port_id":"input"},{"from_step_id":"26b5d8d0-ac69-11ef-b043-d38bcc3eadc6","from_port_id":"true","to_step_id":"b8ff8260-ac62-11ef-b6f8-cbafa6e7af7e","to_port_id":"input"},{"from_step_id":"26b5d8d0-ac69-11ef-b043-d38bcc3eadc6","from_port_id":"false","to_step_id":"3b8c2ac0-ac69-11ef-b043-d38bcc3eadc6","to_port_id":"input"},{"from_step_id":"a0d6d120-ac62-11ef-b6f8-cbafa6e7af7e","from_port_id":"output","to_step_id":"9dbbc2b0-ad58-11ef-b44a-674c2546ad17","to_port_id":"input"},{"from_step_id":"b8ff8260-ac62-11ef-b6f8-cbafa6e7af7e","from_port_id":"output","to_step_id":"b51982d0-ad58-11ef-b44a-674c2546ad17","to_port_id":"input"},{"from_step_id":"9dbbc2b0-ad58-11ef-b44a-674c2546ad17","from_port_id":"output","to_step_id":"89914120-ad58-11ef-b44a-674c2546ad17","to_port_id":"input"},{"from_step_id":"b51982d0-ad58-11ef-b44a-674c2546ad17","from_port_id":"output","to_step_id":"967e1f70-ad58-11ef-b44a-674c2546ad17","to_port_id":"input"}],"patched_fields":[],"workflow_name":"ノベルティを付与する"}}

忘れ物

通知メール側は、"注文編集メール"が飛びます。
デフォルトのままだと、「注文が更新されました 」という表示ですね。
ちょっと不親切なので、「ノベルティが追加されました」と表示するようにしましょう。
今回の私のストアでは、ノベルティ追加が確実に最初に起こる注文編集なので、

通常系として、「ノベルティが追加されました」

"ノベルティ追加済"タグがあれば、「注文が更新されました 」

を送るようにしています。
これが、(🤔)なぜちょっとwaitしてからタグを追加するのか。の正体です。
(注文完了後すぐに様々注文編集が走るストアさんは別途考慮が必要です。)

メールの件名
注文番号 {{name}} を更新しました{% if tags contains "ノベルティ追加済" %}{% else %}   ノベルティが追加されました  {% endif %}
メールの本文
{% capture email_title %}
 {% if tags contains "ノベルティ追加済" %}
  注文が更新されました 
 {% else %}
  ノベルティが追加されました
 {% endif %}
{% endcapture %}
<!DOCTYPE html>
<html lang="ja">
  <head>
  <title>{{ email_title }}</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <meta name="viewport" content="width=device-width">
  <link rel="stylesheet" type="text/css" href="/assets/notifications/styles.css">
  <style>
    .button__cell { background: {{ shop.email_accent_color }}; }
    a, a:hover, a:active, a:visited { color: {{ shop.email_accent_color }}; }
  </style>
</head>

最後に

私はFlowの可能性を信じているのでどんな困難もFlowと共に乗り越えていきます🚀

ありがとうございました!

株式会社Tsuzucle Tech Blog

Discussion