From d06a1fce044a56a12db778cab6506b6b2f24b843 Mon Sep 17 00:00:00 2001 From: Jordan Moncharmont Date: Tue, 27 Nov 2018 12:24:18 -0800 Subject: [PATCH 1/3] fix rake issue preventing rake test_app --- Gemfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gemfile b/Gemfile index 77e2cd4..4cf3786 100644 --- a/Gemfile +++ b/Gemfile @@ -6,5 +6,7 @@ gem 'libnotify' gem 'fuubar' gem 'byebug' gem 'pry-byebug' +# needed to address this issue: https://stackoverflow.com/a/35893625 +gem 'rake', '< 11.0' gemspec From 935a01edb7da59ab2db29a0adbbd91e7320570ce Mon Sep 17 00:00:00 2001 From: Jordan Moncharmont Date: Fri, 16 Jun 2017 09:56:01 -0500 Subject: [PATCH 2/3] Allow logging of guest carts --- .../chimpy/interface/customer_upserter.rb | 124 ++++++++---- spec/lib/customers_interface_spec.rb | 178 ++++++++++-------- 2 files changed, 185 insertions(+), 117 deletions(-) diff --git a/lib/spree/chimpy/interface/customer_upserter.rb b/lib/spree/chimpy/interface/customer_upserter.rb index 26af94c..6bbd8cd 100644 --- a/lib/spree/chimpy/interface/customer_upserter.rb +++ b/lib/spree/chimpy/interface/customer_upserter.rb @@ -3,62 +3,110 @@ module Interface class CustomerUpserter delegate :log, :store_api_call, to: Spree::Chimpy + attr_reader :order def initialize(order) @order = order end - # CUSTOMER will be pulled first from the MC_EID if present on the order.source - # IF that is not found, customer will be found by our Customer ID - # IF that is not found, customer is created with the order email and our Customer ID + + # CUSTOMER will be pulled first from the MC_EID if present on the + # order.source + # IF that is not found, customer will be found by our Customer ID assuming + # there is a user on the order, and their id is `customer_#{user.id}`. + # If that is not found, customer is searched via email address + # IF that is not found, customer is created with the order email and our + # Customer ID, or guest ID def ensure_customer - # use the one from mail chimp or fall back to the order's email - # happens when this is a new user - customer_id = customer_id_from_eid(@order.source.email_id) if @order.source - customer_id || upsert_customer + lookup_customer_id_from_eid || + lookup_customer_id_from_user_id || + lookup_customer_id_from_email_address || + upsert_customer end - def self.mailchimp_customer_id(user_id) - "customer_#{user_id}" + def lookup_customer_id_from_eid + return unless order.source.try(:email_id) + + email = Spree::Chimpy.list.email_for_id(order.source.email_id) + lookup_email_address email if email end - def customer_id_from_eid(mc_eid) - email = Spree::Chimpy.list.email_for_id(mc_eid) - if email - begin - response = store_api_call - .customers - .retrieve(params: { "fields" => "customers.id", "email_address" => email }) - - data = response["customers"].first - data["id"] if data - rescue Gibbon::MailChimpError => e - nil - end + def lookup_customer_id_from_user_id + return unless order.user_id.present? + mailchimp_customer_id = customer_id_from_user_id order.user_id + begin + response = store_api_call. + customer(mailchimp_customer_id). + retrieve(params: { "fields" => "customers.id" }) + + data = response["customers"].first + data["id"] if data + rescue Gibbon::MailChimpError => _e + nil end end + def lookup_customer_id_from_email_address + lookup_email_address order.email + end + private + def lookup_email_address(email_address) + response = store_api_call. + customers. + retrieve params: \ + { "fields" => "customers.id", "email_address" => email_address } + + data = response["customers"].first + data["id"] if data + rescue Gibbon::MailChimpError => _e + nil + end + + def customer_id_from_user_id(user_id) + "customer_#{user_id}" + end + + def mailchimp_customer_id + if order.user_id.present? + customer_id_from_user_id(order.user_id) + else + "guest_#{Digest::MD5.hexdigest email_from_order}" + end + end + + def email_from_order + order.email.downcase + end + + def first_name_from_order + order.name.split(" ").first + end + + def last_name_from_order + order.name.split(" ")[1..-1].join(" ") + end + def upsert_customer - return unless @order.user_id + customer_id = mailchimp_customer_id + email = email_from_order - customer_id = self.class.mailchimp_customer_id(@order.user_id) begin - response = store_api_call - .customers(customer_id) - .retrieve(params: { "fields" => "id,email_address"}) - rescue Gibbon::MailChimpError => e - # Customer Not Found, so create them - response = store_api_call - .customers - .create(body: { + log "upserting customer: #{email}" + store_api_call.customers(customer_id).upsert body: + { id: customer_id, - email_address: @order.email.downcase, - opt_in_status: Spree::Chimpy::Config.subscribe_to_list || false - }) + email_address: email, + first_name: first_name_from_order, + last_name: last_name_from_order, + opt_in_status: Spree::Chimpy::Config.subscribe_to_list || false, + } + customer_id + rescue Gibbon::MailChimpError => e + log "failed to create customer:#{customer_id} with email: #{email}..." + log e + nil end - customer_id end - end end -end \ No newline at end of file +end diff --git a/spec/lib/customers_interface_spec.rb b/spec/lib/customers_interface_spec.rb index e7cca15..b48d27e 100644 --- a/spec/lib/customers_interface_spec.rb +++ b/spec/lib/customers_interface_spec.rb @@ -23,124 +23,144 @@ Spree::Chimpy::Config.subscribe_to_list = true end - describe ".ensure_customers" do - - #TODO: Changed from skips sync when mismatch - - # Updated logic takes the customer attached to the mc_eid regardless of email matching order - # When no customer exists for that mc_eid, it will create the customer for the order email - # Should this remain due to v3.0 updates? - it "retrieves the customer id from the order source if it exists" do - order.source = Spree::Chimpy::OrderSource.new(email_id: 'id-abcd') - order.save - - allow(interface).to receive(:customer_id_from_eid) - .with('id-abcd') - .and_return("customer_999") - - expect(interface.ensure_customer).to eq "customer_999" + describe ".ensure_customer" do + # Cascading lookup of eid, own customer_id, email address, upsert + it "first tries the eid lookup" do + expect(interface). + to receive(:lookup_customer_id_from_eid).and_return(:foobar) + expect(interface.ensure_customer).to eq :foobar end - context "when no customer from order source" do - before(:each) do - allow(interface).to receive(:customer_id_from_eid) - .with('id-abcd') - .and_return(nil) + describe "eid fails" do + before :each do + expect(interface). + to receive(:lookup_customer_id_from_eid).and_return(nil) end - it "upserts the customer" do - allow(interface).to receive(:upsert_customer) { "customer_998" } - - expect(interface.ensure_customer).to eq "customer_998" + it "then tries the customer_id lookup" do + expect(interface). + to receive(:lookup_customer_id_from_user_id).and_return(:foobar) + expect(interface.ensure_customer).to eq :foobar end - it "returns nil if guest checkout" do - order.user_id = nil - expect(interface.ensure_customer).to be_nil + describe "customer_id lookup fails" do + before :each do + expect(interface). + to receive(:lookup_customer_id_from_user_id).and_return(nil) + end + + it "then tries the email address lookup" do + expect(interface).to \ + receive(:lookup_customer_id_from_email_address).and_return(:foobar) + expect(interface.ensure_customer).to eq :foobar + end + + describe "email address lookup fails" do + before :each do + expect(interface).to \ + receive(:lookup_customer_id_from_email_address).and_return(nil) + end + + it "then upserts the customer" do + expect(interface). + to receive(:upsert_customer).and_return(:foobar) + expect(interface.ensure_customer).to eq :foobar + end + end end end end - describe "#upsert_customer" do + describe "#mailchimp_customer_id" do + it "picks customer_* for orders with customers" do + expect(interface.send(:mailchimp_customer_id)). + to eq "customer_#{order.user_id}" + end - before(:each) do - allow(store_api).to receive(:customers) - .and_return(customers_api) - allow(store_api).to receive(:customers) - .with("customer_#{order.user_id}") - .and_return(customer_api) + it "picks guest_* for guest orders" do + order.user = nil + expect(interface.send(:mailchimp_customer_id)). + to start_with("guest_") end + end - it "retrieves based on the customer_id" do - expect(customer_api).to receive(:retrieve) - .with(params: { "fields" => "id,email_address"}) - .and_return({ "id" => "customer_#{order.user_id}", "email_address" => order.email}) + describe "#upsert_customer" do + let(:customer_id) { "customer_#{order.user_id}" } + + before :each do + allow(store_api).to receive(:customers).with(anything). + and_return customers_api + allow(customers_api).to receive(:upsert).and_return(nil) + end - customer_id = interface.send(:upsert_customer) - expect(customer_id).to eq "customer_#{order.user_id}" + it "upserts the customer" do + expect(interface.send(:upsert_customer)).to eq "customer_#{order.user_id}" end - it "creates the customer when lookup fails" do - allow(customer_api).to receive(:retrieve) - .and_raise(Gibbon::MailChimpError) + it "sets first_name and last_name" do + expect(customers_api).to receive(:upsert) do |h| + body = h[:body] + expect(body[:first_name]).to be_present + expect(body[:last_name]).to be_present + end + + interface.send :upsert_customer + end - expect(customers_api).to receive(:create) - .with(:body => { - id: "customer_#{order.user_id}", - email_address: order.email.downcase, - opt_in_status: true - }) + it "picks the id from #mailchimp_customer_id" do + expect(interface).to receive(:mailchimp_customer_id).and_return "foobar" - customer_id = interface.send(:upsert_customer) - expect(customer_id).to eq "customer_#{order.user_id}" + expect(interface.send(:upsert_customer)).to eq "foobar" end it "honors subscribe_to_list settings" do Spree::Chimpy::Config.subscribe_to_list = false - allow(customer_api).to receive(:retrieve) - .and_raise(Gibbon::MailChimpError) - - expect(customers_api).to receive(:create) do |h| + expect(customers_api).to receive(:upsert) do |h| expect(h[:body][:opt_in_status]).to eq false end + interface.send(:upsert_customer) end end - describe "#customer_id_from_eid" do + describe "#lookup_customer_id_from_eid" do let(:email) { "user@example.com" } before(:each) do allow(store_api).to receive(:customers) { customers_api } end - it "returns based on the mailchimp email address when found" do - allow(list).to receive(:email_for_id).with("id-abcd") - .and_return(email) - - expect(customers_api).to receive(:retrieve) - .with(params: { "fields" => "customers.id", "email_address" => email}) - .and_return({ "customers" => [{"id" => "customer_xyz"}] }) - - id = interface.customer_id_from_eid("id-abcd") - expect(id).to eq "customer_xyz" + it "does not lookup and returns nil if there is no source" do + expect(store_api).to_not receive(:customers) + interface.order.source = nil + expect(interface.lookup_customer_id_from_eid).to be_nil end - it "is nil if email for id not found" do - allow(list).to receive(:email_for_id).with("id-abcd") - .and_return(nil) + describe "with an email source" do + it "is nil if email for id not found" do + allow(list).to receive(:email_for_id).with(email_id).and_return(nil) - expect(interface.customer_id_from_eid("id-abcd")).to be_nil - end + expect(interface.lookup_customer_id_from_eid).to be_nil + end - it "is nil if email not found among customers" do - allow(list).to receive(:email_for_id) - .with("id-abcd") - .and_return(email) + describe "with a found email_id" do + before :each do + allow(list).to receive(:email_for_id).with(email_id).and_return(email) + end - expect(customers_api).to receive(:retrieve) - .and_raise(Gibbon::MailChimpError) + it "is nil if email not found among customers" do + expect(customers_api).to receive(:retrieve). + and_raise(Gibbon::MailChimpError) - expect(interface.customer_id_from_eid("id-abcd")).to be_nil + expect(interface.lookup_customer_id_from_eid).to be_nil + end + + it "returns the customer_id if found" do + expect(customers_api).to receive(:retrieve).and_return \ + "customers" => [{ "id" => "customer_123" }] + expect(interface.lookup_customer_id_from_eid).to eq "customer_123" + end + end end end -end \ No newline at end of file +end From f4462a0600a394a47631a596bd71705b6895008a Mon Sep 17 00:00:00 2001 From: Jordan Moncharmont Date: Thu, 29 Nov 2018 14:51:34 -0800 Subject: [PATCH 3/3] Remove restrictions on controller_filters so they always fire --- lib/spree/chimpy/controller_filters.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/spree/chimpy/controller_filters.rb b/lib/spree/chimpy/controller_filters.rb index dd84d09..5a125d8 100644 --- a/lib/spree/chimpy/controller_filters.rb +++ b/lib/spree/chimpy/controller_filters.rb @@ -18,8 +18,7 @@ def set_mailchimp_params end def mailchimp_params? - (!mc_eid.nil? || !mc_cid.nil?) && - (!session[:order_id].nil? || !params[:record_mc_details].nil?) + !mc_eid.nil? || !mc_cid.nil? end def find_mail_chimp_params