From a9955a104367ac0974ae8cfccda8371a23cc0990 Mon Sep 17 00:00:00 2001 From: Daniel Mallory Date: Mon, 16 Sep 2024 16:07:53 +0100 Subject: [PATCH] Fixes to enable using the new KYC for progressive onboarding. (#9436) Co-authored-by: Vlad Olaru Co-authored-by: Vlad Olaru --- changelog/dev-9393-embedded-kyc-po | 4 +++ client/onboarding/kyc/index.tsx | 16 +++++++++-- client/onboarding/steps/embedded-kyc.tsx | 12 ++++++++- client/onboarding/tracking.ts | 9 +++++++ client/onboarding/utils.ts | 5 +--- includes/admin/class-wc-payments-admin.php | 27 ++++++++++++++++++- ...wc-rest-payments-onboarding-controller.php | 17 ++++-------- includes/class-wc-payments-account.php | 20 +++++++------- .../class-wc-payments-onboarding-service.php | 15 ++--------- .../class-wc-payments-api-client.php | 16 +++++------ 10 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 changelog/dev-9393-embedded-kyc-po diff --git a/changelog/dev-9393-embedded-kyc-po b/changelog/dev-9393-embedded-kyc-po new file mode 100644 index 00000000000..07d9ad4bf15 --- /dev/null +++ b/changelog/dev-9393-embedded-kyc-po @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Updates to the Embedded KYC to ensure compatibility with Progressive Onboarding diff --git a/client/onboarding/kyc/index.tsx b/client/onboarding/kyc/index.tsx index d2e9a4b5140..ba19b9145d0 100644 --- a/client/onboarding/kyc/index.tsx +++ b/client/onboarding/kyc/index.tsx @@ -13,11 +13,18 @@ import { OnboardingContextProvider } from 'onboarding/context'; import EmbeddedKyc from 'onboarding/steps/embedded-kyc'; import strings from 'onboarding/strings'; import { getConnectUrl } from 'utils'; +import { trackKycExit } from 'wcpay/onboarding/tracking'; const OnboardingKycPage: React.FC = () => { + const urlParams = new URLSearchParams( window.location.search ); + const collectPayoutRequirements = !! urlParams.get( + 'collect_payout_requirements' + ); + const handleExit = () => { - const urlParams = new URLSearchParams( window.location.search ); + trackKycExit(); + // Let the connect logic determine where the merchant should end up. window.location.href = getConnectUrl( { source: @@ -67,7 +74,12 @@ const OnboardingKycPage: React.FC = () => {
- +
diff --git a/client/onboarding/steps/embedded-kyc.tsx b/client/onboarding/steps/embedded-kyc.tsx index dd41c11b335..e01ed82ca90 100644 --- a/client/onboarding/steps/embedded-kyc.tsx +++ b/client/onboarding/steps/embedded-kyc.tsx @@ -28,10 +28,14 @@ import { getConnectUrl, getOverviewUrl } from 'wcpay/utils'; interface Props { continueKyc?: boolean; + collectPayoutRequirements?: boolean; } // TODO: extract this logic and move it to a generic component to be used for all embedded components, not just onboarding. -const EmbeddedKyc: React.FC< Props > = ( { continueKyc = false } ) => { +const EmbeddedKyc: React.FC< Props > = ( { + continueKyc = false, + collectPayoutRequirements = false, +} ) => { const { data } = useOnboardingContext(); const [ locale, setLocale ] = useState( '' ); const [ publishableKey, setPublishableKey ] = useState( '' ); @@ -188,6 +192,12 @@ const EmbeddedKyc: React.FC< Props > = ( { continueKyc = false } ) => { ) } onExit={ handleOnExit } + collectionOptions={ { + fields: collectPayoutRequirements + ? 'eventually_due' + : 'currently_due', + futureRequirements: 'omit', + } } /> ) } diff --git a/client/onboarding/tracking.ts b/client/onboarding/tracking.ts index e4d9ec557f7..1250e4c5a16 100644 --- a/client/onboarding/tracking.ts +++ b/client/onboarding/tracking.ts @@ -57,6 +57,15 @@ export const trackRedirected = ( isPoEligible: boolean ): void => { } ); }; +export const trackKycExit = (): void => { + const urlParams = new URLSearchParams( window.location.search ); + + recordEvent( 'wcpay_onboarding_kyc_exit', { + source: + urlParams.get( 'source' )?.replace( /[^\w-]+/g, '' ) || 'unknown', + } ); +}; + export const trackAccountReset = (): void => recordEvent( 'wcpay_onboarding_flow_reset' ); diff --git a/client/onboarding/utils.ts b/client/onboarding/utils.ts index efab0971875..a95c3e298ef 100644 --- a/client/onboarding/utils.ts +++ b/client/onboarding/utils.ts @@ -60,18 +60,15 @@ export const getBusinessTypes = (): Country[] => { * * @param data The form data. * @param isPoEligible Whether the user is eligible for a PO account. - * @param collectPayoutRequirements Whether to collect payout requirements. */ export const createAccountSession = async ( data: OnboardingFields, - isPoEligible: boolean, - collectPayoutRequirements = false + isPoEligible: boolean ): Promise< AccountKycSession > => { return await apiFetch< AccountKycSession >( { path: addQueryArgs( `${ NAMESPACE }/onboarding/kyc/session`, { self_assessment: fromDotNotation( data ), progressive: isPoEligible, - collect_payout_requirements: collectPayoutRequirements, } ), method: 'GET', } ); diff --git a/includes/admin/class-wc-payments-admin.php b/includes/admin/class-wc-payments-admin.php index de577e4bcad..9bad5a0ac13 100644 --- a/includes/admin/class-wc-payments-admin.php +++ b/includes/admin/class-wc-payments-admin.php @@ -348,7 +348,7 @@ public function add_payments_menu() { remove_submenu_page( 'wc-admin&path=/payments/connect', 'wc-admin&path=/payments/onboarding' ); } - // Register /payments/onboarding/kyc only when we have a Stripe account, but the Stripe KYC is not finished (details not submitted). + // We handle how we register this page slightly differently depending on if details are submitted or not. if ( WC_Payments_Features::is_embedded_kyc_enabled() && $this->account->is_stripe_connected() && ! $this->account->is_details_submitted() ) { wc_admin_register_page( [ @@ -359,6 +359,7 @@ public function add_payments_menu() { 'capability' => 'manage_woocommerce', 'nav_args' => [ 'parent' => 'wc-payments', + 'order' => 50, ], ] ); @@ -366,6 +367,25 @@ public function add_payments_menu() { } if ( $should_render_full_menu ) { + // Only register if details are submitted and the account is PO. + if ( WC_Payments_Features::is_embedded_kyc_enabled() + && $this->account->is_stripe_connected() + && $this->account->is_details_submitted() + && $this->account->is_progressive_onboarding_in_progress() + ) { + $this->admin_child_pages['wc-payments-onboarding-kyc'] = [ + 'id' => 'wc-payments-onboarding-kyc', + 'title' => __( 'Continue onboarding', 'woocommerce-payments' ), + 'parent' => 'wc-payments', + 'path' => '/payments/onboarding/kyc', + 'capability' => 'manage_woocommerce', + 'nav_args' => [ + 'parent' => 'wc-payments', + 'order' => 50, + ], + ]; + } + if ( $this->account->is_card_present_eligible() && $this->account->has_card_readers_available() ) { $this->admin_child_pages['wc-payments-card-readers'] = [ 'id' => 'wc-payments-card-readers', @@ -415,6 +435,11 @@ public function add_payments_menu() { wc_admin_register_page( $admin_child_page ); } + // Remove the "Continue onboarding" submenu item, if it exists. + if ( in_array( 'wc-payments-onboarding-kyc', array_keys( $this->admin_child_pages ), true ) ) { + remove_submenu_page( 'wc-admin&path=/payments/overview', 'wc-admin&path=/payments/onboarding/kyc' ); + } + wc_admin_connect_page( [ 'id' => 'woocommerce-settings-payments-woocommerce-payments', diff --git a/includes/admin/class-wc-rest-payments-onboarding-controller.php b/includes/admin/class-wc-rest-payments-onboarding-controller.php index da65bf5770c..3124e67d61a 100644 --- a/includes/admin/class-wc-rest-payments-onboarding-controller.php +++ b/includes/admin/class-wc-rest-payments-onboarding-controller.php @@ -56,17 +56,12 @@ public function register_routes() { 'callback' => [ $this, 'get_embedded_kyc_session' ], 'permission_callback' => [ $this, 'check_permission' ], 'args' => [ - 'progressive' => [ + 'progressive' => [ 'required' => false, 'description' => 'Whether the session is for progressive onboarding.', 'type' => 'string', ], - 'collect_payout_requirements' => [ - 'required' => false, - 'description' => 'Whether the session is for collecting payout requirements.', - 'type' => 'string', - ], - 'self_assessment' => [ + 'self_assessment' => [ 'required' => false, 'description' => 'The self-assessment data.', 'type' => 'object', @@ -204,14 +199,12 @@ public function register_routes() { * @return WP_Error|WP_REST_Response */ public function get_embedded_kyc_session( WP_REST_Request $request ) { - $self_assessment_data = ! empty( $request->get_param( 'self_assessment' ) ) ? wc_clean( wp_unslash( $request->get_param( 'self_assessment' ) ) ) : []; - $progressive = ! empty( $request->get_param( 'progressive' ) ) && 'true' === $request->get_param( 'progressive' ); - $collect_payout_requirements = ! empty( $request->get_param( 'collect_payout_requirements' ) ) && 'true' === $request->get_param( 'collect_payout_requirements' ); + $self_assessment_data = ! empty( $request->get_param( 'self_assessment' ) ) ? wc_clean( wp_unslash( $request->get_param( 'self_assessment' ) ) ) : []; + $progressive = ! empty( $request->get_param( 'progressive' ) ) && 'true' === $request->get_param( 'progressive' ); $account_session = $this->onboarding_service->create_embedded_kyc_session( $self_assessment_data, - $progressive, - $collect_payout_requirements + $progressive ); if ( $account_session ) { diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index 33f829ee0de..bde6316122a 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -1537,10 +1537,11 @@ public function maybe_handle_onboarding() { $create_test_drive_account ? 'test_drive' : ( $should_onboard_in_test_mode ? 'test' : 'live' ), $wcpay_connect_param, [ - 'promo' => ! empty( $incentive_id ) ? $incentive_id : false, - 'progressive' => $progressive ? 'true' : false, - 'source' => $onboarding_source, - 'from' => WC_Payments_Onboarding_Service::FROM_STRIPE, + 'promo' => ! empty( $incentive_id ) ? $incentive_id : false, + 'progressive' => $progressive ? 'true' : false, + 'collect_payout_requirements' => $collect_payout_requirements ? 'true' : false, + 'source' => $onboarding_source, + 'from' => WC_Payments_Onboarding_Service::FROM_STRIPE, ] ); @@ -1873,11 +1874,12 @@ private function init_stripe_onboarding( string $setup_mode, string $wcpay_conne WC_Payments_Onboarding_Service::set_onboarding_eligibility_modal_dismissed(); } - // If we are in the middle of an embedded onboarding, go to the KYC page. - // In this case, we don't need to generate a return URL from Stripe, and we - // can rely on the JS logic to generate the session. - // Currently under feature flag. - if ( WC_Payments_Features::is_embedded_kyc_enabled() && $this->onboarding_service->is_embedded_kyc_in_progress() ) { + /* + * If we are in the middle of an embedded onboarding, or this is an attempt to finalize PO, go to the KYC page. + * In this case, we don't need to generate a return URL from Stripe, and we can rely on the JS logic to generate the session. + * Currently under feature flag. + */ + if ( WC_Payments_Features::is_embedded_kyc_enabled() && ( $this->onboarding_service->is_embedded_kyc_in_progress() || $collect_payout_requirements ) ) { // We want to carry over the connect link from value because with embedded KYC // there is no interim step for the user. $additional_args['from'] = WC_Payments_Onboarding_Service::get_from(); diff --git a/includes/class-wc-payments-onboarding-service.php b/includes/class-wc-payments-onboarding-service.php index e4332f42ab9..8bf8f686255 100644 --- a/includes/class-wc-payments-onboarding-service.php +++ b/includes/class-wc-payments-onboarding-service.php @@ -157,13 +157,12 @@ function () use ( $locale ) { * * @param array $self_assessment_data Self assessment data. * @param boolean $progressive Whether the onboarding is progressive. - * @param boolean $collect_payout_requirements Whether to collect payout requirements. * * @return array Session data. * * @throws API_Exception */ - public function create_embedded_kyc_session( array $self_assessment_data, bool $progressive = false, bool $collect_payout_requirements = false ): array { + public function create_embedded_kyc_session( array $self_assessment_data, bool $progressive = false ): array { if ( ! $this->payments_api_client->is_server_connected() ) { return []; } @@ -172,15 +171,6 @@ public function create_embedded_kyc_session( array $self_assessment_data, bool $ // Make sure the onboarding test mode DB flag is set. self::set_test_mode( 'live' !== $setup_mode ); - if ( ! $collect_payout_requirements ) { - // Clear onboarding related account options if this is an initial onboarding attempt. - self::clear_account_options(); - } else { - // Since we assume user has already either gotten here from the eligibility modal, - // or has already dismissed it, we should set the modal as dismissed so it doesn't display again. - self::set_onboarding_eligibility_modal_dismissed(); - } - $site_data = [ 'site_username' => wp_get_current_user()->user_login, 'site_locale' => get_locale(), @@ -196,8 +186,7 @@ public function create_embedded_kyc_session( array $self_assessment_data, bool $ array_filter( $user_data ), // nosemgrep: audit.php.lang.misc.array-filter-no-callback -- output of array_filter is escaped. array_filter( $account_data ), // nosemgrep: audit.php.lang.misc.array-filter-no-callback -- output of array_filter is escaped. $actioned_notes, - $progressive, - $collect_payout_requirements + $progressive ); } catch ( API_Exception $e ) { // If we fail to create the session, return an empty array. diff --git a/includes/wc-payment-api/class-wc-payments-api-client.php b/includes/wc-payment-api/class-wc-payments-api-client.php index 94d5dd6087b..13b25e07dd6 100644 --- a/includes/wc-payment-api/class-wc-payments-api-client.php +++ b/includes/wc-payment-api/class-wc-payments-api-client.php @@ -980,23 +980,21 @@ public function get_onboarding_data( bool $live_account, string $return_url, arr * @param array $account_data Account data to be prefilled. * @param array $actioned_notes Actioned notes to be sent. * @param bool $progressive Whether progressive onboarding should be enabled for this onboarding. - * @param bool $collect_payout_requirements Whether we need to collect payout requirements. * * @return array * * @throws API_Exception */ - public function initialize_onboarding_embedded_kyc( bool $live_account, array $site_data = [], array $user_data = [], array $account_data = [], array $actioned_notes = [], bool $progressive = false, bool $collect_payout_requirements = false ): array { + public function initialize_onboarding_embedded_kyc( bool $live_account, array $site_data = [], array $user_data = [], array $account_data = [], array $actioned_notes = [], bool $progressive = false ): array { $request_args = apply_filters( 'wc_payments_get_onboarding_data_args', [ - 'site_data' => $site_data, - 'user_data' => $user_data, - 'account_data' => $account_data, - 'actioned_notes' => $actioned_notes, - 'create_live_account' => $live_account, - 'progressive' => $progressive, - 'collect_payout_requirements' => $collect_payout_requirements, + 'site_data' => $site_data, + 'user_data' => $user_data, + 'account_data' => $account_data, + 'actioned_notes' => $actioned_notes, + 'create_live_account' => $live_account, + 'progressive' => $progressive, ] );