本ページでは、子注文がフルフィルメントされた時に、親注文を自動でフルフィルメントするShopify Flowの構成と運用手順をご案内します。
以下のFlowファイルをインポートするとShopify Flowを設定できます。
支払い確定方法を「注文全体のフルフィルメントが完了したときに自動で」に設定している場合
ポイント
標準機能では、子注文を発送しても親注文が自動的に発送済みになりません。
関連:支払い確定方法を「注文全体のフルフィルメントが完了したときに自動で」に設定している場合の注意点
親子注文で生成された親注文
関連:親子注文が生成される条件
設定後の実際の動きは以下のとおりです。
子注文が発送される(フルフィルメント作成)と、ワークフローが起動する
起動元の子注文から親注文を特定し、同じ親注文の子注文をすべて取得する
すべての子注文が発送済みであれば、親注文を自動でフルフィルメントする
未発送やキャンセルなどの条件がある場合は、自動処理を行わず終了する
起動タイミングは「子注文の発送ごと」です。最後の子注文が発送された時点で、親注文がフルフィルメントされます。
# | ブロック | 設定 |
|---|---|---|
1 | トリガー | Fulfillment created |
2 | Run code | 子注文のタグ |
3 | Condition | 親注文 ID・親注文番号が空でない |
4 | Get order data | id:{{runCode.parentId}} AND tag:'親注文'(最大10件) |
5 | Get order data | tag:'#{{runCode.parentNumber}}:子注文'(最大100件) |
6 | Run code | 親注文が 1 件・未キャンセル、子注文にキャンセルなし、全子注文が発送済み(起動元はトリガーの値で判定)なら 親注文の ON_HOLD / OPEN のフルフィルメントオーダーを |
7 | Condition | runCode1.shouldFulfill が true |
8 | For each | runCode1.fos の各アイテムで繰り返す |
9 | Condition | fosForeachitem.status が ON_HOLD |
10 | Send Admin API request(9 が True) | fulfillmentOrderReleaseHold |
11 | Send Admin API request(10 の後 / 9 が False) | fulfillmentCreate |
Shopify管理画面 > アプリ > Shopify Flow に進み、ワークフローを作成 をクリック
トリガーに Fulfillment created を選択
Run codeアクションを追加し、以下の3項目の設定を行う
GRAPHQLに以下を設定
query {
fulfillment {
order {
tags
customAttributes { key value }
}
}
}JAVASCRIPTに以下を設定
export default function main(input) {
const order = input.fulfillment.order;
let parentNumber = "";
for (const tag of order.tags || []) {
const m = tag.match(/^#(\d+):子注文$/);
if (m) { parentNumber = m[1]; break; }
}
let parentId = "";
for (const a of order.customAttributes || []) {
if (a.key === "parent_shopify_order_id" && a.value) parentId = a.value.split("/").pop();
}
return { parentNumber, parentId };
}SDLに以下を設定
type Output {
parentNumber: String!
parentId: String!
}このアクションの参照名は runCode になります。
Conditionを追加し、以下を設定
項目 | 設定値 |
|---|---|
条件1・対象 | Parent number( |
条件1・判定 | 空ではなく、存在する |
結合 | AND |
条件2・対象 | Parent id( |
条件2・判定 | 空ではなく、存在する |
分岐の接続:
True: STEP5へ進むFalse: 何もせず終了する
Get order data アクションを追加し、以下を設定
項目 | 設定値 |
|---|---|
検索クエリ | id:{{runCode.parentId}} AND tag:'親注文' |
並び順 | 作成日時(CREATED_AT) の |
最大取得件数 | 10 |
もう1つGet order dataアクションを追加し、以下を設定
項目 | 設定値 |
|---|---|
検索クエリ | tag:'#{{runCode.parentNumber}}:子注文' |
並び順 | 作成日時(CREATED_AT) の |
最大取得件数 | 100 |
Run codeアクションを追加し、以下の3項目の設定を行う
GRAPHQLに以下を設定
query {
fulfillment { order { id displayFulfillmentStatus } }
getOrderData { id cancelledAt fulfillmentOrders { id status } }
getOrderData1 { id cancelledAt displayFulfillmentStatus }
}JAVASCRIPTに以下を設定
export default function main(input) {
const trigger = input.fulfillment.order;
const parents = input.getOrderData || [];
// 検索結果が古い可能性があるので、起動元の子注文はトリガー側の値で上書きする
const children = (input.getOrderData1 || []).map((c) =>
c.id === trigger.id ? Object.assign({}, c, { displayFulfillmentStatus: trigger.displayFulfillmentStatus }) : c
);
const stop = (reason) => ({ shouldFulfill: false, fos: [], reason });
if (parents.length !== 1) return stop("親注文が1件に特定できない: " + parents.length);
if (parents[0].cancelledAt) return stop("親注文がキャンセル済み");
if (children.length >= 100) return stop("子注文が100件以上");
if (!children.some((c) => c.id === trigger.id)) return stop("起動元の子注文が検索結果に無い");
if (children.some((c) => c.cancelledAt)) return stop("キャンセル済みの子注文あり: 手動で金額を調整して確定");
if (!children.every((c) => c.displayFulfillmentStatus === "FULFILLED")) return stop("未発送の子注文が残っている");
const fos = parents[0].fulfillmentOrders || [];
return {
shouldFulfill: true,
fos: fos
.filter((f) => f.status === "ON_HOLD" || f.status === "OPEN")
.map((f) => ({ id: f.id, status: f.status })),
reason: "ok: " + fos.map((f) => f.status).join(","),
};
}SDLに以下を設定
type Fo {
id: ID!
status: String!
}
type Output {
shouldFulfill: Boolean!
fos: [Fo!]!
reason: String!
}判定条件(すべて満たすと shouldFulfill: true):
親注文が1件に特定できる
親注文がキャンセルされていない
子注文が100件未満である
起動元の子注文が検索結果に含まれる
キャンセル済みの子注文がない
すべての子注文が発送済み(
FULFILLED)である
このアクションの参照名は runCode1 になります。
Conditionを追加し、判定がtrueの場合のみフルフィルメント実行に進む
項目 | 設定値 |
|---|---|
条件・対象 | Run code 1 should fulfill( |
条件・判定 | 等しい |
分岐の接続:
True: STEP9へ進むFalse: 何もせず終了する
For eachを追加、判定で対象となったフルフィルメントオーダーを1件ずつ処理する
項目 | 設定値 |
|---|---|
繰り返す対象(リスト) | runCode1.fos |
繰り返しの中にConditionを追加し、フルフィルメントオーダーが保留中(ON_HOLD)かどうかで処理を分ける
項目 | 設定値 |
|---|---|
条件・対象 | Fos foreach item status( |
条件・判定 | 等しい |
分岐の接続:
True: STEP11 → STEP12の順に実行するFalse: STEP13を実行する
Trueの分岐にSend Admin API requestを追加し、保留を解除する
項目 | 設定値 |
|---|---|
操作(API) | fulfillmentOrderReleaseHold |
リクエスト内容:
{ "id": "{{fosForeachitem.id}}" }STEP11の直後にSend Admin API requestを追加し、発送を確定する
項目 | 設定値 |
|---|---|
操作(API) | fulfillmentCreate |
リクエスト内容:
{
"fulfillment": {
"lineItemsByFulfillmentOrder": [{ "fulfillmentOrderId": "{{fosForeachitem.id}}" }],
"notifyCustomer": false
}
}STEP10のFalse分岐にSend Admin API requestを追加し、保留がないフルフィルメントオーダーをそのまま発送確定する
項目 | 設定値 |
|---|---|
操作(API) | fulfillmentCreate |
リクエスト内容:
{
"fulfillment": {
"lineItemsByFulfillmentOrder": [{ "fulfillmentOrderId": "{{fosForeachitem.id}}" }],
"notifyCustomer": false
}
}ポイント
STEP12・13はどちらも発送通知を送りません(notifyCustomer: false)
子注文の発送時に通知する運用を想定しています。
子注文をフルフィルメントする(例:
#1001:子注文のタグが付いた子注文)子注文が複数ある場合は、すべての子注文をフルフィルメントする
対応する親注文(例:
#1001)が発送済みになることを確認するFlowの実行ログで、各ステップが正常に通過しているか確認する