diff --git a/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/README.md b/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/README.md index 2d5c8569..fb836f3d 100644 --- a/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/README.md +++ b/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/README.md @@ -2,7 +2,7 @@ Tags: Auto-Tag, Customers, Loyalty -Running daily, hourly, or manually, this task scans all customers and tags them based on the date of their last order. Choose between tagging customers whose orders are before x days ago, or after x days ago. +Running daily or manually, this task scans all customers who have placed orders and tags them based on the date of their last order. Choose between tagging customers whose orders are before x days ago, or after x days ago. * View in the task library: [tasks.mechanic.dev/tag-customers-when-their-last-order-is-before-after-x-days-ago](https://tasks.mechanic.dev/tag-customers-when-their-last-order-is-before-after-x-days-ago) * Task JSON, for direct import: [task.json](../../tasks/tag-customers-when-their-last-order-is-before-after-x-days-ago.json) @@ -16,7 +16,6 @@ Running daily, hourly, or manually, this task scans all customers and tags them "tag_customers_when_last_order_is_after__boolean": true, "tag_customers_when_last_order_is_before__boolean": null, "customer_tag__required": "recent-customer", - "run_hourly__boolean": false, "run_daily__boolean": false } ``` @@ -28,10 +27,7 @@ Running daily, hourly, or manually, this task scans all customers and tags them ```liquid mechanic/user/trigger mechanic/shopify/bulk_operation - -{% if options.run_hourly__boolean %} - mechanic/scheduler/hourly -{% elsif options.run_daily__boolean %} +{% if options.run_daily__boolean %} mechanic/scheduler/daily {% endif %} ``` @@ -40,7 +36,7 @@ mechanic/shopify/bulk_operation ## Documentation -Running daily, hourly, or manually, this task scans all customers and tags them based on the date of their last order. Choose between tagging customers whose orders are before x days ago, or after x days ago. +Running daily or manually, this task scans all customers who have placed orders and tags them based on the date of their last order. Choose between tagging customers whose orders are before x days ago, or after x days ago. ## Installing this task diff --git a/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/script.liquid b/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/script.liquid index 45ffab20..82c65bbf 100644 --- a/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/script.liquid +++ b/docs/tag-customers-when-their-last-order-is-before-after-x-days-ago/script.liquid @@ -1,32 +1,58 @@ -{% comment %} - Preferred option order: +{% assign days_since_last_order = options.days_since_last_order__required_number %} +{% assign tag_customers_when_last_order_is_after = options.tag_customers_when_last_order_is_after__boolean %} +{% assign tag_customers_when_last_order_is_before = options.tag_customers_when_last_order_is_before__boolean %} +{% assign customer_tag_to_apply = options.customer_tag_to_apply__required %} - {{ options.days_since_last_order__required_number }} - {{ options.tag_customers_when_last_order_is_after__boolean }} - {{ options.tag_customers_when_last_order_is_before__boolean }} - {{ options.customer_tag__required }} -{% endcomment %} - -{% if options.tag_customers_when_last_order_is_after__boolean and options.tag_customers_when_last_order_is_before__boolean %} +{% if tag_customers_when_last_order_is_after and tag_customers_when_last_order_is_before %} {% error "Choose only one of 'Tag customers when last order is after' or 'Tag customers when last order is before' :)" %} -{% elsif options.tag_customers_when_last_order_is_after__boolean == false and options.tag_customers_when_last_order_is_before__boolean == false %} +{% endif %} + +{% unless tag_customers_when_last_order_is_after or tag_customers_when_last_order_is_before %} {% error "Choose either 'Tag customers when last order is after' or 'Tag customers when last order is before'" %} +{% endunless %} + +{% capture advance_period -%} + -{{ days_since_last_order }} days +{%- endcapture %} + +{% assign order_processed_at_threshold = "now" | date: "%F", advance: advance_period %} + +{% if tag_customers_when_last_order_is_after %} + {% log %} + "Threshold for tagging customers: {{ order_processed_at_threshold }} and after" + {% endlog %} + +{% elsif tag_customers_when_last_order_is_before %} + {% log %} + "Threshold for tagging customers: {{ order_processed_at_threshold }} and before" + {% endlog %} {% endif %} {% if event.topic == "mechanic/user/trigger" or event.topic contains "mechanic/scheduler/" %} + {% comment %} + -- get IDs of all customers who have placed an order after or before the threshold, and/or have the configured tag + -- due to limited data in customer segments, the bulk op query only serves to reduce the overall count of customers being reviewed + {% endcomment %} + + {% if tag_customers_when_last_order_is_after %} + {% capture customer_segment_query -%} + last_order_date >= {{ order_processed_at_threshold }} OR customer_tags CONTAINS '{{ customer_tag_to_apply }}' + {%- endcapture %} + + {% elsif tag_customers_when_last_order_is_before %} + {% capture customer_segment_query -%} + last_order_date <= {{ order_processed_at_threshold }} OR customer_tags CONTAINS '{{ customer_tag_to_apply }}' + {%- endcapture %} + {% endif %} + {% capture bulk_operation_query %} query { - customers( - sortKey: LAST_ORDER_DATE - query: "orders_count:>0" + customerSegmentMembers( + query: {{ customer_segment_query | json }} ) { edges { node { id - tags - lastOrder { - processedAt - } } } } @@ -49,105 +75,130 @@ } } {% endaction %} -{% elsif event.topic == "mechanic/shopify/bulk_operation" %} - {% assign order_processed_at_interval_s = options.days_since_last_order__required_number | times: 24 | times: 60 | times: 60 %} - {% assign order_processed_at_threshold_s = "now" | date: "%s" | minus: order_processed_at_interval_s %} - {% assign order_processed_at_threshold_human = order_processed_at_threshold_s | date: "%Y-%m-%d %H:%M %:z" %} - - {% log %}{{ "Threshold for tagging customers: " | append: order_processed_at_threshold_human | json }}{% endlog %} +{% elsif event.topic == "mechanic/shopify/bulk_operation" %} {% if event.preview %} + {% capture jsonl_string %} + {"id":"gid:\/\/shopify\/CustomerSegmentMember\/1234567890"} + {"id":"gid:\/\/shopify\/CustomerSegmentMember\/2345678901"} + {% endcapture %} + {% assign bulkOperation = hash %} - {% assign bulkOperation["objects"] = array %} - {% assign bulkOperation["objects"][0] = hash %} - {% assign bulkOperation["objects"][0]["id"] = "gid://shopify/Customer/1234567890" %} - {% assign bulkOperation["objects"][0]["tags"] = "" %} - {% assign bulkOperation["objects"][0]["lastOrder"] = hash %} - - {% if options.tag_customers_when_last_order_is_after__boolean %} - {% assign bulkOperation["objects"][0]["lastOrder"]["processedAt"] = order_processed_at_threshold_s | plus: 1 | date: "%FT%T%:z" %} - {% elsif options.tag_customers_when_last_order_is_before__boolean %} - {% assign bulkOperation["objects"][0]["lastOrder"]["processedAt"] = order_processed_at_threshold_s | minus: 1 | date: "%FT%T%:z" %} - {% endif %} + {% assign bulkOperation["objects"] = jsonl_string | parse_jsonl %} {% endif %} - {% assign customers = bulkOperation.objects %} + {% assign customer_segment_member_ids = bulkOperation.objects | map: "id" %} - {% for customer in customers %} - {% if customer.lastOrder == nil %} - {% continue %} - {% endif %} + {% comment %} + -- get tags and last order data from customer resource, since it's not available in customer segments + {% endcomment %} - {% assign customer_should_be_tagged = false %} + {% for customer_segment_member_id in customer_segment_member_ids %} + {% assign customer_should_be_tagged = nil %} - {% assign customer_last_order_processed_at_s = customer.lastOrder.processedAt | date: "%s" | times: 1 %} + {% capture query %} + query { + customer(id: {{ customer_segment_member_id | remove: "SegmentMember" | json }}) { + id + tags + lastOrder { + processedAt + } + } + } + {% endcapture %} + + {% assign result = query | shopify %} + + {% if event.preview %} + {% capture result_json %} + { + "data": { + "customer": { + "id": "gid://shopify/Customer/1234567890", + "lastOrder": { + {% if tag_customers_when_last_order_is_after %} + "processedAt": {{ "now" | date: "%F" | json }} + {% elsif tag_customers_when_last_order_is_before %} + "processedAt": "2000-01-01" + {% endif %} + } + } + } + } + {% endcapture %} + + {% assign result = result_json | parse_json %} + {% endif %} - {% if options.tag_customers_when_last_order_is_after__boolean and customer_last_order_processed_at_s >= order_processed_at_threshold_s %} + {% assign customer = result.data.customer %} + {% assign customer_last_order_processed_at = customer.lastOrder.processedAt | date: "%F" %} + + {% if tag_customers_when_last_order_is_after and customer_last_order_processed_at >= order_processed_at_threshold %} {% assign customer_should_be_tagged = true %} - {% elsif options.tag_customers_when_last_order_is_before__boolean and customer_last_order_processed_at_s <= order_processed_at_threshold_s %} + {% elsif tag_customers_when_last_order_is_before and customer_last_order_processed_at <= order_processed_at_threshold %} {% assign customer_should_be_tagged = true %} {% endif %} - {% assign customer_tags = customer.tags %} - {% assign customer_is_tagged = false %} - {% if customer_tags contains options.customer_tag__required %} - {% assign customer_is_tagged = true %} - {% endif %} + {% comment %} + -- add and remove customer tags as needed + {% endcomment %} - {% if customer_should_be_tagged and customer_is_tagged %} - {% comment %}no-op{% endcomment %} - {% elsif customer_should_be_tagged and customer_is_tagged == false %} - {% action "shopify" %} - mutation { - tagsAdd( - id: {{ customer.id | json }} - tags: {{ options.customer_tag__required | json }} - ) { - node { - ... on Customer { - id - email - tags - lastOrder { - name - processedAt + {% if customer_should_be_tagged %} + {% unless customer.tags contains customer_tag_to_apply %} + {% action "shopify" %} + mutation { + tagsAdd( + id: {{ customer.id | json }} + tags: {{ customer_tag_to_apply | json }} + ) { + node { + ... on Customer { + id + email + tags + lastOrder { + name + processedAt + } } } - } - userErrors { - field - message + userErrors { + field + message + } } } - } - {% endaction %} - {% elsif customer_should_be_tagged == false and customer_is_tagged %} - {% action "shopify" %} - mutation { - tagsRemove( - id: {{ customer.id | json }} - tags: {{ options.customer_tag__required | json }} - ) { - node { - ... on Customer { - id - email - tags - lastOrder { - name - processedAt + {% endaction %} + {% endunless %} + + {% else %} + {% if customer.tags contains customer_tag_to_apply %} + {% action "shopify" %} + mutation { + tagsRemove( + id: {{ customer.id | json }} + tags: {{ customer_tag_to_apply | json }} + ) { + node { + ... on Customer { + id + email + tags + lastOrder { + name + processedAt + } } } - } - userErrors { - field - message + userErrors { + field + message + } } } - } - {% endaction %} - {% elsif customer_should_be_tagged == false and customer_is_tagged == false %} - {% comment %}no-op{% endcomment %} + {% endaction %} + {% endif %} {% endif %} {% endfor %} {% endif %} diff --git a/tasks/tag-customers-when-their-last-order-is-before-after-x-days-ago.json b/tasks/tag-customers-when-their-last-order-is-before-after-x-days-ago.json index 43cfc5b1..51a4bded 100644 --- a/tasks/tag-customers-when-their-last-order-is-before-after-x-days-ago.json +++ b/tasks/tag-customers-when-their-last-order-is-before-after-x-days-ago.json @@ -1,5 +1,5 @@ { - "docs": "Running daily, hourly, or manually, this task scans all customers and tags them based on the date of their last order. Choose between tagging customers whose orders are before x days ago, or after x days ago.", + "docs": "Running daily or manually, this task scans all customers who have placed orders and tags them based on the date of their last order. Choose between tagging customers whose orders are before x days ago, or after x days ago.", "halt_action_run_sequence_on_error": false, "name": "Tag customers when their last order is before/after x days ago", "online_store_javascript": null, @@ -8,17 +8,16 @@ "tag_customers_when_last_order_is_after__boolean": true, "tag_customers_when_last_order_is_before__boolean": null, "customer_tag__required": "recent-customer", - "run_hourly__boolean": false, "run_daily__boolean": false }, "order_status_javascript": null, "perform_action_runs_in_sequence": false, - "script": "{% comment %}\n Preferred option order:\n\n {{ options.days_since_last_order__required_number }}\n {{ options.tag_customers_when_last_order_is_after__boolean }}\n {{ options.tag_customers_when_last_order_is_before__boolean }}\n {{ options.customer_tag__required }}\n{% endcomment %}\n\n{% if options.tag_customers_when_last_order_is_after__boolean and options.tag_customers_when_last_order_is_before__boolean %}\n {% error \"Choose only one of 'Tag customers when last order is after' or 'Tag customers when last order is before' :)\" %}\n{% elsif options.tag_customers_when_last_order_is_after__boolean == false and options.tag_customers_when_last_order_is_before__boolean == false %}\n {% error \"Choose either 'Tag customers when last order is after' or 'Tag customers when last order is before'\" %}\n{% endif %}\n\n{% if event.topic == \"mechanic/user/trigger\" or event.topic contains \"mechanic/scheduler/\" %}\n {% capture bulk_operation_query %}\n query {\n customers(\n sortKey: LAST_ORDER_DATE\n query: \"orders_count:>0\"\n ) {\n edges {\n node {\n id\n tags\n lastOrder {\n processedAt\n }\n }\n }\n }\n }\n {% endcapture %}\n\n {% action \"shopify\" %}\n mutation {\n bulkOperationRunQuery(\n query: {{ bulk_operation_query | json }}\n ) {\n bulkOperation {\n id\n status\n }\n userErrors {\n field\n message\n }\n }\n }\n {% endaction %}\n{% elsif event.topic == \"mechanic/shopify/bulk_operation\" %}\n {% assign order_processed_at_interval_s = options.days_since_last_order__required_number | times: 24 | times: 60 | times: 60 %}\n {% assign order_processed_at_threshold_s = \"now\" | date: \"%s\" | minus: order_processed_at_interval_s %}\n {% assign order_processed_at_threshold_human = order_processed_at_threshold_s | date: \"%Y-%m-%d %H:%M %:z\" %}\n\n {% log %}{{ \"Threshold for tagging customers: \" | append: order_processed_at_threshold_human | json }}{% endlog %}\n\n {% if event.preview %}\n {% assign bulkOperation = hash %}\n {% assign bulkOperation[\"objects\"] = array %}\n {% assign bulkOperation[\"objects\"][0] = hash %}\n {% assign bulkOperation[\"objects\"][0][\"id\"] = \"gid://shopify/Customer/1234567890\" %}\n {% assign bulkOperation[\"objects\"][0][\"tags\"] = \"\" %}\n {% assign bulkOperation[\"objects\"][0][\"lastOrder\"] = hash %}\n\n {% if options.tag_customers_when_last_order_is_after__boolean %}\n {% assign bulkOperation[\"objects\"][0][\"lastOrder\"][\"processedAt\"] = order_processed_at_threshold_s | plus: 1 | date: \"%FT%T%:z\" %}\n {% elsif options.tag_customers_when_last_order_is_before__boolean %}\n {% assign bulkOperation[\"objects\"][0][\"lastOrder\"][\"processedAt\"] = order_processed_at_threshold_s | minus: 1 | date: \"%FT%T%:z\" %}\n {% endif %}\n {% endif %}\n\n {% assign customers = bulkOperation.objects %}\n\n {% for customer in customers %}\n {% if customer.lastOrder == nil %}\n {% continue %}\n {% endif %}\n\n {% assign customer_should_be_tagged = false %}\n\n {% assign customer_last_order_processed_at_s = customer.lastOrder.processedAt | date: \"%s\" | times: 1 %}\n\n {% if options.tag_customers_when_last_order_is_after__boolean and customer_last_order_processed_at_s >= order_processed_at_threshold_s %}\n {% assign customer_should_be_tagged = true %}\n {% elsif options.tag_customers_when_last_order_is_before__boolean and customer_last_order_processed_at_s <= order_processed_at_threshold_s %}\n {% assign customer_should_be_tagged = true %}\n {% endif %}\n\n {% assign customer_tags = customer.tags %}\n {% assign customer_is_tagged = false %}\n {% if customer_tags contains options.customer_tag__required %}\n {% assign customer_is_tagged = true %}\n {% endif %}\n\n {% if customer_should_be_tagged and customer_is_tagged %}\n {% comment %}no-op{% endcomment %}\n {% elsif customer_should_be_tagged and customer_is_tagged == false %}\n {% action \"shopify\" %}\n mutation {\n tagsAdd(\n id: {{ customer.id | json }}\n tags: {{ options.customer_tag__required | json }}\n ) {\n node {\n ... on Customer {\n id\n email\n tags\n lastOrder {\n name\n processedAt\n }\n }\n }\n userErrors {\n field\n message\n }\n }\n }\n {% endaction %}\n {% elsif customer_should_be_tagged == false and customer_is_tagged %}\n {% action \"shopify\" %}\n mutation {\n tagsRemove(\n id: {{ customer.id | json }}\n tags: {{ options.customer_tag__required | json }}\n ) {\n node {\n ... on Customer {\n id\n email\n tags\n lastOrder {\n name\n processedAt\n }\n }\n }\n userErrors {\n field\n message\n }\n }\n }\n {% endaction %}\n {% elsif customer_should_be_tagged == false and customer_is_tagged == false %}\n {% comment %}no-op{% endcomment %}\n {% endif %}\n {% endfor %}\n{% endif %}", + "script": "{% assign days_since_last_order = options.days_since_last_order__required_number %}\n{% assign tag_customers_when_last_order_is_after = options.tag_customers_when_last_order_is_after__boolean %}\n{% assign tag_customers_when_last_order_is_before = options.tag_customers_when_last_order_is_before__boolean %}\n{% assign customer_tag_to_apply = options.customer_tag_to_apply__required %}\n\n{% if tag_customers_when_last_order_is_after and tag_customers_when_last_order_is_before %}\n {% error \"Choose only one of 'Tag customers when last order is after' or 'Tag customers when last order is before' :)\" %}\n{% endif %}\n\n{% unless tag_customers_when_last_order_is_after or tag_customers_when_last_order_is_before %}\n {% error \"Choose either 'Tag customers when last order is after' or 'Tag customers when last order is before'\" %}\n{% endunless %}\n\n{% capture advance_period -%}\n -{{ days_since_last_order }} days\n{%- endcapture %}\n\n{% assign order_processed_at_threshold = \"now\" | date: \"%F\", advance: advance_period %}\n\n{% if tag_customers_when_last_order_is_after %}\n {% log %}\n \"Threshold for tagging customers: {{ order_processed_at_threshold }} and after\"\n {% endlog %}\n\n{% elsif tag_customers_when_last_order_is_before %}\n {% log %}\n \"Threshold for tagging customers: {{ order_processed_at_threshold }} and before\"\n {% endlog %}\n{% endif %}\n\n{% if event.topic == \"mechanic/user/trigger\" or event.topic contains \"mechanic/scheduler/\" %}\n {% comment %}\n -- get IDs of all customers who have placed an order after or before the threshold, and/or have the configured tag\n -- due to limited data in customer segments, the bulk op query only serves to reduce the overall count of customers being reviewed\n {% endcomment %}\n\n {% if tag_customers_when_last_order_is_after %}\n {% capture customer_segment_query -%}\n last_order_date >= {{ order_processed_at_threshold }} OR customer_tags CONTAINS '{{ customer_tag_to_apply }}'\n {%- endcapture %}\n\n {% elsif tag_customers_when_last_order_is_before %}\n {% capture customer_segment_query -%}\n last_order_date <= {{ order_processed_at_threshold }} OR customer_tags CONTAINS '{{ customer_tag_to_apply }}'\n {%- endcapture %}\n {% endif %}\n\n {% capture bulk_operation_query %}\n query {\n customerSegmentMembers(\n query: {{ customer_segment_query | json }}\n ) {\n edges {\n node {\n id\n }\n }\n }\n }\n {% endcapture %}\n\n {% action \"shopify\" %}\n mutation {\n bulkOperationRunQuery(\n query: {{ bulk_operation_query | json }}\n ) {\n bulkOperation {\n id\n status\n }\n userErrors {\n field\n message\n }\n }\n }\n {% endaction %}\n\n{% elsif event.topic == \"mechanic/shopify/bulk_operation\" %}\n {% if event.preview %}\n {% capture jsonl_string %}\n {\"id\":\"gid:\\/\\/shopify\\/CustomerSegmentMember\\/1234567890\"}\n {\"id\":\"gid:\\/\\/shopify\\/CustomerSegmentMember\\/2345678901\"}\n {% endcapture %}\n\n {% assign bulkOperation = hash %}\n {% assign bulkOperation[\"objects\"] = jsonl_string | parse_jsonl %}\n {% endif %}\n\n {% assign customer_segment_member_ids = bulkOperation.objects | map: \"id\" %}\n\n {% comment %}\n -- get tags and last order data from customer resource, since it's not available in customer segments\n {% endcomment %}\n\n {% for customer_segment_member_id in customer_segment_member_ids %}\n {% assign customer_should_be_tagged = nil %}\n\n {% capture query %}\n query {\n customer(id: {{ customer_segment_member_id | remove: \"SegmentMember\" | json }}) {\n id\n tags\n lastOrder {\n processedAt\n }\n }\n }\n {% endcapture %}\n\n {% assign result = query | shopify %}\n\n {% if event.preview %}\n {% capture result_json %}\n {\n \"data\": {\n \"customer\": {\n \"id\": \"gid://shopify/Customer/1234567890\",\n \"lastOrder\": {\n {% if tag_customers_when_last_order_is_after %}\n \"processedAt\": {{ \"now\" | date: \"%F\" | json }}\n {% elsif tag_customers_when_last_order_is_before %}\n \"processedAt\": \"2000-01-01\"\n {% endif %}\n }\n }\n }\n }\n {% endcapture %}\n\n {% assign result = result_json | parse_json %}\n {% endif %}\n\n {% assign customer = result.data.customer %}\n {% assign customer_last_order_processed_at = customer.lastOrder.processedAt | date: \"%F\" %}\n\n {% if tag_customers_when_last_order_is_after and customer_last_order_processed_at >= order_processed_at_threshold %}\n {% assign customer_should_be_tagged = true %}\n {% elsif tag_customers_when_last_order_is_before and customer_last_order_processed_at <= order_processed_at_threshold %}\n {% assign customer_should_be_tagged = true %}\n {% endif %}\n\n {% comment %}\n -- add and remove customer tags as needed\n {% endcomment %}\n\n {% if customer_should_be_tagged %}\n {% unless customer.tags contains customer_tag_to_apply %}\n {% action \"shopify\" %}\n mutation {\n tagsAdd(\n id: {{ customer.id | json }}\n tags: {{ customer_tag_to_apply | json }}\n ) {\n node {\n ... on Customer {\n id\n email\n tags\n lastOrder {\n name\n processedAt\n }\n }\n }\n userErrors {\n field\n message\n }\n }\n }\n {% endaction %}\n {% endunless %}\n\n {% else %}\n {% if customer.tags contains customer_tag_to_apply %}\n {% action \"shopify\" %}\n mutation {\n tagsRemove(\n id: {{ customer.id | json }}\n tags: {{ customer_tag_to_apply | json }}\n ) {\n node {\n ... on Customer {\n id\n email\n tags\n lastOrder {\n name\n processedAt\n }\n }\n }\n userErrors {\n field\n message\n }\n }\n }\n {% endaction %}\n {% endif %}\n {% endif %}\n {% endfor %}\n{% endif %}\n", "subscriptions": [ "mechanic/user/trigger", "mechanic/shopify/bulk_operation" ], - "subscriptions_template": "mechanic/user/trigger\nmechanic/shopify/bulk_operation\n\n{% if options.run_hourly__boolean %}\n mechanic/scheduler/hourly\n{% elsif options.run_daily__boolean %}\n mechanic/scheduler/daily\n{% endif %}", + "subscriptions_template": "mechanic/user/trigger\nmechanic/shopify/bulk_operation\n{% if options.run_daily__boolean %}\n mechanic/scheduler/daily\n{% endif %}", "tags": [ "Auto-Tag", "Customers",