404 lines
12 KiB
PHP
404 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Class WC_REST_Payments_Onboarding_Controller
|
|
*
|
|
* @package WooCommerce\Payments\Admin
|
|
*/
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
use WCPay\Logger;
|
|
|
|
/**
|
|
* REST controller for account details and status.
|
|
*/
|
|
class WC_REST_Payments_Onboarding_Controller extends WC_Payments_REST_Controller {
|
|
|
|
const RESULT_BAD_REQUEST = 'bad_request';
|
|
|
|
/**
|
|
* Onboarding Service.
|
|
*
|
|
* @var WC_Payments_Onboarding_Service
|
|
*/
|
|
protected $onboarding_service;
|
|
|
|
/**
|
|
* Endpoint path.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $rest_base = 'payments/onboarding';
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param WC_Payments_API_Client $api_client WooCommerce Payments API client.
|
|
* @param WC_Payments_Onboarding_Service $onboarding_service Onboarding Service class instance.
|
|
*/
|
|
public function __construct(
|
|
WC_Payments_API_Client $api_client,
|
|
WC_Payments_Onboarding_Service $onboarding_service
|
|
) {
|
|
parent::__construct( $api_client );
|
|
$this->onboarding_service = $onboarding_service;
|
|
}
|
|
|
|
/**
|
|
* Configure REST API routes.
|
|
*/
|
|
public function register_routes() {
|
|
register_rest_route(
|
|
$this->namespace,
|
|
'/' . $this->rest_base . '/kyc/session',
|
|
[
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => [ $this, 'create_embedded_kyc_session' ],
|
|
'permission_callback' => [ $this, 'check_permission' ],
|
|
'args' => [
|
|
'self_assessment' => [
|
|
'required' => false,
|
|
'description' => 'The self-assessment data.',
|
|
'type' => 'object',
|
|
'properties' => [
|
|
'country' => [
|
|
'type' => 'string',
|
|
'description' => 'The country code where the company is legally registered.',
|
|
],
|
|
'business_type' => [
|
|
'type' => 'string',
|
|
'description' => 'The company incorporation type.',
|
|
],
|
|
'mcc' => [
|
|
'type' => 'string',
|
|
'description' => 'The merchant category code. This can either be a true MCC or an MCCs tree item id from the onboarding form.',
|
|
],
|
|
'site' => [
|
|
'type' => 'string',
|
|
'description' => 'The URL of the site.',
|
|
],
|
|
],
|
|
],
|
|
'capabilities' => [
|
|
'description' => 'The capabilities to request and enable for the test-drive account. Leave empty to use the default capabilities.',
|
|
'type' => 'object',
|
|
'default' => [],
|
|
'required' => false,
|
|
'properties' => [
|
|
'*' => [
|
|
'type' => 'boolean',
|
|
],
|
|
],
|
|
],
|
|
'mode' => [
|
|
'description' => 'The account mode the user selected: live or test. Overrides environment-based auto-detection (except dev mode).',
|
|
'type' => 'string',
|
|
'required' => false,
|
|
'enum' => [ 'live', 'test' ],
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$this->namespace,
|
|
'/' . $this->rest_base . '/kyc/finalize',
|
|
[
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => [ $this, 'finalize_embedded_kyc' ],
|
|
'permission_callback' => [ $this, 'check_permission' ],
|
|
'args' => [
|
|
'source' => [
|
|
'required' => false,
|
|
'description' => 'The very first entry point the merchant entered our onboarding flow.',
|
|
'type' => 'string',
|
|
],
|
|
'from' => [
|
|
'required' => false,
|
|
'description' => 'The previous step in the onboarding flow leading the merchant to arrive at the current step.',
|
|
'type' => 'string',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$this->namespace,
|
|
'/' . $this->rest_base . '/reset',
|
|
[
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => [ $this, 'reset_onboarding' ],
|
|
'permission_callback' => [ $this, 'check_permission' ],
|
|
'args' => [
|
|
'source' => [
|
|
'required' => false,
|
|
'description' => 'The very first entry point the merchant entered our onboarding flow.',
|
|
'type' => 'string',
|
|
],
|
|
'from' => [
|
|
'required' => false,
|
|
'description' => 'The previous step in the onboarding flow leading the merchant to arrive at the current step.',
|
|
'type' => 'string',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$this->namespace,
|
|
'/' . $this->rest_base . '/fields',
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [ $this, 'get_fields' ],
|
|
'permission_callback' => [ $this, 'check_permission' ],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$this->namespace,
|
|
'/' . $this->rest_base . '/business_types',
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [ $this, 'get_business_types' ],
|
|
'permission_callback' => [ $this, 'check_permission' ],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$this->namespace,
|
|
'/' . $this->rest_base . '/test_drive_account/init',
|
|
[
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => [ $this, 'init_test_drive_account' ],
|
|
'permission_callback' => [ $this, 'check_permission' ],
|
|
'args' => [
|
|
'country' => [
|
|
'type' => 'string',
|
|
'description' => 'The country code for which to create the test-drive account.',
|
|
'required' => false,
|
|
],
|
|
'capabilities' => [
|
|
'description' => 'The capabilities to request and enable for the test-drive account. Leave empty to use the default capabilities.',
|
|
'type' => 'object',
|
|
'default' => [],
|
|
'required' => false,
|
|
'properties' => [
|
|
'*' => [
|
|
'type' => 'boolean',
|
|
],
|
|
],
|
|
],
|
|
'account_data' => [
|
|
'description' => 'Additional account data to pass to the platform during account creation.',
|
|
'type' => 'object',
|
|
'default' => [],
|
|
'required' => false,
|
|
'properties' => [
|
|
'extra_bootstrapping' => [ 'type' => 'boolean' ],
|
|
],
|
|
'additionalProperties' => false,
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$this->namespace,
|
|
'/' . $this->rest_base . '/test_drive_account/disable',
|
|
[
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => [ $this, 'disable_test_drive_account' ],
|
|
'permission_callback' => [ $this, 'check_permission' ],
|
|
'args' => [
|
|
'source' => [
|
|
'required' => false,
|
|
'description' => 'The very first entry point the merchant entered our onboarding flow.',
|
|
'type' => 'string',
|
|
],
|
|
'from' => [
|
|
'required' => false,
|
|
'description' => 'The previous step in the onboarding flow leading the merchant to arrive at the current step.',
|
|
'type' => 'string',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create an account embedded KYC session via the API.
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_Error|WP_REST_Response Response object containing the account session, or an error if session creation failed.
|
|
*/
|
|
public function create_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' ) ) ) : [];
|
|
$capabilities = ! empty( $request->get_param( 'capabilities' ) ) ? wc_clean( wp_unslash( $request->get_param( 'capabilities' ) ) ) : [];
|
|
$mode = ! empty( $request->get_param( 'mode' ) ) ? sanitize_text_field( $request->get_param( 'mode' ) ) : null;
|
|
|
|
try {
|
|
$account_session = $this->onboarding_service->create_embedded_kyc_session(
|
|
$self_assessment_data,
|
|
$capabilities,
|
|
$mode
|
|
);
|
|
} catch ( Exception $e ) {
|
|
Logger::error( 'Failed to create embedded KYC session: ' . $e->getMessage() );
|
|
return new WP_Error( 'wcpay_onboarding_duplicate_session', $e->getMessage(), [ 'status' => 409 ] );
|
|
}
|
|
|
|
if ( empty( $account_session ) ) {
|
|
WC_Payments_Utils::log_to_wc( 'Failed to create embedded KYC session: Empty response from onboarding service.' );
|
|
} elseif ( empty( $account_session['publishableKey'] ) ) {
|
|
WC_Payments_Utils::log_to_wc(
|
|
sprintf( 'Embedded KYC session missing publishableKey. Session keys: %s.', implode( ', ', array_keys( $account_session ) ) ),
|
|
'warning'
|
|
);
|
|
}
|
|
|
|
if ( $account_session ) {
|
|
$account_session['locale'] = get_user_locale();
|
|
}
|
|
|
|
return rest_ensure_response( $account_session );
|
|
}
|
|
|
|
/**
|
|
* Finalize the embedded KYC session via the API.
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response|WP_Error
|
|
*/
|
|
public function finalize_embedded_kyc( WP_REST_Request $request ) {
|
|
$source = $request->get_param( 'source' ) ?? '';
|
|
$from = $request->get_param( 'from' ) ?? '';
|
|
$actioned_notes = WC_Payments_Onboarding_Service::get_actioned_notes();
|
|
|
|
// Call the API to finalize the onboarding.
|
|
try {
|
|
$response = $this->onboarding_service->finalize_embedded_kyc(
|
|
get_user_locale(),
|
|
$source,
|
|
$actioned_notes
|
|
);
|
|
} catch ( Exception $e ) {
|
|
return new WP_Error( self::RESULT_BAD_REQUEST, $e->getMessage(), [ 'status' => 400 ] );
|
|
}
|
|
|
|
// Handle some post-onboarding tasks and get the redirect params.
|
|
$finalize = WC_Payments::get_account_service()->finalize_embedded_connection(
|
|
$response['mode'],
|
|
[
|
|
'promo' => $response['promotion_id'] ?? '',
|
|
'from' => $from,
|
|
'source' => $source,
|
|
]
|
|
);
|
|
|
|
// Return the response, the client will handle the redirect.
|
|
return rest_ensure_response(
|
|
array_merge(
|
|
$response,
|
|
$finalize
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Reset the onboarding via the API.
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response|WP_Error
|
|
*/
|
|
public function reset_onboarding( WP_REST_Request $request ) {
|
|
$context = [
|
|
'from' => $request->get_param( 'from' ) ?? '',
|
|
'source' => $request->get_param( 'source' ) ?? '',
|
|
];
|
|
|
|
try {
|
|
$result = $this->onboarding_service->reset_onboarding( $context );
|
|
} catch ( Exception $e ) {
|
|
return new WP_Error( self::RESULT_BAD_REQUEST, $e->getMessage(), [ 'status' => 400 ] );
|
|
}
|
|
|
|
return rest_ensure_response( [ 'success' => $result ] );
|
|
}
|
|
|
|
/**
|
|
* Get fields data via API.
|
|
*
|
|
* @return WP_REST_Response|WP_Error
|
|
*/
|
|
public function get_fields() {
|
|
$fields = $this->onboarding_service->get_fields_data( get_user_locale() );
|
|
if ( is_null( $fields ) ) {
|
|
return new WP_Error( self::RESULT_BAD_REQUEST, 'Failed to retrieve the onboarding fields.', [ 'status' => 400 ] );
|
|
}
|
|
|
|
return rest_ensure_response( [ 'data' => $fields ] );
|
|
}
|
|
|
|
/**
|
|
* Get business types via API.
|
|
*
|
|
* @return WP_REST_Response|WP_Error
|
|
*/
|
|
public function get_business_types() {
|
|
$business_types = $this->onboarding_service->get_cached_business_types();
|
|
return rest_ensure_response( [ 'data' => $business_types ] );
|
|
}
|
|
|
|
/**
|
|
* Initialize a test-drive account.
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response|WP_Error
|
|
*/
|
|
public function init_test_drive_account( WP_REST_Request $request ) {
|
|
$country = $request->get_param( 'country' );
|
|
if ( empty( $country ) ) {
|
|
// Fall back to the store's base country if no country is provided.
|
|
$country = WC()->countries->get_base_country() ?? 'US';
|
|
}
|
|
|
|
try {
|
|
$success = $this->onboarding_service->init_test_drive_account( $country, $request->get_param( 'capabilities' ) ?? [], $request->get_param( 'account_data' ) ?? [] );
|
|
} catch ( Exception $e ) {
|
|
return new WP_Error( self::RESULT_BAD_REQUEST, $e->getMessage(), [ 'status' => 400 ] );
|
|
}
|
|
|
|
return rest_ensure_response(
|
|
[
|
|
'success' => $success,
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Disable Test Drive account API.
|
|
*
|
|
* @param WP_REST_Request $request Request object.
|
|
*
|
|
* @return WP_REST_Response|WP_Error
|
|
*/
|
|
public function disable_test_drive_account( WP_REST_Request $request ) {
|
|
$context = [
|
|
'from' => $request->get_param( 'from' ) ?? '',
|
|
'source' => $request->get_param( 'source' ) ?? '',
|
|
];
|
|
|
|
try {
|
|
$result = $this->onboarding_service->disable_test_drive_account( $context );
|
|
} catch ( Exception $e ) {
|
|
return new WP_Error( self::RESULT_BAD_REQUEST, $e->getMessage(), [ 'status' => 400 ] );
|
|
}
|
|
|
|
return rest_ensure_response( [ 'success' => $result ] );
|
|
}
|
|
}
|