こんにちは。
ディレクターの田辺です。
今回は、こちらの記事で予告した、
Shopify FlowのRun codeを利用して、1人の顧客が、特定の期間内に、特定の商品を、何個購入できるかを規制する
を実装してみたので、そのShopify Flowをご紹介します。
なお、本記事で紹介するShopify Flowは十分に検証しておりません。
実際にご利用になったり、参考にされたりする場合は、十分に動作検証することをおすすめします。
準備
1人の顧客が、特定の期間内に、特定の商品を、何個購入できるか、を指定するため、商品にメタフィールドを設定します。今回は下記のように設定しました。
メタフィールド | 商品 |
ネームスペース | custom |
キー | purchase_condition |
型 | meta object※詳細は後述 |
meta objectの利用
Run codeにおけるmeta object(メタオブジェクト)の利用の仕方について、あまりドキュメントがないようだったのでトライアルも兼ねて、今回はmeta objectを利用します。
meta objectの内容
タイプ | purchase_condition |
field1 ネーム | 期間 |
field1 キー | period |
field1 型 | 整数 |
field2 ネーム | 個数 |
field2 キー | quantity |
field2 型 | 整数 |
期間 (period) に、過去何日間分のデータを集計するかの情報を、
個数 (quantity) に、「期間」中に何個購入できるかの情報を、
登録します。
例えば、過去30日間に3個まで購入可能な商品であれば、
期間 (period) が、30
個数 (quantity) が、3
となります。
メタフィールドとメタオブジェクトの準備ができたら、適当な商品を見繕って、購入制限情報を設定します。
実装
早速ですが、下図のようなShopify Flowになります。
- トリガー:
Order created
- アクション:
Run code
- 条件:
Run code
のisHold
がtrue
であれば - アクション:
Hold fulfillment order
Run codeの内容
入力
query{
order{
createdAt
lineItems {
quantity
product {
id
metafields {
namespace
key
reference {
...on Metaobject {
fields {
key
value
}
}
}
}
}
}
customer {
orders {
createdAt
lineItems {
quantity
product {
id
}
}
}
}
}
}
Run codeにて、meta objectを取り出すには、下記のようにします。
metafields {
namespace
key
reference {
...on Metaobject {
fields {
key
value
}
}
}
}
referenceを利用するのが肝です。
なお、meta objectの「リスト」をメタフィールドに設定している場合は、おそらく、referenceではなくreferencesを利用します。(検証はしておりません。)
コード
export default function main(input) {
const lineItems = input.order.lineItems;
const customerOrders = input.order.customer.orders;
const lastDate = new Date(input.order.createdAt);
const META_FIELD_NAMESPACE = "custom";
const META_FIELD_KEY = "purchase_condition";
const productsWithConditios = lineItems.map(lineItem => {
const metafields = lineItem.product.metafields;
const metaObject = metafields.reduce((obj, metafield) => {
if (metafield.namespace === META_FIELD_NAMESPACE && metafield.key === META_FIELD_KEY && metafield.reference) {
obj = metafield.reference.Metaobject.fields.reduce((acc, cur) => {
acc[cur.key] = cur.value;
return acc;
},{});
return obj;
}
},{});
if (metaObject) {
return {
id: lineItem.product.id,
quantity: lineItem.quantity,
period: metaObject.period,
limitQuantity: metaObject.quantity
}
}
}).filter(Boolean);
const unavailableProducts = productsWithConditios.map(product => {
const firstDate = lastDate;
firstDate.setDate(lastDate.getDate() - product.period);
const totalQuantity = customerOrders.reduce((init, order) => {
const orderCreatedAt = new Date(order.createdAt);
if ((orderCreatedAt.getTime() - firstDate.getTime()) >= 0) {
const targetProducts = order.lineItems.filter(lineItem => lineItem.product.id === product.id);
if (targetProducts.length >= 1) {
init = init + targetProducts.reduce((q, targetProduct) => {
q = q + targetProduct.quantity;
return q;
},0);
}
}
return init;
},0);
if (totalQuantity > product.limitQuantity) {
product.totalQuantity = totalQuantity;
return product;
}
}).filter(Boolean)
return {
isHold: unavailableProducts.length > 0 ? true : false,
unavailableProducts: unavailableProducts
}
}
処理のポイントは下記です。
- 最新の注文の作成日時を基準日時(lastDate)として考えます。
- その基準日時から、meta objectに指定した「期間」を引いた日時(firstDate)までが、集計期間になります。
- 最新の注文に、meta objectが指定してある商品があれば処理を行います。
- 最新の注文に含まれるmeta objectが指定してある商品ごとに、顧客の注文履歴をチェックします。
- チェックする顧客の注文履歴は「集計期間内」のものだけです。
- 集計期間中にmeta objectが設定されている商品を何個購入したか、を集計します。
- もし、集計結果がmeta objectに指定した「個数」を超える場合は、その商品情報を配列に格納します。
- 上記の配列の長さが0より大きい場合、isHoldフラグをtrueにし、そうでなければ、falseにします。
出力
type Output {
isHold: Boolean!
unavailableProducts: [Product!]
}
type Product {
id: ID!
quantity: Int!
period: Int!
limitQuantity: Int!
totalQuantity: Int!
}
Run codeの返り値のサンプルと説明は下記です。
runCode = {
isHold: true, // 発送を保留するかどうかのフラグ
unavailableProducts: [ // 購入制限に引っかかった商品群
{
id: "gid://shopify/Product/xxxxxxxxxxxx", // 商品ID
quantity: 2, // 今回購入された個数
period: 30, // 集計期間
limitQuantity: 3, // 制限個数
totalQuantity: 4 // 集計期間中の購入個数
}
]
}
今回は、 runCode.isHold
しか、Shopify Flowでの制御に利用していませんが、ストアオーナーにアラート通知を送るようにした場合に、 runCode.unavailableProducts
を利用することで、どの商品が、どれくらいの個数オーバーして発送保留になったかを記載することもできます。
まとめ
こちらの記事で予告してから、本記事を執筆するまで1年もかかってしまいました。
時が経つのは早いものです。
さて、Run Codeには、
- 現在時刻を参照できない (
new Date()
の結果が現在時刻にならない ) - 外部APIをコールできない
などの制限があります。
1年前の時点では、2024のQ3には外部APIコールができるようになるロードマップだったと思うのですが、今も実装されていないということはロードマップから削除されたのかもしれません。
なお、Run codeを利用する上で参考になる「利用例(テンプレート)」が公開されているので、そちらも参考にすると、よりRun codeを有効活用できるかと思います。
利用例(テンプレート): https://help.shopify.com/ja/manual/shopify-flow/reference/actions/run-code#templates
それでは。