Skip to content

Commit

Permalink
Fixes to enable using the new KYC for progressive onboarding. (#9436)
Browse files Browse the repository at this point in the history
Co-authored-by: Vlad Olaru <[email protected]>
Co-authored-by: Vlad Olaru <[email protected]>
  • Loading branch information
3 people authored Sep 16, 2024
1 parent 0b88126 commit a9955a1
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 51 deletions.
4 changes: 4 additions & 0 deletions changelog/dev-9393-embedded-kyc-po
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Updates to the Embedded KYC to ensure compatibility with Progressive Onboarding
16 changes: 14 additions & 2 deletions client/onboarding/kyc/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -67,7 +74,12 @@ const OnboardingKycPage: React.FC = () => {
</div>
<div className="stepper__wrapper">
<div className="stepper__content">
<EmbeddedKyc continueKyc={ true } />
<EmbeddedKyc
continueKyc={ true }
collectPayoutRequirements={
collectPayoutRequirements
}
/>
</div>
</div>
</OnboardingContextProvider>
Expand Down
12 changes: 11 additions & 1 deletion client/onboarding/steps/embedded-kyc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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( '' );
Expand Down Expand Up @@ -188,6 +192,12 @@ const EmbeddedKyc: React.FC< Props > = ( { continueKyc = false } ) => {
)
}
onExit={ handleOnExit }
collectionOptions={ {
fields: collectPayoutRequirements
? 'eventually_due'
: 'currently_due',
futureRequirements: 'omit',
} }
/>
</ConnectComponentsProvider>
) }
Expand Down
9 changes: 9 additions & 0 deletions client/onboarding/tracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' );

Expand Down
5 changes: 1 addition & 4 deletions client/onboarding/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
} );
Expand Down
27 changes: 26 additions & 1 deletion includes/admin/class-wc-payments-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
[
Expand All @@ -359,13 +359,33 @@ public function add_payments_menu() {
'capability' => 'manage_woocommerce',
'nav_args' => [
'parent' => 'wc-payments',
'order' => 50,
],
]
);
remove_submenu_page( 'wc-admin&path=/payments/connect', 'wc-admin&path=/payments/onboarding/kyc' );
}

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',
Expand Down Expand Up @@ -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',
Expand Down
17 changes: 5 additions & 12 deletions includes/admin/class-wc-rest-payments-onboarding-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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 ) {
Expand Down
20 changes: 11 additions & 9 deletions includes/class-wc-payments-account.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
]
);

Expand Down Expand Up @@ -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();
Expand Down
15 changes: 2 additions & 13 deletions includes/class-wc-payments-onboarding-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 [];
}
Expand All @@ -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(),
Expand All @@ -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.
Expand Down
16 changes: 7 additions & 9 deletions includes/wc-payment-api/class-wc-payments-api-client.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
]
);

Expand Down

0 comments on commit a9955a1

Please sign in to comment.