Description
Issue summary
Before opening this issue, I have:
- Upgraded to the latest version of the package
shopify_api
version: 2024-01- Ruby version: 3.2.3
- Operating system: Ubuntu 22.04 LTS
- Set
log_level: :debug
in my configuration, if applicable - Found a reliable way to reproduce the problem that indicates it's a problem with the package
- Looked for similar issues in this repository
- Checked that this isn't an issue with a Shopify API
- If it is, please create a post in the Shopify community forums or report it to Shopify Partner Support
When updating a customer's email marketing consent state, the Shopify API seems to require both the state
and opt_in_level
. However, if the opt_in_level
does not change, the gem does not send up the opt_in_level
part of the hash, which results in a 422.
Aside: The process of updating a customer's email marketing consent is not well documented. The official REST docs have an example titled "update a customer's marketing opt-in state" but it uses the old, deprecated parameters.
Expected behavior
The gem should send up all required parameters, regardless of whether or not they change.
Actual behavior
The gem only sends up fields that change, this makes it impossible to update a customer's email marketing consent state when the opt-in level doesn't change.
Steps to reproduce the problem
- Fetch a customer from Shopify
- Create a new hash for the
email_marketing_consent
field that contains all the same attributes, but a differentstate
(e.g. use "subscribed" if the customer was not subscribed) - Try to save the customer
Alternatively, try adding these tests to the test/rest/2024_01/customer_test.rb
file.
The first test is a "control" to ensure the test works as expected when the opt-in level changes. This test should pass.
sig do
void
end
def test_x_control
session = ShopifyAPI::Auth::Session.new(
shop: "test-shop.myshopify.io",
access_token: "this_is_a_test_token"
)
# Simulate fetching an existing customer via the API:
customer = ShopifyAPI::Customer.create_instance(
session: session,
data: {
"id" => 207119551,
"email_marketing_consent" => {
"state" => "not_subscribed",
"opt_in_level" => "confirmed_opt_in",
"consent_updated_at" => "2023-01-01T00:00:00.000Z"
}
}
)
# Stub update with full `email_marketing_consent` hash included:
stub_request(:put, "https://test-shop.myshopify.io/admin/api/2024-01/customers/207119551.json")
.with(
# This stub matches because `opt_in_level` changes.
body: { "customer" => hash_including({"email_marketing_consent" => {"state" => "subscribed", "opt_in_level" => "single_opt_in", "consent_updated_at" => "2024-01-01T00:00:00.000Z"}}) }
)
.to_return(status: 200, body: JSON.generate({"customer" => {"email" => "[email protected]", "first_name" => "Bob", "last_name" => "Norman", "id" => 207119551, "accepts_marketing" => false, "created_at" => "2024-01-02T09:24:29-05:00", "updated_at" => "2024-01-02T09:24:29-05:00", "orders_count" => 1, "state" => "disabled", "total_spent" => "199.65", "last_order_id" => 450789469, "note" => nil, "verified_email" => true, "multipass_identifier" => nil, "tax_exempt" => false, "tags" => "L\u00E9on, No\u00EBl", "last_order_name" => "#1001", "currency" => "USD", "phone" => "+16136120707", "addresses" => [{"id" => 207119551, "customer_id" => 207119551, "first_name" => nil, "last_name" => nil, "company" => nil, "address1" => "Chestnut Street 92", "address2" => "", "city" => "Louisville", "province" => "Kentucky", "country" => "United States", "zip" => "40202", "phone" => "555-625-1199", "name" => "", "province_code" => "KY", "country_code" => "US", "country_name" => "United States", "default" => true}], "accepts_marketing_updated_at" => "2005-06-12T11:57:11-04:00", "marketing_opt_in_level" => nil, "tax_exemptions" => [], "email_marketing_consent" => {"state" => "not_subscribed", "opt_in_level" => nil, "consent_updated_at" => "2004-06-13T11:57:11-04:00"}, "sms_marketing_consent" => {"state" => "not_subscribed", "opt_in_level" => "single_opt_in", "consent_updated_at" => "2024-01-02T09:24:29-05:00", "consent_collected_from" => "OTHER"}, "admin_graphql_api_id" => "gid://shopify/Customer/207119551", "default_address" => {"id" => 207119551, "customer_id" => 207119551, "first_name" => nil, "last_name" => nil, "company" => nil, "address1" => "Chestnut Street 92", "address2" => "", "city" => "Louisville", "province" => "Kentucky", "country" => "United States", "zip" => "40202", "phone" => "555-625-1199", "name" => "", "province_code" => "KY", "country_code" => "US", "country_name" => "United States", "default" => true}}}), headers: {})
customer.email_marketing_consent = {
"state" => "subscribed",
"opt_in_level" => "single_opt_in",
"consent_updated_at" => "2024-01-01T00:00:00.000Z"
}
# Trigger put request which will match the stubbed request.
customer.save
assert_requested(:put, "https://test-shop.myshopify.io/admin/api/2024-01/customers/207119551.json")
end
The second test is the same as the first, the only difference is that the opt-in level stays the same. This test currently fails (but should pass when the bug gets fixed).
sig do
void
end
def test_x_broken
session = ShopifyAPI::Auth::Session.new(
shop: "test-shop.myshopify.io",
access_token: "this_is_a_test_token"
)
# Simulate fetching an existing customer via the API:
customer = ShopifyAPI::Customer.create_instance(
session: session,
data: {
"id" => 207119551,
"email_marketing_consent" => {
"state" => "not_subscribed",
"opt_in_level" => "single_opt_in",
"consent_updated_at" => "2023-01-01T00:00:00.000Z"
}
}
)
# Stub update with full `email_marketing_consent` hash included:
stub_request(:put, "https://test-shop.myshopify.io/admin/api/2024-01/customers/207119551.json")
.with(
# This stub isn't going to match because the `opt_in_level` doesn't change and therefore isn't sent up.
body: { "customer" => hash_including({"email_marketing_consent" => {"state" => "subscribed", "opt_in_level" => "single_opt_in", "consent_updated_at" => "2024-01-01T00:00:00.000Z"}}) }
)
.to_return(status: 200, body: JSON.generate({"customer" => {"email" => "[email protected]", "first_name" => "Bob", "last_name" => "Norman", "id" => 207119551, "accepts_marketing" => false, "created_at" => "2024-01-02T09:24:29-05:00", "updated_at" => "2024-01-02T09:24:29-05:00", "orders_count" => 1, "state" => "disabled", "total_spent" => "199.65", "last_order_id" => 450789469, "note" => nil, "verified_email" => true, "multipass_identifier" => nil, "tax_exempt" => false, "tags" => "L\u00E9on, No\u00EBl", "last_order_name" => "#1001", "currency" => "USD", "phone" => "+16136120707", "addresses" => [{"id" => 207119551, "customer_id" => 207119551, "first_name" => nil, "last_name" => nil, "company" => nil, "address1" => "Chestnut Street 92", "address2" => "", "city" => "Louisville", "province" => "Kentucky", "country" => "United States", "zip" => "40202", "phone" => "555-625-1199", "name" => "", "province_code" => "KY", "country_code" => "US", "country_name" => "United States", "default" => true}], "accepts_marketing_updated_at" => "2005-06-12T11:57:11-04:00", "marketing_opt_in_level" => nil, "tax_exemptions" => [], "email_marketing_consent" => {"state" => "not_subscribed", "opt_in_level" => nil, "consent_updated_at" => "2004-06-13T11:57:11-04:00"}, "sms_marketing_consent" => {"state" => "not_subscribed", "opt_in_level" => "single_opt_in", "consent_updated_at" => "2024-01-02T09:24:29-05:00", "consent_collected_from" => "OTHER"}, "admin_graphql_api_id" => "gid://shopify/Customer/207119551", "default_address" => {"id" => 207119551, "customer_id" => 207119551, "first_name" => nil, "last_name" => nil, "company" => nil, "address1" => "Chestnut Street 92", "address2" => "", "city" => "Louisville", "province" => "Kentucky", "country" => "United States", "zip" => "40202", "phone" => "555-625-1199", "name" => "", "province_code" => "KY", "country_code" => "US", "country_name" => "United States", "default" => true}}}), headers: {})
customer.email_marketing_consent = {
"state" => "subscribed",
"opt_in_level" => "single_opt_in",
"consent_updated_at" => "2024-01-01T00:00:00.000Z"
}
# Trigger put request which won't match the stubbed request.
customer.save
assert_requested(:put, "https://test-shop.myshopify.io/admin/api/2024-01/customers/207119551.json")
end
Debug logs
// Paste any relevant logs here