mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 09:08:09 +08:00
Add save payment method for purchase later (WIP)
This commit is contained in:
parent
9f41d5c874
commit
34cc1bffe4
8 changed files with 388 additions and 8 deletions
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\ApiClient;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\UserIdToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions;
|
||||
|
@ -249,6 +250,13 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.payment-method-tokens' => static function( ContainerInterface $container ): PaymentMethodTokensEndpoint {
|
||||
return new PaymentMethodTokensEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.repository.application-context' => static function( ContainerInterface $container ) : ApplicationContextRepository {
|
||||
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
/**
|
||||
* The Payment Method Tokens endpoint.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
class PaymentMethodTokensEndpoint {
|
||||
|
||||
use RequestTrait;
|
||||
|
||||
private string $host;
|
||||
private Bearer $bearer;
|
||||
private LoggerInterface $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 {
|
||||
$data = array(
|
||||
'payment_source' => array(
|
||||
$payment_source->name() => $payment_source->properties()
|
||||
),
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v3/vault/setup-tokens';
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to create setup token.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( ! in_array( $status_code, array( 200, 201 ), true ) ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
public function payment_tokens(PaymentSource $payment_source) {
|
||||
$data = array(
|
||||
'payment_source' => array(
|
||||
$payment_source->name() => $payment_source->properties()
|
||||
),
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v3/vault/payment-tokens';
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to create setup token.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( ! in_array( $status_code, array( 200, 201 ), true ) ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderTransient;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\ValidationException;
|
||||
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
|
|
|
@ -7,6 +7,58 @@ import {
|
|||
import {setVisible} from "../../../ppcp-button/resources/js/modules/Helper/Hiding";
|
||||
import {loadPaypalJsScript} from "../../../ppcp-button/resources/js/modules/Helper/ScriptLoading";
|
||||
|
||||
loadPaypalJsScript(
|
||||
{
|
||||
clientId: ppcp_add_payment_method.client_id,
|
||||
merchantId: ppcp_add_payment_method.merchant_id,
|
||||
dataUserIdToken: ppcp_add_payment_method.id_token,
|
||||
},
|
||||
{
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(ppcp_add_payment_method.ajax.create_setup_token.endpoint, {
|
||||
method: "POST",
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: ppcp_add_payment_method.ajax.create_setup_token.nonce,
|
||||
})
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
if(result.data.id) {
|
||||
return result.data.id
|
||||
}
|
||||
},
|
||||
onApprove: async ({ vaultSetupToken }) => {
|
||||
console.log(vaultSetupToken)
|
||||
|
||||
const response = await fetch(ppcp_add_payment_method.ajax.create_payment_token.endpoint, {
|
||||
method: "POST",
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: ppcp_add_payment_method.ajax.create_payment_token.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
})
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
console.log(result)
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error)
|
||||
}
|
||||
},
|
||||
`#ppc-button-${PaymentMethods.PAYPAL}-save-payment-method`
|
||||
);
|
||||
|
||||
|
||||
|
||||
const init = () => {
|
||||
setVisible(ORDER_BUTTON_SELECTOR, getCurrentPaymentMethod() !== PaymentMethods.PAYPAL);
|
||||
setVisible(`#ppc-button-${PaymentMethods.PAYPAL}-save-payment-method`, getCurrentPaymentMethod() === PaymentMethods.PAYPAL);
|
||||
|
@ -18,12 +70,6 @@ document.addEventListener(
|
|||
jQuery(document.body).on('click init_add_payment_method', '.payment_methods input.input-radio', function () {
|
||||
init()
|
||||
});
|
||||
|
||||
loadPaypalJsScript(
|
||||
{},
|
||||
{},
|
||||
`#ppc-button-${PaymentMethods.PAYPAL}-save-payment-method`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
|
||||
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Helper\SavePaymentMethodsApplies;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -52,4 +54,16 @@ return array(
|
|||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'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')
|
||||
);
|
||||
},
|
||||
'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')
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
|
||||
class CreatePaymentToken implements EndpointInterface {
|
||||
|
||||
const ENDPOINT = 'ppc-create-payment-token';
|
||||
|
||||
private RequestData $request_data;
|
||||
private PaymentMethodTokensEndpoint $payment_method_tokens_endpoint;
|
||||
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
PaymentMethodTokensEndpoint $payment_method_tokens_endpoint
|
||||
) {
|
||||
$this->request_data = $request_data;
|
||||
$this->payment_method_tokens_endpoint = $payment_method_tokens_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception On Error.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
|
||||
$payment_source = new PaymentSource(
|
||||
'token',
|
||||
(object) array(
|
||||
'id' => $data['vault_setup_token'],
|
||||
'type' => 'SETUP-TOKEN',
|
||||
)
|
||||
);
|
||||
|
||||
$result = $this->payment_method_tokens_endpoint->payment_tokens( $payment_source );
|
||||
wp_send_json_success( $result );
|
||||
return true;
|
||||
} catch ( Exception $exception ) {
|
||||
wp_send_json_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
|
||||
class CreateSetupToken implements EndpointInterface
|
||||
{
|
||||
const ENDPOINT = 'ppc-create-setup-token';
|
||||
|
||||
/**
|
||||
* * The request data helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private RequestData $request_data;
|
||||
|
||||
/**
|
||||
* Payment Method Tokens endpoint.
|
||||
*
|
||||
* @var PaymentMethodTokensEndpoint
|
||||
*/
|
||||
private PaymentMethodTokensEndpoint $payment_method_tokens_endpoint;
|
||||
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
PaymentMethodTokensEndpoint $payment_method_tokens_endpoint
|
||||
)
|
||||
{
|
||||
$this->request_data = $request_data;
|
||||
$this->payment_method_tokens_endpoint = $payment_method_tokens_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string
|
||||
{
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception On Error.
|
||||
*/
|
||||
public function handle_request(): bool
|
||||
{
|
||||
try {
|
||||
$this->request_data->read_request( $this->nonce() );
|
||||
|
||||
$payment_source = new PaymentSource(
|
||||
'paypal',
|
||||
(object) array(
|
||||
'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);
|
||||
|
||||
wp_send_json_success($result);
|
||||
return true;
|
||||
} catch (Exception $exception) {
|
||||
wp_send_json_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,8 @@ use WooCommerce\PayPalCommerce\ApiClient\Authentication\UserIdToken;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenFactory;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenPayPal;
|
||||
|
@ -58,7 +60,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
|
||||
try {
|
||||
$target_customer_id = '';
|
||||
if ( get_current_user_id() !== 0 ) {
|
||||
if ( is_user_logged_in() ) {
|
||||
$target_customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true );
|
||||
}
|
||||
|
||||
|
@ -167,6 +169,48 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
$c->get( 'ppcp.asset-version' ),
|
||||
true
|
||||
);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
$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' ),
|
||||
'merchant_id' => $c->get( 'api.merchant_id' ),
|
||||
'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(
|
||||
'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);
|
||||
|
||||
$error = $exception->getMessage();
|
||||
if (is_a($exception, PayPalApiException::class)) {
|
||||
$error = $exception->get_details($error);
|
||||
}
|
||||
|
||||
$logger->error($error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -180,5 +224,25 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
echo '<div id="ppc-button-' . PayPalGateway::ID . '-save-payment-method"></div>';
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . CreateSetupToken::ENDPOINT,
|
||||
static function () use ( $c ) {
|
||||
$endpoint = $c->get( 'save-payment-methods.endpoint.create-setup-token' );
|
||||
assert($endpoint instanceof CreateSetupToken);
|
||||
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . CreatePaymentToken::ENDPOINT,
|
||||
static function () use ( $c ) {
|
||||
$endpoint = $c->get( 'save-payment-methods.endpoint.create-payment-token' );
|
||||
assert($endpoint instanceof CreatePaymentToken);
|
||||
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue