From 5626fbfbd2dcaa6fb5d791994c4ee19e90937b70 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Jul 2021 21:40:23 +0200 Subject: [PATCH 1/5] adds firnd or create method to HS service --- app/services/hub_spot_service.rb | 36 +- .../files/contact_hub_spot_found.json | 713 ++++++++++++++++++ .../files/contact_hub_spot_not_found.json | 11 + spec/requests/api/hub_spot/create_spec.rb | 20 +- spec/requests/api/inquiries/create_spec.rb | 52 ++ 5 files changed, 819 insertions(+), 13 deletions(-) create mode 100644 spec/fixtures/files/contact_hub_spot_found.json create mode 100644 spec/fixtures/files/contact_hub_spot_not_found.json diff --git a/app/services/hub_spot_service.rb b/app/services/hub_spot_service.rb index 1df1ada..79787bf 100644 --- a/app/services/hub_spot_service.rb +++ b/app/services/hub_spot_service.rb @@ -2,8 +2,8 @@ module HubSpotService @api_key = Rails.application.credentials.dig(:hub_spot, :api_key) def self.move(inquiry) inquiry = OpenStruct.new(inquiry) unless inquiry.is_a?(Inquiry) - contact = create_contact(inquiry) - id = JSON.parse(contact.body)['vid'] + contact = find_or_create_contact(inquiry) + id = contact[:vid] note = if inquiry.try(:officeProvider).nil? format_note(inquiry) else @@ -14,16 +14,28 @@ def self.move(inquiry) true end - def self.create_contact(inquiry) - RestClient.post( - "https://api.hubapi.com/contacts/v1/contact?hapikey=#{@api_key}", - { - properties: [ - { property: 'email', value: inquiry.email }, - { property: 'phone', value: inquiry.phone } - ] - }.to_json, { content_type: :json, accept: :json } - ) + def self.find_or_create_contact(inquiry) + properties = { + properties: [ + { property: 'email', value: inquiry.email }, + { property: 'phone', value: inquiry.phone } + ] + }.to_json + contact = JSON.parse( + RestClient.get("https://api.hubapi.com/contacts/v1/contact/email/#{inquiry.email}/profile?hapikey=#{@api_key}") + ).symbolize_keys + if contact[:status] != 'error' + RestClient.post( + "https://api.hubapi.com/contacts/v1/contact/vid/#{contact[:vid]}/profile?hapikey=#{@api_key}", + properties, { content_type: :json, accept: :json } + ) + else + RestClient.post( + "https://api.hubapi.com/contacts/v1/contact?hapikey=#{@api_key}", + properties, { content_type: :json, accept: :json } + ) + end + contact end def self.create_note(note, id, timestamp) diff --git a/spec/fixtures/files/contact_hub_spot_found.json b/spec/fixtures/files/contact_hub_spot_found.json new file mode 100644 index 0000000..529428d --- /dev/null +++ b/spec/fixtures/files/contact_hub_spot_found.json @@ -0,0 +1,713 @@ +{ + "vid": 1251, + "canonical-vid": 1251, + "merged-vids": [], + "portal-id": 20246979, + "is-contact": true, + "properties": { + "hs_is_unworked": { + "value": "false", + "versions": [ + { + "value": "false", + "source-type": "CALCULATED", + "source-id": "CalculatedPropertyComputer", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625822583806, + "selected": false + }, + { + "value": "true", + "source-type": "CALCULATED", + "source-id": "CalculatedPropertyComputer", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331142, + "selected": false + } + ] + }, + "firstname": { + "value": "Thomas", + "versions": [ + { + "value": "Thomas", + "source-type": "CRM_UI", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331070, + "selected": false + } + ] + }, + "associatedcompanyid": { + "value": "6247765371", + "versions": [ + { + "value": "6247765371", + "source-type": "CALCULATED", + "source-id": "RollupProperties", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331610, + "selected": false + } + ] + }, + "num_unique_conversion_events": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "CALCULATED", + "source-id": null, + "source-label": null, + "updated-by-user-id": null, + "timestamp": 0, + "selected": false + } + ] + }, + "hs_analytics_revenue": { + "value": "0.0", + "versions": [ + { + "value": "0.0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_social_num_broadcast_clicks": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "createdate": { + "value": "1625820331142", + "versions": [ + { + "value": "1625820331142", + "source-type": "CONTACTS", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331142, + "selected": false + } + ] + }, + "hs_analytics_num_visits": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_social_linkedin_clicks": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hubspot_owner_id": { + "value": "84375625", + "versions": [ + { + "value": "84375625", + "source-type": "CRM_UI", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331070, + "selected": false + } + ] + }, + "num_contacted_notes": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ENGAGEMENTS", + "source-id": "ObjectPropertyUpdater", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625822583792, + "selected": false + } + ] + }, + "hs_analytics_source": { + "value": "OFFLINE", + "versions": [ + { + "value": "OFFLINE", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_email_domain": { + "value": "craftacademy.se", + "versions": [ + { + "value": "craftacademy.se", + "source-type": "CALCULATED", + "source-id": null, + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331142, + "selected": false + } + ] + }, + "hs_analytics_num_page_views": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_all_owner_ids": { + "value": "84375625", + "versions": [ + { + "value": "84375625", + "source-type": "CALCULATED", + "source-id": "PermissionsUpdater", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332102, + "selected": false + } + ] + }, + "hs_count_is_worked": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "CALCULATED", + "source-id": "CalculatedPropertyComputer", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331142, + "selected": false + } + ] + }, + "email": { + "value": "thomas@craftacademy.se", + "versions": [ + { + "value": "thomas@craftacademy.se", + "source-type": "CONTACTS", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331142, + "selected": false + } + ] + }, + "notes_last_updated": { + "value": "1625822580238", + "versions": [ + { + "value": "1625822580238", + "source-type": "ENGAGEMENTS", + "source-id": "ObjectPropertyUpdater", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625822583792, + "selected": false + } + ] + }, + "lastmodifieddate": { + "value": "1625822583806", + "versions": [ + { + "value": "1625822583806", + "source-type": "CALCULATED", + "source-id": null, + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625822583806, + "selected": false + } + ] + }, + "hs_analytics_first_timestamp": { + "value": "1625820331070", + "versions": [ + { + "value": "1625820331070", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_social_google_plus_clicks": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_lifecyclestage_subscriber_date": { + "value": "1625820331070", + "versions": [ + { + "value": "1625820331070", + "source-type": "CRM_UI", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331070, + "selected": false + } + ] + }, + "hs_user_ids_of_all_owners": { + "value": "25179223", + "versions": [ + { + "value": "25179223", + "source-type": "CALCULATED", + "source-id": "PermissionsUpdater", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332102, + "selected": false + } + ] + }, + "hs_analytics_average_page_views": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_all_contact_vids": { + "value": "1251", + "versions": [ + { + "value": "1251", + "source-type": "CALCULATED", + "source-id": null, + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331189, + "selected": false + } + ] + }, + "lastname": { + "value": "Ochman", + "versions": [ + { + "value": "Ochman", + "source-type": "CRM_UI", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331070, + "selected": false + } + ] + }, + "hs_social_facebook_clicks": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_is_contact": { + "value": "true", + "versions": [ + { + "value": "true", + "source-type": "CALCULATED", + "source-id": null, + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331194, + "selected": false + } + ] + }, + "hubspot_owner_assigneddate": { + "value": "1625820331070", + "versions": [ + { + "value": "1625820331070", + "source-type": "CRM_UI", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331070, + "selected": false + } + ] + }, + "num_conversion_events": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "CALCULATED", + "source-id": null, + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331142, + "selected": false + } + ] + }, + "hs_object_id": { + "value": "1251", + "versions": [ + { + "value": "1251", + "source-type": "CALCULATED", + "source-id": null, + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331142, + "selected": false + } + ] + }, + "hs_analytics_num_event_completions": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_social_twitter_clicks": { + "value": "0", + "versions": [ + { + "value": "0", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_analytics_source_data_2": { + "value": "userId:25179223", + "versions": [ + { + "value": "userId:25179223", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "hs_analytics_source_data_1": { + "value": "CONTACTS", + "versions": [ + { + "value": "CONTACTS", + "source-type": "ANALYTICS", + "source-id": "ContactAnalyticsDetailsUpdateWorker", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820332117, + "selected": false + } + ] + }, + "lifecyclestage": { + "value": "subscriber", + "versions": [ + { + "value": "subscriber", + "source-type": "CRM_UI", + "source-id": "userId:25179223", + "source-label": null, + "updated-by-user-id": 25179223, + "timestamp": 1625820331070, + "selected": false + } + ] + }, + "hs_sales_email_last_replied": { + "value": "1625822580238", + "versions": [ + { + "value": "1625822580238", + "source-type": "ENGAGEMENTS", + "source-id": "ObjectPropertyUpdater", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625822583792, + "selected": false + } + ] + }, + "num_notes": { + "value": "1", + "versions": [ + { + "value": "1", + "source-type": "ENGAGEMENTS", + "source-id": "ObjectPropertyUpdater", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625822583792, + "selected": false + } + ] + }, + "hs_count_is_unworked": { + "value": "1", + "versions": [ + { + "value": "1", + "source-type": "CALCULATED", + "source-id": "CalculatedPropertyComputer", + "source-label": null, + "updated-by-user-id": null, + "timestamp": 1625820331142, + "selected": false + } + ] + } + }, + "form-submissions": [], + "list-memberships": [], + "identity-profiles": [ + { + "vid": 1251, + "saved-at-timestamp": 1625820331194, + "deleted-changed-timestamp": 0, + "identities": [ + { + "type": "EMAIL", + "value": "thomas@craftacademy.se", + "timestamp": 1625820331142, + "is-primary": true + }, + { + "type": "LEAD_GUID", + "value": "97e59193-4eb8-408b-9daa-91307c6d623a", + "timestamp": 1625820331189 + } + ] + } + ], + "merge-audits": [], + "associated-company": { + "company-id": 6247765371, + "portal-id": 20246979, + "properties": { + "country": { + "value": "Sweden" + }, + "city": { + "value": "Göteborg" + }, + "num_associated_contacts": { + "value": "1" + }, + "timezone": { + "value": "Europe/Stockholm" + }, + "facebook_company_page": { + "value": "https://facebook.com/craftacademysweden" + }, + "createdate": { + "value": "1623832057959" + }, + "description": { + "value": "Vill du kunna bygga nästa Uber eller Airbnb? Det handlar inte bara om att ha en bra idé - det handlar även om att KUNNA förverkliga den. Makers Academys unika utbildning ger dig det du behöver för att kunna skapa, utveckla och sjösätta webbaserade tjän..." + }, + "hs_num_blockers": { + "value": "0" + }, + "web_technologies": { + "value": "apache;ubuntu;typeform;facebook_connect;google_analytics;google_apps;facebook_advertiser" + }, + "numberofemployees": { + "value": "10" + }, + "hs_analytics_num_visits": { + "value": "0" + }, + "linkedin_company_page": { + "value": "https://www.linkedin.com/company/craftacademy" + }, + "hs_analytics_source": { + "value": "OFFLINE" + }, + "num_contacted_notes": { + "value": "0" + }, + "founded_year": { + "value": "2015" + }, + "hs_analytics_num_page_views": { + "value": "0" + }, + "state": { + "value": "Västra Götalands län" + }, + "linkedinbio": { + "value": "Vill du kunna bygga nästa Uber eller Airbnb? Det handlar inte bara om att ha en bra idé - det handlar även om att KUNNA förverkliga den. Makers Academys unika utbildning ger dig det du behöver för att kunna skapa, utveckla och sjösätta webbaserade tjän..." + }, + "hs_num_open_deals": { + "value": "0" + }, + "zip": { + "value": "41129" + }, + "notes_last_updated": { + "value": "1625822580238" + }, + "website": { + "value": "craftacademy.se" + }, + "address": { + "value": "1 Holtermansgatan" + }, + "hs_analytics_first_timestamp": { + "value": "1625820331070" + }, + "first_contact_createdate": { + "value": "1625820331142" + }, + "twitterhandle": { + "value": "CraftAcademySE" + }, + "hs_target_account_probability": { + "value": "0.38625118136405945" + }, + "hs_lastmodifieddate": { + "value": "1626091204873" + }, + "hs_num_decision_makers": { + "value": "0" + }, + "phone": { + "value": "+46 73 261 25 27" + }, + "domain": { + "value": "craftacademy.se" + }, + "hs_num_child_companies": { + "value": "0" + }, + "hs_num_contacts_with_buying_roles": { + "value": "0" + }, + "hs_object_id": { + "value": "6247765371" + }, + "is_public": { + "value": "false" + }, + "name": { + "value": "Craft Academy" + }, + "hs_analytics_source_data_2": { + "value": "userId:25179223" + }, + "hs_analytics_source_data_1": { + "value": "CONTACTS" + }, + "hs_sales_email_last_replied": { + "value": "1625822580238" + }, + "num_notes": { + "value": "1" + } + } + } +} \ No newline at end of file diff --git a/spec/fixtures/files/contact_hub_spot_not_found.json b/spec/fixtures/files/contact_hub_spot_not_found.json new file mode 100644 index 0000000..6b01a03 --- /dev/null +++ b/spec/fixtures/files/contact_hub_spot_not_found.json @@ -0,0 +1,11 @@ +{ + "status": "error", + "message": "contact does not exist", + "correlationId": "87cd9842-60b3-4999-b56b-e01cef171853", + "errors": [ + { + "message": "The contact testingapis@hubspot.com does not exist." + } + ], + "category": "OBJECT_NOT_FOUND" +} diff --git a/spec/requests/api/hub_spot/create_spec.rb b/spec/requests/api/hub_spot/create_spec.rb index f6e246d..4f6b288 100644 --- a/spec/requests/api/hub_spot/create_spec.rb +++ b/spec/requests/api/hub_spot/create_spec.rb @@ -4,8 +4,18 @@ let(:broker_headers) { { HTTP_ACCEPT: 'application/json' }.merge!(credentials) } let(:inquiry) { create(:inquiry, inquiry_status: 'started', email: 'steve@yahoo.se') } + before do + stub_request( + :get, + %r{https://api.hubapi.com/contacts/v1/contact/email} + ).to_return( + status: 200, + body: file_fixture('contact_hub_spot_not_found.json').read + ) + end describe 'successfully' do before do + post "/api/inquiries/#{inquiry.id}/hub_spot", headers: broker_headers end @@ -23,7 +33,15 @@ expect(inquiry.notes.last.body).to eq 'This inquiry was exported to HubSpot' end - it 'is expected to send off HubSpot request for contact' do + it 'is expected to send off HubSpot request for finding contact' do + expect(a_request( + :get, + "https://api.hubapi.com/contacts/v1/contact/email/steve@yahoo.se/profile?hapikey=#{Rails.application.credentials.dig(:hub_spot, + :api_key)}" + )).to have_been_made.times(1) + end + + it 'is expected to send off HubSpot request for creating contact' do expect(a_request( :post, "https://api.hubapi.com/contacts/v1/contact?hapikey=#{Rails.application.credentials.dig(:hub_spot, diff --git a/spec/requests/api/inquiries/create_spec.rb b/spec/requests/api/inquiries/create_spec.rb index e8ee756..4a53fec 100644 --- a/spec/requests/api/inquiries/create_spec.rb +++ b/spec/requests/api/inquiries/create_spec.rb @@ -132,6 +132,58 @@ describe 'rent out office inquiry' do let(:mail_delivery) { ActionMailer::Base.deliveries } before do + stub_request( + :get, + %r{https://api.hubapi.com/contacts/v1/contact/email} + ).to_return( + status: 200, + body: file_fixture('contact_hub_spot_found.json').read + ) + + stub_request( + :post, + %r{https://api.hubapi.com/contacts/v1/contact/vid} + ).to_return( + status: 204, + body: nil + ) + post '/api/inquiries', + params: { + inquiry: { + officeProvider: true, + name: 'Thomas', + phone: '031111111', + email: 'thomas@mail.com', + notes: 'I really need to get someone to share my office with', + language: 'en' + } + } + end + + it 'is expected to return a 200 status' do + expect(response).to have_http_status 200 + end + + it 'is expected to respond with a success message' do + expect(response_json['message']).to eq 'Thanks for your answers! We\'ll be in touch' + end + + it 'is expected to NOT have created a new Inquiry' do + expect(Inquiry.all.count).to eq 0 + end + end + + describe 'rent out office inquiry with email for existing user' do + # test case for updating a record if the user already exists on HubSpot + let(:mail_delivery) { ActionMailer::Base.deliveries } + before do + stub_request( + :get, + %r{https://api.hubapi.com/contacts/v1/contact/email} + ).to_return( + status: 200, + body: file_fixture('contact_hub_spot_not_found.json').read + ) post '/api/inquiries', params: { inquiry: { From 08f211318d609fad7d0801c70d2ba54fee8a6cd6 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Jul 2021 23:20:04 +0200 Subject: [PATCH 2/5] refactors hubspot service and webmock stub for not found contact --- app/services/hub_spot_service.rb | 19 ++++++++++++------- spec/requests/api/inquiries/create_spec.rb | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/services/hub_spot_service.rb b/app/services/hub_spot_service.rb index 79787bf..073851b 100644 --- a/app/services/hub_spot_service.rb +++ b/app/services/hub_spot_service.rb @@ -15,24 +15,29 @@ def self.move(inquiry) end def self.find_or_create_contact(inquiry) - properties = { + data = { properties: [ { property: 'email', value: inquiry.email }, { property: 'phone', value: inquiry.phone } ] - }.to_json - contact = JSON.parse( - RestClient.get("https://api.hubapi.com/contacts/v1/contact/email/#{inquiry.email}/profile?hapikey=#{@api_key}") - ).symbolize_keys + } + inquiry.try(:name).try(:present?) && data[:properties].push({ property: 'firstname', value: inquiry.name }) + begin + contact = JSON.parse( + RestClient.get("https://api.hubapi.com/contacts/v1/contact/email/#{inquiry.email}/profile?hapikey=#{@api_key}") + ).symbolize_keys + rescue StandardError => e + contact = JSON.parse(e.response.body).symbolize_keys + end if contact[:status] != 'error' RestClient.post( "https://api.hubapi.com/contacts/v1/contact/vid/#{contact[:vid]}/profile?hapikey=#{@api_key}", - properties, { content_type: :json, accept: :json } + data.to_json, { content_type: :json, accept: :json } ) else RestClient.post( "https://api.hubapi.com/contacts/v1/contact?hapikey=#{@api_key}", - properties, { content_type: :json, accept: :json } + data.to_json, { content_type: :json, accept: :json } ) end contact diff --git a/spec/requests/api/inquiries/create_spec.rb b/spec/requests/api/inquiries/create_spec.rb index 4a53fec..5562632 100644 --- a/spec/requests/api/inquiries/create_spec.rb +++ b/spec/requests/api/inquiries/create_spec.rb @@ -181,7 +181,7 @@ :get, %r{https://api.hubapi.com/contacts/v1/contact/email} ).to_return( - status: 200, + status: 404, body: file_fixture('contact_hub_spot_not_found.json').read ) post '/api/inquiries', From 448bfee0ed77d0e726ccc59500b8e3a6e51a1c56 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 13 Jul 2021 11:20:02 +0200 Subject: [PATCH 3/5] extracts data format to private function refactors rent out inquiry spec to reflect actual behaviour --- app/services/hub_spot_service.rb | 19 +++++++++------ spec/requests/api/inquiries/create_spec.rb | 28 ++++++++++------------ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/app/services/hub_spot_service.rb b/app/services/hub_spot_service.rb index 073851b..645744b 100644 --- a/app/services/hub_spot_service.rb +++ b/app/services/hub_spot_service.rb @@ -15,13 +15,7 @@ def self.move(inquiry) end def self.find_or_create_contact(inquiry) - data = { - properties: [ - { property: 'email', value: inquiry.email }, - { property: 'phone', value: inquiry.phone } - ] - } - inquiry.try(:name).try(:present?) && data[:properties].push({ property: 'firstname', value: inquiry.name }) + data = format_data(inquiry) begin contact = JSON.parse( RestClient.get("https://api.hubapi.com/contacts/v1/contact/email/#{inquiry.email}/profile?hapikey=#{@api_key}") @@ -87,4 +81,15 @@ def self.format_rent_out_note(inquiry)
  • Notes: #{inquiry.notes}
  • " end + + def self.format_data(inquiry) + data = { + properties: [ + { property: 'email', value: inquiry.email }, + { property: 'phone', value: inquiry.phone } + ] + } + inquiry.try(:name).try(:present?) && data[:properties].push({ property: 'firstname', value: inquiry.name }) + data + end end diff --git a/spec/requests/api/inquiries/create_spec.rb b/spec/requests/api/inquiries/create_spec.rb index 5562632..8804384 100644 --- a/spec/requests/api/inquiries/create_spec.rb +++ b/spec/requests/api/inquiries/create_spec.rb @@ -1,8 +1,7 @@ RSpec.describe 'POST /api/inquiries', type: :request do + let(:mail_delivery) { ActionMailer::Base.deliveries } describe 'regular inquiry' do describe 'successfully' do - let(:mail_delivery) { ActionMailer::Base.deliveries } - before do post '/api/inquiries', params: { @@ -129,23 +128,14 @@ end end - describe 'rent out office inquiry' do - let(:mail_delivery) { ActionMailer::Base.deliveries } + describe 'rent out office inquiry for new contact' do before do stub_request( :get, %r{https://api.hubapi.com/contacts/v1/contact/email} ).to_return( status: 200, - body: file_fixture('contact_hub_spot_found.json').read - ) - - stub_request( - :post, - %r{https://api.hubapi.com/contacts/v1/contact/vid} - ).to_return( - status: 204, - body: nil + body: file_fixture('contact_hub_spot_not_found.json').read ) post '/api/inquiries', params: { @@ -174,15 +164,21 @@ end describe 'rent out office inquiry with email for existing user' do - # test case for updating a record if the user already exists on HubSpot - let(:mail_delivery) { ActionMailer::Base.deliveries } before do stub_request( :get, %r{https://api.hubapi.com/contacts/v1/contact/email} ).to_return( status: 404, - body: file_fixture('contact_hub_spot_not_found.json').read + body: file_fixture('contact_hub_spot_found.json').read + ) + + stub_request( + :post, + %r{https://api.hubapi.com/contacts/v1/contact/vid} + ).to_return( + status: 204, + body: nil ) post '/api/inquiries', params: { From b4debc89106ea354dca05d297bce48a576adcfe3 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 13 Jul 2021 11:46:58 +0200 Subject: [PATCH 4/5] refactors hub spot service method from move -> send --- app/controllers/api/hub_spot_controller.rb | 2 +- app/controllers/api/inquiries_controller.rb | 2 +- app/services/hub_spot_service.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/hub_spot_controller.rb b/app/controllers/api/hub_spot_controller.rb index 0775bdc..54a6141 100644 --- a/app/controllers/api/hub_spot_controller.rb +++ b/app/controllers/api/hub_spot_controller.rb @@ -3,7 +3,7 @@ class Api::HubSpotController < ApplicationController def create inquiry = Inquiry.find(params[:inquiry_id]) - HubSpotService.move(inquiry) + HubSpotService.send(inquiry) inquiry.notes.create(body: "This inquiry was exported to HubSpot", creator: current_user) render json: { message: 'Successfully added to HubSpot' } rescue => error diff --git a/app/controllers/api/inquiries_controller.rb b/app/controllers/api/inquiries_controller.rb index 0716927..484019d 100644 --- a/app/controllers/api/inquiries_controller.rb +++ b/app/controllers/api/inquiries_controller.rb @@ -5,7 +5,7 @@ class Api::InquiriesController < ApplicationController def create if @office_provider_inquiry - HubSpotService.move(params[:inquiry]) + HubSpotService.send(params[:inquiry]) render json: { message: 'Thanks for your answers! We\'ll be in touch' } and return else inquiry = Inquiry.create(inquiry_params) diff --git a/app/services/hub_spot_service.rb b/app/services/hub_spot_service.rb index 645744b..1f93445 100644 --- a/app/services/hub_spot_service.rb +++ b/app/services/hub_spot_service.rb @@ -1,6 +1,6 @@ module HubSpotService @api_key = Rails.application.credentials.dig(:hub_spot, :api_key) - def self.move(inquiry) + def self.send(inquiry) inquiry = OpenStruct.new(inquiry) unless inquiry.is_a?(Inquiry) contact = find_or_create_contact(inquiry) id = contact[:vid] From 6bb0477e19f308295993c748204a46a45b4afb05 Mon Sep 17 00:00:00 2001 From: sevader14 Date: Mon, 11 Oct 2021 14:39:49 +0200 Subject: [PATCH 5/5] changes office type emun to new values, fixes tests --- app/models/inquiry.rb | 2 +- spec/models/inquiry_spec.rb | 45 +++++++++++----------- spec/requests/api/inquiries/create_spec.rb | 4 +- spec/requests/api/inquiries/index_spec.rb | 2 +- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/app/models/inquiry.rb b/app/models/inquiry.rb index 989fd40..f480286 100644 --- a/app/models/inquiry.rb +++ b/app/models/inquiry.rb @@ -48,7 +48,7 @@ def aasm_event_failed(event_name, old_state_name) after_create :send_notifications - enum office_type: { office: 1, open_space: 2, combined: 3 } + enum office_type: { office_space: 1, office_room: 2, fixed_space: 3, flexible_space: 4 } enum inquiry_status: { pending: 1, started: 2, done: 3 } enum flexible: { yes: 1, no: 2, mixed: 3 } enum start_date: { now: 1, quarter: 2, unsure: 3 } diff --git a/spec/models/inquiry_spec.rb b/spec/models/inquiry_spec.rb index 26334e7..eac86f8 100644 --- a/spec/models/inquiry_spec.rb +++ b/spec/models/inquiry_spec.rb @@ -61,7 +61,7 @@ describe 'Office type' do it { is_expected.to define_enum_for(:office_type) - .with_values({ office: 1, open_space: 2, combined: 3 }) + .with_values({ office_space: 1, office_room: 2, fixed_space: 3, flexible_space: 4 }) } end @@ -135,54 +135,53 @@ describe 'Pending inquiry' do it 'is expected to be able to ":start' do - expect{ + expect do pending_inquiry.start - } - .not_to raise_error + end + .not_to raise_error end it 'is expected to not be able to ":finish"' do - expect{ + expect do pending_inquiry.finish - } - .to raise_error(StandardError) - .with_message("You can't perform this on an inquiry that is 'pending'") + end + .to raise_error(StandardError) + .with_message("You can't perform this on an inquiry that is 'pending'") end end describe 'Started inquiry' do it 'is expected to be able to ":set_to_pending"' do - expect{ + expect do started_inquiry.set_to_pending - } - .not_to raise_error + end + .not_to raise_error end it 'is expected to be able to "finish"' do - expect{ + expect do started_inquiry.finish - } - .not_to raise_error + end + .not_to raise_error end end describe 'Done inquiry' do it 'is expected to not be able to ":set_to_pending"' do - expect{ + expect do done_inquiry.set_to_pending - } - .to raise_error(StandardError) - .with_message("You can't perform this on an inquiry that is 'done'") + end + .to raise_error(StandardError) + .with_message("You can't perform this on an inquiry that is 'done'") end it 'is expected to not be able to ":start"' do - expect{ + expect do done_inquiry.start - } - .to raise_error(StandardError) - .with_message("You can't perform this on an inquiry that is 'done'") + end + .to raise_error(StandardError) + .with_message("You can't perform this on an inquiry that is 'done'") end end end - end diff --git a/spec/requests/api/inquiries/create_spec.rb b/spec/requests/api/inquiries/create_spec.rb index 8804384..f4ee30a 100644 --- a/spec/requests/api/inquiries/create_spec.rb +++ b/spec/requests/api/inquiries/create_spec.rb @@ -7,7 +7,7 @@ params: { inquiry: { size: 1, - office_type: 'office', + office_type: 'office_room', inquiry_status: 'pending', peers: 'Yes', email: 'example@example.com', @@ -105,7 +105,7 @@ params: { inquiry: { size: 1, - office_type: 'office', + office_type: 'office_room', inquiry_status: 'pending', company: 'Craft', peers: 'Yes', diff --git a/spec/requests/api/inquiries/index_spec.rb b/spec/requests/api/inquiries/index_spec.rb index d0d73d6..f83a960 100644 --- a/spec/requests/api/inquiries/index_spec.rb +++ b/spec/requests/api/inquiries/index_spec.rb @@ -21,7 +21,7 @@ end it 'is expected to include the inquiry\'s office type' do - expect(response_json['inquiries'].first['office_type']).to eq 'office' + expect(response_json['inquiries'].first['office_type']).to eq 'office_space' end it 'is expected to include the inquiry\'s status type' do