diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 7381cec69..de2ba1a68 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -69,8 +69,8 @@ def mark_users_updated redirect_to actions_admin_users_path, notice: 'Incremented unread update count' end - def force_update_lead - Newflow::CreateOrUpdateSalesforceLead.call(user: get_user) + def force_update_contact + Newflow::CreateOrUpdateSalesforceContact.call(user: get_user) end protected diff --git a/app/handlers/newflow/educator_signup/complete_profile.rb b/app/handlers/newflow/educator_signup/complete_profile.rb index 10b9d6456..f387b9414 100644 --- a/app/handlers/newflow/educator_signup/complete_profile.rb +++ b/app/handlers/newflow/educator_signup/complete_profile.rb @@ -108,7 +108,7 @@ def handle transfer_errors_from(@user, {type: :verbatim}, :fail_if_errors) - CreateOrUpdateSalesforceLead.perform_later(user: @user) + CreateOrUpdateSalesforceContact.perform_later(user: @user) #output the user to the lev handler outputs.user = @user diff --git a/app/handlers/newflow/educator_signup/sheerid_webhook.rb b/app/handlers/newflow/educator_signup/sheerid_webhook.rb index 85cf22d96..cd9d86f66 100644 --- a/app/handlers/newflow/educator_signup/sheerid_webhook.rb +++ b/app/handlers/newflow/educator_signup/sheerid_webhook.rb @@ -136,7 +136,7 @@ def handle(verification_id=nil) event_data: { verification: verification_details_from_sheerid.inspect }) end - CreateOrUpdateSalesforceLead.perform_later(user: user) + CreateOrUpdateSalesforceContact.perform_later(user: user) SecurityLog.create!(user: user, event_type: :sheerid_webhook_processed) diff --git a/app/routines/newflow/create_or_update_salesforce_lead.rb b/app/routines/newflow/create_or_update_salesforce_contact.rb similarity index 54% rename from app/routines/newflow/create_or_update_salesforce_lead.rb rename to app/routines/newflow/create_or_update_salesforce_contact.rb index 3bf66d693..099b60bf7 100644 --- a/app/routines/newflow/create_or_update_salesforce_lead.rb +++ b/app/routines/newflow/create_or_update_salesforce_contact.rb @@ -1,9 +1,8 @@ module Newflow - class CreateOrUpdateSalesforceLead + class CreateOrUpdateSalesforceContact lev_routine active_job_enqueue_options: { queue: :salesforce } - LEAD_SOURCE = 'Account Creation' DEFAULT_REFERRING_APP_NAME = 'Accounts' ADOPTION_STATUS_FROM_USER = { @@ -24,7 +23,7 @@ def exec(user:) SecurityLog.create!( user: user, - event_type: :starting_salesforce_lead_creation + event_type: :starting_salesforce_contact_creation ) sf_school_id = user.school&.salesforce_id @@ -47,7 +46,7 @@ def exec(user:) adoption_json = build_book_adoption_json_for_salesforce(user) end - # Check the state of the SheerID response and profile completion to determine faculty status for lead + # Check the state of the SheerID response and profile completion to determine faculty status for contact sheerid_response = SheeridVerification.find_by(verification_id: user.sheerid_verification_id) if user.is_profile_complete? user.faculty_status = :pending_faculty @@ -59,47 +58,55 @@ def exec(user:) user.faculty_status = :incomplete_signup end - - if user.salesforce_lead_id - lead = OpenStax::Salesforce::Remote::Lead.find_by(email: user.best_email_address_for_salesforce) + # Find existing contact or create new one + if user.salesforce_contact_id + contact = OpenStax::Salesforce::Remote::Contact.find_by(id: user.salesforce_contact_id) else - lead = OpenStax::Salesforce::Remote::Lead.new(email: user.best_email_address_for_salesforce) + # Look for existing contact by email first + contact = OpenStax::Salesforce::Remote::Contact.find_by(email: user.best_email_address_for_salesforce) + + # If found, update the user with the contact ID + if contact + user.salesforce_contact_id = contact.id + user.save + else + # Create new contact + contact = OpenStax::Salesforce::Remote::Contact.new(email: user.best_email_address_for_salesforce) + end end - if lead.nil? - Sentry.capture_message("Lead for user not found #{user.uuid} not found", level: :error) + if contact.nil? + Sentry.capture_message("Contact for user #{user.uuid} not found", level: :error) return end - lead.first_name = user.first_name - lead.last_name = user.last_name - lead.phone = user.phone_number - lead.source = LEAD_SOURCE - lead.application_source = DEFAULT_REFERRING_APP_NAME - lead.role = sf_role - lead.position = sf_position - lead.title = user.other_role_name - lead.who_chooses_books = user.who_chooses_books - lead.subject_interest = user.which_books - lead.num_students = user.how_many_students - lead.adoption_status = ADOPTION_STATUS_FROM_USER[user.using_openstax_how] - lead.adoption_json = adoption_json - lead.os_accounts_id = user.id - lead.accounts_uuid = user.uuid - lead.school = user.most_accurate_school_name - lead.city = user.most_accurate_school_city - lead.country = user.most_accurate_school_country - lead.verification_status = user.faculty_status == User::NO_FACULTY_INFO ? nil : user.faculty_status - lead.b_r_i_marketing = user.is_b_r_i_user? - lead.title_1_school = user.title_1_school? - lead.newsletter = user.receive_newsletter? - lead.newsletter_opt_in = user.receive_newsletter? - lead.self_reported_school = user.self_reported_school - lead.sheerid_school_name = user.sheerid_reported_school - lead.account_id = sf_school_id - lead.school_id = sf_school_id - lead.signup_date = user.created_at.strftime("%Y-%m-%dT%T.%L%z") - lead.tracking_parameters = "#{Rails.application.secrets.openstax_url}/accounts/i/signup/" + contact.first_name = user.first_name + contact.last_name = user.last_name + contact.phone = user.phone_number + contact.lead_source = DEFAULT_REFERRING_APP_NAME + contact.role = sf_role + contact.position = sf_position + contact.title = user.other_role_name + contact.who_chooses_books = user.who_chooses_books + contact.subject_interest = user.which_books + contact.num_students = user.how_many_students + contact.adoption_status = ADOPTION_STATUS_FROM_USER[user.using_openstax_how] + contact.adoption_json = adoption_json + contact.os_accounts_id = user.id + contact.accounts_uuid = user.uuid + contact.school = user.most_accurate_school_name + contact.city = user.most_accurate_school_city + contact.country = user.most_accurate_school_country + contact.verification_status = user.faculty_status == User::NO_FACULTY_INFO ? nil : user.faculty_status + contact.b_r_i_marketing = user.is_b_r_i_user? + contact.title_1_school = user.title_1_school? + contact.newsletter = user.receive_newsletter? + contact.newsletter_opt_in = user.receive_newsletter? + contact.self_reported_school = user.self_reported_school + contact.sheerid_school_name = user.sheerid_reported_school + contact.account_id = sf_school_id + contact.signup_date = user.created_at.strftime("%Y-%m-%dT%T.%L%z") + contact.tracking_parameters = "#{Rails.application.secrets.openstax_url}/accounts/i/signup/" state = user.most_accurate_school_state unless state.blank? @@ -108,40 +115,40 @@ def exec(user:) unless state.nil? # Figure out if the State is an abbreviation or the full name if state == state.upcase - lead.state_code = state + contact.state_code = state else - lead.state = state + contact.state = state end end SecurityLog.create!( user: user, - event_type: :attempting_to_create_user_lead, - event_data: { lead_data: lead } + event_type: :attempting_to_create_user_contact, + event_data: { contact_data: contact } ) - if lead.save - user.salesforce_lead_id = lead.id + if contact.save + user.salesforce_contact_id = contact.id if user.save SecurityLog.create!( user: user, - event_type: :created_salesforce_lead, - event_data: { lead_id: lead.id.to_s } + event_type: :created_salesforce_contact, + event_data: { contact_id: contact.id.to_s } ) else - if lead.errors.messages.inspect.include? == 'INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY' + if contact.errors.messages.inspect.include? == 'INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY' Sentry.capture_message("Invalid school (#{user.school.salesforce_id}) for user (#{user.id})") end SecurityLog.create!( user: user, event_type: :educator_sign_up_failed, - event_data: { lead_id: lead.id } + event_data: { contact_id: contact.id } ) - Sentry.capture_message("User #{user.id} was not successfully saved with lead #{lead.id}") + Sentry.capture_message("User #{user.id} was not successfully saved with contact #{contact.id}") end end - outputs.lead = lead + outputs.contact = contact outputs.user = user end @@ -174,4 +181,4 @@ def build_book_adoption_json_for_salesforce(user) adoption_json.to_json end end -end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 4d9f9f3b5..1313c94c9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -283,7 +283,7 @@ get 'js_search', on: :collection get 'actions', on: :collection put 'mark_users_updated', on: :collection - post 'force_update_lead', on: :member + post 'force_update_contact', on: :member delete 'soft_delete', on: :member end diff --git a/spec/cassettes/Newflow_CreateOrUpdateSalesforceLead/sf_setup.yml b/spec/cassettes/Newflow_CreateOrUpdateSalesforceLead/sf_setup.yml deleted file mode 100644 index e655045b8..000000000 --- a/spec/cassettes/Newflow_CreateOrUpdateSalesforceLead/sf_setup.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https:///services/oauth2/token - body: - encoding: US-ASCII - string: grant_type=password&client_id=&client_secret=&username=&password= - headers: - User-Agent: - - Faraday v1.10.4 - Content-Type: - - application/x-www-form-urlencoded - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Date: - - Tue, 08 Oct 2024 15:04:38 GMT - Set-Cookie: - - BrowserId=o5XNPYWGEe-UUm_L3BTUAA; domain=.salesforce.com; path=/; expires=Wed, - 08-Oct-2025 15:04:38 GMT; Max-Age=31536000; secure; SameSite=None - - CookieConsentPolicy=0:0; path=/; expires=Wed, 08-Oct-2025 15:04:38 GMT; Max-Age=31536000; - secure - - LSKey-c$CookieConsentPolicy=0:0; path=/; expires=Wed, 08-Oct-2025 15:04:38 - GMT; Max-Age=31536000; secure - Strict-Transport-Security: - - max-age=63072000; includeSubDomains - X-Content-Type-Options: - - nosniff - Cache-Control: - - no-cache,must-revalidate,max-age=0,no-store,private - Expires: - - Thu, 01 Jan 1970 00:00:00 GMT - X-Readonlymode: - - 'false' - Content-Type: - - application/json;charset=UTF-8 - Vary: - - Accept-Encoding - Transfer-Encoding: - - chunked - body: - encoding: ASCII-8BIT - string: '{"access_token":"","instance_url":"","id":"https:///id/00DU0000000KwchMAC/005U0000005akrEIAQ","token_type":"Bearer","issued_at":"1728399879076","signature":""}' - http_version: - recorded_at: Tue, 08 Oct 2024 15:04:39 GMT -recorded_with: VCR 3.0.3 diff --git a/spec/cassettes/Newflow_CreateOrUpdateSalesforceLead/works_on_the_happy_path.yml b/spec/cassettes/Newflow_CreateOrUpdateSalesforceLead/works_on_the_happy_path.yml deleted file mode 100644 index 8a3c4101e..000000000 --- a/spec/cassettes/Newflow_CreateOrUpdateSalesforceLead/works_on_the_happy_path.yml +++ /dev/null @@ -1,128 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: "/services/data/v51.0/query?q=SELECT%20Id,%20Name,%20BillingCity,%20BillingState,%20BillingCountry,%20Type,%20School_Location__c,%20SheerID_School_Name__c,%20K_I_P__c,%20child_of_kip__c,%20Total_School_Enrollment__c,%20Has_Assignable_Contacts__c%20FROM%20Account%20WHERE%20(Name%20=%20%27Find%20Me%20A%20Home%27)%20LIMIT%201" - body: - encoding: US-ASCII - string: '' - headers: - User-Agent: - - Faraday v1.10.3 - Authorization: - - OAuth - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Date: - - Wed, 04 Sep 2024 16:55:26 GMT - Content-Type: - - application/json;charset=UTF-8 - Transfer-Encoding: - - chunked - Connection: - - keep-alive - Strict-Transport-Security: - - max-age=63072000; includeSubDomains - X-Content-Type-Options: - - nosniff - Set-Cookie: - - BrowserId=fBTaLmreEe-4jc39-qgTow; domain=.salesforce.com; path=/; expires=Thu, - 04-Sep-2025 16:55:26 GMT; Max-Age=31536000; secure; SameSite=None - - CookieConsentPolicy=0:1; path=/; expires=Thu, 04-Sep-2025 16:55:26 GMT; Max-Age=31536000; - secure - - LSKey-c$CookieConsentPolicy=0:1; path=/; expires=Thu, 04-Sep-2025 16:55:26 - GMT; Max-Age=31536000; secure - Vary: - - Accept-Encoding - Sforce-Limit-Info: - - api-usage=37968/5000000 - Cache-Control: - - no-cache,must-revalidate,max-age=0,no-store,private - X-Robots-Tag: - - none - Server: - - sfdcedge - X-Sfdc-Request-Id: - - 25f505e7c7c08bdbfdf32fde9d97142b - X-Sfdc-Edge-Cache: - - MISS - body: - encoding: ASCII-8BIT - string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"Account","url":"/services/data/v51.0/sobjects/Account/0016f00002iPs9mAAC"},"Id":"0016f00002iPs9mAAC","Name":"Find - Me A Home","BillingCity":"Abu Dhabi","BillingState":null,"BillingCountry":"United - Arab Emirates","Type":"Other","School_Location__c":"Foreign","SheerID_School_Name__c":"Find - Me A Home","K_I_P__c":false,"child_of_kip__c":false,"Total_School_Enrollment__c":null,"20Has_Assignable_Contacts__c":false}]}' - http_version: - recorded_at: Wed, 04 Sep 2024 16:55:26 GMT -- request: - method: post - uri: "/services/data/v51.0/sobjects/Lead" - body: - encoding: UTF-8 - string: '{"FirstName":"Max","LastName":"Liebermann","Subject_Interest__c":"AP - Macro Econ","Company":"Test University","Country":"United States","Phone":"+17133484799","LeadSource":"Account - Creation","Newsletter__c":false,"Newsletter_Opt_In__c":false,"Adoption_Status__c":"Confirmed - Adoption Won","Number_of_Students__c":"35","Accounts_ID__c":1,"Accounts_UUID__c":"86ed61c4-e556-4a05-9c55-5453bbdd9f28","Application_Source__c":"Accounts","Role__c":"Instructor","Position__c":"instructor","who_chooses_books__c":"instructor","FV_Status__c":"pending_faculty","BRI_Marketing__c":false,"Title_1_school__c":false,"Signup_Date__c":"2024-09-04T16:55:26.508+0000","Self_Reported_School__c":"Test - University","Tracking_Parameters__c":"https://dev.openstax.org/accounts/i/signup/","Account_ID__c":"0016f00002iPs9mAAC","School__c":"0016f00002iPs9mAAC"}' - headers: - User-Agent: - - Faraday v1.10.3 - Content-Type: - - application/json - Authorization: - - OAuth - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - response: - status: - code: 201 - message: Created - headers: - Date: - - Wed, 04 Sep 2024 16:55:32 GMT - Content-Type: - - application/json;charset=UTF-8 - Transfer-Encoding: - - chunked - Connection: - - keep-alive - Strict-Transport-Security: - - max-age=63072000; includeSubDomains - Location: - - "/services/data/v51.0/sobjects/Lead/00QOx00000aLVDoMAO" - Vary: - - Accept-Encoding - Cache-Control: - - no-cache,must-revalidate,max-age=0,no-store,private - Sforce-Limit-Info: - - api-usage=37968/5000000 - Set-Cookie: - - BrowserId=fEgf2WreEe-pC3-63Rbixw; domain=.salesforce.com; path=/; expires=Thu, - 04-Sep-2025 16:55:27 GMT; Max-Age=31536000; secure; SameSite=None - - CookieConsentPolicy=0:1; path=/; expires=Thu, 04-Sep-2025 16:55:27 GMT; Max-Age=31536000; - secure - - LSKey-c$CookieConsentPolicy=0:1; path=/; expires=Thu, 04-Sep-2025 16:55:27 - GMT; Max-Age=31536000; secure - X-Content-Type-Options: - - nosniff - X-Robots-Tag: - - none - Server: - - sfdcedge - X-Sfdc-Request-Id: - - 195fe1b23acf0aa4438508370eda95c5 - body: - encoding: ASCII-8BIT - string: '{"id":"00QOx00000aLVDoMAO","success":true,"errors":[]}' - http_version: - recorded_at: Wed, 04 Sep 2024 16:55:32 GMT -recorded_with: VCR 3.0.3 diff --git a/spec/features/newflow/user_login_signup_with_social_network_spec.rb b/spec/features/newflow/user_login_signup_with_social_network_spec.rb index 97584ade5..c7a0c1d0c 100644 --- a/spec/features/newflow/user_login_signup_with_social_network_spec.rb +++ b/spec/features/newflow/user_login_signup_with_social_network_spec.rb @@ -5,7 +5,7 @@ turn_on_student_feature_flag turn_on_educator_feature_flag load('db/seeds.rb') - allow_any_instance_of(Newflow::CreateOrUpdateSalesforceLead).to receive(:exec) + allow_any_instance_of(Newflow::CreateOrUpdateSalesforceContact).to receive(:exec) end let(:email) { 'user@example.com' } diff --git a/spec/routines/newflow/create_or_update_salesforce_lead_spec.rb b/spec/routines/newflow/create_or_update_salesforce_lead_spec.rb deleted file mode 100644 index c34a2e089..000000000 --- a/spec/routines/newflow/create_or_update_salesforce_lead_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'rails_helper' -require 'vcr_helper' - -module Newflow - describe CreateOrUpdateSalesforceLead, type: :routine, vcr: VCR_OPTS do - - before(:all) do - VCR.use_cassette('Newflow_CreateOrUpdateSalesforceLead/sf_setup', VCR_OPTS) do - @proxy = SalesforceProxy.new - @proxy.setup_cassette - end - end - - let(:user) do - User.create do |u| - u.first_name = "Max" - u.last_name = "Liebermann" - u.state = "activated" - u.faculty_status = "pending_faculty" - u.self_reported_school = "Test University" - u.role = "instructor" - u.school_type = "unknown_school_type" - u.using_openstax = false - u.receive_newsletter = false - u.is_newflow = true - u.phone_number = "+17133484799" - u.school_location = "unknown_school_location" - u.opt_out_of_cookies = false - u.how_many_students = "35" - u.which_books = "AP Macro Econ" - u.who_chooses_books = "instructor" - u.using_openstax_how = "as_primary" - u.is_profile_complete = true - end - end - - it 'works on the happy path' do - expect(Rails.logger).not_to receive(:warn) - - lead = described_class[user: user] - - expect(user.salesforce_lead_id).not_to be_nil - end - end -end