Skip to content

Commit

Permalink
Extensively document and refactor for clarity the account onboarding …
Browse files Browse the repository at this point in the history
…handling
  • Loading branch information
vladolaru committed Jul 16, 2024
1 parent 6b31dc2 commit aa3cbe2
Showing 1 changed file with 113 additions and 32 deletions.
145 changes: 113 additions & 32 deletions includes/class-wc-payments-account.php
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,11 @@ public function maybe_handle_onboarding() {
return;
}

/**
* ==================
* Handle Stripe dashboard login links.
* ==================
*/
if ( isset( $_GET['wcpay-login'] ) && check_admin_referer( 'wcpay-login' ) ) {
try {
if ( $this->is_stripe_connected() && ! $this->is_details_submitted() ) {
Expand All @@ -889,9 +894,19 @@ public function maybe_handle_onboarding() {

$this->redirect_service->redirect_to_overview_page_with_error( [ 'wcpay-login-error' => '1' ] );
}

// We should not reach this point as we either redirect to the Stripe dashboard
// or to the Payments > Overview page with an error message.
return;
}

/**
* ==================
* Handle the Jetpack re-connection in case of missing connection owner.
*
* @see self::get_wpcom_reconnect_url()
* ==================
*/
if ( isset( $_GET['wcpay-reconnect-wpcom'] ) && check_admin_referer( 'wcpay-reconnect-wpcom' ) ) {
// Track the Jetpack connection start.
$this->tracks_event( self::TRACKS_EVENT_ACCOUNT_CONNECT_WPCOM_CONNECTION_START );
Expand All @@ -900,55 +915,74 @@ public function maybe_handle_onboarding() {
return;
}

/**
* ==================
* Handle connect links that trigger either the onboarding flow start or its continuation.
*
* If the onboarding has finished, we will redirect to the Payments > Overview page.
* ==================
*/
if ( isset( $_GET['wcpay-connect'] ) && check_admin_referer( 'wcpay-connect' ) ) {
$wcpay_connect_param = sanitize_text_field( wp_unslash( $_GET['wcpay-connect'] ) );
$incentive = ! empty( $_GET['promo'] ) ? sanitize_text_field( wp_unslash( $_GET['promo'] ) ) : '';
$progressive = ! empty( $_GET['progressive'] ) && 'true' === $_GET['progressive'];
$create_builder_account = ! empty( $_GET['create_builder_account'] ) && 'true' === $_GET['create_builder_account'];

// Track connection start.
if ( ! isset( $_GET['wcpay-connect-jetpack-success'] ) ) {
// Determine the original source from where the merchant entered the onboarding flow.
$onboarding_source = WC_Payments_Onboarding_Service::get_source( (string) wp_get_referer(), $_GET );

// Hide menu notification badge upon starting setup.
update_option( 'wcpay_menu_badge_hidden', 'yes' );

$test_mode = isset( $_GET['test_mode'] ) ? boolval( wc_clean( wp_unslash( $_GET['test_mode'] ) ) ) : false;
// Track WooPayments onboarding (aka connection) start.
// We should not have a connected Stripe account. If we do, it means we are not at the very start,
// but somewhere in between.
// Exclude returns from the Jetpack/WPCOM connection screens.
if ( ! $this->is_stripe_connected() && ! isset( $_GET['wcpay-connect-jetpack-success'] ) ) {
$test_mode = isset( $_GET['test_mode'] ) && wc_clean( wp_unslash( $_GET['test_mode'] ) );
$event_properties = [
'incentive' => $incentive,
'mode' => $test_mode || WC_Payments::mode()->is_test() ? 'test' : 'live',
'source' => $onboarding_source,
];
$this->tracks_event(
self::TRACKS_EVENT_ACCOUNT_CONNECT_START,
$event_properties
);
}

$connect_page_source = WC_Payments_Onboarding_Service::get_source( (string) wp_get_referer(), $_GET );
// Redirect to the onboarding flow page if the account is not onboarded otherwise to the overview page.
// Builder accounts are handled below and redirected to Stripe KYC directly.
if ( ! $create_builder_account && in_array(
$connect_page_source,
// Main onboarding flow sources/entry-points are handled separately:
// - redirect to the Jetpack connection screens if there is no connection;
// - redirect to our onboarding wizard (MOX) if we have a connection but no Stripe account;
// - let other states be handled by the default business logic.
// We exclude builder flow onboardings from this special handling and let them use the fallback handling.
if ( in_array(
$onboarding_source,
[
WC_Payments_Onboarding_Service::SOURCE_WCADMIN_PAYMENT_TASK,
WC_Payments_Onboarding_Service::SOURCE_WCPAY_CONNECT_PAGE,
WC_Payments_Onboarding_Service::SOURCE_WCADMIN_SETTINGS_PAGE,
WC_Payments_Onboarding_Service::SOURCE_WCADMIN_INCENTIVE_PAGE,
],
true
) ) {
// Redirect non-onboarded account to the onboarding flow, otherwise to payments overview page.
) && ! $create_builder_account ) {

// Handle the state with no Stripe account.
// We either need to redirect to the onboarding wizard (MOX)
// or first set up the Jetpack connection and redirect to the onboarding wizard after a successful connection.
if ( ! $this->is_stripe_connected() ) {
$should_onboard_in_test_mode = isset( $_GET['test_mode'] ) ? boolval( wc_clean( wp_unslash( $_GET['test_mode'] ) ) ) : false;
$should_onboard_in_test_mode = isset( $_GET['test_mode'] ) && wc_clean( wp_unslash( $_GET['test_mode'] ) );
if ( ! $should_onboard_in_test_mode && WC_Payments_Onboarding_Service::is_test_mode_enabled() ) {
// If there is no test mode in the URL informing us to onboard in test mode,
// but the onboarding test mode is enabled in our DB, we should disable it.
// This is most likely a leftover from a previous onboarding attempt.
WC_Payments_Onboarding_Service::set_test_mode( false );
}

if ( WC_Payments_Onboarding_Service::SOURCE_WCADMIN_SETTINGS_PAGE === $connect_page_source ) {
$this->redirect_service->redirect_to_connect_page( null, 'WCADMIN_PAYMENT_SETTINGS' );
} else {
$this->redirect_to_onboarding_page_or_start_server_connection( $connect_page_source );
}
} elseif ( WC_Payments_Onboarding_Service::SOURCE_WCADMIN_SETTINGS_PAGE === $connect_page_source && ! $this->is_details_submitted() ) {
$this->redirect_to_onboarding_page_or_start_server_connection( $onboarding_source );
} elseif ( ! $this->is_details_submitted() && $this->has_working_jetpack_connection() ) {
// Handle the state where we have a connected Stripe account, but it is not fully onboarded.
// We redirect to the Stripe KYC for the merchant to finish verifications.
try {
$this->init_stripe_onboarding(
$wcpay_connect_param,
Expand All @@ -963,48 +997,61 @@ public function maybe_handle_onboarding() {
__( 'There was a problem redirecting you to the account connection page. Please try again.', 'woocommerce-payments' )
);
}

// We should not reach this point as we either redirect to the Stripe KYC
// or to the Connect page with an error message.
return;
} else {
// Accounts with Stripe account connected will be redirected to the overview page.
$this->redirect_service->redirect_to_overview_page();
}
}

// Handle the flow for a builder moving from test to live.
if ( WC_Payments_Onboarding_Service::SOURCE_WCPAY_SETUP_LIVE_PAYMENTS === $connect_page_source ) {
// Handle the flow for [a builder] moving from test to live.
if ( ! empty( $_GET['wcpay-disable-onboarding-test-mode'] ) && 'true' === $_GET['wcpay-disable-onboarding-test-mode'] ) {
$test_mode = WC_Payments_Onboarding_Service::is_test_mode_enabled();

// Delete the account if the test mode is enabled otherwise it'll cause issues to onboard again.
// Delete the account if the test mode is enabled,
// otherwise it'll cause issues when trying to onboard again.
if ( $test_mode ) {
// Delete the account.
$this->payments_api_client->delete_account( $test_mode );
// Make sure we clear the cached account data as it may take a while
// for the account update webhook to come from our platform.
$this->clear_cache();
}

// Set the test mode to false now that we are handling a real onboarding.
WC_Payments_Onboarding_Service::set_test_mode( false );
$this->redirect_to_onboarding_page_or_start_server_connection( $connect_page_source );

$this->redirect_to_onboarding_page_or_start_server_connection( $onboarding_source );
return;
}

if ( WC_Payments_Onboarding_Service::SOURCE_WCPAY_RESET_ACCOUNT === $connect_page_source ) {
// Handle the flow for resetting an account (aka restarting onboarding).
if ( ! empty( $_GET['wcpay-reset-account'] ) && 'true' === $_GET['wcpay-reset-account'] ) {
$test_mode = WC_Payments_Onboarding_Service::is_test_mode_enabled() || WC_Payments::mode()->is_dev();

// Delete the account.
$this->payments_api_client->delete_account( $test_mode );
$this->redirect_to_onboarding_page_or_start_server_connection( $connect_page_source );
// Make sure we clear the cached account data as it may take a while
// for the account update webhook to come from our platform.
$this->clear_cache();

$this->redirect_to_onboarding_page_or_start_server_connection( $onboarding_source );
return;
}

// Hide menu notification badge upon starting setup.
update_option( 'wcpay_menu_badge_hidden', 'yes' );

// Handle the return from the WPCOM/Jetpack connection screens.
// The merchant either completed the connection or failed. We handle both scenarios.
if ( isset( $_GET['wcpay-connect-jetpack-success'] ) ) {
$test_mode = isset( $_GET['test_mode'] ) && wc_clean( wp_unslash( $_GET['test_mode'] ) );
$event_properties = [
'incentive' => $incentive,
'mode' => $test_mode || WC_Payments::mode()->is_test() ? 'test' : 'live',
'source' => $onboarding_source,
];

if ( ! $this->payments_api_client->is_server_connected() ) {
// If the merchant failed to set up the WPCOM/Jetpack connection,
// we redirect them back to the Connect page with an error message.
if ( ! $this->has_working_jetpack_connection() ) {
// Track unsuccessful Jetpack connection.
$this->tracks_event(
self::TRACKS_EVENT_ACCOUNT_CONNECT_WPCOM_CONNECTION_FAILURE,
Expand All @@ -1029,12 +1076,14 @@ public function maybe_handle_onboarding() {
);
}

// First, default/fallback handling of the WPCOM/Jetpack connection.
try {
$this->maybe_init_jetpack_connection(
$wcpay_connect_param,
[
'promo' => $incentive,
'progressive' => $progressive,
'source' => $onboarding_source,
]
);
} catch ( Exception $e ) {
Expand All @@ -1045,6 +1094,10 @@ public function maybe_handle_onboarding() {
return;
}

// Second, default/fallback handling of the Stripe account initialization and/or redirect to the Stripe KYC.
// This is used at the end of our onboarding wizard (MOX).
// In case everything is already OK and there is no need for Stripe KYC,
// the merchant will get redirected to the Payments > Overview page.
try {
$this->init_stripe_onboarding(
$wcpay_connect_param,
Expand All @@ -1056,19 +1109,38 @@ public function maybe_handle_onboarding() {
} catch ( Exception $e ) {
Logger::error( 'Init Stripe onboarding flow failed. ' . $e );
$this->redirect_service->redirect_to_connect_page(
/* translators: error message. */
__( 'There was a problem redirecting you to the account connection page. Please try again.', 'woocommerce-payments' )
);
return;
}

// We should not reach this point as the merchant should be redirected to the proper place.
// But as a failsafe, redirect to either the Payments > Overview page or the Connect page.
if ( $this->is_stripe_connected() && $this->has_working_jetpack_connection() ) {
$this->redirect_service->redirect_to_overview_page();
} else {
$this->redirect_service->redirect_to_connect_page();
}
return;
}

/**
* ==================
* Handle the redirect back from the Stripe KYC.
*
* @see self::finalize_connection()
* ==================
*/
if (
isset( $_GET['wcpay-state'] )
&& isset( $_GET['wcpay-mode'] )
) {
$state = sanitize_text_field( wp_unslash( $_GET['wcpay-state'] ) );
$mode = sanitize_text_field( wp_unslash( $_GET['wcpay-mode'] ) );

$this->finalize_connection( $state, $mode );

return;
}
}
Expand Down Expand Up @@ -1207,8 +1279,8 @@ public static function is_on_boarding_disabled() {
* @throws API_Exception If there was an error when registering the site on WP.com.
*/
private function maybe_init_jetpack_connection( $wcpay_connect_from, $additional_args = [] ) {
$is_jetpack_fully_connected = $this->payments_api_client->is_server_connected() && $this->payments_api_client->has_server_connection_owner();
if ( $is_jetpack_fully_connected ) {
// Nothing to do if we already have a working Jetpack connection.
if ( $this->has_working_jetpack_connection() ) {
return;
}

Expand All @@ -1229,6 +1301,15 @@ private function maybe_init_jetpack_connection( $wcpay_connect_from, $additional
$this->payments_api_client->start_server_connection( $redirect );
}

/**
* Determine if the store has a working Jetpack connection.
*
* @return bool Whether the Jetpack connection is established and working or not.
*/
private function has_working_jetpack_connection() {
return $this->payments_api_client->is_server_connected() && $this->payments_api_client->has_server_connection_owner();
}

/**
* Builds the URL to return the user to after the Jetpack/Onboarding flow.
*
Expand Down

0 comments on commit aa3cbe2

Please sign in to comment.