2023-10-17 15:11:48 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* The save payment methods module.
|
|
|
|
*
|
|
|
|
* @package WooCommerce\PayPalCommerce\Applepay
|
|
|
|
*/
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
|
|
|
|
|
2023-10-19 16:15:20 +02:00
|
|
|
use Psr\Log\LoggerInterface;
|
2023-10-20 12:54:00 +02:00
|
|
|
use WC_Order;
|
2023-10-31 14:22:17 +01:00
|
|
|
use WC_Payment_Tokens;
|
2023-10-19 16:15:20 +02:00
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\UserIdToken;
|
2023-11-02 10:54:08 +01:00
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
2023-10-20 12:54:00 +02:00
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
2023-10-27 15:28:01 +02:00
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
2023-10-19 16:15:20 +02:00
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
2023-10-26 16:36:38 +02:00
|
|
|
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
|
|
|
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
2023-10-17 15:11:48 +02:00
|
|
|
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
|
|
|
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
|
|
|
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
|
|
|
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
2023-11-22 13:19:28 +01:00
|
|
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
2023-10-20 16:26:19 +02:00
|
|
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
2023-10-17 15:11:48 +02:00
|
|
|
|
2023-10-18 17:03:15 +02:00
|
|
|
/**
|
|
|
|
* Class SavePaymentMethodsModule
|
|
|
|
*/
|
2023-10-17 15:11:48 +02:00
|
|
|
class SavePaymentMethodsModule implements ModuleInterface {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function setup(): ServiceProviderInterface {
|
|
|
|
return new ServiceProvider(
|
|
|
|
require __DIR__ . '/../services.php',
|
|
|
|
require __DIR__ . '/../extensions.php'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-10-18 17:03:15 +02:00
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
2023-10-19 11:18:01 +02:00
|
|
|
public function run( ContainerInterface $c ): void {
|
|
|
|
if ( ! $c->get( 'save-payment-methods.eligible' ) ) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-19 16:15:20 +02:00
|
|
|
|
|
|
|
// Adds `id_token` to localized script data.
|
|
|
|
add_filter(
|
|
|
|
'woocommerce_paypal_payments_localized_script_data',
|
|
|
|
function( array $localized_script_data ) use ( $c ) {
|
|
|
|
$api = $c->get( 'api.user-id-token' );
|
|
|
|
assert( $api instanceof UserIdToken );
|
|
|
|
|
|
|
|
try {
|
2023-10-20 16:46:02 +02:00
|
|
|
$target_customer_id = '';
|
2023-10-26 16:36:38 +02:00
|
|
|
if ( is_user_logged_in() ) {
|
2023-10-20 16:46:02 +02:00
|
|
|
$target_customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true );
|
|
|
|
}
|
|
|
|
|
|
|
|
$id_token = $api->id_token( $target_customer_id );
|
2023-10-19 16:15:20 +02:00
|
|
|
$localized_script_data['save_payment_methods'] = array(
|
|
|
|
'id_token' => $id_token,
|
|
|
|
);
|
|
|
|
|
|
|
|
$localized_script_data['data_client_id']['set_attribute'] = false;
|
|
|
|
|
|
|
|
} 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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $localized_script_data;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Adds attributes needed to save payment method.
|
|
|
|
add_filter(
|
|
|
|
'ppcp_create_order_request_body_data',
|
2023-11-23 11:40:21 +01:00
|
|
|
function( array $data, string $payment_method ): array {
|
2023-10-31 14:22:17 +01:00
|
|
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
|
|
|
$wc_order_action = wc_clean( wp_unslash( $_POST['wc_order_action'] ?? '' ) );
|
|
|
|
if ( $wc_order_action === 'wcs_process_renewal' ) {
|
|
|
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
|
|
|
$subscription_id = wc_clean( wp_unslash( $_POST['post_ID'] ?? '' ) );
|
|
|
|
$subscription = wcs_get_subscription( (int) $subscription_id );
|
|
|
|
if ( $subscription ) {
|
|
|
|
$customer_id = $subscription->get_customer_id();
|
|
|
|
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
|
|
|
foreach ( $wc_tokens as $token ) {
|
|
|
|
$data['payment_source'] = array(
|
|
|
|
'paypal' => array(
|
|
|
|
'vault_id' => $token->get_token(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-22 13:19:28 +01:00
|
|
|
if ( $payment_method === CreditCardGateway::ID ) {
|
|
|
|
$data['payment_source'] = array(
|
|
|
|
'card' => array(
|
|
|
|
'attributes' => array(
|
|
|
|
'vault' => array(
|
|
|
|
'store_in_vault' => 'ON_SUCCESS',
|
|
|
|
),
|
2023-10-19 16:15:20 +02:00
|
|
|
),
|
|
|
|
),
|
2023-11-22 13:19:28 +01:00
|
|
|
);
|
2023-11-23 11:40:21 +01:00
|
|
|
|
|
|
|
$target_customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true );
|
|
|
|
if ( $target_customer_id ) {
|
|
|
|
$data['payment_source']['card']['attributes']['customer'] = array(
|
|
|
|
'id' => $target_customer_id,
|
|
|
|
);
|
|
|
|
}
|
2023-11-22 13:19:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( $payment_method === PayPalGateway::ID ) {
|
|
|
|
$data['payment_source'] = array(
|
|
|
|
'paypal' => array(
|
|
|
|
'attributes' => array(
|
|
|
|
'vault' => array(
|
|
|
|
'store_in_vault' => 'ON_SUCCESS',
|
|
|
|
'usage_type' => 'MERCHANT',
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2023-10-19 16:15:20 +02:00
|
|
|
|
|
|
|
return $data;
|
2023-11-23 11:40:21 +01:00
|
|
|
},
|
|
|
|
10,
|
|
|
|
2
|
2023-10-19 16:15:20 +02:00
|
|
|
);
|
2023-10-20 12:54:00 +02:00
|
|
|
|
|
|
|
add_action(
|
|
|
|
'woocommerce_paypal_payments_after_order_processor',
|
2023-10-20 16:26:19 +02:00
|
|
|
function( WC_Order $wc_order, Order $order ) use ( $c ) {
|
2023-10-27 15:28:01 +02:00
|
|
|
$payment_source = $order->payment_source();
|
|
|
|
assert( $payment_source instanceof PaymentSource );
|
|
|
|
|
|
|
|
$payment_vault_attributes = $payment_source->properties()->attributes->vault ?? null;
|
2023-10-20 16:26:19 +02:00
|
|
|
if ( $payment_vault_attributes ) {
|
2023-11-27 11:10:08 +01:00
|
|
|
$customer_id = $payment_vault_attributes->customer->id ?? '';
|
|
|
|
$token_id = $payment_vault_attributes->id ?? '';
|
|
|
|
if ( ! $customer_id || ! $token_id ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id );
|
2023-10-20 16:26:19 +02:00
|
|
|
|
2023-11-22 13:19:28 +01:00
|
|
|
$wc_payment_tokens = $c->get( 'save-payment-methods.wc-payment-tokens' );
|
|
|
|
assert( $wc_payment_tokens instanceof WooCommercePaymentTokens );
|
2023-10-20 16:26:19 +02:00
|
|
|
|
2023-11-22 13:19:28 +01:00
|
|
|
if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) {
|
|
|
|
$token = new \WC_Payment_Token_CC();
|
2023-11-27 11:10:08 +01:00
|
|
|
$token->set_token( $token_id );
|
2023-11-22 13:19:28 +01:00
|
|
|
$token->set_user_id( $wc_order->get_customer_id() );
|
|
|
|
$token->set_gateway_id( CreditCardGateway::ID );
|
2023-10-20 16:26:19 +02:00
|
|
|
|
2023-11-22 13:19:28 +01:00
|
|
|
$token->set_last4( $payment_source->properties()->last_digits ?? '' );
|
|
|
|
$expiry = explode( '-', $payment_source->properties()->expiry ?? '' );
|
|
|
|
$token->set_expiry_year( $expiry[0] ?? '' );
|
|
|
|
$token->set_expiry_month( $expiry[1] ?? '' );
|
|
|
|
$token->set_card_type( $payment_source->properties()->brand ?? '' );
|
2023-10-20 16:26:19 +02:00
|
|
|
|
2023-11-22 13:19:28 +01:00
|
|
|
$token->save();
|
|
|
|
}
|
2023-10-20 16:26:19 +02:00
|
|
|
|
2023-11-22 13:19:28 +01:00
|
|
|
if ( $wc_order->get_payment_method() === PayPalGateway::ID ) {
|
|
|
|
$wc_payment_tokens->create_payment_token_paypal(
|
|
|
|
$wc_order->get_customer_id(),
|
2023-11-27 11:10:08 +01:00
|
|
|
$token_id,
|
2023-11-22 13:19:28 +01:00
|
|
|
$payment_source->properties()->email_address ?? ''
|
|
|
|
);
|
|
|
|
}
|
2023-10-20 16:26:19 +02:00
|
|
|
}
|
2023-10-20 12:54:00 +02:00
|
|
|
},
|
|
|
|
10,
|
|
|
|
2
|
|
|
|
);
|
2023-10-23 16:50:43 +02:00
|
|
|
|
|
|
|
add_filter( 'woocommerce_paypal_payments_disable_add_payment_method', '__return_false' );
|
2023-11-02 10:54:08 +01:00
|
|
|
add_filter( 'woocommerce_paypal_payments_subscription_renewal_return_before_create_order_without_token', '__return_false' );
|
2023-11-27 12:48:10 +01:00
|
|
|
add_filter( 'woocommerce_paypal_payments_should_render_card_custom_fields', '__return_false' );
|
2023-10-31 14:22:17 +01:00
|
|
|
|
2023-10-23 16:50:43 +02:00
|
|
|
add_action(
|
|
|
|
'wp_enqueue_scripts',
|
|
|
|
function() use ( $c ) {
|
|
|
|
if ( ! is_user_logged_in() || ! is_add_payment_method_page() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$module_url = $c->get( 'save-payment-methods.module.url' );
|
|
|
|
wp_enqueue_script(
|
|
|
|
'ppcp-add-payment-method',
|
|
|
|
untrailingslashit( $module_url ) . '/assets/js/add-payment-method.js',
|
|
|
|
array( 'jquery' ),
|
|
|
|
$c->get( 'ppcp.asset-version' ),
|
|
|
|
true
|
|
|
|
);
|
2023-10-26 16:36:38 +02:00
|
|
|
|
2023-10-27 12:25:42 +02:00
|
|
|
$api = $c->get( 'api.user-id-token' );
|
|
|
|
assert( $api instanceof UserIdToken );
|
2023-10-26 16:36:38 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
$target_customer_id = '';
|
2023-10-27 12:25:42 +02:00
|
|
|
if ( is_user_logged_in() ) {
|
|
|
|
$target_customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true );
|
2023-10-26 16:36:38 +02:00
|
|
|
}
|
|
|
|
|
2023-10-27 12:25:42 +02:00
|
|
|
$id_token = $api->id_token( $target_customer_id );
|
2023-10-26 16:36:38 +02:00
|
|
|
|
|
|
|
wp_localize_script(
|
|
|
|
'ppcp-add-payment-method',
|
|
|
|
'ppcp_add_payment_method',
|
|
|
|
array(
|
2023-10-27 12:25:42 +02:00
|
|
|
'client_id' => $c->get( 'button.client_id' ),
|
2023-10-26 16:36:38 +02:00
|
|
|
'merchant_id' => $c->get( 'api.merchant_id' ),
|
2023-10-27 12:25:42 +02:00
|
|
|
'id_token' => $id_token,
|
|
|
|
'ajax' => array(
|
|
|
|
'create_setup_token' => array(
|
2023-10-26 16:36:38 +02:00
|
|
|
'endpoint' => \WC_AJAX::get_endpoint( CreateSetupToken::ENDPOINT ),
|
|
|
|
'nonce' => wp_create_nonce( CreateSetupToken::nonce() ),
|
|
|
|
),
|
2023-10-27 12:25:42 +02:00
|
|
|
'create_payment_token' => array(
|
2023-10-26 16:36:38 +02:00
|
|
|
'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ),
|
|
|
|
'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
);
|
2023-10-27 12:25:42 +02:00
|
|
|
} catch ( RuntimeException $exception ) {
|
|
|
|
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
|
|
|
assert( $logger instanceof LoggerInterface );
|
2023-10-26 16:36:38 +02:00
|
|
|
|
|
|
|
$error = $exception->getMessage();
|
2023-10-27 12:25:42 +02:00
|
|
|
if ( is_a( $exception, PayPalApiException::class ) ) {
|
|
|
|
$error = $exception->get_details( $error );
|
2023-10-26 16:36:38 +02:00
|
|
|
}
|
|
|
|
|
2023-10-27 12:25:42 +02:00
|
|
|
$logger->error( $error );
|
2023-10-26 16:36:38 +02:00
|
|
|
}
|
2023-10-23 16:50:43 +02:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
add_action(
|
|
|
|
'woocommerce_add_payment_method_form_bottom',
|
|
|
|
function () {
|
|
|
|
if ( ! is_user_logged_in() || ! is_add_payment_method_page() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-27 12:25:42 +02:00
|
|
|
echo '<div id="ppc-button-' . esc_attr( PayPalGateway::ID ) . '-save-payment-method"></div>';
|
2023-10-23 16:50:43 +02:00
|
|
|
}
|
|
|
|
);
|
2023-10-26 16:36:38 +02:00
|
|
|
|
|
|
|
add_action(
|
|
|
|
'wc_ajax_' . CreateSetupToken::ENDPOINT,
|
|
|
|
static function () use ( $c ) {
|
|
|
|
$endpoint = $c->get( 'save-payment-methods.endpoint.create-setup-token' );
|
2023-10-27 12:25:42 +02:00
|
|
|
assert( $endpoint instanceof CreateSetupToken );
|
2023-10-26 16:36:38 +02:00
|
|
|
|
|
|
|
$endpoint->handle_request();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
add_action(
|
|
|
|
'wc_ajax_' . CreatePaymentToken::ENDPOINT,
|
|
|
|
static function () use ( $c ) {
|
|
|
|
$endpoint = $c->get( 'save-payment-methods.endpoint.create-payment-token' );
|
2023-10-27 12:25:42 +02:00
|
|
|
assert( $endpoint instanceof CreatePaymentToken );
|
2023-10-26 16:36:38 +02:00
|
|
|
|
|
|
|
$endpoint->handle_request();
|
|
|
|
}
|
|
|
|
);
|
2023-11-02 10:54:08 +01:00
|
|
|
|
|
|
|
add_action(
|
|
|
|
'woocommerce_paypal_payments_before_delete_payment_token',
|
|
|
|
function( string $token_id ) use ( $c ) {
|
|
|
|
try {
|
|
|
|
$endpoint = $c->get( 'api.endpoint.payment-tokens' );
|
|
|
|
assert( $endpoint instanceof PaymentTokensEndpoint );
|
|
|
|
|
|
|
|
$endpoint->delete( $token_id );
|
|
|
|
} 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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2023-11-22 13:19:28 +01:00
|
|
|
|
|
|
|
add_filter(
|
|
|
|
'woocommerce_paypal_payments_credit_card_gateway_vault_supports',
|
|
|
|
function( array $supports ) use ( $c ): array {
|
|
|
|
$settings = $c->get( 'wcgateway.settings' );
|
|
|
|
assert( $settings instanceof ContainerInterface );
|
|
|
|
|
|
|
|
if ( $settings->has( 'vault_enabled_dcc' ) && $settings->get( 'vault_enabled_dcc' ) ) {
|
|
|
|
$supports[] = 'tokenization';
|
|
|
|
}
|
|
|
|
|
|
|
|
return $supports;
|
|
|
|
}
|
|
|
|
);
|
2023-10-19 11:18:01 +02:00
|
|
|
}
|
2023-10-17 15:11:48 +02:00
|
|
|
}
|