From 56aeb701cd1a31cb96e1dfae544fe30d0a6ad4f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oriol=20Roqu=C3=A9=20Paniagua?= Date: Mon, 19 May 2025 15:41:48 +0000 Subject: [PATCH] Merged PR 5256: Reporting version of New Dash Onboarding # Description Reporting version of New Dash Onboarding It also adds a missing description of a field. It also adapts the logic for Hubspot Onboarding Owner, after a discussion with Alex. It still does not cover 100% of the cases but he's investigating the rest. # Checklist - [X] The edited models and dependants run properly with production data. - [X] The edited models are sufficiently documented. - [X] The edited models contain PK tests, and I've ran and passed them. - [ ] I have checked for DRY opportunities with other models and docs. - [ ] I've picked the right materialization for the affected models. # Other - [ ] Check if a full-refresh is required after this PR is merged. Related work items: #30249 --- models/intermediate/cross/schema.yml | 8 + .../hubspot/int_hubspot__deal.sql | 29 +- .../general/new_dash_deal_onboarding.sql | 47 +++ models/reporting/general/schema.yml | 343 ++++++++++++++++++ seeds/stg_seed__hubspot_account_owner.csv | 20 +- 5 files changed, 439 insertions(+), 8 deletions(-) create mode 100644 models/reporting/general/new_dash_deal_onboarding.sql diff --git a/models/intermediate/cross/schema.yml b/models/intermediate/cross/schema.yml index bc91f64..40da0c7 100644 --- a/models/intermediate/cross/schema.yml +++ b/models/intermediate/cross/schema.yml @@ -3874,6 +3874,14 @@ models: List of all distinct services that are applied in all listings for this account, separated by "|" and ordered alphabetically. + - name: active_services_in_programs_applied_to_listings + data_type: text + description: | + List of all distinct services that are currently active i.e., that + are applied in active listings for this account, separated by "|" + and ordered alphabetically. + These are the current services that can be applied to new bookings. + - name: has_churned data_type: boolean description: | diff --git a/models/intermediate/hubspot/int_hubspot__deal.sql b/models/intermediate/hubspot/int_hubspot__deal.sql index a6db0c7..63446bd 100644 --- a/models/intermediate/hubspot/int_hubspot__deal.sql +++ b/models/intermediate/hubspot/int_hubspot__deal.sql @@ -1,5 +1,6 @@ {% set id_deal_pipelines_excluded = "('15380854')" %} -{% set generic_account_manager_names = "('Host Services')" %} +{% set generic_account_manager_names = "('HOST SERVICES')" %} +{% set guardhog_customer_conversion_source = "('GUARDHOG CUSTOMER CONVERSION')" %} with stg_hubspot__deals as (select * from {{ ref("stg_hubspot__deals") }}), @@ -20,13 +21,29 @@ select d.live_date_utc, d.cancellation_date_utc, d.account_manager, + -- Following logic discussed with Alex A. on 2025-05-19 to determine the + -- onboarding owner case - when d.onboarding_owner is not null - then onboarding_owner - when - d.onboarding_owner is null - and d.account_manager in {{ generic_account_manager_names }} + -- 1. If the cloned onboarding owner is not null, use that. This should reflect + -- most of the cases. + when d.onboarding_owner__cloned_ is not null + then d.onboarding_owner__cloned_ + -- 2. If the cloned onboarding owner is null and the onboarding owner is not + -- null, use the second. It should cover few exceptional cases. + when d.onboarding_owner__cloned_ is null and d.onboarding_owner is not null + then d.onboarding_owner + -- 3. If the deal is a conversion from Guardhog to Truvi, the onboarding owner + -- should always be the HubSpot account owner. + when upper(d.deal_source) in {{ guardhog_customer_conversion_source }} then hao.hubspot_account_owner + -- 4. If the onboarding owner is null and the account manager is in the generic + -- account manager names, use the HubSpot account owner. This is because is + -- actually a Sales person that handles the onboarding. + when + d.onboarding_owner__cloned_ is null + and upper(d.account_manager) in {{ generic_account_manager_names }} + then hao.hubspot_account_owner + -- For all other cases, set the onboarding owner to null. else null end as onboarding_owner, dp.deal_pipeline_name as deal_pipeline, diff --git a/models/reporting/general/new_dash_deal_onboarding.sql b/models/reporting/general/new_dash_deal_onboarding.sql new file mode 100644 index 0000000..64bca25 --- /dev/null +++ b/models/reporting/general/new_dash_deal_onboarding.sql @@ -0,0 +1,47 @@ +with + int_new_dash_deal_onboarding as ( + select * from {{ ref("int_new_dash_deal_onboarding") }} + ) +select + id_deal, + deal_name, + id_deal || '-' || coalesce(deal_name, '') as deal, + onboarding_owner, + account_manager, + platform_company_name, + count_platform_accounts, + count_listings, + count_active_listings, + count_listings_with_upgraded_programs, + count_active_listings_with_active_upgraded_programs, + count_bookings, + count_bookings_with_paid_service, + count_programs_at_deal_level, + count_upgraded_programs_at_deal_level, + count_upgraded_programs_at_listing_level, + count_active_upgraded_programs_at_active_listing_level, + contract_signed_date_utc, + live_date_utc, + cancellation_date_utc, + backend_account_creation_utc, + first_listing_created_at_utc, + first_booking_created_at_utc, + first_program_created_at_utc, + first_upgraded_program_created_at_utc, + first_upgraded_program_applied_to_listing_at_utc, + first_booking_with_paid_services_created_at_utc, + first_invoice_at_utc, + expressed_service_interest, + services_in_programs_at_deal_level, + services_in_programs_applied_to_listings, + active_services_in_programs_applied_to_listings, + has_churned, + has_listings, + has_active_listings, + has_bookings, + has_been_invoiced, + are_all_bookings_free, + is_account_no_longer_generating_paid_bookings, + has_account_changed_services_applied_in_listings, + are_active_services_different_from_expressed_interest +from int_new_dash_deal_onboarding diff --git a/models/reporting/general/schema.yml b/models/reporting/general/schema.yml index af71d2a..20cf9fd 100644 --- a/models/reporting/general/schema.yml +++ b/models/reporting/general/schema.yml @@ -2692,3 +2692,346 @@ models: Flag indicating if the account has switched to major decline in the current month. 1 for yes, 0 for no. + + - name: new_dash_deal_onboarding + description: | + A dedicated model to track the onboarding stages of new accounts (deals) + in New Dash. + This excludes any deal that has been migrated from Old Dash, so it just + contains "new business". + + columns: + - name: id_deal + data_type: text + description: | + Unique identifier of an account. + data_tests: + - not_null + - unique + + - name: deal_name + data_type: text + description: | + Name of the deal according to HubSpot. + data_tests: + - not_null + - unique + + - name: deal + data_type: text + description: | + Combination of the ID and the Name of the deal. + + - name: onboarding_owner + data_type: text + description: | + Name of the person that is in charge of onboarding this account. + + - name: account_manager + data_type: text + description: | + Account manager in charge of the account. + + - name: platform_company_name + data_type: text + description: | + Name of the company in Truvi's backend. + + - name: count_platform_accounts + data_type: integer + description: | + Amount of Backend accounts (users) linked to this Deal. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 1 + max_value: 1 + strictly: false + + - name: count_programs_at_deal_level + data_type: integer + description: | + Total amount of programs that this account has. These might not + necessarily be applied to a Listing. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + strictly: false + - name: count_listings + data_type: integer + description: | + Total count of Listings from this account. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + strictly: false + + - name: count_active_listings + data_type: integer + description: | + Count of Listings that are currently active, meaning, that have not + been deactivated. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + max_value: count_listings + strictly: false + + - name: count_listings_with_upgraded_programs + data_type: integer + description: | + Count of Listings that have had a program applied that contains at least + one service different to Basic Screening. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + max_value: count_listings + strictly: false + + - name: count_active_listings_with_active_upgraded_programs + data_type: integer + description: | + Count of Listings that are currently active and that currently have an + active upgraded program, meaning, that contains at least one service + different to Basic Screening. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + max_value: count_active_listings + strictly: false + + - name: count_bookings + data_type: integer + description: | + Total count of Bookings generated from this account. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + strictly: false + + - name: count_bookings_with_paid_service + data_type: integer + description: | + Count of Bookings that have at least one paid service. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + max_value: count_bookings + strictly: false + + - name: count_upgraded_programs_at_deal_level + data_type: integer + description: | + Count of programs that this account has that contain, at least, one + service different to Basic Screening. These might not necessarily + be applied to a Listing. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + max_value: count_programs_at_deal_level + strictly: false + + - name: count_upgraded_programs_at_listing_level + data_type: integer + description: | + Count of programs that contain at least one service different to + Basic Screening that have been applied to a Listing. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + max_value: count_upgraded_programs_at_deal_level + strictly: false + + - name: count_active_upgraded_programs_at_active_listing_level + data_type: integer + description: | + Count of programs that contain at least one service different to + Basic Screening that are currently active and applied to an + active Listing. + data_tests: + - not_null + - dbt_expectations.expect_column_values_to_be_between: + min_value: 0 + max_value: count_upgraded_programs_at_listing_level + strictly: false + + - name: contract_signed_date_utc + data_type: date + description: | + Date in which the contract was signed according to HubSpot. + + - name: live_date_utc + data_type: date + description: | + Date in which the Deal went live according to HubSpot. + + - name: cancellation_date_utc + data_type: date + description: | + Date in which the Deal was cancelled according to HubSpot. + + - name: backend_account_creation_utc + data_type: timestamp without timezone + description: | + Timestamp in which the account was created in the backend. + + - name: first_listing_created_at_utc + data_type: timestamp without timezone + description: | + Timestamp in which the first listing was created in the backend. + + - name: first_booking_created_at_utc + data_type: timestamp without timezone + description: | + Timestamp in which the first booking was created in the backend. + + - name: first_program_created_at_utc + data_type: timestamp without timezone + description: | + Timestamp in which the first program was created at account level + in the backend. + + - name: first_upgraded_program_created_at_utc + data_type: timestamp without timezone + description: | + Timestamp in which the first program was applied to a listing + for this account, in the backend. + + - name: first_upgraded_program_applied_to_listing_at_utc + data_type: timestamp without timezone + description: | + Timestamp in which the first upgraded program was applied to a listing + for this account, in the backend. + + - name: first_booking_with_paid_services_created_at_utc + data_type: timestamp without timezone + description: | + Timestamp in which the first booking that contained paid services + was created for this account, in the backend. + + - name: first_invoice_at_utc + data_type: timestamp without timezone + description: | + Timestamp in which the first invoice happened for this account in Xero. + + - name: expressed_service_interest + data_type: text + description: | + List of services that during onboarding generated interest + to the client. + + - name: services_in_programs_at_deal_level + data_type: text + description: | + List of all distinct services that appear in programs at + deal level, separated by "|" and ordered alphabetically. + + - name: services_in_programs_applied_to_listings + data_type: text + description: | + List of all distinct services that are applied in all listings + for this account, separated by "|" and ordered alphabetically. + + - name: active_services_in_programs_applied_to_listings + data_type: text + description: | + List of all distinct services that are currently active i.e., that + are applied in active listings for this account, separated by "|" + and ordered alphabetically. + These are the current services that can be applied to new bookings. + + - name: has_churned + data_type: boolean + description: | + True if the account has a cancellation date in HubSpot, + False otherwise. + data_tests: + - not_null + + - name: has_listings + data_type: boolean + description: | + True if the account has at least one listing appearing in + the backend, False otherwise. + data_tests: + - not_null + + - name: has_active_listings + data_type: boolean + description: | + True if the account has at least one listing that is currently + active in the backend, False otherwise. + data_tests: + - not_null + + - name: has_bookings + data_type: boolean + description: | + True if the account has at least one booking appearing in + the backend, False otherwise. + data_tests: + - not_null + + - name: has_been_invoiced + data_type: boolean + description: | + True if the account has at least one invoice appearing in + Xero, False otherwise. + data_tests: + - not_null + + - name: are_all_bookings_free + data_type: boolean + description: | + True if the account has bookings but all of them are free, + meaning, there's not a single service being paid. + data_tests: + - not_null + + - name: is_account_no_longer_generating_paid_bookings + data_type: boolean + description: | + True if the account has had in the past paid bookings but + at the moment there's not a single listing that contains + an active upgraded program. + Encouraged to be used alongside a filter to determine if + the account has churned or not. + data_tests: + - not_null + + - name: has_account_changed_services_applied_in_listings + data_type: boolean + description: | + True if the active services in programs applied to listings + is different than the services that were historically applied. + By nature, this always means that at least one service was + being applied before that is no longer being applied. This can + indicate a real decrease in services applied that could be linked to + a potential revenue loss (decrease in booking fees), + although it's also possible that the account has changed from a + certain low-level tier to a higher-level one (ex: from Basic + Protection to Protection Pro). + data_tests: + - not_null + + - name: are_active_services_different_from_expressed_interest + data_type: boolean + description: | + True if the services that are currently applied to listings + are different than the ones that were expressed as interest + during onboarding. + This can indicate a potential need for upselling for business + teams to act upon, although it's also possible that the account + has added new services that where not expressed as interest + during onboarding. + data_tests: + - not_null diff --git a/seeds/stg_seed__hubspot_account_owner.csv b/seeds/stg_seed__hubspot_account_owner.csv index c91043f..6256ab2 100644 --- a/seeds/stg_seed__hubspot_account_owner.csv +++ b/seeds/stg_seed__hubspot_account_owner.csv @@ -3,5 +3,21 @@ "679781281",Cali Bowen "203088812",Chloe Fraser "1837277529",Danielle Miller -"76054743",María belén Florio -"76054690",Paola Zapata \ No newline at end of file +"76054743",María Belén Florio +"76054690",Paola Zapata +"208877189",Evan Roll +"52620291",Lucy Hiden +"26221498",Steven Hughes +"49206237",Cailtin Ayliffe +"67553424",Mackenzie Kapral +"63001264",Emyr Hyde +"66104586",Sally Farrell +"13487398",Sarah Barrett +"46718836",Francisco Ochoa +"46715149",Tony Amigleo +"67553422",Abby Matlin +"48878520",Nicole Lamb +"48026832",Kat Volkova +"46715149",Tony Amigleo +"11891326",Hannah Audin +"9580086",Hannah Audin \ No newline at end of file