diff --git a/api/app/settings/common.py b/api/app/settings/common.py index 0c295f971e73..48140ad9d626 100644 --- a/api/app/settings/common.py +++ b/api/app/settings/common.py @@ -1036,7 +1036,31 @@ ENABLE_HUBSPOT_LEAD_TRACKING = env.bool("ENABLE_HUBSPOT_LEAD_TRACKING", False) HUBSPOT_IGNORE_DOMAINS = env.list("HUBSPOT_IGNORE_DOMAINS", []) HUBSPOT_IGNORE_DOMAINS_REGEX = env("HUBSPOT_IGNORE_DOMAINS_REGEX", "") - +HUBSPOT_IGNORE_ORGANISATION_DOMAINS = env.list( + "HUBSPOT_IGNORE_ORGANISATION_DOMAINS", + [ + "126.com", + "163.com", + "aol.com", + "att.net", + "comcast.net", + "gmail.com", + "gmx.com", + "hotmail.com", + "icloud.com", + "live.com", + "mail.com", + "mail.ru", + "outlook.co.uk", + "outlook.com", + "protonmail.com", + "qq.com", + "sina.com", + "yahoo.com", + "yandex.com", + "zoho.com", + ], +) # List of plan ids that support seat upgrades AUTO_SEAT_UPGRADE_PLANS = env.list("AUTO_SEAT_UPGRADE_PLANS", default=[]) diff --git a/api/integrations/lead_tracking/hubspot/client.py b/api/integrations/lead_tracking/hubspot/client.py index 8d0f9544fe8f..e982337b6538 100644 --- a/api/integrations/lead_tracking/hubspot/client.py +++ b/api/integrations/lead_tracking/hubspot/client.py @@ -68,13 +68,19 @@ def create_contact(self, user: FFAdminUser, hubspot_company_id: str) -> dict: return response.to_dict() def create_company( - self, name: str, active_subscription: str, organisation_id: int + self, + name: str, + active_subscription: str, + organisation_id: int, + domain: str | None, ) -> dict: properties = { "name": name, "active_subscription": active_subscription, "orgid": str(organisation_id), } + if domain: + properties["domain"] = domain simple_public_object_input_for_create = SimplePublicObjectInputForCreate( properties=properties, diff --git a/api/integrations/lead_tracking/hubspot/lead_tracker.py b/api/integrations/lead_tracking/hubspot/lead_tracker.py index 15722d01ea54..59a225240e98 100644 --- a/api/integrations/lead_tracking/hubspot/lead_tracker.py +++ b/api/integrations/lead_tracking/hubspot/lead_tracker.py @@ -58,21 +58,28 @@ def create_lead(self, user: FFAdminUser, organisation: Organisation) -> None: # for an existing organisation, so return early. return - hubspot_id = self.get_or_create_organisation_hubspot_id(organisation) + hubspot_id = self.get_or_create_organisation_hubspot_id(organisation, user) self.client.create_contact(user, hubspot_id) - def get_or_create_organisation_hubspot_id(self, organisation: Organisation) -> str: + def get_or_create_organisation_hubspot_id( + self, organisation: Organisation, user: FFAdminUser + ) -> str: """ Return the Hubspot API's id for an organisation. """ if getattr(organisation, "hubspot_organisation", None): return organisation.hubspot_organisation.hubspot_id + if user.email_domain in settings.HUBSPOT_IGNORE_ORGANISATION_DOMAINS: + domain = None + else: + domain = user.email_domain response = self.client.create_company( name=organisation.name, active_subscription=organisation.subscription.plan, organisation_id=organisation.id, + domain=domain, ) # Store the organisation data in the database since we are diff --git a/api/tests/unit/integrations/lead_tracking/hubspot/test_unit_hubspot_lead_tracking.py b/api/tests/unit/integrations/lead_tracking/hubspot/test_unit_hubspot_lead_tracking.py index 8f16082d12d0..b525d967832c 100644 --- a/api/tests/unit/integrations/lead_tracking/hubspot/test_unit_hubspot_lead_tracking.py +++ b/api/tests/unit/integrations/lead_tracking/hubspot/test_unit_hubspot_lead_tracking.py @@ -19,8 +19,102 @@ def test_hubspot_with_new_contact_and_new_organisation( ) -> None: # Given settings.ENABLE_HUBSPOT_LEAD_TRACKING = True + domain = "example.com" user = FFAdminUser.objects.create( - email="new.user@example.com", + email=f"new.user@{domain}", + first_name="Frank", + last_name="Louis", + marketing_consent_given=True, + ) + + future_hubspot_id = "10280696017" + mock_create_company = mocker.patch( + "integrations.lead_tracking.hubspot.client.HubspotClient.create_company", + return_value={ + "id": future_hubspot_id, + "properties": { + "createdate": "2024-02-26T19:41:57.959Z", + "hs_lastmodifieddate": "2024-02-26T19:41:57.959Z", + "hs_object_id": future_hubspot_id, + "hs_object_source": "INTEGRATION", + "hs_object_source_id": "2902325", + "hs_object_source_label": "INTEGRATION", + "name": organisation.name, + }, + "properties_with_history": None, + "created_at": datetime.datetime(2024, 2, 26, 19, 41, 57, 959000), + "updated_at": datetime.datetime(2024, 2, 26, 19, 41, 57, 959000), + "archived": False, + "archived_at": None, + }, + ) + + mock_get_contact = mocker.patch( + "integrations.lead_tracking.hubspot.client.HubspotClient.get_contact", + return_value=None, + ) + + mock_create_contact = mocker.patch( + "integrations.lead_tracking.hubspot.client.HubspotClient.create_contact", + return_value={ + "archived": False, + "archived_at": None, + "created_at": datetime.datetime(2024, 2, 26, 20, 2, 50, 69000), + "id": "1000551", + "properties": { + "createdate": "2024-02-26T20:02:50.069Z", + "email": user.email, + "firstname": user.first_name, + "hs_all_contact_vids": "1000551", + "hs_email_domain": "example.com", + "hs_is_contact": "true", + "hs_is_unworked": "true", + "hs_marketable_status": user.marketing_consent_given, + "hs_object_id": "1000551", + "hs_object_source": "INTEGRATION", + "hs_object_source_id": "2902325", + "hs_object_source_label": "INTEGRATION", + "hs_pipeline": "contacts-lifecycle-pipeline", + "lastmodifieddate": "2024-02-26T20:02:50.069Z", + "lastname": user.last_name, + }, + "properties_with_history": None, + "updated_at": datetime.datetime(2024, 2, 26, 20, 2, 50, 69000), + }, + ) + + assert getattr(organisation, "hubspot_organisation", None) is None + # When + user.add_organisation(organisation, role=OrganisationRole.ADMIN) + + # Then + organisation.refresh_from_db() + assert organisation.hubspot_organisation.hubspot_id == future_hubspot_id + + mock_create_company.assert_called_once_with( + name=organisation.name, + domain=domain, + active_subscription="free", + organisation_id=organisation.id, + ) + mock_create_contact.assert_called_once_with(user, future_hubspot_id) + mock_get_contact.assert_called_once_with(user) + + +def test_hubspot_with_filtered_email_domain_contact_and_new_organisation( + organisation: Organisation, + settings: SettingsWrapper, + mocker: MockerFixture, +) -> None: + # Given + settings.ENABLE_HUBSPOT_LEAD_TRACKING = True + domain = "example.com" + + # Setting that will filter out the domain for the user. + settings.HUBSPOT_IGNORE_ORGANISATION_DOMAINS = [domain] + + user = FFAdminUser.objects.create( + email=f"new.user@{domain}", first_name="Frank", last_name="Louis", marketing_consent_given=True, @@ -89,8 +183,10 @@ def test_hubspot_with_new_contact_and_new_organisation( # Then organisation.refresh_from_db() assert organisation.hubspot_organisation.hubspot_id == future_hubspot_id + # Domain is `None` since it was filtered out. mock_create_company.assert_called_once_with( name=organisation.name, + domain=None, active_subscription="free", organisation_id=organisation.id, )