diff --git a/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php b/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php index c8e945954..ab8d5473b 100644 --- a/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php +++ b/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php @@ -16,25 +16,61 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; +/** + * Class PaymentMethodTokensEndpoint + */ class PaymentMethodTokensEndpoint { use RequestTrait; - private string $host; - private Bearer $bearer; - private LoggerInterface $logger; + /** + * The host. + * + * @var string + */ + private $host; - public function __construct(string $host, Bearer $bearer, LoggerInterface $logger) - { - $this->host = $host; + /** + * The bearer. + * + * @var Bearer + */ + private $bearer; + + /** + * The logger. + * + * @var LoggerInterface + */ + private $logger; + + /** + * PaymentMethodTokensEndpoint constructor. + * + * @param string $host The host. + * @param Bearer $bearer The bearer. + * @param LoggerInterface $logger The logger. + */ + public function __construct( string $host, Bearer $bearer, LoggerInterface $logger ) { + $this->host = $host; $this->bearer = $bearer; $this->logger = $logger; } - public function setup_tokens(PaymentSource $payment_source): stdClass { + /** + * Creates a setup token. + * + * @param PaymentSource $payment_source The payment source. + * + * @return stdClass + * + * @throws RuntimeException When something when wrong with the request. + * @throws PayPalApiException When something when wrong setting up the token. + */ + public function setup_tokens( PaymentSource $payment_source ): stdClass { $data = array( 'payment_source' => array( - $payment_source->name() => $payment_source->properties() + $payment_source->name() => $payment_source->properties(), ), ); @@ -44,9 +80,9 @@ class PaymentMethodTokensEndpoint { $args = array( 'method' => 'POST', 'headers' => array( - 'Authorization' => 'Bearer ' . $bearer->token(), - 'Content-Type' => 'application/json', - 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), + 'Authorization' => 'Bearer ' . $bearer->token(), + 'Content-Type' => 'application/json', + 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), ), 'body' => wp_json_encode( $data ), ); @@ -69,10 +105,20 @@ class PaymentMethodTokensEndpoint { return $json; } - public function payment_tokens(PaymentSource $payment_source) { + /** + * Creates a payment token for the given payment source. + * + * @param PaymentSource $payment_source The payment source. + * + * @return stdClass + * + * @throws RuntimeException When something when wrong with the request. + * @throws PayPalApiException When something when wrong setting up the token. + */ + public function payment_tokens( PaymentSource $payment_source ): stdClass { $data = array( 'payment_source' => array( - $payment_source->name() => $payment_source->properties() + $payment_source->name() => $payment_source->properties(), ), ); @@ -82,9 +128,9 @@ class PaymentMethodTokensEndpoint { $args = array( 'method' => 'POST', 'headers' => array( - 'Authorization' => 'Bearer ' . $bearer->token(), - 'Content-Type' => 'application/json', - 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), + 'Authorization' => 'Bearer ' . $bearer->token(), + 'Content-Type' => 'application/json', + 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), ), 'body' => wp_json_encode( $data ), ); diff --git a/modules/ppcp-save-payment-methods/services.php b/modules/ppcp-save-payment-methods/services.php index 051bbfc95..ceee1efac 100644 --- a/modules/ppcp-save-payment-methods/services.php +++ b/modules/ppcp-save-payment-methods/services.php @@ -15,7 +15,7 @@ use WooCommerce\PayPalCommerce\SavePaymentMethods\Helper\SavePaymentMethodsAppli use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; return array( - 'save-payment-methods.eligible' => static function ( ContainerInterface $container ): bool { + 'save-payment-methods.eligible' => static function ( ContainerInterface $container ): bool { $save_payment_methods_applies = $container->get( 'save-payment-methods.helpers.save-payment-methods-applies' ); assert( $save_payment_methods_applies instanceof SavePaymentMethodsApplies ); @@ -43,7 +43,7 @@ return array( ) ); }, - 'save-payment-methods.module.url' => static function ( ContainerInterface $container ): string { + 'save-payment-methods.module.url' => static function ( ContainerInterface $container ): string { /** * The path cannot be false. * @@ -54,16 +54,24 @@ return array( dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ); }, - 'save-payment-methods.endpoint.create-setup-token' => static function (ContainerInterface $container): CreateSetupToken { + 'save-payment-methods.endpoint.create-setup-token' => static function ( ContainerInterface $container ): CreateSetupToken { return new CreateSetupToken( $container->get( 'button.request-data' ), - $container->get('api.endpoint.payment-method-tokens') + $container->get( 'api.endpoint.payment-method-tokens' ) ); }, - 'save-payment-methods.endpoint.create-payment-token' => static function (ContainerInterface $container): CreatePaymentToken { - return new CreatePaymentToken( - $container->get('button.request-data'), - $container->get('api.endpoint.payment-method-tokens') + 'save-payment-methods.wc-payment-tokens' => static function( ContainerInterface $container ): WooCommercePaymentTokens { + return new WooCommercePaymentTokens( + $container->get( 'vaulting.payment-token-helper' ), + $container->get( 'vaulting.payment-token-factory' ), + $container->get( 'woocommerce.logger.woocommerce' ) ); -} + }, + 'save-payment-methods.endpoint.create-payment-token' => static function ( ContainerInterface $container ): CreatePaymentToken { + return new CreatePaymentToken( + $container->get( 'button.request-data' ), + $container->get( 'api.endpoint.payment-method-tokens' ), + $container->get( 'save-payment-methods.wc-payment-tokens' ) + ); + }, ); diff --git a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php index 459355f5b..104eebf70 100644 --- a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php +++ b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php @@ -1,4 +1,11 @@ request_data = $request_data; $this->payment_method_tokens_endpoint = $payment_method_tokens_endpoint; + $this->wc_payment_tokens = $wc_payment_tokens; } /** @@ -46,11 +84,27 @@ class CreatePaymentToken implements EndpointInterface { 'token', (object) array( 'id' => $data['vault_setup_token'], - 'type' => 'SETUP-TOKEN', + 'type' => 'SETUP_TOKEN', ) ); $result = $this->payment_method_tokens_endpoint->payment_tokens( $payment_source ); + + if ( is_user_logged_in() && isset( $result->customer->id ) ) { + update_user_meta( get_current_user_id(), '_ppcp_target_customer_id', $result->customer->id ); + + $email = ''; + if ( isset( $result->payment_source->paypal->email_address ) ) { + $email = $result->payment_source->paypal->email_address; + } + + $this->wc_payment_tokens->create_payment_token_paypal( + get_current_user_id(), + $result->id, + $email + ); + } + wp_send_json_success( $result ); return true; } catch ( Exception $exception ) { diff --git a/modules/ppcp-save-payment-methods/src/Endpoint/CreateSetupToken.php b/modules/ppcp-save-payment-methods/src/Endpoint/CreateSetupToken.php index 6541d9d4b..77c68e3ba 100644 --- a/modules/ppcp-save-payment-methods/src/Endpoint/CreateSetupToken.php +++ b/modules/ppcp-save-payment-methods/src/Endpoint/CreateSetupToken.php @@ -1,4 +1,11 @@ request_data = $request_data; + ) { + $this->request_data = $request_data; $this->payment_method_tokens_endpoint = $payment_method_tokens_endpoint; } @@ -40,8 +55,7 @@ class CreateSetupToken implements EndpointInterface * * @return string */ - public static function nonce(): string - { + public static function nonce(): string { return self::ENDPOINT; } @@ -51,27 +65,26 @@ class CreateSetupToken implements EndpointInterface * @return bool * @throws Exception On Error. */ - public function handle_request(): bool - { + public function handle_request(): bool { try { $this->request_data->read_request( $this->nonce() ); $payment_source = new PaymentSource( 'paypal', (object) array( - 'usage_type' => 'MERCHANT', + 'usage_type' => 'MERCHANT', 'experience_context' => (object) array( 'return_url' => esc_url( wc_get_account_endpoint_url( 'payment-methods' ) ), 'cancel_url' => esc_url( wc_get_account_endpoint_url( 'add-payment-method' ) ), - ) + ), ) ); - $result = $this->payment_method_tokens_endpoint->setup_tokens($payment_source); + $result = $this->payment_method_tokens_endpoint->setup_tokens( $payment_source ); - wp_send_json_success($result); + wp_send_json_success( $result ); return true; - } catch (Exception $exception) { + } catch ( Exception $exception ) { wp_send_json_error(); return false; } diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php index a93b4921f..80b5890db 100644 --- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php +++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php @@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\SavePaymentMethods; use Exception; use Psr\Log\LoggerInterface; +use stdClass; use WC_Order; use WC_Payment_Tokens; use WooCommerce\PayPalCommerce\ApiClient\Authentication\UserIdToken; @@ -116,36 +117,20 @@ class SavePaymentMethodsModule implements ModuleInterface { $payment_token_helper = $c->get( 'vaulting.payment-token-helper' ); assert( $payment_token_helper instanceof PaymentTokenHelper ); - $wc_tokens = WC_Payment_Tokens::get_customer_tokens( $wc_order->get_customer_id(), PayPalGateway::ID ); - if ( $payment_token_helper->token_exist( $wc_tokens, $payment_vault_attributes->id ) ) { - return; - } - $payment_token_factory = $c->get( 'vaulting.payment-token-factory' ); assert( $payment_token_factory instanceof PaymentTokenFactory ); - $payment_token_paypal = $payment_token_factory->create( 'paypal' ); - assert( $payment_token_paypal instanceof PaymentTokenPayPal ); + $logger = $c->get( 'woocommerce.logger.woocommerce' ); + assert( $logger instanceof LoggerInterface ); - $payment_token_paypal->set_token( $payment_vault_attributes->id ); - $payment_token_paypal->set_user_id( $wc_order->get_customer_id() ); - $payment_token_paypal->set_gateway_id( PayPalGateway::ID ); + $wc_payment_tokens = $c->get( 'save-payment-methods.wc-payment-tokens' ); + assert( $wc_payment_tokens instanceof WooCommercePaymentTokens ); - $email = $order->payment_source()->properties()->email_address ?? ''; - if ( $email && is_email( $email ) ) { - $payment_token_paypal->set_email( $email ); - } - - try { - $payment_token_paypal->save(); - } catch ( Exception $exception ) { - $logger = $c->get( 'woocommerce.logger.woocommerce' ); - assert( $logger instanceof LoggerInterface ); - - $logger->error( - "Could not save WC payment token PayPal for order #{$wc_order->get_id()}. " . $exception->getMessage() - ); - } + $wc_payment_tokens->create_payment_token_paypal( + $wc_order->get_customer_id(), + $payment_vault_attributes->id, + $order->payment_source()->properties()->email_address ?? '' + ); } }, 10, @@ -170,46 +155,46 @@ class SavePaymentMethodsModule implements ModuleInterface { true ); - $api = $c->get('api.user-id-token'); - assert($api instanceof UserIdToken); + $api = $c->get( 'api.user-id-token' ); + assert( $api instanceof UserIdToken ); try { $target_customer_id = ''; - if (is_user_logged_in()) { - $target_customer_id = get_user_meta(get_current_user_id(), '_ppcp_target_customer_id', true); + if ( is_user_logged_in() ) { + $target_customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true ); } - $id_token = $api->id_token($target_customer_id); + $id_token = $api->id_token( $target_customer_id ); wp_localize_script( 'ppcp-add-payment-method', 'ppcp_add_payment_method', array( - 'client_id' => $c->get( 'button.client_id' ), + 'client_id' => $c->get( 'button.client_id' ), 'merchant_id' => $c->get( 'api.merchant_id' ), - 'id_token' => $id_token, - 'ajax' => array( - 'create_setup_token' => array( + 'id_token' => $id_token, + 'ajax' => array( + 'create_setup_token' => array( 'endpoint' => \WC_AJAX::get_endpoint( CreateSetupToken::ENDPOINT ), 'nonce' => wp_create_nonce( CreateSetupToken::nonce() ), ), - 'create_payment_token' => array( + 'create_payment_token' => array( 'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ), 'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ), ), ), ) ); - } catch (RuntimeException $exception) { - $logger = $c->get('woocommerce.logger.woocommerce'); - assert($logger instanceof LoggerInterface); + } catch ( RuntimeException $exception ) { + $logger = $c->get( 'woocommerce.logger.woocommerce' ); + assert( $logger instanceof LoggerInterface ); $error = $exception->getMessage(); - if (is_a($exception, PayPalApiException::class)) { - $error = $exception->get_details($error); + if ( is_a( $exception, PayPalApiException::class ) ) { + $error = $exception->get_details( $error ); } - $logger->error($error); + $logger->error( $error ); } } ); @@ -221,7 +206,7 @@ class SavePaymentMethodsModule implements ModuleInterface { return; } - echo '
'; + echo '
'; } ); @@ -229,7 +214,7 @@ class SavePaymentMethodsModule implements ModuleInterface { 'wc_ajax_' . CreateSetupToken::ENDPOINT, static function () use ( $c ) { $endpoint = $c->get( 'save-payment-methods.endpoint.create-setup-token' ); - assert($endpoint instanceof CreateSetupToken); + assert( $endpoint instanceof CreateSetupToken ); $endpoint->handle_request(); } @@ -239,7 +224,7 @@ class SavePaymentMethodsModule implements ModuleInterface { 'wc_ajax_' . CreatePaymentToken::ENDPOINT, static function () use ( $c ) { $endpoint = $c->get( 'save-payment-methods.endpoint.create-payment-token' ); - assert($endpoint instanceof CreatePaymentToken); + assert( $endpoint instanceof CreatePaymentToken ); $endpoint->handle_request(); } diff --git a/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php new file mode 100644 index 000000000..4fb066b6e --- /dev/null +++ b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php @@ -0,0 +1,102 @@ +payment_token_helper = $payment_token_helper; + $this->payment_token_factory = $payment_token_factory; + $this->logger = $logger; + } + + /** + * Creates a WC Payment Token for PayPal payment. + * + * @param int $customer_id The WC customer ID. + * @param string $token The PayPal payment token. + * @param string $email The PayPal customer email. + * + * @return void + */ + public function create_payment_token_paypal( + int $customer_id, + string $token, + string $email + ): void { + + $wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID ); + if ( $this->payment_token_helper->token_exist( $wc_tokens, $token ) ) { + return; + } + + $payment_token_paypal = $this->payment_token_factory->create( 'paypal' ); + assert( $payment_token_paypal instanceof PaymentTokenPayPal ); + + $payment_token_paypal->set_token( $token ); + $payment_token_paypal->set_user_id( $customer_id ); + $payment_token_paypal->set_gateway_id( PayPalGateway::ID ); + + if ( $email && is_email( $email ) ) { + $payment_token_paypal->set_email( $email ); + } + + try { + $payment_token_paypal->save(); + } catch ( Exception $exception ) { + $this->logger->error( + "Could not create WC payment token PayPal for customer {$customer_id}. " . $exception->getMessage() + ); + } + } +} diff --git a/modules/ppcp-wc-gateway/extensions.php b/modules/ppcp-wc-gateway/extensions.php index 7b3c1b127..5ab1fc8ab 100644 --- a/modules/ppcp-wc-gateway/extensions.php +++ b/modules/ppcp-wc-gateway/extensions.php @@ -60,7 +60,6 @@ return array( $source ); }, - 'wcgateway.settings.fields' => function ( ContainerInterface $container, array $fields ): array { $path_to_settings_fields = __DIR__ . '/src/Settings/Fields';