Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot update email marketing consent state if opt-in level doesn't change #1287

Open
4 of 5 tasks
ClaytonPassmore opened this issue Mar 11, 2024 · 4 comments · May be fixed by #1332
Open
4 of 5 tasks

Cannot update email marketing consent state if opt-in level doesn't change #1287

ClaytonPassmore opened this issue Mar 11, 2024 · 4 comments · May be fixed by #1332
Assignees

Comments

@ClaytonPassmore
Copy link
Contributor

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

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

  1. Fetch a customer from Shopify
  2. Create a new hash for the email_marketing_consent field that contains all the same attributes, but a different state (e.g. use "subscribed" if the customer was not subscribed)
  3. 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
@matteodepalo
Copy link
Contributor

Hi @ClaytonPassmore, thank you for opening an issue with this level of detail! I'm going to add it to our internal workflow.

@ClaytonPassmore
Copy link
Contributor Author

Awesome, thank you @matteodepalo 🙏

@paulomarg paulomarg self-assigned this Aug 1, 2024
@paulomarg paulomarg linked a pull request Aug 1, 2024 that will close this issue
4 tasks
@paulomarg
Copy link
Contributor

Thanks for providing the failing test, that was super helpful in fixing this!

@ClaytonPassmore
Copy link
Contributor Author

Happy to help @paulomarg! Looking forward to seeing the fix merged 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants
@matteodepalo @ClaytonPassmore @paulomarg and others