diff --git a/changelog.txt b/changelog.txt index c184dd3a5..0360265be 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,19 @@ *** Changelog *** += 1.6.5 - TBD = +* Fix - Allow guest users to purchase subscription products #422 +* Fix - Transaction ID missing for renewal order #424 +* Fix - Save your credit card checkbox should be removed in pay for order for subscriptions #420 +* Fix - Null currency error when the Aelia currency switcher plugin is active #426 +* Fix - Hide Reference Transactions check from logs #428 +* Fix - Doubled plugin module URL path causing failure #438 +* Fix - is_ajax deprecated #441 +* Fix - Place order button from PayPal Card Processing does not get translated #290 +* Fix - AMEX missing from supported cards for DCC Australia #432 +* Fix - "Save your Credit Card" text not clickable to change checkbox state #430 +* Fix - Improve DCC error notice when not available #435 +* Enhancement - Add View Logs link #416 + = 1.6.4 - 2021-12-27 = * Fix - Non admin user cannot save changes to the plugin settings #278 * Fix - Empty space in invoice prefix causes smart buttons to not load #390 diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index f254169ed..3759e5372 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -43,6 +43,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies; use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository; use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository; +use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository; use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData; use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository; use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository; @@ -108,7 +109,7 @@ return array( $container->get( 'api.bearer' ), $container->get( 'api.factory.payment-token' ), $container->get( 'woocommerce.logger.woocommerce' ), - $container->get( 'api.prefix' ) + $container->get( 'api.repository.customer' ) ); }, 'api.endpoint.webhook' => static function ( ContainerInterface $container ) : WebhookEndpoint { @@ -131,14 +132,14 @@ return array( }, 'api.endpoint.identity-token' => static function ( ContainerInterface $container ) : IdentityToken { $logger = $container->get( 'woocommerce.logger.woocommerce' ); - $prefix = $container->get( 'api.prefix' ); $settings = $container->get( 'wcgateway.settings' ); + $customer_repository = $container->get( 'api.repository.customer' ); return new IdentityToken( $container->get( 'api.host' ), $container->get( 'api.bearer' ), $logger, - $prefix, - $settings + $settings, + $customer_repository ); }, 'api.endpoint.payments' => static function ( ContainerInterface $container ): PaymentsEndpoint { @@ -219,6 +220,10 @@ return array( $merchant_id = $container->get( 'api.merchant_id' ); return new PayeeRepository( $merchant_email, $merchant_id ); }, + 'api.repository.customer' => static function( ContainerInterface $container ): CustomerRepository { + $prefix = $container->get( 'api.prefix' ); + return new CustomerRepository( $prefix ); + }, 'api.factory.application-context' => static function ( ContainerInterface $container ) : ApplicationContextFactory { return new ApplicationContextFactory(); }, diff --git a/modules/ppcp-api-client/src/Endpoint/IdentityToken.php b/modules/ppcp-api-client/src/Endpoint/IdentityToken.php index 2e73b1af9..a01e746ac 100644 --- a/modules/ppcp-api-client/src/Endpoint/IdentityToken.php +++ b/modules/ppcp-api-client/src/Endpoint/IdentityToken.php @@ -14,6 +14,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Token; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; /** @@ -44,13 +45,6 @@ class IdentityToken { */ private $logger; - /** - * The prefix. - * - * @var string - */ - private $prefix; - /** * The settings * @@ -58,32 +52,45 @@ class IdentityToken { */ private $settings; + /** + * The customer repository. + * + * @var CustomerRepository + */ + protected $customer_repository; + /** * IdentityToken constructor. * - * @param string $host The host. - * @param Bearer $bearer The bearer. - * @param LoggerInterface $logger The logger. - * @param string $prefix The prefix. - * @param Settings $settings The settings. + * @param string $host The host. + * @param Bearer $bearer The bearer. + * @param LoggerInterface $logger The logger. + * @param Settings $settings The settings. + * @param CustomerRepository $customer_repository The customer repository. */ - public function __construct( string $host, Bearer $bearer, LoggerInterface $logger, string $prefix, Settings $settings ) { - $this->host = $host; - $this->bearer = $bearer; - $this->logger = $logger; - $this->prefix = $prefix; - $this->settings = $settings; + public function __construct( + string $host, + Bearer $bearer, + LoggerInterface $logger, + Settings $settings, + CustomerRepository $customer_repository + ) { + $this->host = $host; + $this->bearer = $bearer; + $this->logger = $logger; + $this->settings = $settings; + $this->customer_repository = $customer_repository; } /** - * Generates a token for a specific customer. + * Generates a token for a specific user. * - * @param int $customer_id The id of the customer. + * @param int $user_id The id of the user. * * @return Token * @throws RuntimeException If the request fails. */ - public function generate_for_customer( int $customer_id ): Token { + public function generate_for_user( int $user_id ): Token { $bearer = $this->bearer->bearer(); $url = trailingslashit( $this->host ) . 'v1/identity/generate-token'; @@ -95,11 +102,16 @@ class IdentityToken { ), ); if ( - $customer_id - && ( $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ) ) + ( $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ) ) && defined( 'PPCP_FLAG_SUBSCRIPTION' ) && PPCP_FLAG_SUBSCRIPTION ) { - $args['body'] = wp_json_encode( array( 'customer_id' => $this->prefix . $customer_id ) ); + $customer_id = $this->customer_repository->customer_id_for_user( ( $user_id ) ); + + $args['body'] = wp_json_encode( + array( + 'customer_id' => $customer_id, + ) + ); } $response = $this->request( $url, $args ); diff --git a/modules/ppcp-api-client/src/Endpoint/PaymentTokenEndpoint.php b/modules/ppcp-api-client/src/Endpoint/PaymentTokenEndpoint.php index e3c8ed903..1e8dcf871 100644 --- a/modules/ppcp-api-client/src/Endpoint/PaymentTokenEndpoint.php +++ b/modules/ppcp-api-client/src/Endpoint/PaymentTokenEndpoint.php @@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory; use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository; /** * Class PaymentTokenEndpoint @@ -50,12 +51,13 @@ class PaymentTokenEndpoint { * @var LoggerInterface */ private $logger; + /** - * The prefix. + * The customer repository. * - * @var string + * @var CustomerRepository */ - private $prefix; + protected $customer_repository; /** * PaymentTokenEndpoint constructor. @@ -64,21 +66,21 @@ class PaymentTokenEndpoint { * @param Bearer $bearer The bearer. * @param PaymentTokenFactory $factory The payment token factory. * @param LoggerInterface $logger The logger. - * @param string $prefix The prefix. + * @param CustomerRepository $customer_repository The customer repository. */ public function __construct( string $host, Bearer $bearer, PaymentTokenFactory $factory, LoggerInterface $logger, - string $prefix + CustomerRepository $customer_repository ) { - $this->host = $host; - $this->bearer = $bearer; - $this->factory = $factory; - $this->logger = $logger; - $this->prefix = $prefix; + $this->host = $host; + $this->bearer = $bearer; + $this->factory = $factory; + $this->logger = $logger; + $this->customer_repository = $customer_repository; } /** @@ -91,10 +93,8 @@ class PaymentTokenEndpoint { */ public function for_user( int $id ): array { $bearer = $this->bearer->bearer(); - - $customer_id = $this->prefix . $id; - $url = trailingslashit( $this->host ) . 'v2/vault/payment-tokens/?customer_id=' . $customer_id; - $args = array( + $url = trailingslashit( $this->host ) . 'v2/vault/payment-tokens/?customer_id=' . $this->customer_repository->customer_id_for_user( $id ); + $args = array( 'method' => 'GET', 'headers' => array( 'Authorization' => 'Bearer ' . $bearer->token(), diff --git a/modules/ppcp-api-client/src/Repository/CustomerRepository.php b/modules/ppcp-api-client/src/Repository/CustomerRepository.php new file mode 100644 index 000000000..eb6e0cf6a --- /dev/null +++ b/modules/ppcp-api-client/src/Repository/CustomerRepository.php @@ -0,0 +1,59 @@ +prefix = $prefix; + } + + /** + * Returns the customer ID for the given user ID. + * + * @param int $user_id The user ID. + * @return string + */ + public function customer_id_for_user( int $user_id ): string { + if ( 0 === $user_id ) { + $guest_customer_id = WC()->session->get( 'ppcp_guest_customer_id' ); + if ( is_string( $guest_customer_id ) && $guest_customer_id ) { + return $guest_customer_id; + } + + $unique_id = $this->prefix . uniqid(); + WC()->session->set( 'ppcp_guest_customer_id', $unique_id ); + + return $unique_id; + } + + $guest_customer_id = get_user_meta( $user_id, 'ppcp_guest_customer_id', true ); + if ( $guest_customer_id ) { + return $guest_customer_id; + } + + return $this->prefix . (string) $user_id; + } +} diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js index 49fd98b52..402781bbf 100644 --- a/modules/ppcp-button/resources/js/button.js +++ b/modules/ppcp-button/resources/js/button.js @@ -82,8 +82,16 @@ document.addEventListener( console.error('PayPal button could not be configured.'); return; } - const script = document.createElement('script'); + if ( + PayPalCommerceGateway.context !== 'checkout' + && PayPalCommerceGateway.data_client_id.user === 0 + && PayPalCommerceGateway.data_client_id.has_subscriptions + ) { + return; + } + + const script = document.createElement('script'); script.addEventListener('load', (event) => { bootstrap(); }); diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index a5901c750..fba90a1c8 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -90,7 +90,7 @@ return array( 'button.url' => static function ( ContainerInterface $container ): string { return plugins_url( '/modules/ppcp-button/', - dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php' + dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ); }, 'button.request-data' => static function ( ContainerInterface $container ): RequestData { diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index cf0cef554..46a1f44fc 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -392,9 +392,6 @@ class SmartButton implements SmartButtonInterface { if ( ! is_checkout() && ! $buttons_enabled ) { return false; } - if ( ! $this->can_save_vault_token() && $this->has_subscriptions() ) { - return false; - } $load_script = false; if ( is_checkout() && $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) ) { @@ -407,7 +404,7 @@ class SmartButton implements SmartButtonInterface { if ( in_array( $this->context(), array( 'pay-now', 'checkout' ), true ) && $this->can_render_dcc() ) { wp_enqueue_style( 'ppcp-hosted-fields', - $this->module_url . '/assets/css/hosted-fields.css', + untrailingslashit( $this->module_url ) . '/assets/css/hosted-fields.css', array(), 1 ); @@ -415,7 +412,7 @@ class SmartButton implements SmartButtonInterface { if ( $load_script ) { wp_enqueue_script( 'ppcp-smart-button', - $this->module_url . '/assets/js/button.js', + untrailingslashit( $this->module_url ) . '/assets/js/button.js', array( 'jquery' ), '1.3.2', true @@ -599,7 +596,7 @@ class SmartButton implements SmartButtonInterface { return false; } - return is_user_logged_in(); + return true; } /** @@ -650,10 +647,11 @@ class SmartButton implements SmartButtonInterface { $localize = array( 'script_attributes' => $this->attributes(), 'data_client_id' => array( - 'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token(), - 'endpoint' => home_url( \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ) ), - 'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ), - 'user' => get_current_user_id(), + 'set_attribute' => $this->can_save_vault_token(), + 'endpoint' => home_url( \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ) ), + 'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ), + 'user' => get_current_user_id(), + 'has_subscriptions' => $this->has_subscriptions(), ), 'redirect' => wc_get_checkout_url(), 'context' => $this->context(), diff --git a/modules/ppcp-button/src/Endpoint/DataClientIdEndpoint.php b/modules/ppcp-button/src/Endpoint/DataClientIdEndpoint.php index ad5b1e750..c516d07bd 100644 --- a/modules/ppcp-button/src/Endpoint/DataClientIdEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/DataClientIdEndpoint.php @@ -80,7 +80,7 @@ class DataClientIdEndpoint implements EndpointInterface { try { $this->request_data->read_request( $this->nonce() ); $user_id = get_current_user_id(); - $token = $this->identity_token->generate_for_customer( $user_id ); + $token = $this->identity_token->generate_for_user( $user_id ); wp_send_json( array( 'token' => $token->token(), diff --git a/modules/ppcp-onboarding/services.php b/modules/ppcp-onboarding/services.php index 18b633bae..cfafbd55f 100644 --- a/modules/ppcp-onboarding/services.php +++ b/modules/ppcp-onboarding/services.php @@ -140,7 +140,7 @@ return array( 'onboarding.url' => static function ( ContainerInterface $container ): string { return plugins_url( '/modules/ppcp-onboarding/', - dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php' + dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ); }, diff --git a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php index 33ff78730..57a632860 100644 --- a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php +++ b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php @@ -63,14 +63,14 @@ class OnboardingAssets { */ public function register(): bool { - $url = $this->module_url . '/assets/css/onboarding.css'; + $url = untrailingslashit( $this->module_url ) . '/assets/css/onboarding.css'; wp_register_style( 'ppcp-onboarding', $url, array(), 1 ); - $url = $this->module_url . '/assets/js/settings.js'; + $url = untrailingslashit( $this->module_url ) . '/assets/js/settings.js'; wp_register_script( 'ppcp-settings', $url, @@ -79,7 +79,7 @@ class OnboardingAssets { true ); - $url = $this->module_url . '/assets/js/onboarding.js'; + $url = untrailingslashit( $this->module_url ) . '/assets/js/onboarding.js'; wp_register_script( 'ppcp-onboarding', $url, diff --git a/modules/ppcp-vaulting/services.php b/modules/ppcp-vaulting/services.php index e81fc55ad..0e3e2d7d1 100644 --- a/modules/ppcp-vaulting/services.php +++ b/modules/ppcp-vaulting/services.php @@ -17,7 +17,7 @@ return array( 'vaulting.module-url' => static function ( ContainerInterface $container ): string { return plugins_url( '/modules/ppcp-vaulting/', - dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php' + dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ); }, 'vaulting.assets.myaccount-payments' => function( ContainerInterface $container ) : MyAccountPaymentsAssets { diff --git a/modules/ppcp-vaulting/src/Assets/MyAccountPaymentsAssets.php b/modules/ppcp-vaulting/src/Assets/MyAccountPaymentsAssets.php index 275107f18..80e9bc3db 100644 --- a/modules/ppcp-vaulting/src/Assets/MyAccountPaymentsAssets.php +++ b/modules/ppcp-vaulting/src/Assets/MyAccountPaymentsAssets.php @@ -42,7 +42,7 @@ class MyAccountPaymentsAssets { public function enqueue(): void { wp_enqueue_script( 'ppcp-vaulting-myaccount-payments', - $this->module_url . '/assets/js/myaccount-payments.js', + untrailingslashit( $this->module_url ) . '/assets/js/myaccount-payments.js', array( 'jquery' ), '1', true diff --git a/modules/ppcp-vaulting/src/VaultingModule.php b/modules/ppcp-vaulting/src/VaultingModule.php index a2090a2c1..d74dfc86e 100644 --- a/modules/ppcp-vaulting/src/VaultingModule.php +++ b/modules/ppcp-vaulting/src/VaultingModule.php @@ -98,6 +98,17 @@ class VaultingModule implements ModuleInterface { } ); + $subscription_helper = $container->get( 'subscription.helper' ); + add_action( + 'woocommerce_created_customer', + function( int $customer_id ) use ( $subscription_helper ) { + $guest_customer_id = WC()->session->get( 'ppcp_guest_customer_id' ); + if ( $guest_customer_id && $subscription_helper->cart_contains_subscription() ) { + update_user_meta( $customer_id, 'ppcp_guest_customer_id', $guest_customer_id ); + } + } + ); + $asset_loader = $container->get( 'vaulting.assets.myaccount-payments' ); add_action( 'wp_enqueue_scripts', diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 24e7b753a..ed33337c9 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -121,8 +121,7 @@ return array( 'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways { $session_handler = $container->get( 'session.handler' ); $settings = $container->get( 'wcgateway.settings' ); - $subscription_helper = $container->get( 'subscription.helper' ); - return new DisableGateways( $session_handler, $settings, $subscription_helper ); + return new DisableGateways( $session_handler, $settings ); }, 'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool { $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; @@ -2035,7 +2034,7 @@ return array( 'wcgateway.url' => static function ( ContainerInterface $container ): string { return plugins_url( $container->get( 'wcgateway.relative-path' ), - dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php' + dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ); }, 'wcgateway.relative-path' => static function( ContainerInterface $container ): string { @@ -2043,7 +2042,7 @@ return array( }, 'wcgateway.absolute-path' => static function( ContainerInterface $container ): string { return plugin_dir_path( - dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php' + dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ) . $container->get( 'wcgateway.relative-path' ); }, diff --git a/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php b/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php index db22c2c2f..fd89636ad 100644 --- a/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php +++ b/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php @@ -59,7 +59,7 @@ class SettingsPageAssets { add_action( 'admin_enqueue_scripts', function() use ( $bearer ) { - if ( ! is_admin() || is_ajax() ) { + if ( ! is_admin() || wp_doing_ajax() ) { return; } diff --git a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php index cf4a7291d..64520b38c 100644 --- a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php +++ b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php @@ -10,7 +10,6 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway\Checkout; use WooCommerce\PayPalCommerce\Session\SessionHandler; -use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use Psr\Container\ContainerInterface; @@ -34,29 +33,19 @@ class DisableGateways { */ private $settings; - /** - * The subscription helper - * - * @var SubscriptionHelper - */ - private $subscription_helper; - /** * DisableGateways constructor. * * @param SessionHandler $session_handler The Session Handler. * @param ContainerInterface $settings The Settings. - * @param SubscriptionHelper $subscription_helper The subscription helper. */ public function __construct( SessionHandler $session_handler, - ContainerInterface $settings, - SubscriptionHelper $subscription_helper + ContainerInterface $settings ) { - $this->session_handler = $session_handler; - $this->settings = $settings; - $this->subscription_helper = $subscription_helper; + $this->session_handler = $session_handler; + $this->settings = $settings; } /** @@ -110,10 +99,6 @@ class DisableGateways { return true; } - if ( $this->subscription_helper->cart_contains_subscription() && ! is_user_logged_in() ) { - return true; - } - return false; } diff --git a/modules/ppcp-webhooks/services.php b/modules/ppcp-webhooks/services.php index 13b0b5e54..536abaa1b 100644 --- a/modules/ppcp-webhooks/services.php +++ b/modules/ppcp-webhooks/services.php @@ -197,7 +197,7 @@ return array( 'webhook.module-url' => static function ( ContainerInterface $container ): string { return plugins_url( '/modules/ppcp-webhooks/', - dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php' + dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ); }, ); diff --git a/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php b/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php index 5d5248329..27f0c0dd1 100644 --- a/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php +++ b/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php @@ -45,14 +45,14 @@ class WebhooksStatusPageAssets { public function register(): void { wp_register_style( 'ppcp-webhooks-status-page-style', - $this->module_url . '/assets/css/status-page.css', + untrailingslashit( $this->module_url ) . '/assets/css/status-page.css', array(), '1' ); wp_register_script( 'ppcp-webhooks-status-page', - $this->module_url . '/assets/js/status-page.js', + untrailingslashit( $this->module_url ) . '/assets/js/status-page.js', array(), '1', true diff --git a/package.json b/package.json index 1f4cbb977..b52394321 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "woocommerce-paypal-payments", - "version": "1.6.4", + "version": "1.6.5", "description": "WooCommerce PayPal Payments", "repository": "https://github.com/woocommerce/woocommerce-paypal-payments", "license": "GPL-2.0", diff --git a/readme.txt b/readme.txt index 1611198ce..f01ee26dd 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell, Requires at least: 5.3 Tested up to: 5.8 Requires PHP: 7.1 -Stable tag: 1.6.4 +Stable tag: 1.6.5 License: GPLv2 License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -81,6 +81,20 @@ Follow the steps below to connect the plugin to your PayPal account: == Changelog == += 1.6.5 = +* Fix - Allow guest users to purchase subscription products #422 +* Fix - Transaction ID missing for renewal order #424 +* Fix - Save your credit card checkbox should be removed in pay for order for subscriptions #420 +* Fix - Null currency error when the Aelia currency switcher plugin is active #426 +* Fix - Hide Reference Transactions check from logs #428 +* Fix - Doubled plugin module URL path causing failure #438 +* Fix - is_ajax deprecated #441 +* Fix - Place order button from PayPal Card Processing does not get translated #290 +* Fix - AMEX missing from supported cards for DCC Australia #432 +* Fix - "Save your Credit Card" text not clickable to change checkbox state #430 +* Fix - Improve DCC error notice when not available #435 +* Enhancement - Add View Logs link #416 + = 1.6.4 = * Fix - Non admin user cannot save changes to the plugin settings #278 * Fix - Empty space in invoice prefix causes smart buttons to not load #390 diff --git a/tests/PHPUnit/ApiClient/Endpoint/IdentityTokenTest.php b/tests/PHPUnit/ApiClient/Endpoint/IdentityTokenTest.php index 6cfc69c83..255a59032 100644 --- a/tests/PHPUnit/ApiClient/Endpoint/IdentityTokenTest.php +++ b/tests/PHPUnit/ApiClient/Endpoint/IdentityTokenTest.php @@ -9,6 +9,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer; use WooCommerce\PayPalCommerce\ApiClient\Entity\Token; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; +use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository; use WooCommerce\PayPalCommerce\ApiClient\TestCase; use Mockery; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; @@ -20,8 +21,8 @@ class IdentityTokenTest extends TestCase private $host; private $bearer; private $logger; - private $prefix; private $settings; + private $customer_repository; private $sut; public function setUp(): void @@ -31,10 +32,16 @@ class IdentityTokenTest extends TestCase $this->host = 'https://example.com/'; $this->bearer = Mockery::mock(Bearer::class); $this->logger = Mockery::mock(LoggerInterface::class); - $this->prefix = 'prefix'; $this->settings = Mockery::mock(Settings::class); + $this->customer_repository = Mockery::mock(CustomerRepository::class); - $this->sut = new IdentityToken($this->host, $this->bearer, $this->logger, $this->prefix, $this->settings); + $this->sut = new IdentityToken( + $this->host, + $this->bearer, + $this->logger, + $this->settings, + $this->customer_repository + ); } public function testGenerateForCustomerReturnsToken() @@ -52,6 +59,7 @@ class IdentityTokenTest extends TestCase $this->logger->shouldReceive('debug'); $this->settings->shouldReceive('has')->andReturn(true); $this->settings->shouldReceive('get')->andReturn(true); + $this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('prefix1'); $rawResponse = [ 'body' => '{"client_token":"abc123", "expires_in":3600}', @@ -82,8 +90,9 @@ class IdentityTokenTest extends TestCase expect('is_wp_error')->with($rawResponse)->andReturn(false); expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200); when('wc_print_r')->returnArg(); + when('get_user_meta')->justReturn(''); - $result = $this->sut->generate_for_customer(1); + $result = $this->sut->generate_for_user(1); $this->assertInstanceOf(Token::class, $result); } @@ -104,9 +113,10 @@ class IdentityTokenTest extends TestCase $this->logger->shouldReceive('debug'); $this->settings->shouldReceive('has')->andReturn(true); $this->settings->shouldReceive('get')->andReturn(true); + $this->customer_repository->shouldReceive('customer_id_for_user'); $this->expectException(RuntimeException::class); - $this->sut->generate_for_customer(1); + $this->sut->generate_for_user(1); } public function testGenerateForCustomerFailsBecauseResponseCodeIsNot200() @@ -130,8 +140,9 @@ class IdentityTokenTest extends TestCase $this->logger->shouldReceive('debug'); $this->settings->shouldReceive('has')->andReturn(true); $this->settings->shouldReceive('get')->andReturn(true); + $this->customer_repository->shouldReceive('customer_id_for_user'); $this->expectException(PayPalApiException::class); - $this->sut->generate_for_customer(1); + $this->sut->generate_for_user(1); } } diff --git a/tests/PHPUnit/ApiClient/Endpoint/PaymentTokenEndpointTest.php b/tests/PHPUnit/ApiClient/Endpoint/PaymentTokenEndpointTest.php index 7f1b8fd7c..50a49d912 100644 --- a/tests/PHPUnit/ApiClient/Endpoint/PaymentTokenEndpointTest.php +++ b/tests/PHPUnit/ApiClient/Endpoint/PaymentTokenEndpointTest.php @@ -11,6 +11,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Token; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory; +use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository; use WooCommerce\PayPalCommerce\ApiClient\TestCase; use Mockery; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; @@ -24,7 +25,7 @@ class PaymentTokenEndpointTest extends TestCase private $bearer; private $factory; private $logger; - private $prefix; + private $customer_repository; private $sut; public function setUp(): void @@ -35,13 +36,13 @@ class PaymentTokenEndpointTest extends TestCase $this->bearer = Mockery::mock(Bearer::class); $this->factory = Mockery::mock(PaymentTokenFactory::class); $this->logger = Mockery::mock(LoggerInterface::class); - $this->prefix = 'prefix'; + $this->customer_repository = Mockery::mock(CustomerRepository::class); $this->sut = new PaymentTokenEndpoint( $this->host, $this->bearer, $this->factory, $this->logger, - $this->prefix + $this->customer_repository ); } @@ -64,7 +65,7 @@ class PaymentTokenEndpointTest extends TestCase $token->shouldReceive('token') ->andReturn('bearer'); - $this->ensureRequestForUser($rawResponse, $id); + $this->ensureRequestForUser($rawResponse, '123abc'); expect('is_wp_error')->with($rawResponse)->andReturn(false); expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200); @@ -73,6 +74,8 @@ class PaymentTokenEndpointTest extends TestCase $this->logger->shouldReceive('debug'); + $this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('123abc'); + $result = $this->sut->for_user($id); $this->assertInstanceOf(PaymentToken::class, $result[0]); @@ -89,13 +92,15 @@ class PaymentTokenEndpointTest extends TestCase ->andReturn($token); $token->shouldReceive('token') ->andReturn('bearer'); - $this->ensureRequestForUser($rawResponse, $id); + $this->ensureRequestForUser($rawResponse, '123abc'); expect('wp_remote_get')->andReturn($rawResponse); expect('is_wp_error')->with($rawResponse)->andReturn(true); $this->logger->shouldReceive('log'); $this->logger->shouldReceive('debug'); + $this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('123abc'); + $this->expectException(RuntimeException::class); $this->sut->for_user($id); } @@ -114,7 +119,7 @@ class PaymentTokenEndpointTest extends TestCase ->andReturn($token); $token->shouldReceive('token') ->andReturn('bearer'); - $this->ensureRequestForUser($rawResponse, $id); + $this->ensureRequestForUser($rawResponse, '123abc'); expect('wp_remote_get')->andReturn($rawResponse); @@ -123,6 +128,8 @@ class PaymentTokenEndpointTest extends TestCase $this->logger->shouldReceive('log'); $this->logger->shouldReceive('debug'); + $this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('123abc'); + $this->expectException(PayPalApiException::class); $this->sut->for_user($id); } @@ -179,13 +186,12 @@ class PaymentTokenEndpointTest extends TestCase * @param int $id * @throws \Brain\Monkey\Expectation\Exception\ExpectationArgsRequired */ - private function ensureRequestForUser(array $rawResponse, int $id): void + private function ensureRequestForUser(array $rawResponse, string $id): void { $host = $this->host; - $prefix = $this->prefix; expect('wp_remote_get')->andReturnUsing( - function ($url, $args) use ($rawResponse, $host, $prefix, $id) { - if ($url !== $host . 'v2/vault/payment-tokens/?customer_id=' . $prefix . $id) { + function ($url, $args) use ($rawResponse, $host, $id) { + if ($url !== $host . 'v2/vault/payment-tokens/?customer_id=' . $id) { return false; } if ($args['headers']['Authorization'] !== 'Bearer bearer') { diff --git a/tests/PHPUnit/Button/Endpoint/DataClientIdEndpointTest.php b/tests/PHPUnit/Button/Endpoint/DataClientIdEndpointTest.php index eea5df229..c5ec7fd8d 100644 --- a/tests/PHPUnit/Button/Endpoint/DataClientIdEndpointTest.php +++ b/tests/PHPUnit/Button/Endpoint/DataClientIdEndpointTest.php @@ -34,7 +34,7 @@ class DataClientIdEndpointTest extends TestCase $this->requestData->shouldReceive('read_request') ->with($this->sut::nonce()); when('get_current_user_id')->justReturn($userId); - $this->identityToken->shouldReceive('generate_for_customer') + $this->identityToken->shouldReceive('generate_for_user') ->with($userId) ->andReturn($token); diff --git a/tests/PHPUnit/WcGateway/Assets/SettingsPagesAssetsTest.php b/tests/PHPUnit/WcGateway/Assets/SettingsPagesAssetsTest.php index 51179aa9c..e27c27ca6 100644 --- a/tests/PHPUnit/WcGateway/Assets/SettingsPagesAssetsTest.php +++ b/tests/PHPUnit/WcGateway/Assets/SettingsPagesAssetsTest.php @@ -19,7 +19,7 @@ class SettingsPagesAssetsTest extends TestCase when('is_admin') ->justReturn(true); - when('is_ajax') + when('wp_doing_ajax') ->justReturn(false); $testee->register_assets(); diff --git a/woocommerce-paypal-payments.php b/woocommerce-paypal-payments.php index a4cf1ca41..49f8134ee 100644 --- a/woocommerce-paypal-payments.php +++ b/woocommerce-paypal-payments.php @@ -3,13 +3,13 @@ * Plugin Name: WooCommerce PayPal Payments * Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/ * Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage. - * Version: 1.6.4 + * Version: 1.6.5 * Author: WooCommerce * Author URI: https://woocommerce.com/ * License: GPL-2.0 * Requires PHP: 7.1 * WC requires at least: 3.9 - * WC tested up to: 6.0 + * WC tested up to: 6.1 * Text Domain: woocommerce-paypal-payments * * @package WooCommerce\PayPalCommerce