From 2f2dc5feebcf86d706462788210c17f1bdda5264 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Tue, 14 May 2024 13:51:20 +0200 Subject: [PATCH 01/48] AXO: Fix Ryan flow credit card icons --- modules/ppcp-axo/resources/js/Views/CardView.js | 6 +++--- modules/ppcp-axo/services.php | 3 ++- modules/ppcp-axo/src/Assets/AxoManager.php | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-axo/resources/js/Views/CardView.js b/modules/ppcp-axo/resources/js/Views/CardView.js index 9ca8670a2..a72a38ff3 100644 --- a/modules/ppcp-axo/resources/js/Views/CardView.js +++ b/modules/ppcp-axo/resources/js/Views/CardView.js @@ -34,8 +34,8 @@ class CardView { const cardIcons = { 'VISA': 'visa-light.svg', 'MASTER_CARD': 'mastercard-light.svg', - 'AMEX': 'amex.svg', - 'DISCOVER': 'discover.svg', + 'AMEX': 'amex-light.svg', + 'DISCOVER': 'discover-light.svg', 'DINERS': 'dinersclub-light.svg', 'JCB': 'jcb-light.svg', 'UNIONPAY': 'unionpay-light.svg', @@ -52,7 +52,7 @@ class CardView { ${data.value('brand')} diff --git a/modules/ppcp-axo/services.php b/modules/ppcp-axo/services.php index 44253f22d..61db78977 100644 --- a/modules/ppcp-axo/services.php +++ b/modules/ppcp-axo/services.php @@ -58,7 +58,8 @@ return array( $container->get( 'onboarding.environment' ), $container->get( 'wcgateway.settings.status' ), $container->get( 'api.shop.currency' ), - $container->get( 'woocommerce.logger.woocommerce' ) + $container->get( 'woocommerce.logger.woocommerce' ), + $container->get( 'wcgateway.url' ) ); }, diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php index 2ed5fc04c..d7042b6e5 100644 --- a/modules/ppcp-axo/src/Assets/AxoManager.php +++ b/modules/ppcp-axo/src/Assets/AxoManager.php @@ -78,6 +78,13 @@ class AxoManager { */ private $session_handler; + /** + * The WcGateway module URL. + * + * @var string + */ + private $wcgateway_module_url; + /** * AxoManager constructor. * @@ -89,6 +96,7 @@ class AxoManager { * @param SettingsStatus $settings_status The Settings status helper. * @param string $currency 3-letter currency code of the shop. * @param LoggerInterface $logger The logger. + * @param string $wcgateway_module_url The WcGateway module URL. */ public function __construct( string $module_url, @@ -98,7 +106,8 @@ class AxoManager { Environment $environment, SettingsStatus $settings_status, string $currency, - LoggerInterface $logger + LoggerInterface $logger, + string $wcgateway_module_url ) { $this->module_url = $module_url; @@ -109,6 +118,7 @@ class AxoManager { $this->settings_status = $settings_status; $this->currency = $currency; $this->logger = $logger; + $this->wcgateway_module_url = $wcgateway_module_url; } /** @@ -197,7 +207,7 @@ class AxoManager { 'CA' => WC()->countries->get_states( 'CA' ), ), ), - 'module_url' => untrailingslashit( $this->module_url ), + 'icons_directory' => esc_url( $this->wcgateway_module_url ) . 'assets/images/axo/', ); } From 41ac4197eee1004d4ee2dddf1da800f9652d178d Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Wed, 15 May 2024 14:42:40 +0200 Subject: [PATCH 02/48] Force cart and block-cart button loctions when AXO is active (3091) --- modules/ppcp-axo/services.php | 31 +++++++++++++++++++ modules/ppcp-axo/src/Assets/AxoManager.php | 2 +- modules/ppcp-axo/src/AxoModule.php | 22 +++++++++++++ .../ppcp-wc-gateway/resources/css/common.scss | 7 ++++- .../Fields/paypal-smart-button-fields.php | 10 ++++++ .../src/Settings/SettingsListener.php | 24 ++++++++++++++ 6 files changed, 94 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-axo/services.php b/modules/ppcp-axo/services.php index 44253f22d..088ecfacb 100644 --- a/modules/ppcp-axo/services.php +++ b/modules/ppcp-axo/services.php @@ -13,7 +13,10 @@ use WooCommerce\PayPalCommerce\Axo\Assets\AxoManager; use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway; use WooCommerce\PayPalCommerce\Axo\Helper\ApmApplies; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Helper\CartCheckoutDetector; +use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; return array( @@ -193,4 +196,32 @@ return array( return '

' . $notice_content . '

'; }, + + 'axo.smart-button-location-notice' => static function ( ContainerInterface $container ) : string { + $settings = $container->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + if ( $settings->has( 'axo_enabled' ) && $settings->get( 'axo_enabled' ) ) { + $fastlane_settings_url = admin_url( + sprintf( + 'admin.php?page=wc-settings&tab=checkout§ion=%1$s&ppcp-tab=%2$s#field-axo_heading', + PayPalGateway::ID, + CreditCardGateway::ID + ) + ); + + $notice_content = sprintf( + /* translators: %1$s: URL to the Checkout edit page. */ + __( + 'Important: The Cart & Classic Cart Smart Button Locations cannot be disabled while Fastlane is active.', + 'woocommerce-paypal-payments' + ), + esc_url( $fastlane_settings_url ) + ); + } else { + return ''; + } + + return '

' . $notice_content . '

'; + }, ); diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php index 2ed5fc04c..d9b4313fc 100644 --- a/modules/ppcp-axo/src/Assets/AxoManager.php +++ b/modules/ppcp-axo/src/Assets/AxoManager.php @@ -197,7 +197,7 @@ class AxoManager { 'CA' => WC()->countries->get_states( 'CA' ), ), ), - 'module_url' => untrailingslashit( $this->module_url ), + 'module_url' => untrailingslashit( $this->module_url ), ); } diff --git a/modules/ppcp-axo/src/AxoModule.php b/modules/ppcp-axo/src/AxoModule.php index dfb76ef60..bd1028ef5 100644 --- a/modules/ppcp-axo/src/AxoModule.php +++ b/modules/ppcp-axo/src/AxoModule.php @@ -24,6 +24,7 @@ use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Helper\CartCheckoutDetector; +use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener; /** * Class AxoModule @@ -108,6 +109,27 @@ class AxoModule implements ModuleInterface { } ); + // Force 'cart-block' and 'cart' Smart Button locations in the settings. + add_action( + 'admin_init', + static function () use ( $c ) { + $listener = $c->get( 'wcgateway.settings.listener' ); + assert( $listener instanceof SettingsListener ); + + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + $listener->filter_settings( + $settings->has( 'axo_enabled' ) && $settings->get( 'axo_enabled' ), + 'smart_button_locations', + function( array $existing_setting_value ) { + $axo_forced_locations = array( 'cart-block', 'cart' ); + return array_unique( array_merge( $existing_setting_value, $axo_forced_locations ) ); + } + ); + } + ); + add_action( 'init', function () use ( $c, $module ) { diff --git a/modules/ppcp-wc-gateway/resources/css/common.scss b/modules/ppcp-wc-gateway/resources/css/common.scss index 1345cb810..d9f40345f 100644 --- a/modules/ppcp-wc-gateway/resources/css/common.scss +++ b/modules/ppcp-wc-gateway/resources/css/common.scss @@ -61,8 +61,13 @@ $background-ident-color: #fbfbfb; border: 1px solid #c3c4c7; border-left-width: 4px; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); - margin: 5px 15px 2px; + margin: 5px 15px 2px 0; padding: 1px 12px; + + p, .form-table td & p { + margin-top: 4px; + margin-bottom: 4px; + } } .ppcp-notice-warning { diff --git a/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php b/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php index 0d02ad679..9db7f2601 100644 --- a/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php +++ b/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php @@ -60,6 +60,16 @@ return function ( ContainerInterface $container, array $fields ): array { '' ), ), + 'smart_button_locations_notice' => array( + 'heading' => '', + 'html' => $container->get( 'axo.smart-button-location-notice' ), + 'type' => 'ppcp-html', + 'classes' => array(), + 'class' => array(), + 'screens' => array( State::STATE_START, State::STATE_ONBOARDED ), + 'requirements' => array(), + 'gateway' => 'paypal', + ), 'smart_button_locations' => array( 'title' => __( 'Smart Button Locations', 'woocommerce-paypal-payments' ), 'type' => 'ppcp-multiselect', diff --git a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php index b7d0c39bd..c6d7e7231 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php +++ b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php @@ -729,4 +729,28 @@ class SettingsListener { } } + /** + * Filter settings based on a condition. + * + * @param bool $condition The condition. + * @param string $setting_slug The setting slug. + * @param callable $filter_function The filter function. + * @param bool $persist Whether to persist the settings. + */ + public function filter_settings( bool $condition, string $setting_slug, callable $filter_function, bool $persist = true ): void { + if ( ! $this->is_valid_site_request() || State::STATE_ONBOARDED !== $this->state->current_state() ) { + return; + } + + $existing_setting_value = $this->settings->has( $setting_slug ) ? $this->settings->get( $setting_slug ) : null; + + if ( $condition ) { + $new_setting_value = $filter_function( $existing_setting_value ); + $this->settings->set( $setting_slug, $new_setting_value ); + + if ( $persist ) { + $this->settings->persist(); + } + } + } } From a362fdc3ba5559e1344ac84ada7c6490c2e98f43 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Thu, 16 May 2024 19:51:47 +0200 Subject: [PATCH 03/48] Ensure the classic cart and checkout check works for the regular WooCommerce shortcodes --- modules/ppcp-axo/src/Assets/AxoManager.php | 2 +- .../src/Helper/CartCheckoutDetector.php | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php index 2ed5fc04c..d9b4313fc 100644 --- a/modules/ppcp-axo/src/Assets/AxoManager.php +++ b/modules/ppcp-axo/src/Assets/AxoManager.php @@ -197,7 +197,7 @@ class AxoManager { 'CA' => WC()->countries->get_states( 'CA' ), ), ), - 'module_url' => untrailingslashit( $this->module_url ), + 'module_url' => untrailingslashit( $this->module_url ), ); } diff --git a/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php b/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php index faac7f257..253193758 100644 --- a/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php +++ b/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php @@ -114,7 +114,7 @@ class CartCheckoutDetector { */ public static function has_classic_checkout(): bool { $checkout_page_id = wc_get_page_id( 'checkout' ); - return $checkout_page_id && has_block( 'woocommerce/classic-shortcode', $checkout_page_id ); + return $checkout_page_id && ( has_block( 'woocommerce/classic-shortcode', $checkout_page_id ) || self::has_classic_shortcode( $checkout_page_id, 'woocommerce_checkout' ) ); } /** @@ -124,6 +124,25 @@ class CartCheckoutDetector { */ public static function has_classic_cart(): bool { $cart_page_id = wc_get_page_id( 'cart' ); - return $cart_page_id && has_block( 'woocommerce/classic-shortcode', $cart_page_id ); + return $cart_page_id && ( has_block( 'woocommerce/classic-shortcode', $cart_page_id ) || self::has_classic_shortcode( $cart_page_id, 'woocommerce_cart' ) ); + } + + /** + * Check if a page has a specific shortcode. + * + * @param int $page_id The ID of the page. + * @param string $shortcode The shortcode to check for. + * + * @return bool + */ + private static function has_classic_shortcode( int $page_id, string $shortcode ): bool { + if ( ! $page_id ) { + return false; + } + + $page = get_post( $page_id ); + $page_content = is_object($page) ? $page->post_content : ''; + + return str_contains( $page_content, $shortcode ); } } From 934da12d6070223f027b70af488ee27e822dfdad Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Thu, 16 May 2024 22:29:26 +0200 Subject: [PATCH 04/48] Fix PHPCS issues --- modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php b/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php index 253193758..e18fb703e 100644 --- a/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php +++ b/modules/ppcp-wc-gateway/src/Helper/CartCheckoutDetector.php @@ -141,7 +141,7 @@ class CartCheckoutDetector { } $page = get_post( $page_id ); - $page_content = is_object($page) ? $page->post_content : ''; + $page_content = is_object( $page ) ? $page->post_content : ''; return str_contains( $page_content, $shortcode ); } From c6a775298aa3dc6d9a645ac11261068a091fda21 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Thu, 16 May 2024 23:59:03 +0200 Subject: [PATCH 05/48] Fastlane notice location and color changes --- modules/ppcp-axo/services.php | 4 ++-- modules/ppcp-wc-gateway/resources/css/common.scss | 15 +++++++++++++-- .../Fields/paypal-smart-button-fields.php | 12 +----------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/modules/ppcp-axo/services.php b/modules/ppcp-axo/services.php index 088ecfacb..27ad74501 100644 --- a/modules/ppcp-axo/services.php +++ b/modules/ppcp-axo/services.php @@ -194,7 +194,7 @@ return array( return ''; } - return '

' . $notice_content . '

'; + return '

' . $notice_content . '

'; }, 'axo.smart-button-location-notice' => static function ( ContainerInterface $container ) : string { @@ -222,6 +222,6 @@ return array( return ''; } - return '

' . $notice_content . '

'; + return '

' . $notice_content . '

'; }, ); diff --git a/modules/ppcp-wc-gateway/resources/css/common.scss b/modules/ppcp-wc-gateway/resources/css/common.scss index d9f40345f..edc9b4689 100644 --- a/modules/ppcp-wc-gateway/resources/css/common.scss +++ b/modules/ppcp-wc-gateway/resources/css/common.scss @@ -68,15 +68,26 @@ $background-ident-color: #fbfbfb; margin-top: 4px; margin-bottom: 4px; } + + .highlight { + background: transparent; + font-weight: 600; + } } .ppcp-notice-warning { border-left-color: #dba617; .highlight { - background: transparent; color: #dba617; - font-weight: 600; + } +} + +.ppcp-notice-error { + border-left-color: #d63638; + + .highlight { + color: #d63638; } } diff --git a/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php b/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php index 9db7f2601..9e6038606 100644 --- a/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php +++ b/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php @@ -60,22 +60,12 @@ return function ( ContainerInterface $container, array $fields ): array { '' ), ), - 'smart_button_locations_notice' => array( - 'heading' => '', - 'html' => $container->get( 'axo.smart-button-location-notice' ), - 'type' => 'ppcp-html', - 'classes' => array(), - 'class' => array(), - 'screens' => array( State::STATE_START, State::STATE_ONBOARDED ), - 'requirements' => array(), - 'gateway' => 'paypal', - ), 'smart_button_locations' => array( 'title' => __( 'Smart Button Locations', 'woocommerce-paypal-payments' ), 'type' => 'ppcp-multiselect', 'input_class' => array( 'wc-enhanced-select' ), 'default' => $container->get( 'wcgateway.button.default-locations' ), - 'description' => __( 'Select where the PayPal smart buttons should be displayed.', 'woocommerce-paypal-payments' ), + 'description' => __( 'Select where the PayPal smart buttons should be displayed.', 'woocommerce-paypal-payments' ) . $container->get( 'axo.smart-button-location-notice' ), 'options' => $container->get( 'wcgateway.button.locations' ), 'screens' => array( State::STATE_START, State::STATE_ONBOARDED ), 'requirements' => array(), From 9a55140802d63ae8f3f287bf1f69f8ff28efa71a Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 20 May 2024 15:29:56 +0400 Subject: [PATCH 06/48] Allow shipping callback with subscriptions --- modules/ppcp-blocks/extensions.php | 11 +---------- modules/ppcp-button/services.php | 2 -- .../src/Endpoint/ApproveOrderEndpoint.php | 12 +----------- modules/ppcp-wc-gateway/services.php | 1 - .../src/Settings/SettingsListener.php | 19 ------------------- 5 files changed, 2 insertions(+), 43 deletions(-) diff --git a/modules/ppcp-blocks/extensions.php b/modules/ppcp-blocks/extensions.php index c2b607780..b32f5bbc6 100644 --- a/modules/ppcp-blocks/extensions.php +++ b/modules/ppcp-blocks/extensions.php @@ -51,16 +51,7 @@ return array( ); } - $subscription_helper = $container->get( 'wc-subscriptions.helper' ); - - if ( $subscription_helper->plugin_is_active() ) { - $label .= __( - '

Important: Cannot be deactivated while the WooCommerce Subscriptions plugin is active.

', - 'woocommerce-paypal-payments' - ); - } - - $should_disable_checkbox = $subscription_helper->plugin_is_active() || apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ); + $should_disable_checkbox = apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ); return $insert_after( $fields, diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index 3d14c9a74..7c564d1ef 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -239,7 +239,6 @@ return array( $final_review_enabled = $container->get( 'blocks.settings.final_review_enabled' ); $wc_order_creator = $container->get( 'button.helper.wc-order-creator' ); $gateway = $container->get( 'wcgateway.paypal-gateway' ); - $subscription_helper = $container->get( 'wc-subscriptions.helper' ); $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new ApproveOrderEndpoint( $request_data, @@ -252,7 +251,6 @@ return array( $final_review_enabled, $gateway, $wc_order_creator, - $subscription_helper, $logger ); }, diff --git a/modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php b/modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php index 9e3d43c6f..775be302e 100644 --- a/modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/ApproveOrderEndpoint.php @@ -105,13 +105,6 @@ class ApproveOrderEndpoint implements EndpointInterface { */ protected $wc_order_creator; - /** - * The Subscription Helper. - * - * @var SubscriptionHelper - */ - protected $subscription_helper; - /** * The logger. * @@ -132,7 +125,6 @@ class ApproveOrderEndpoint implements EndpointInterface { * @param bool $final_review_enabled Whether the final review is enabled. * @param PayPalGateway $gateway The WC gateway. * @param WooCommerceOrderCreator $wc_order_creator The WooCommerce order creator. - * @param SubscriptionHelper $subscription_helper The subscription helper. * @param LoggerInterface $logger The logger. */ public function __construct( @@ -146,7 +138,6 @@ class ApproveOrderEndpoint implements EndpointInterface { bool $final_review_enabled, PayPalGateway $gateway, WooCommerceOrderCreator $wc_order_creator, - SubscriptionHelper $subscription_helper, LoggerInterface $logger ) { @@ -160,7 +151,6 @@ class ApproveOrderEndpoint implements EndpointInterface { $this->final_review_enabled = $final_review_enabled; $this->gateway = $gateway; $this->wc_order_creator = $wc_order_creator; - $this->subscription_helper = $subscription_helper; $this->logger = $logger; } @@ -247,7 +237,7 @@ class ApproveOrderEndpoint implements EndpointInterface { $this->session_handler->replace_order( $order ); - if ( ! $this->subscription_helper->plugin_is_active() && apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ) ) { + if ( apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ) ) { $this->toggle_final_review_enabled_setting(); } diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 9ba0021b0..f2991d9ef 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -347,7 +347,6 @@ return array( $container->get( 'api.partner_merchant_id-production' ), $container->get( 'api.partner_merchant_id-sandbox' ), $container->get( 'api.endpoint.billing-agreements' ), - $container->get( 'wc-subscriptions.helper' ), $logger ); }, diff --git a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php index 6966f97c0..68c3572c2 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php +++ b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php @@ -10,8 +10,6 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway\Settings; use Psr\Log\LoggerInterface; -use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message; -use WooCommerce\PayPalCommerce\AdminNotices\Repository\Repository; use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer; use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint; @@ -23,9 +21,7 @@ use WooCommerce\PayPalCommerce\Onboarding\Helper\OnboardingUrl; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus; use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus; -use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar; -use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; use WooCommerce\WooCommerce\Logging\Logger\NullLogger; /** @@ -161,13 +157,6 @@ class SettingsListener { */ private $billing_agreements_endpoint; - /** - * The subscription helper - * - * @var SubscriptionHelper - */ - protected $subscription_helper; - /** * The logger. * @@ -193,7 +182,6 @@ class SettingsListener { * @param string $partner_merchant_id_production Partner merchant ID production. * @param string $partner_merchant_id_sandbox Partner merchant ID sandbox. * @param BillingAgreementsEndpoint $billing_agreements_endpoint Billing Agreements endpoint. - * @param SubscriptionHelper $subscription_helper The subscription helper. * @param ?LoggerInterface $logger The logger. */ public function __construct( @@ -212,7 +200,6 @@ class SettingsListener { string $partner_merchant_id_production, string $partner_merchant_id_sandbox, BillingAgreementsEndpoint $billing_agreements_endpoint, - SubscriptionHelper $subscription_helper, LoggerInterface $logger = null ) { @@ -231,7 +218,6 @@ class SettingsListener { $this->partner_merchant_id_production = $partner_merchant_id_production; $this->partner_merchant_id_sandbox = $partner_merchant_id_sandbox; $this->billing_agreements_endpoint = $billing_agreements_endpoint; - $this->subscription_helper = $subscription_helper; $this->logger = $logger ?: new NullLogger(); } @@ -403,11 +389,6 @@ class SettingsListener { $this->settings->persist(); } - if ( $this->subscription_helper->plugin_is_active() ) { - $this->settings->set( 'blocks_final_review_enabled', true ); - $this->settings->persist(); - } - if ( $subscription_mode === 'disable_paypal_subscriptions' && $vault_enabled === '1' ) { $this->settings->set( 'vault_enabled', false ); $this->settings->persist(); From 7a3579209564a6882e1400cc9d72f8e6fbfffeb4 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Mon, 20 May 2024 16:17:55 +0200 Subject: [PATCH 07/48] AXO: Fix the Has Profile/No CC scenario --- modules/ppcp-axo/resources/js/AxoManager.js | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index a250c09b7..d6ab6a888 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -24,7 +24,8 @@ class AxoManager { active: false, validEmail: false, hasProfile: false, - useEmailWidget: this.useEmailWidget() + useEmailWidget: this.useEmailWidget(), + hasCard: false, }; this.data = { @@ -257,11 +258,12 @@ class AxoManager { } if (scenario.axoProfileViews) { - this.el.billingAddressContainer.hide(); this.shippingView.activate(); - this.billingView.activate(); - this.cardView.activate(); + + if (this.status.hasCard) { + this.cardView.activate(); + } // Move watermark to after shipping. this.$(this.el.shippingAddressContainer.selector).after( @@ -584,12 +586,20 @@ class AxoManager { log(JSON.stringify(authResponse)); const shippingData = authResponse.profileData.shippingAddress; - if(shippingData) { + if (shippingData) { this.setShipping(shippingData); } + if (authResponse.profileData.card) { + this.setStatus('hasCard', true); + } else { + this.cardComponent = (await this.fastlane.FastlaneCardComponent( + this.cardComponentData() + )).render(this.el.paymentContainer.selector + '-form'); + } + const cardBillingAddress = authResponse.profileData?.card?.paymentSource?.card?.billingAddress; - if(cardBillingAddress) { + if (cardBillingAddress) { this.setCard(authResponse.profileData.card); const billingData = { From e566e376b98d85fc6aeafd3923c524484472ebd7 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Mon, 20 May 2024 17:03:35 +0200 Subject: [PATCH 08/48] AXO: Fix hiding/showing of the alternative payment gatways with Twenty Twenty-Four theme --- modules/ppcp-axo/resources/js/AxoManager.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index a250c09b7..5780f7ccd 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -156,6 +156,7 @@ class AxoManager { this.el.showGatewaySelectionLink.on('click', async () => { this.hideGatewaySelection = false; this.$('.wc_payment_methods label').show(); + this.$('.wc_payment_methods input').show(); this.cardView.refresh(); }); @@ -608,6 +609,7 @@ class AxoManager { this.hideGatewaySelection = true; this.$('.wc_payment_methods label').hide(); + this.$('.wc_payment_methods input').hide(); await this.renderWatermark(false); From 1de72ed0bfd4fc67e696de9990bf87d90611929b Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Tue, 21 May 2024 18:41:27 +0400 Subject: [PATCH 09/48] allow skipping confirmation page for subscriptions --- .../ActionHandler/CartActionHandler.js | 7 ++- modules/ppcp-button/services.php | 11 +++- .../Endpoint/ApproveSubscriptionEndpoint.php | 58 ++++++++++++++++--- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js index 2b3066395..e5c0dbac1 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js @@ -23,7 +23,8 @@ class CartActionHandler { body: JSON.stringify({ nonce: this.config.ajax.approve_subscription.nonce, order_id: data.orderID, - subscription_id: data.subscriptionID + subscription_id: data.subscriptionID, + should_create_wc_order: !context.config.vaultingEnabled || data.paymentSource !== 'venmo' }) }).then((res)=>{ return res.json(); @@ -33,7 +34,9 @@ class CartActionHandler { throw Error(data.data.message); } - location.href = this.config.redirect; + let orderReceivedUrl = data.data?.order_received_url + + location.href = orderReceivedUrl ? orderReceivedUrl : context.config.redirect; }); }, onError: (err) => { diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index 7c564d1ef..aa518f13f 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -258,7 +258,10 @@ return array( return new ApproveSubscriptionEndpoint( $container->get( 'button.request-data' ), $container->get( 'api.endpoint.order' ), - $container->get( 'session.handler' ) + $container->get( 'session.handler' ), + $container->get( 'blocks.settings.final_review_enabled' ), + $container->get( 'button.helper.wc-order-creator' ), + $container->get( 'wcgateway.paypal-gateway' ) ); }, 'button.checkout-form-saver' => static function ( ContainerInterface $container ): CheckoutFormSaver { @@ -360,6 +363,10 @@ return array( }, 'button.helper.wc-order-creator' => static function ( ContainerInterface $container ): WooCommerceOrderCreator { - return new WooCommerceOrderCreator( $container->get( 'wcgateway.funding-source.renderer' ), $container->get( 'session.handler' ) ); + return new WooCommerceOrderCreator( + $container->get( 'wcgateway.funding-source.renderer' ), + $container->get( 'session.handler' ), + $container->get( 'wc-subscriptions.helper' ) + ); }, ); diff --git a/modules/ppcp-button/src/Endpoint/ApproveSubscriptionEndpoint.php b/modules/ppcp-button/src/Endpoint/ApproveSubscriptionEndpoint.php index d2ca73b83..d89a0a1af 100644 --- a/modules/ppcp-button/src/Endpoint/ApproveSubscriptionEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/ApproveSubscriptionEndpoint.php @@ -11,13 +11,18 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException; +use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait; +use WooCommerce\PayPalCommerce\Button\Helper\WooCommerceOrderCreator; use WooCommerce\PayPalCommerce\Session\SessionHandler; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; /** * Class ApproveSubscriptionEndpoint */ class ApproveSubscriptionEndpoint implements EndpointInterface { + use ContextTrait; + const ENDPOINT = 'ppc-approve-subscription'; /** @@ -41,21 +46,51 @@ class ApproveSubscriptionEndpoint implements EndpointInterface { */ private $session_handler; + /** + * Whether the final review is enabled. + * + * @var bool + */ + protected $final_review_enabled; + + /** + * The WooCommerce order creator. + * + * @var WooCommerceOrderCreator + */ + protected $wc_order_creator; + + /** + * The WC gateway. + * + * @var PayPalGateway + */ + protected $gateway; + /** * ApproveSubscriptionEndpoint constructor. * - * @param RequestData $request_data The request data helper. - * @param OrderEndpoint $order_endpoint The order endpoint. - * @param SessionHandler $session_handler The session handler. + * @param RequestData $request_data The request data helper. + * @param OrderEndpoint $order_endpoint The order endpoint. + * @param SessionHandler $session_handler The session handler. + * @param bool $final_review_enabled Whether the final review is enabled. + * @param WooCommerceOrderCreator $wc_order_creator The WooCommerce order creator. + * @param PayPalGateway $gateway The WC gateway. */ public function __construct( RequestData $request_data, OrderEndpoint $order_endpoint, - SessionHandler $session_handler + SessionHandler $session_handler, + bool $final_review_enabled, + WooCommerceOrderCreator $wc_order_creator, + PayPalGateway $gateway ) { - $this->request_data = $request_data; - $this->order_endpoint = $order_endpoint; - $this->session_handler = $session_handler; + $this->request_data = $request_data; + $this->order_endpoint = $order_endpoint; + $this->session_handler = $session_handler; + $this->final_review_enabled = $final_review_enabled; + $this->wc_order_creator = $wc_order_creator; + $this->gateway = $gateway; } /** @@ -88,6 +123,15 @@ class ApproveSubscriptionEndpoint implements EndpointInterface { WC()->session->set( 'ppcp_subscription_id', $data['subscription_id'] ); } + $should_create_wc_order = $data['should_create_wc_order'] ?? false; + if ( ! $this->final_review_enabled && ! $this->is_checkout() && $should_create_wc_order ) { + $wc_order = $this->wc_order_creator->create_from_paypal_order( $order, WC()->cart ); + $this->gateway->process_payment( $wc_order->get_id() ); + $order_received_url = $wc_order->get_checkout_order_received_url(); + + wp_send_json_success( array( 'order_received_url' => $order_received_url ) ); + } + wp_send_json_success(); return true; } From feab77ed03b25a5d6cf21d937b7f83789f628064 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Tue, 21 May 2024 18:42:03 +0400 Subject: [PATCH 10/48] Create subscription order --- .../src/Helper/WooCommerceOrderCreator.php | 101 ++++++++++++++++-- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php b/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php index 92f07c0fd..6f26626e3 100644 --- a/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php +++ b/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php @@ -14,12 +14,14 @@ use WC_Cart; use WC_Order; use WC_Order_Item_Product; use WC_Order_Item_Shipping; +use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer; use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; +use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; /** * Class WooCommerceOrderCreator @@ -40,18 +42,28 @@ class WooCommerceOrderCreator { */ protected $session_handler; + /** + * The subscription helper + * + * @var SubscriptionHelper + */ + protected $subscription_helper; + /** * WooCommerceOrderCreator constructor. * * @param FundingSourceRenderer $funding_source_renderer The funding source renderer. * @param SessionHandler $session_handler The session handler. + * @param SubscriptionHelper $subscription_helper The subscription helper. */ public function __construct( FundingSourceRenderer $funding_source_renderer, - SessionHandler $session_handler + SessionHandler $session_handler, + SubscriptionHelper $subscription_helper ) { $this->funding_source_renderer = $funding_source_renderer; $this->session_handler = $session_handler; + $this->subscription_helper = $subscription_helper; } /** @@ -69,10 +81,13 @@ class WooCommerceOrderCreator { throw new RuntimeException( 'Problem creating WC order.' ); } - $this->configure_line_items( $wc_order, $wc_cart ); - $this->configure_shipping( $wc_order, $order->payer(), $order->purchase_units()[0]->shipping() ); + $payer = $order->payer(); + $shipping = $order->purchase_units()[0]->shipping(); + $this->configure_payment_source( $wc_order ); $this->configure_customer( $wc_order ); + $this->configure_line_items( $wc_order, $wc_cart, $payer, $shipping ); + $this->configure_shipping( $wc_order, $payer, $shipping ); $this->configure_coupons( $wc_order, $wc_cart->get_applied_coupons() ); $wc_order->calculate_totals(); @@ -84,11 +99,13 @@ class WooCommerceOrderCreator { /** * Configures the line items. * - * @param WC_Order $wc_order The WC order. - * @param WC_Cart $wc_cart The Cart. + * @param WC_Order $wc_order The WC order. + * @param WC_Cart $wc_cart The Cart. + * @param Payer|null $payer The payer. + * @param Shipping|null $shipping The shipping. * @return void */ - protected function configure_line_items( WC_Order $wc_order, WC_Cart $wc_cart ): void { + protected function configure_line_items( WC_Order $wc_order, WC_Cart $wc_cart, ?Payer $payer, ?Shipping $shipping ): void { $cart_contents = $wc_cart->get_cart(); foreach ( $cart_contents as $cart_item ) { @@ -111,9 +128,37 @@ class WooCommerceOrderCreator { return; } + $total = $product->get_price() * $quantity; + $item->set_name( $product->get_name() ); - $item->set_subtotal( $product->get_price() * $quantity ); - $item->set_total( $product->get_price() * $quantity ); + $item->set_subtotal( $total ); + $item->set_total( $total ); + + $product_id = $product->get_id(); + + if ( $this->is_subscription( $product_id ) ) { + $subscription = $this->create_subscription( $wc_order, $product_id ); + $sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee( $product ); + $subscription_total = $total + $sign_up_fee; + + $item->set_subtotal( $subscription_total ); + $item->set_total( $subscription_total ); + + $subscription->add_product( $product ); + $this->configure_shipping( $subscription, $payer, $shipping ); + $this->configure_payment_source( $subscription ); + $this->configure_coupons( $subscription, $wc_cart->get_applied_coupons() ); + + $dates = array( + 'trial_end' => WC_Subscriptions_Product::get_trial_expiration_date( $product_id ), + 'next_payment' => WC_Subscriptions_Product::get_first_renewal_payment_date( $product_id ), + 'end' => WC_Subscriptions_Product::get_expiration_date( $product_id ), + ); + + $subscription->update_dates( $dates ); + $subscription->calculate_totals(); + $subscription->payment_complete_for_order( $wc_order ); + } $wc_order->add_item( $item ); } @@ -179,6 +224,14 @@ class WooCommerceOrderCreator { $shipping->set_method_id( $shipping_options->id() ); $shipping->set_total( $shipping_options->amount()->value_str() ); + $items = $wc_order->get_items(); + $items_in_package = array(); + foreach ( $items as $item ) { + $items_in_package[] = $item->get_name() . ' × ' . $item->get_quantity(); + } + + $shipping->add_meta_data( __( 'Items', 'woocommerce-paypal-payments' ), implode( ', ', $items_in_package ) ); + $wc_order->add_item( $shipping ); } } @@ -225,4 +278,36 @@ class WooCommerceOrderCreator { } } + /** + * Checks if the product with given ID is WC subscription. + * + * @param int $product_id The product ID. + * @return bool true if the product is subscription, otherwise false. + */ + protected function is_subscription( int $product_id ): bool { + if ( ! $this->subscription_helper->plugin_is_active() ) { + return false; + } + + return WC_Subscriptions_Product::is_subscription( $product_id ); + } + + /** + * Creates WC subscription from given order and product ID. + * + * @param WC_Order $wc_order The WC order. + * @param int $product_id The product ID. + * @return WC_Order The subscription order + */ + protected function create_subscription( WC_Order $wc_order, int $product_id ): WC_Order { + return wcs_create_subscription( + array( + 'order_id' => $wc_order->get_id(), + 'status' => 'pending', + 'billing_period' => WC_Subscriptions_Product::get_period( $product_id ), + 'billing_interval' => WC_Subscriptions_Product::get_interval( $product_id ), + 'customer_id' => $wc_order->get_customer_id(), + ) + ); + } } From 6e575acd2210503dcfa24b677c35697e2860e446 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Wed, 22 May 2024 00:03:43 +0200 Subject: [PATCH 11/48] Fix AXO psalm errors --- modules/ppcp-axo/src/Assets/AxoManager.php | 2 +- modules/ppcp-blocks/extensions.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php index 2ed5fc04c..d9b4313fc 100644 --- a/modules/ppcp-axo/src/Assets/AxoManager.php +++ b/modules/ppcp-axo/src/Assets/AxoManager.php @@ -197,7 +197,7 @@ class AxoManager { 'CA' => WC()->countries->get_states( 'CA' ), ), ), - 'module_url' => untrailingslashit( $this->module_url ), + 'module_url' => untrailingslashit( $this->module_url ), ); } diff --git a/modules/ppcp-blocks/extensions.php b/modules/ppcp-blocks/extensions.php index c2b607780..2409d1bbc 100644 --- a/modules/ppcp-blocks/extensions.php +++ b/modules/ppcp-blocks/extensions.php @@ -54,10 +54,11 @@ return array( $subscription_helper = $container->get( 'wc-subscriptions.helper' ); if ( $subscription_helper->plugin_is_active() ) { - $label .= __( - '

Important: Cannot be deactivated while the WooCommerce Subscriptions plugin is active.

', + $notice_content = __( + 'Important: Cannot be deactivated while the WooCommerce Subscriptions plugin is active.', 'woocommerce-paypal-payments' ); + $label .= '

' . $notice_content . '

'; } $should_disable_checkbox = $subscription_helper->plugin_is_active() || apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ); From 8ee4a524bb29ad33479df3d960c0027e94c36762 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Thu, 23 May 2024 01:30:20 +0200 Subject: [PATCH 12/48] First attempt to optimize the checkout loading of the Fastlane experience to make it nice and smooth --- modules/ppcp-axo/resources/css/styles.scss | 35 +++++++++++++++ modules/ppcp-axo/resources/js/AxoManager.js | 26 ++++++++++- .../js/Components/DomElementCollection.js | 2 +- modules/ppcp-axo/src/Assets/AxoManager.php | 2 +- modules/ppcp-axo/src/AxoModule.php | 44 +++++++++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-axo/resources/css/styles.scss b/modules/ppcp-axo/resources/css/styles.scss index 605ac18b2..9edd122fa 100644 --- a/modules/ppcp-axo/resources/css/styles.scss +++ b/modules/ppcp-axo/resources/css/styles.scss @@ -1,6 +1,15 @@ .ppcp-axo-watermark-container { max-width: 200px; margin-top: 10px; + position: relative; + + &.loader:before { + height: 12px; + width: 12px; + margin-left: -6px; + margin-top: -6px; + left: 12px; + } } .ppcp-axo-payment-container { @@ -28,6 +37,7 @@ .ppcp-axo-customer-details { margin-bottom: 40px; + position: relative; } .axo-checkout-header-section { @@ -44,6 +54,31 @@ padding: 0.6em 1em; } +.ppcp-axo-watermark-loading { + min-height: 12px; +} + +.ppcp-axo-overlay, +.ppcp-axo-watermark-loading:after { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(255, 255, 255, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 999; + content: ''; +} + +.ppcp-axo-loading .col-1 { + position: relative; + opacity: 0.9; + transition: opacity 0.5s ease; +} + #payment .payment_methods li label[for="payment_method_ppcp-axo-gateway"] { img { float: none; diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index a250c09b7..aa94427a8 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -231,6 +231,7 @@ class AxoManager { if (scenario.defaultFormFields) { this.el.customerDetails.show(); + this.toggleLoaderAndOverlay(this.el.customerDetails, 'loader', 'ppcp-axo-overlay'); } else { this.el.customerDetails.hide(); } @@ -248,7 +249,6 @@ class AxoManager { this.$(this.el.fieldBillingEmail.selector).append( this.$(this.el.watermarkContainer.selector) ); - } else { this.el.emailWidgetContainer.hide(); if (!scenario.defaultEmailField) { @@ -496,6 +496,8 @@ class AxoManager { (await this.fastlane.FastlaneWatermarkComponent({ includeAdditionalInfo })).render(this.el.watermarkContainer.selector); + + this.toggleWatermarkLoading(this.el.watermarkContainer, 'ppcp-axo-watermark-loading', 'loader'); } watchEmail() { @@ -840,6 +842,28 @@ class AxoManager { data.billing_phone = phone; } } + + toggleLoaderAndOverlay(element, loaderClass, overlayClass) { + const loader = document.querySelector(`${element.selector} .${loaderClass}`); + const overlay = document.querySelector(`${element.selector} .${overlayClass}`); + if (loader) { + loader.classList.toggle(loaderClass); + } + if (overlay) { + overlay.classList.toggle(overlayClass); + } + } + + toggleWatermarkLoading(container, loadingClass, loaderClass) { + const watermarkLoading = document.querySelector(`${container.selector}.${loadingClass}`); + const watermarkLoader = document.querySelector(`${container.selector}.${loaderClass}`); + if (watermarkLoading) { + watermarkLoading.classList.toggle(loadingClass); + } + if (watermarkLoader) { + watermarkLoader.classList.toggle(loaderClass); + } + } } export default AxoManager; diff --git a/modules/ppcp-axo/resources/js/Components/DomElementCollection.js b/modules/ppcp-axo/resources/js/Components/DomElementCollection.js index fc44a2823..35f19ec6d 100644 --- a/modules/ppcp-axo/resources/js/Components/DomElementCollection.js +++ b/modules/ppcp-axo/resources/js/Components/DomElementCollection.js @@ -20,7 +20,7 @@ class DomElementCollection { this.watermarkContainer = new DomElement({ id: 'ppcp-axo-watermark-container', selector: '#ppcp-axo-watermark-container', - className: 'ppcp-axo-watermark-container' + className: 'ppcp-axo-watermark-container ppcp-axo-watermark-loading loader' }); this.customerDetails = new DomElement({ diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php index 2ed5fc04c..d9b4313fc 100644 --- a/modules/ppcp-axo/src/Assets/AxoManager.php +++ b/modules/ppcp-axo/src/Assets/AxoManager.php @@ -197,7 +197,7 @@ class AxoManager { 'CA' => WC()->countries->get_states( 'CA' ), ), ), - 'module_url' => untrailingslashit( $this->module_url ), + 'module_url' => untrailingslashit( $this->module_url ), ); } diff --git a/modules/ppcp-axo/src/AxoModule.php b/modules/ppcp-axo/src/AxoModule.php index dfb76ef60..cdea50ee2 100644 --- a/modules/ppcp-axo/src/AxoModule.php +++ b/modules/ppcp-axo/src/AxoModule.php @@ -217,6 +217,8 @@ class AxoModule implements ModuleInterface { 1 ); + // Add the markup necessary for displaying overlays and loaders for Axo on the checkout page. + $this->add_checkout_loader_markup( $c ); } /** @@ -292,4 +294,46 @@ class AxoModule implements ModuleInterface { && CartCheckoutDetector::has_classic_checkout() && $is_axo_enabled; } + + /** + * Adds the markup necessary for displaying overlays and loaders for Axo on the checkout page. + * + * @param ContainerInterface $c The container. + */ + private function add_checkout_loader_markup( $c ) { + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + if ( $this->should_render_fastlane( $settings ) ) { + add_action( + 'woocommerce_checkout_before_customer_details', + function () { + echo '
'; + } + ); + + add_action( + 'woocommerce_checkout_after_customer_details', + function () { + echo '
'; + } + ); + + add_action( + 'woocommerce_checkout_billing', + function () { + echo '
'; + }, + 8 + ); + + add_action( + 'woocommerce_checkout_billing', + function () { + echo '
'; + }, + 12 + ); + } + } } From 97cd436efe36cc5651e9d65c9f898fe869ea239e Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Thu, 23 May 2024 10:51:27 +0200 Subject: [PATCH 13/48] Change opacity of the overlay color --- modules/ppcp-axo/resources/css/styles.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-axo/resources/css/styles.scss b/modules/ppcp-axo/resources/css/styles.scss index 9edd122fa..3513d0642 100644 --- a/modules/ppcp-axo/resources/css/styles.scss +++ b/modules/ppcp-axo/resources/css/styles.scss @@ -65,7 +65,7 @@ left: 0; width: 100%; height: 100%; - background: rgba(255, 255, 255, 0.8); + background: rgba(255, 255, 255, 0.5); display: flex; justify-content: center; align-items: center; From 451361dca03d1a75f783268f79cf593dd14394bc Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Thu, 23 May 2024 11:18:35 +0200 Subject: [PATCH 14/48] Fix Psalm errors --- modules/ppcp-axo/src/AxoModule.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-axo/src/AxoModule.php b/modules/ppcp-axo/src/AxoModule.php index cdea50ee2..ba8d1d78b 100644 --- a/modules/ppcp-axo/src/AxoModule.php +++ b/modules/ppcp-axo/src/AxoModule.php @@ -299,8 +299,9 @@ class AxoModule implements ModuleInterface { * Adds the markup necessary for displaying overlays and loaders for Axo on the checkout page. * * @param ContainerInterface $c The container. + * @return void */ - private function add_checkout_loader_markup( $c ) { + private function add_checkout_loader_markup( ContainerInterface $c ): void { $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); From c011ce659f721edb57dad880d56bc16a8bdda013 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Thu, 23 May 2024 19:29:33 +0400 Subject: [PATCH 15/48] Fix more than 1 shipping option selected problem --- .../ppcp-api-client/src/Factory/ShippingOptionFactory.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-api-client/src/Factory/ShippingOptionFactory.php b/modules/ppcp-api-client/src/Factory/ShippingOptionFactory.php index 08af8c79e..3c21d4161 100644 --- a/modules/ppcp-api-client/src/Factory/ShippingOptionFactory.php +++ b/modules/ppcp-api-client/src/Factory/ShippingOptionFactory.php @@ -50,9 +50,7 @@ class ShippingOptionFactory { $cart->calculate_shipping(); $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods', array() ); - if ( ! is_array( $chosen_shipping_methods ) ) { - $chosen_shipping_methods = array(); - } + $chosen_shipping_method = $chosen_shipping_methods[0] ?? false; $packages = WC()->shipping()->get_packages(); $options = array(); @@ -62,11 +60,10 @@ class ShippingOptionFactory { if ( ! $rate instanceof \WC_Shipping_Rate ) { continue; } - $options[] = new ShippingOption( $rate->get_id(), $rate->get_label(), - in_array( $rate->get_id(), $chosen_shipping_methods, true ), + $rate->get_id() === $chosen_shipping_method, new Money( (float) $rate->get_cost(), get_woocommerce_currency() From da3fb6d8d64420f16a98407b3b06b82694971e6b Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Fri, 24 May 2024 09:38:40 +0200 Subject: [PATCH 16/48] Fix the two AXO bugs: Billing details missing and select another payment gateway missing --- modules/ppcp-axo/resources/js/AxoManager.js | 3 ++- modules/ppcp-axo/resources/js/Views/CardView.js | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index d3dd2fee7..79c2ac5a2 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -261,9 +261,10 @@ class AxoManager { if (scenario.axoProfileViews) { this.shippingView.activate(); + this.cardView.activate(); if (this.status.hasCard) { - this.cardView.activate(); + this.billingView.activate(); } // Move watermark to after shipping. diff --git a/modules/ppcp-axo/resources/js/Views/CardView.js b/modules/ppcp-axo/resources/js/Views/CardView.js index a72a38ff3..82c15079c 100644 --- a/modules/ppcp-axo/resources/js/Views/CardView.js +++ b/modules/ppcp-axo/resources/js/Views/CardView.js @@ -20,10 +20,6 @@ class CardView { if (data.isEmpty()) { return `
-
-
Please fill in your card details.
-
-

Add card details

${selectOtherPaymentMethod()}
`; From be9de3517580e8ed3d45339b516c5a0ac78127ca Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Fri, 24 May 2024 11:38:48 +0200 Subject: [PATCH 17/48] Rename `name` to `cardholderName` --- modules/ppcp-axo/resources/js/AxoManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index d3dd2fee7..a6672d83e 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -728,7 +728,7 @@ class AxoManager { tokenizeData() { return { - name: { + cardholderName: { fullName: this.billingView.fullName() }, billingAddress: { From bd745cb7d4047266426196e25326e6d1175de73b Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Fri, 24 May 2024 18:49:10 +0400 Subject: [PATCH 18/48] Do not update shipping when subscription --- .../js/modules/Helper/ShippingHandler.js | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js b/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js index 49f45ab2d..311b8a949 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js +++ b/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js @@ -39,19 +39,21 @@ export const handleShippingOptionsChange = async (data, actions, config) => { }) } - const res = await fetch(config.ajax.update_shipping.endpoint, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - nonce: config.ajax.update_shipping.nonce, - order_id: data.orderID, - }) - }); + if (!config.data_client_id.has_subscriptions) { + const res = await fetch(config.ajax.update_shipping.endpoint, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + nonce: config.ajax.update_shipping.nonce, + order_id: data.orderID, + }) + }); - const json = await res.json(); + const json = await res.json(); - if (!json.success) { - throw new Error(json.data.message); + if (!json.success) { + throw new Error(json.data.message); + } } } catch (e) { console.error(e); @@ -104,19 +106,21 @@ export const handleShippingAddressChange = async (data, actions, config) => { }) }) - const res = await fetch(config.ajax.update_shipping.endpoint, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - nonce: config.ajax.update_shipping.nonce, - order_id: data.orderID, - }) - }); + if (!config.data_client_id.has_subscriptions) { + const res = await fetch(config.ajax.update_shipping.endpoint, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + nonce: config.ajax.update_shipping.nonce, + order_id: data.orderID, + }) + }); - const json = await res.json(); + const json = await res.json(); - if (!json.success) { - throw new Error(json.data.message); + if (!json.success) { + throw new Error(json.data.message); + } } } catch (e) { console.error(e); From 11244fa055cdd8402f535e0800e5552ea2344429 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Fri, 24 May 2024 18:54:44 +0400 Subject: [PATCH 19/48] Fix the tests --- tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php b/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php index 92d3f50d1..c34146f3e 100644 --- a/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php +++ b/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php @@ -60,7 +60,6 @@ class SettingsListenerTest extends ModularTestCase '', '', $billing_agreement_endpoint, - $subscription_helper, $logger ); From ac42b18592e1c94f9995ffeab30a46da8e6f9400 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Fri, 24 May 2024 19:08:44 +0400 Subject: [PATCH 20/48] Fix the Psalm errors --- .../src/Helper/WooCommerceOrderCreator.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php b/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php index 6f26626e3..313fb5e62 100644 --- a/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php +++ b/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php @@ -14,6 +14,7 @@ use WC_Cart; use WC_Order; use WC_Order_Item_Product; use WC_Order_Item_Shipping; +use WC_Subscription; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer; @@ -22,6 +23,7 @@ use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; +use WP_Error; /** * Class WooCommerceOrderCreator @@ -227,7 +229,7 @@ class WooCommerceOrderCreator { $items = $wc_order->get_items(); $items_in_package = array(); foreach ( $items as $item ) { - $items_in_package[] = $item->get_name() . ' × ' . $item->get_quantity(); + $items_in_package[] = $item->get_name() . ' × ' . (string) $item->get_quantity(); } $shipping->add_meta_data( __( 'Items', 'woocommerce-paypal-payments' ), implode( ', ', $items_in_package ) ); @@ -297,10 +299,11 @@ class WooCommerceOrderCreator { * * @param WC_Order $wc_order The WC order. * @param int $product_id The product ID. - * @return WC_Order The subscription order + * @return WC_Subscription The subscription order + * @throws RuntimeException If problem creating. */ - protected function create_subscription( WC_Order $wc_order, int $product_id ): WC_Order { - return wcs_create_subscription( + protected function create_subscription( WC_Order $wc_order, int $product_id ): WC_Subscription { + $subscription = wcs_create_subscription( array( 'order_id' => $wc_order->get_id(), 'status' => 'pending', @@ -309,5 +312,11 @@ class WooCommerceOrderCreator { 'customer_id' => $wc_order->get_customer_id(), ) ); + + if ( $subscription instanceof WP_Error ) { + throw new RuntimeException( $subscription->get_error_message() ); + } + + return $subscription; } } From f6d07d9225085d12304870bc3e34e83619179d87 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Fri, 24 May 2024 17:13:43 +0200 Subject: [PATCH 21/48] Adding frontend logger (WIP) --- modules/ppcp-axo/resources/js/AxoManager.js | 17 +++++ modules/ppcp-axo/services.php | 6 ++ modules/ppcp-axo/src/Assets/AxoManager.php | 7 +++ modules/ppcp-axo/src/AxoModule.php | 10 +++ .../ppcp-axo/src/FrontendLoggerEndpoint.php | 63 +++++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 modules/ppcp-axo/src/FrontendLoggerEndpoint.php diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index a6672d83e..11605dbd6 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -88,6 +88,20 @@ class AxoManager { this.triggerGatewayChange(); } + async log(message, level = 'info') { + await fetch(axoConfig.ajax.frontend_logger.endpoint, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + nonce: axoConfig.ajax.frontend_logger.nonce, + log: { + message, + level, + } + }) + }); + } + registerEventHandlers() { this.$(document).on('change', 'input[name=payment_method]', (ev) => { @@ -697,6 +711,8 @@ class AxoManager { this.ensureBillingPhoneNumber(data); + this.log(`Ryan flow - submitted nonce: ${this.data.card.id}` ) + this.submit(this.data.card.id, data); } else { // Gary flow @@ -706,6 +722,7 @@ class AxoManager { this.cardComponent.getPaymentToken( this.tokenizeData() ).then((response) => { + this.log(`Gary flow - submitted nonce: ${response.id}` ) this.submit(response.id); }); } catch (e) { diff --git a/modules/ppcp-axo/services.php b/modules/ppcp-axo/services.php index ffed3f1e2..8af3df17d 100644 --- a/modules/ppcp-axo/services.php +++ b/modules/ppcp-axo/services.php @@ -225,4 +225,10 @@ return array( return '

' . $notice_content . '

'; }, + 'axo.endpoint.frontend-logger' => static function (ContainerInterface $container): FrontendLoggerEndpoint { + return new FrontendLoggerEndpoint( + $container->get( 'button.request-data' ), + $container->get( 'woocommerce.logger.woocommerce' ) + ); + }, ); diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php index 24b574975..4e75f56fa 100644 --- a/modules/ppcp-axo/src/Assets/AxoManager.php +++ b/modules/ppcp-axo/src/Assets/AxoManager.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Axo\Assets; use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\Axo\FrontendLoggerEndpoint; use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus; @@ -209,6 +210,12 @@ class AxoManager { ), 'icons_directory' => esc_url( $this->wcgateway_module_url ) . 'assets/images/axo/', 'module_url' => untrailingslashit( $this->module_url ), + 'ajax' => array( + 'frontend_logger' => array( + 'endpoint' => \WC_AJAX::get_endpoint( FrontendLoggerEndpoint::ENDPOINT ), + 'nonce' => wp_create_nonce( FrontendLoggerEndpoint::nonce() ), + ), + ), ); } diff --git a/modules/ppcp-axo/src/AxoModule.php b/modules/ppcp-axo/src/AxoModule.php index 3770117c6..7a10c34ad 100644 --- a/modules/ppcp-axo/src/AxoModule.php +++ b/modules/ppcp-axo/src/AxoModule.php @@ -239,6 +239,16 @@ class AxoModule implements ModuleInterface { 1 ); + add_action( + 'wc_ajax_' . FrontendLoggerEndpoint::ENDPOINT, + static function () use ( $c ) { + $endpoint = $c->get( 'axo.endpoint.frontend-logger' ); + assert( $endpoint instanceof FrontendLoggerEndpoint ); + + $endpoint->handle_request(); + } + ); + // Add the markup necessary for displaying overlays and loaders for Axo on the checkout page. $this->add_checkout_loader_markup( $c ); } diff --git a/modules/ppcp-axo/src/FrontendLoggerEndpoint.php b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php new file mode 100644 index 000000000..34f8096f3 --- /dev/null +++ b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php @@ -0,0 +1,63 @@ +request_data = $request_data; + $this->logger = $logger; + } + + /** + * 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 { + $data = $this->request_data->read_request( $this->nonce() ); + + $this->logger->info("[AXO] " . $data['log']['message']); + + wp_send_json_success(); + return true; + } +} From ff3091b3a6b6106c4559594b557e53faaafc15b8 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Fri, 24 May 2024 17:20:44 +0200 Subject: [PATCH 22/48] Use uuid for `data-client-metadata-id` --- .../ppcp-button/resources/js/modules/Helper/ScriptLoading.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js b/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js index dce3136c8..6fbd419cb 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js +++ b/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js @@ -63,9 +63,10 @@ export const loadPaypalScript = (config, onLoaded, onError = null) => { // Axo SDK options const sdkClientToken = config?.axo?.sdk_client_token; + const uuid = self.crypto.randomUUID(); if(sdkClientToken) { scriptOptions['data-sdk-client-token'] = sdkClientToken; - scriptOptions['data-client-metadata-id'] = 'ppcp-cm-id'; + scriptOptions['data-client-metadata-id'] = uuid; } // Load PayPal script for special case with data-client-token From a3c610bc1c56899da3888511bd8ff048674eacf7 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Mon, 27 May 2024 11:33:34 +0200 Subject: [PATCH 23/48] Replace crypto.randomUUID with a dependency (3165) --- .../ppcp-button/resources/js/modules/Helper/ScriptLoading.js | 3 ++- package.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js b/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js index 6fbd419cb..55866fe9d 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js +++ b/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js @@ -4,6 +4,7 @@ import widgetBuilder from "../Renderer/WidgetBuilder"; import merge from "deepmerge"; import {keysToCamelCase} from "./Utils"; import {getCurrentPaymentMethod} from "./CheckoutMethodState"; +import { v4 as uuidv4 } from 'uuid'; // This component may be used by multiple modules. This assures that options are shared between all instances. let options = window.ppcpWidgetBuilder = window.ppcpWidgetBuilder || { @@ -63,7 +64,7 @@ export const loadPaypalScript = (config, onLoaded, onError = null) => { // Axo SDK options const sdkClientToken = config?.axo?.sdk_client_token; - const uuid = self.crypto.randomUUID(); + const uuid = uuidv4().replace(/-/g, ''); if(sdkClientToken) { scriptOptions['data-sdk-client-token'] = sdkClientToken; scriptOptions['data-client-metadata-id'] = uuid; diff --git a/package.json b/package.json index bf52a8677..1e060a0ce 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "dotenv": "^16.0.3", "npm-run-all": "^4.1.5", "playwright": "^1.43.0", - "run-s": "^0.0.0" + "run-s": "^0.0.0", + "uuid": "^9.0.1" } } From cb190796ed25057b9116d98a4407dd037dbbd065 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 27 May 2024 12:21:38 +0200 Subject: [PATCH 24/48] Add error logs --- modules/ppcp-axo/resources/js/AxoManager.js | 42 ++++++++++++------- .../ppcp-axo/src/FrontendLoggerEndpoint.php | 23 ++++++++-- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index 11605dbd6..6659fbb2c 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -88,20 +88,6 @@ class AxoManager { this.triggerGatewayChange(); } - async log(message, level = 'info') { - await fetch(axoConfig.ajax.frontend_logger.endpoint, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - nonce: axoConfig.ajax.frontend_logger.nonce, - log: { - message, - level, - } - }) - }); - } - registerEventHandlers() { this.$(document).on('change', 'input[name=payment_method]', (ev) => { @@ -590,6 +576,8 @@ class AxoManager { async lookupCustomerByEmail() { const lookupResponse = await this.fastlane.identity.lookupCustomerByEmail(this.emailInput.value); + await this.log(`lookupCustomerByEmail: ${JSON.stringify(lookupResponse)}`); + if (lookupResponse.customerContextId) { // Email is associated with a Connect profile or a PayPal member. // Authenticate the customer to get access to their profile. @@ -598,6 +586,7 @@ class AxoManager { const authResponse = await this.fastlane.identity.triggerAuthenticationFlow(lookupResponse.customerContextId); log('AuthResponse', authResponse); + await this.log(`triggerAuthenticationFlow: ${JSON.stringify(authResponse)}`); if (authResponse.authenticationState === 'succeeded') { log(JSON.stringify(authResponse)); @@ -728,6 +717,7 @@ class AxoManager { } catch (e) { log('Error tokenizing.'); alert('Error tokenizing data.'); + this.log(`Error tokenizing data. ${e.message}`, 'error'); } } } @@ -807,7 +797,10 @@ class AxoManager { scrollTop: $notices.offset().top }, 500); } + console.error('Failure:', responseData); + this.log(`Error sending checkout form. ${responseData}`, 'error'); + this.hideLoading(); return; } @@ -817,6 +810,8 @@ class AxoManager { }) .catch(error => { console.error('Error:', error); + this.log(`Error sending checkout form. ${error.message}`, 'error'); + this.hideLoading(); }); @@ -893,6 +888,25 @@ class AxoManager { watermarkLoader.classList.toggle(loaderClass); } } + + async log(message, level = 'info') { + const endpoint = this.axoConfig?.ajax?.frontend_logger?.endpoint; + if(!endpoint) { + return; + } + + await fetch(endpoint, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + nonce: this.axoConfig.ajax.frontend_logger.nonce, + log: { + message, + level, + } + }) + }); + } } export default AxoManager; diff --git a/modules/ppcp-axo/src/FrontendLoggerEndpoint.php b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php index 34f8096f3..ad7f01375 100644 --- a/modules/ppcp-axo/src/FrontendLoggerEndpoint.php +++ b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php @@ -14,6 +14,9 @@ use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface; use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData; +/** + * Class FrontendLoggerEndpoint + */ class FrontendLoggerEndpoint implements EndpointInterface { const ENDPOINT = 'ppc-frontend-logger'; @@ -32,9 +35,15 @@ class FrontendLoggerEndpoint implements EndpointInterface { */ private $logger; - public function __construct(RequestData $request_data, LoggerInterface $logger){ + /** + * FrontendLoggerEndpoint constructor. + * + * @param RequestData $request_data The request data helper. + * @param LoggerInterface $logger The logger. + */ + public function __construct( RequestData $request_data, LoggerInterface $logger ) { $this->request_data = $request_data; - $this->logger = $logger; + $this->logger = $logger; } /** @@ -54,8 +63,16 @@ class FrontendLoggerEndpoint implements EndpointInterface { */ public function handle_request(): bool { $data = $this->request_data->read_request( $this->nonce() ); + $level = $data['log']['level'] ?? 'info'; - $this->logger->info("[AXO] " . $data['log']['message']); + switch ( $level ) { + case 'error': + $this->logger->error( '[AXO] ' . esc_html( $data['log']['message'] ) ); + break; + default: + $this->logger->info( '[AXO] ' . esc_html( $data['log']['message'] ) ); + break; + } wp_send_json_success(); return true; From 5b8d9b352081cf642bf4172d50742a82ac0465fc Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Mon, 27 May 2024 12:27:59 +0200 Subject: [PATCH 25/48] AXO: Remove Billing Details from the Ryan flow (3173) --- .../ppcp-axo/resources/js/Views/BillingView.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/modules/ppcp-axo/resources/js/Views/BillingView.js b/modules/ppcp-axo/resources/js/Views/BillingView.js index aba44afcf..24f8a3682 100644 --- a/modules/ppcp-axo/resources/js/Views/BillingView.js +++ b/modules/ppcp-axo/resources/js/Views/BillingView.js @@ -34,22 +34,7 @@ class BillingView { `; } - return ` -
-
-

Billing

- Edit -
-
${data.value('email')}
-
${data.value('company')}
-
${data.value('firstName')} ${data.value('lastName')}
-
${data.value('street1')}
-
${data.value('street2')}
-
${data.value('postCode')} ${data.value('city')}
-
${valueOfSelect('#billing_state', data.value('stateCode'))}
-
${valueOfSelect('#billing_country', data.value('countryCode'))}
-
- `; + return ``; }, fields: { email: { From 65a74d12a5a7c5157976ce9298bf942870bc08ae Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Mon, 27 May 2024 12:40:17 +0200 Subject: [PATCH 26/48] Replace backticks with single quotes --- modules/ppcp-axo/resources/js/Views/BillingView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-axo/resources/js/Views/BillingView.js b/modules/ppcp-axo/resources/js/Views/BillingView.js index 24f8a3682..f2903d4ef 100644 --- a/modules/ppcp-axo/resources/js/Views/BillingView.js +++ b/modules/ppcp-axo/resources/js/Views/BillingView.js @@ -34,7 +34,7 @@ class BillingView { `; } - return ``; + return ''; }, fields: { email: { From 90397b5dbd783fc108a16c20d1bc8dba15afff1b Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 27 May 2024 13:04:14 +0200 Subject: [PATCH 27/48] Fix phpcs --- modules/ppcp-axo/services.php | 2 +- modules/ppcp-axo/src/FrontendLoggerEndpoint.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-axo/services.php b/modules/ppcp-axo/services.php index 8af3df17d..0020169a7 100644 --- a/modules/ppcp-axo/services.php +++ b/modules/ppcp-axo/services.php @@ -225,7 +225,7 @@ return array( return '

' . $notice_content . '

'; }, - 'axo.endpoint.frontend-logger' => static function (ContainerInterface $container): FrontendLoggerEndpoint { + 'axo.endpoint.frontend-logger' => static function ( ContainerInterface $container ): FrontendLoggerEndpoint { return new FrontendLoggerEndpoint( $container->get( 'button.request-data' ), $container->get( 'woocommerce.logger.woocommerce' ) diff --git a/modules/ppcp-axo/src/FrontendLoggerEndpoint.php b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php index ad7f01375..2623051f8 100644 --- a/modules/ppcp-axo/src/FrontendLoggerEndpoint.php +++ b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php @@ -38,7 +38,7 @@ class FrontendLoggerEndpoint implements EndpointInterface { /** * FrontendLoggerEndpoint constructor. * - * @param RequestData $request_data The request data helper. + * @param RequestData $request_data The request data helper. * @param LoggerInterface $logger The logger. */ public function __construct( RequestData $request_data, LoggerInterface $logger ) { @@ -62,7 +62,7 @@ class FrontendLoggerEndpoint implements EndpointInterface { * @throws Exception On Error. */ public function handle_request(): bool { - $data = $this->request_data->read_request( $this->nonce() ); + $data = $this->request_data->read_request( $this->nonce() ); $level = $data['log']['level'] ?? 'info'; switch ( $level ) { From 64dee95a76b31c26943d3cfee84c21d3286f3197 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Mon, 27 May 2024 15:59:46 +0200 Subject: [PATCH 28/48] AXO: Disable payment method selection during OTP interaction (3174) --- modules/ppcp-axo/resources/js/AxoManager.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index 7c2a21964..5229573ae 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -571,7 +571,9 @@ class AxoManager { page_type: 'checkout' }); + this.disableGatewaySelection(); await this.lookupCustomerByEmail(); + this.enableGatewaySelection(); } async lookupCustomerByEmail() { @@ -659,6 +661,14 @@ class AxoManager { } } + disableGatewaySelection() { + this.$('.wc_payment_methods input').prop('disabled', true); + } + + enableGatewaySelection() { + this.$('.wc_payment_methods input').prop('disabled', false); + } + clearData() { this.data = { email: null, From 0245fa640bd163e7a4ed92fc50ae414498924f82 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 27 May 2024 19:57:00 +0400 Subject: [PATCH 29/48] Determine if venmo button is clicked and do not pass shipping callback handlers --- .../resources/js/modules/Renderer/Renderer.js | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js b/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js index 895a7845b..a95621456 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js @@ -68,14 +68,6 @@ class Renderer { } } - shouldHandleShippingInPaypal = (venmoButtonClicked) => { - if (!this.defaultSettings.should_handle_shipping_in_paypal) { - return false; - } - - return !venmoButtonClicked || !this.defaultSettings.vaultingEnabled; - } - renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) { if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) ) { // Try to render registered buttons again in case they were removed from the DOM by an external source. @@ -93,7 +85,16 @@ class Renderer { const options = { style, ...contextConfig, - onClick: this.onSmartButtonClick, + onClick: (data, actions) => { + if (this.onSmartButtonClick) { + this.onSmartButtonClick(data, actions); + } + + venmoButtonClicked = false; + if (data.fundingSource === 'venmo') { + venmoButtonClicked = true; + } + }, onInit: (data, actions) => { if (this.onSmartButtonsInit) { this.onSmartButtonsInit(data, actions); @@ -103,9 +104,17 @@ class Renderer { }; // Check the condition and add the handler if needed - if (this.shouldHandleShippingInPaypal(venmoButtonClicked)) { - options.onShippingOptionsChange = (data, actions) => handleShippingOptionsChange(data, actions, this.defaultSettings); - options.onShippingAddressChange = (data, actions) => handleShippingAddressChange(data, actions, this.defaultSettings); + if (this.defaultSettings.should_handle_shipping_in_paypal) { + options.onShippingOptionsChange = (data, actions) => { + !this.isVenmoButtonClickedWhenVaultingIsEnabled(venmoButtonClicked) + ? handleShippingOptionsChange(data, actions, this.defaultSettings) + : null; + } + options.onShippingAddressChange = (data, actions) => { + !this.isVenmoButtonClickedWhenVaultingIsEnabled(venmoButtonClicked) + ? handleShippingAddressChange(data, actions, this.defaultSettings) + : null; + } } return options; @@ -139,6 +148,10 @@ class Renderer { } } + isVenmoButtonClickedWhenVaultingIsEnabled = (venmoButtonClicked) => { + return venmoButtonClicked && this.defaultSettings.vaultingEnabled; + } + isAlreadyRendered(wrapper, fundingSource) { return this.renderedSources.has(wrapper + (fundingSource ?? '')); } From 49d943e25bb6cc7abf66e25842b12da87ae17f8d Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 27 May 2024 19:57:30 +0400 Subject: [PATCH 30/48] use funding source instead of payment source as they are same --- modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php index fbfb22309..868f9bf6c 100644 --- a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php @@ -246,7 +246,6 @@ class CreateOrderEndpoint implements EndpointInterface { $this->parsed_request_data = $data; $payment_method = $data['payment_method'] ?? ''; $funding_source = $data['funding_source'] ?? ''; - $payment_source = $data['payment_source'] ?? ''; $wc_order = null; if ( 'pay-now' === $data['context'] ) { $wc_order = wc_get_order( (int) $data['order_id'] ); @@ -262,7 +261,7 @@ class CreateOrderEndpoint implements EndpointInterface { } $this->purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order ); } else { - $this->purchase_unit = $this->purchase_unit_factory->from_wc_cart( null, $this->should_handle_shipping_in_paypal( $payment_source ) ); + $this->purchase_unit = $this->purchase_unit_factory->from_wc_cart( null, $this->should_handle_shipping_in_paypal( $funding_source ) ); // Do not allow completion by webhooks when started via non-checkout buttons, // it is needed only for some APMs in checkout. @@ -615,16 +614,16 @@ class CreateOrderEndpoint implements EndpointInterface { /** * Checks if the shipping should be handled in PayPal popup. * - * @param string $payment_source The payment source. + * @param string $funding_source The funding source. * @return bool true if the shipping should be handled in PayPal popup, otherwise false. */ - protected function should_handle_shipping_in_paypal( string $payment_source ): bool { + protected function should_handle_shipping_in_paypal( string $funding_source ): bool { $is_vaulting_enabled = $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ); if ( ! $this->handle_shipping_in_paypal ) { return false; } - return ! $is_vaulting_enabled || $payment_source !== 'venmo'; + return ! $is_vaulting_enabled || $funding_source !== 'venmo'; } } From 84616d07da5afbd0cc0f86c610eff15454f88757 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 27 May 2024 19:57:48 +0400 Subject: [PATCH 31/48] dont need to pass the payment source --- .../resources/js/modules/ActionHandler/CartActionHandler.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js index 2b3066395..0400c8013 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CartActionHandler.js @@ -60,8 +60,7 @@ class CartActionHandler { funding_source: window.ppcpFundingSource, bn_code:bnCode, payer, - context:this.config.context, - payment_source: data.paymentSource + context:this.config.context }), }).then(function(res) { return res.json(); From 8e573918ef21a0c71f5bc166a2c575b4dccac51f Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Tue, 28 May 2024 18:32:49 +0200 Subject: [PATCH 32/48] AXO: Update Fastlane settings (3166) --- modules/ppcp-axo/extensions.php | 42 +++++++++---------- .../src/Helper/PropertiesDictionary.php | 12 ++++++ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/modules/ppcp-axo/extensions.php b/modules/ppcp-axo/extensions.php index e6d0f4836..8d8bf4378 100644 --- a/modules/ppcp-axo/extensions.php +++ b/modules/ppcp-axo/extensions.php @@ -148,14 +148,8 @@ return array( 'axo_privacy' => array( 'title' => __( 'Privacy', 'woocommerce-paypal-payments' ), 'type' => 'select', - 'label' => __( - 'This setting will control whether Fastlane branding is shown by email field. -

PayPal powers this accelerated checkout solution from Fastlane. Since you\'ll share consumers\' email addresses with PayPal, please consult your legal advisors on the apropriate privacy setting for your business.

', - 'woocommerce-paypal-payments' - ), - 'desc_tip' => true, 'description' => __( - 'This setting will control whether Fastlane branding is shown by email field.', + 'PayPal powers this accelerated checkout solution from Fastlane. Since you\'ll share consumers\' email address with PayPal, please consult your legal advisors on the appropriate privacy setting for your business.', 'woocommerce-paypal-payments' ), 'classes' => array( 'ppcp-field-indent' ), @@ -168,12 +162,14 @@ return array( 'requirements' => array( 'axo' ), ), 'axo_name_on_card' => array( - 'title' => __( 'Display Name on Card', 'woocommerce-paypal-payments' ), - 'type' => 'checkbox', + 'title' => __( 'Cardholder Name', 'woocommerce-paypal-payments' ), + 'type' => 'select', 'default' => 'yes', + 'options' => PropertiesDictionary::cardholder_name_options(), 'classes' => array( 'ppcp-field-indent' ), 'class' => array(), - 'label' => __( 'Enable this to display the "Name on Card" field for new Fastlane buyers.', 'woocommerce-paypal-payments' ), + 'input_class' => array( 'wc-enhanced-select' ), + 'description' => __( 'This setting will control whether or not the cardholder name is displayed in the card field\'s UI.', 'woocommerce-paypal-payments' ), 'screens' => array( State::STATE_ONBOARDED ), 'gateway' => array( 'dcc', 'axo' ), 'requirements' => array( 'axo' ), @@ -196,7 +192,7 @@ return array( sprintf( // translators: %1$s and %2$s is a link tag. __( - 'Leave the default styling, or customize how Fastlane looks on your website. %1$sSee PayPal\'s developer docs%2$s for info', + 'Leave the default styling, or customize how Fastlane looks on your website. Styles that don\'t meet accessibility guidelines will revert to the defaults. See %1$sPayPal\'s developer docs%2$s for info.', 'woocommerce-paypal-payments' ), '', @@ -236,18 +232,6 @@ return array( 'requirements' => array( 'axo' ), 'gateway' => array( 'dcc', 'axo' ), ), - 'axo_style_root_primary_color' => array( - 'title' => __( 'Primary Color', 'woocommerce-paypal-payments' ), - 'type' => 'text', - 'placeholder' => '#0057F', - 'classes' => array( 'ppcp-field-indent' ), - 'default' => '', - 'screens' => array( - State::STATE_ONBOARDED, - ), - 'requirements' => array( 'axo' ), - 'gateway' => array( 'dcc', 'axo' ), - ), 'axo_style_root_error_color' => array( 'title' => __( 'Error Color', 'woocommerce-paypal-payments' ), 'type' => 'text', @@ -308,6 +292,18 @@ return array( 'requirements' => array( 'axo' ), 'gateway' => array( 'dcc', 'axo' ), ), + 'axo_style_root_primary_color' => array( + 'title' => __( 'Primary Color', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'placeholder' => '#0057FF', + 'classes' => array( 'ppcp-field-indent' ), + 'default' => '', + 'screens' => array( + State::STATE_ONBOARDED, + ), + 'requirements' => array( 'axo' ), + 'gateway' => array( 'dcc', 'axo' ), + ), 'axo_style_input_heading' => array( 'heading' => __( 'Input Settings', 'woocommerce-paypal-payments' ), 'type' => 'ppcp-heading', diff --git a/modules/ppcp-axo/src/Helper/PropertiesDictionary.php b/modules/ppcp-axo/src/Helper/PropertiesDictionary.php index 024c3649c..a07c4ace3 100644 --- a/modules/ppcp-axo/src/Helper/PropertiesDictionary.php +++ b/modules/ppcp-axo/src/Helper/PropertiesDictionary.php @@ -26,4 +26,16 @@ class PropertiesDictionary { ); } + /** + * Returns the list of possible cardholder name options. + * + * @return array + */ + public static function cardholder_name_options(): array { + return array( + 'yes' => __( 'Yes', 'woocommerce-paypal-payments' ), + 'no' => __( 'No', 'woocommerce-paypal-payments' ), + ); + } + } From 1524d03ba2b383ba413367d4eda2a7726ffad706 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 29 May 2024 14:53:58 +0200 Subject: [PATCH 33/48] Consolidate logging --- modules/ppcp-axo/resources/js/AxoManager.js | 72 ++++++------------- modules/ppcp-axo/resources/js/Helper/Debug.js | 26 ++++++- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index e868eb207..b93703ace 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -60,7 +60,6 @@ class AxoManager { } document.axoDebugObject = () => { - console.log(this); return this; } @@ -166,9 +165,8 @@ class AxoManager { this.$('form.woocommerce-checkout input').on('keydown', async (ev) => { if(ev.key === 'Enter' && getCurrentPaymentMethod() === 'ppcp-axo-gateway' ) { ev.preventDefault(); - log('Enter key attempt'); - log('emailInput', this.emailInput.value); - log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity); + log(`Enter key attempt - emailInput: ${this.emailInput.value}`); + log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`); if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) { await this.onChangeEmail(); } @@ -177,7 +175,7 @@ class AxoManager { // Clear last email checked identity when email field is focused. this.$('#billing_email_field input').on('focus', (ev) => { - log('Clear the last email checked:', this.lastEmailCheckedIdentity); + log(`Clear the last email checked: ${this.lastEmailCheckedIdentity}`); this.lastEmailCheckedIdentity = ''; }); @@ -214,7 +212,7 @@ class AxoManager { this.status.hasProfile ); - log('Scenario', scenario); + log(`Scenario: ${scenario}`); // Reset some elements to a default status. this.el.watermarkContainer.hide(); @@ -376,7 +374,7 @@ class AxoManager { setStatus(key, value) { this.status[key] = value; - log('Status updated', JSON.parse(JSON.stringify(this.status))); + log(`Status updated: ${JSON.parse(JSON.stringify(this.status))}`); document.dispatchEvent(new CustomEvent("axo_status_updated", {detail: this.status})); @@ -388,9 +386,8 @@ class AxoManager { this.initFastlane(); this.setStatus('active', true); - log('Attempt on activation'); - log('emailInput', this.emailInput.value); - log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity); + log(`Attempt on activation - emailInput: ${this.emailInput.value}`); + log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`); if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) { this.onChangeEmail(); } @@ -512,17 +509,15 @@ class AxoManager { } else { this.emailInput.addEventListener('change', async ()=> { - log('Change event attempt'); - log('emailInput', this.emailInput.value); - log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity); + log(`Change event attempt - emailInput: ${this.emailInput.value}`); + log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`); if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) { this.onChangeEmail(); } }); - log('Last, this.emailInput.value attempt'); - log('emailInput', this.emailInput.value); - log('this.lastEmailCheckedIdentity', this.lastEmailCheckedIdentity); + log(`Last, this.emailInput.value attempt - emailInput: ${this.emailInput.value}`); + log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`); if (this.emailInput.value) { this.onChangeEmail(); } @@ -542,7 +537,7 @@ class AxoManager { return; } - log('Email changed: ' + (this.emailInput ? this.emailInput.value : '')); + log(`Email changed: ${this.emailInput ? this.emailInput.value : ''}`); this.$(this.el.paymentContainer.selector + '-detail').html(''); this.$(this.el.paymentContainer.selector + '-form').html(''); @@ -579,7 +574,7 @@ class AxoManager { async lookupCustomerByEmail() { const lookupResponse = await this.fastlane.identity.lookupCustomerByEmail(this.emailInput.value); - await this.log(`lookupCustomerByEmail: ${JSON.stringify(lookupResponse)}`); + log(`lookupCustomerByEmail: ${JSON.stringify(lookupResponse)}`); if (lookupResponse.customerContextId) { // Email is associated with a Connect profile or a PayPal member. @@ -588,12 +583,9 @@ class AxoManager { const authResponse = await this.fastlane.identity.triggerAuthenticationFlow(lookupResponse.customerContextId); - log('AuthResponse', authResponse); - await this.log(`triggerAuthenticationFlow: ${JSON.stringify(authResponse)}`); + log(`AuthResponse - triggerAuthenticationFlow: ${JSON.stringify(authResponse)}`); if (authResponse.authenticationState === 'succeeded') { - log(JSON.stringify(authResponse)); - const shippingData = authResponse.profileData.shippingAddress; if (shippingData) { this.setShipping(shippingData); @@ -700,7 +692,7 @@ class AxoManager { // TODO: validate data. if (this.data.card) { // Ryan flow - log('Ryan flow.'); + log('Starting Ryan flow.'); this.$('#ship-to-different-address-checkbox').prop('checked', 'checked'); @@ -711,24 +703,23 @@ class AxoManager { this.ensureBillingPhoneNumber(data); - this.log(`Ryan flow - submitted nonce: ${this.data.card.id}` ) + log(`Ryan flow - submitted nonce: ${this.data.card.id}` ) this.submit(this.data.card.id, data); } else { // Gary flow - log('Gary flow.'); + log('Starting Gary flow.'); try { this.cardComponent.getPaymentToken( this.tokenizeData() ).then((response) => { - this.log(`Gary flow - submitted nonce: ${response.id}` ) + log(`Gary flow - submitted nonce: ${response.id}` ) this.submit(response.id); }); } catch (e) { - log('Error tokenizing.'); alert('Error tokenizing data.'); - this.log(`Error tokenizing data. ${e.message}`, 'error'); + log(`Error tokenizing data. ${e.message}`, 'error'); } } } @@ -809,8 +800,7 @@ class AxoManager { }, 500); } - console.error('Failure:', responseData); - this.log(`Error sending checkout form. ${responseData}`, 'error'); + log(`Error sending checkout form. ${responseData}`, 'error'); this.hideLoading(); return; @@ -820,8 +810,7 @@ class AxoManager { } }) .catch(error => { - console.error('Error:', error); - this.log(`Error sending checkout form. ${error.message}`, 'error'); + log(`Error sending checkout form. ${error.message}`, 'error'); this.hideLoading(); }); @@ -899,25 +888,6 @@ class AxoManager { watermarkLoader.classList.toggle(loaderClass); } } - - async log(message, level = 'info') { - const endpoint = this.axoConfig?.ajax?.frontend_logger?.endpoint; - if(!endpoint) { - return; - } - - await fetch(endpoint, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - nonce: this.axoConfig.ajax.frontend_logger.nonce, - log: { - message, - level, - } - }) - }); - } } export default AxoManager; diff --git a/modules/ppcp-axo/resources/js/Helper/Debug.js b/modules/ppcp-axo/resources/js/Helper/Debug.js index e473d4a3b..8073c2683 100644 --- a/modules/ppcp-axo/resources/js/Helper/Debug.js +++ b/modules/ppcp-axo/resources/js/Helper/Debug.js @@ -1,4 +1,26 @@ +export function log(message, level = 'info') { + const endpoint = this.axoConfig?.ajax?.frontend_logger?.endpoint; + if(!endpoint) { + return; + } -export function log(...args) { - //console.log('[AXO] ', ...args); + fetch(endpoint, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + nonce: this.axoConfig.ajax.frontend_logger.nonce, + log: { + message, + level, + } + }) + }).then(() => { + switch (level) { + case 'error': + console.error(`[AXO] ${message}`); + break; + default: + console.log(`[AXO] ${message}`); + } + }); } From b3ffa1030d311283323556e7595b64b4046c46d1 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 29 May 2024 15:21:21 +0200 Subject: [PATCH 34/48] Fix stringify objects --- modules/ppcp-axo/resources/js/AxoManager.js | 4 ++-- modules/ppcp-axo/resources/js/Helper/Debug.js | 4 ++-- yarn.lock | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js index b93703ace..960da7f26 100644 --- a/modules/ppcp-axo/resources/js/AxoManager.js +++ b/modules/ppcp-axo/resources/js/AxoManager.js @@ -212,7 +212,7 @@ class AxoManager { this.status.hasProfile ); - log(`Scenario: ${scenario}`); + log(`Scenario: ${JSON.stringify(scenario)}`); // Reset some elements to a default status. this.el.watermarkContainer.hide(); @@ -374,7 +374,7 @@ class AxoManager { setStatus(key, value) { this.status[key] = value; - log(`Status updated: ${JSON.parse(JSON.stringify(this.status))}`); + log(`Status updated: ${JSON.stringify(this.status)}`); document.dispatchEvent(new CustomEvent("axo_status_updated", {detail: this.status})); diff --git a/modules/ppcp-axo/resources/js/Helper/Debug.js b/modules/ppcp-axo/resources/js/Helper/Debug.js index 8073c2683..c08fa8087 100644 --- a/modules/ppcp-axo/resources/js/Helper/Debug.js +++ b/modules/ppcp-axo/resources/js/Helper/Debug.js @@ -1,5 +1,5 @@ export function log(message, level = 'info') { - const endpoint = this.axoConfig?.ajax?.frontend_logger?.endpoint; + const endpoint = window.wc_ppcp_axo?.ajax?.frontend_logger?.endpoint; if(!endpoint) { return; } @@ -8,7 +8,7 @@ export function log(message, level = 'info') { method: 'POST', credentials: 'same-origin', body: JSON.stringify({ - nonce: this.axoConfig.ajax.frontend_logger.nonce, + nonce: window.wc_ppcp_axo.ajax.frontend_logger.nonce, log: { message, level, diff --git a/yarn.lock b/yarn.lock index 722df19c5..81af54726 100644 --- a/yarn.lock +++ b/yarn.lock @@ -598,6 +598,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" From f08d6c089cfff30e08859624416a2eee78c30ec1 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 29 May 2024 15:28:37 +0200 Subject: [PATCH 35/48] Fix stringify objects --- modules/ppcp-axo/src/FrontendLoggerEndpoint.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-axo/src/FrontendLoggerEndpoint.php b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php index 2623051f8..e17a819e4 100644 --- a/modules/ppcp-axo/src/FrontendLoggerEndpoint.php +++ b/modules/ppcp-axo/src/FrontendLoggerEndpoint.php @@ -67,10 +67,10 @@ class FrontendLoggerEndpoint implements EndpointInterface { switch ( $level ) { case 'error': - $this->logger->error( '[AXO] ' . esc_html( $data['log']['message'] ) ); + $this->logger->error( '[AXO] ' . $data['log']['message'] ); break; default: - $this->logger->info( '[AXO] ' . esc_html( $data['log']['message'] ) ); + $this->logger->info( '[AXO] ' . $data['log']['message'] ); break; } From b1bfa2940b0414af8c19d55617da0b4eb92ec0f3 Mon Sep 17 00:00:00 2001 From: George Burduli Date: Wed, 29 May 2024 17:44:28 +0400 Subject: [PATCH 36/48] Disable Pay Upon Invoice if billing/shipping country not set --- modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php b/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php index 823caf611..c140b0976 100644 --- a/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php +++ b/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php @@ -57,13 +57,13 @@ class PayUponInvoiceHelper { // phpcs:ignore WordPress.Security.NonceVerification.Missing $billing_country = wc_clean( wp_unslash( $_POST['country'] ?? '' ) ); - if ( $billing_country && 'DE' !== $billing_country ) { + if ( empty( $billing_country ) || 'DE' !== $billing_country ) { return false; } // phpcs:ignore WordPress.Security.NonceVerification.Missing $shipping_country = wc_clean( wp_unslash( $_POST['s_country'] ?? '' ) ); - if ( $shipping_country && 'DE' !== $shipping_country ) { + if ( empty( $shipping_country ) || 'DE' !== $shipping_country ) { return false; } From b753cf1ec907ba851d8b83415801ed285240a40e Mon Sep 17 00:00:00 2001 From: Philipp Stracker Date: Wed, 29 May 2024 16:18:17 +0200 Subject: [PATCH 37/48] =?UTF-8?q?=F0=9F=90=9B=20Fix=20fallback=20logic=20w?= =?UTF-8?q?hen=20vaulting=20is=20disabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added condition to handle incorrect condition: hardcoded default setting did ignore the form's input value. --- .../src/Settings/SettingsListener.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php index 6966f97c0..97b1cd776 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php +++ b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php @@ -394,7 +394,18 @@ class SettingsListener { if ( $reference_transaction_enabled !== true ) { $this->settings->set( 'vault_enabled', false ); - $this->settings->set( 'subscriptions_mode', 'subscriptions_api' ); + + /** + * If Vaulting-API was previously enabled, then fall-back to the + * PayPal subscription mode, to ensure subscriptions are still + * possible on this shop. + * + * This can happen when switching to a different PayPal merchant account + */ + if ( 'vaulting_api' === $subscription_mode ) { + $this->settings->set( 'subscriptions_mode', 'subscriptions_api' ); + } + $this->settings->persist(); } From 424b9ea91622dce8db62ce08fc1544712919a245 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 30 May 2024 14:47:50 +0200 Subject: [PATCH 38/48] Remove `www` in domain --- modules/ppcp-api-client/src/Authentication/SdkClientToken.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ppcp-api-client/src/Authentication/SdkClientToken.php b/modules/ppcp-api-client/src/Authentication/SdkClientToken.php index 200ba2322..ba0f3a373 100644 --- a/modules/ppcp-api-client/src/Authentication/SdkClientToken.php +++ b/modules/ppcp-api-client/src/Authentication/SdkClientToken.php @@ -73,6 +73,7 @@ class SdkClientToken { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $domain = wp_unslash( $_SERVER['HTTP_HOST'] ?? '' ); + $domain = preg_replace( '/^www\./', '', $domain ); $url = trailingslashit( $this->host ) . 'v1/oauth2/token?grant_type=client_credentials&response_type=client_token&intent=sdk_init&domains[]=' . $domain; From 4a3345113b554b28e399a57c4a7920b5bb80086f Mon Sep 17 00:00:00 2001 From: George Burduli Date: Fri, 31 May 2024 13:07:41 +0400 Subject: [PATCH 39/48] Use WC Customer API to retrieve billing and shipping countries --- modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php b/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php index c140b0976..b91eca8a0 100644 --- a/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php +++ b/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceHelper.php @@ -56,13 +56,13 @@ class PayUponInvoiceHelper { } // phpcs:ignore WordPress.Security.NonceVerification.Missing - $billing_country = wc_clean( wp_unslash( $_POST['country'] ?? '' ) ); + $billing_country = WC()->customer->get_billing_country(); if ( empty( $billing_country ) || 'DE' !== $billing_country ) { return false; } // phpcs:ignore WordPress.Security.NonceVerification.Missing - $shipping_country = wc_clean( wp_unslash( $_POST['s_country'] ?? '' ) ); + $shipping_country = WC()->customer->get_shipping_country(); if ( empty( $shipping_country ) || 'DE' !== $shipping_country ) { return false; } From 2cb76ed8f2fca7dea858a632c0f392460d2b5621 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Fri, 31 May 2024 15:36:32 +0400 Subject: [PATCH 40/48] Apply the Venmo + vaulting functionality on block pages --- .../resources/js/checkout-block.js | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index df003f494..8a158828f 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -23,6 +23,9 @@ import { import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher"; import BlockCheckoutMessagesBootstrap from "./Bootstrap/BlockCheckoutMessagesBootstrap"; import {keysToCamelCase} from "../../../ppcp-button/resources/js/modules/Helper/Utils"; +import { + handleShippingOptionsChange +} from "../../../ppcp-button/resources/js/modules/Helper/ShippingHandler"; const config = wc.wcSettings.getSetting('ppcp-gateway_data'); window.ppcpFundingSource = config.fundingSource; @@ -146,7 +149,7 @@ const PayPalComponent = ({ shipping_address: addresses.shippingAddress, }), ]; - if (!config.finalReviewEnabled) { + if (shouldHandleShippingInPayPal()) { // set address in UI promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress)); if (shippingData.needsShipping) { @@ -181,7 +184,7 @@ const PayPalComponent = ({ throw new Error(config.scriptData.labels.error.generic) } - if (config.finalReviewEnabled) { + if (!shouldHandleShippingInPayPal()) { location.href = getCheckoutRedirectUrl(); } else { setGotoContinuationOnError(true); @@ -220,7 +223,7 @@ const PayPalComponent = ({ shipping_address: addresses.shippingAddress, }), ]; - if (!config.finalReviewEnabled) { + if (shouldHandleShippingInPayPal()) { // set address in UI promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress)); if (shippingData.needsShipping) { @@ -255,7 +258,7 @@ const PayPalComponent = ({ throw new Error(config.scriptData.labels.error.generic) } - if (config.finalReviewEnabled) { + if (!shouldHandleShippingInPayPal()) { location.href = getCheckoutRedirectUrl(); } else { setGotoContinuationOnError(true); @@ -297,8 +300,12 @@ const PayPalComponent = ({ onClick(); }; - const isVenmoAndVaultingEnabled = () => { - return window.ppcpFundingSource === 'venmo' && config.scriptData.vaultingEnabled; + const shouldHandleShippingInPayPal = () => { + if (config.finalReviewEnabled) { + return false; + } + + return window.ppcpFundingSource !== 'venmo' || !config.scriptData.vaultingEnabled; } let handleShippingOptionsChange = null; @@ -306,7 +313,7 @@ const PayPalComponent = ({ let handleSubscriptionShippingOptionsChange = null; let handleSubscriptionShippingAddressChange = null; - if (shippingData.needsShipping && !config.finalReviewEnabled) { + if (shippingData.needsShipping && shouldHandleShippingInPayPal()) { handleShippingOptionsChange = async (data, actions) => { try { const shippingOptionId = data.selectedShippingOption?.id; @@ -447,7 +454,7 @@ const PayPalComponent = ({ if (config.scriptData.continuation) { return true; } - if (!config.finalReviewEnabled) { + if (shouldHandleShippingInPayPal()) { location.href = getCheckoutRedirectUrl(); } return true; @@ -493,8 +500,16 @@ const PayPalComponent = ({ onError={onClose} createSubscription={createSubscription} onApprove={handleApproveSubscription} - onShippingOptionsChange={handleSubscriptionShippingOptionsChange} - onShippingAddressChange={handleSubscriptionShippingAddressChange} + onShippingOptionsChange={(data, actions) => { + shouldHandleShippingInPayPal() + ? handleSubscriptionShippingOptionsChange(data, actions) + : null; + }} + onShippingAddressChange={(data, actions) => { + shouldHandleShippingInPayPal() + ? handleSubscriptionShippingAddressChange(data, actions) + : null; + }} /> ); } @@ -508,8 +523,16 @@ const PayPalComponent = ({ onError={onClose} createOrder={createOrder} onApprove={handleApprove} - onShippingOptionsChange={handleShippingOptionsChange} - onShippingAddressChange={handleShippingAddressChange} + onShippingOptionsChange={(data, actions) => { + shouldHandleShippingInPayPal() + ? handleShippingOptionsChange(data, actions) + : null; + }} + onShippingAddressChange={(data, actions) => { + shouldHandleShippingInPayPal() + ? handleShippingAddressChange(data, actions) + : null; + }} /> ); } From bfb566162c6537a6b4665615c577368d9ef383e2 Mon Sep 17 00:00:00 2001 From: Daniel Dudzic Date: Fri, 31 May 2024 13:55:30 +0200 Subject: [PATCH 41/48] AXO: Only enqueue JS scripts on the WooCommerce checkout page --- modules/ppcp-axo/src/AxoModule.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-axo/src/AxoModule.php b/modules/ppcp-axo/src/AxoModule.php index 7a10c34ad..d1731b4fe 100644 --- a/modules/ppcp-axo/src/AxoModule.php +++ b/modules/ppcp-axo/src/AxoModule.php @@ -44,7 +44,6 @@ class AxoModule implements ModuleInterface { * {@inheritDoc} */ public function run( ContainerInterface $c ): void { - $module = $this; add_filter( 'woocommerce_payment_gateways', @@ -132,7 +131,8 @@ class AxoModule implements ModuleInterface { add_action( 'init', - function () use ( $c, $module ) { + function () use ( $c ) { + $module = $this; // Check if the module is applicable, correct country, currency, ... etc. if ( ! $c->get( 'axo.eligible' ) ) { @@ -145,11 +145,15 @@ class AxoModule implements ModuleInterface { // Enqueue frontend scripts. add_action( 'wp_enqueue_scripts', - static function () use ( $c, $manager ) { + static function () use ( $c, $manager, $module ) { + + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + $smart_button = $c->get( 'button.smart-button' ); assert( $smart_button instanceof SmartButtonInterface ); - if ( $smart_button->should_load_ppcp_script() ) { + if ( $module->should_render_fastlane( $settings ) && $smart_button->should_load_ppcp_script() ) { $manager->enqueue(); } } From dccb038e5e97efe168234e9032c07664f9668192 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Fri, 31 May 2024 18:46:21 +0400 Subject: [PATCH 42/48] Calculate totals after adding shipping to include taxes. --- modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php b/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php index 92f07c0fd..4dd7a3293 100644 --- a/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php +++ b/modules/ppcp-button/src/Helper/WooCommerceOrderCreator.php @@ -181,6 +181,8 @@ class WooCommerceOrderCreator { $wc_order->add_item( $shipping ); } + + $wc_order->calculate_totals(); } /** From 4967c472e7b48399de8e05d5309f917ee377f68e Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 3 Jun 2024 15:27:01 +0400 Subject: [PATCH 43/48] Update the shipping option for subscriptions on address change --- .../ppcp-blocks/resources/js/checkout-block.js | 15 +++++++++++++++ .../js/modules/Helper/ShippingHandler.js | 2 -- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index df003f494..9ac471352 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -391,6 +391,21 @@ const PayPalComponent = ({ await shippingData.setShippingAddress(address); + const res = await fetch(config.ajax.update_shipping.endpoint, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + nonce: config.ajax.update_shipping.nonce, + order_id: data.orderID, + }) + }); + + const json = await res.json(); + + if (!json.success) { + throw new Error(json.data.message); + } + } catch (e) { console.error(e); diff --git a/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js b/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js index 311b8a949..c67bee5bb 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js +++ b/modules/ppcp-button/resources/js/modules/Helper/ShippingHandler.js @@ -106,7 +106,6 @@ export const handleShippingAddressChange = async (data, actions, config) => { }) }) - if (!config.data_client_id.has_subscriptions) { const res = await fetch(config.ajax.update_shipping.endpoint, { method: 'POST', credentials: 'same-origin', @@ -121,7 +120,6 @@ export const handleShippingAddressChange = async (data, actions, config) => { if (!json.success) { throw new Error(json.data.message); } - } } catch (e) { console.error(e); From f4b34b6a3233fac9b8eabf030a3bcb5cd4b416c1 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 3 Jun 2024 14:47:00 +0200 Subject: [PATCH 44/48] Bump 2.7.1-rc1 version --- changelog.txt | 12 ++++++++++++ package.json | 2 +- readme.txt | 14 +++++++++++++- woocommerce-paypal-payments.php | 6 +++--- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3ca38e0e2..cad6f366e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,17 @@ *** Changelog *** += 2.8.0 - xxxx-xx-xx = +* Fix - Calculate totals after adding shipping to include taxes #2296 +* Fix - Package tracking integration throws error in 2.7.1 #2289 +* Fix - Make PayPal Subscription products unique in cart #2265 +* Fix - PayPal declares subscription support when merchant not enabled for Reference Transactions #2282 +* Fix - Google Pay and Apple Pay Settings button from Connection tab have wrong links #2273 +* Fix - Smart Buttons in Block Checkout not respecting the location setting (2830) #2278 +* Fix - Disable Pay Upon Invoice if billing/shipping country not set #2281 +* Enhancement - Enable shipping callback for WC subscriptions #2259 +* Enhancement - Disable the shipping callback for "venmo" when vaulting is active #2269 +* Enhancement - Improve "Could not retrieve order" error message #2271 + = 2.7.1 - 2024-05-28 = * Fix - Ensure package tracking data is sent to original PayPal transaction #2180 * Fix - Set the 'Woo_PPCP' as a default value for data-partner-attribution-id #2188 diff --git a/package.json b/package.json index bf52a8677..2bc0582d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "woocommerce-paypal-payments", - "version": "2.7.1", + "version": "2.8.0", "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 0c6bdbb1a..111dc667c 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, checkout, cart, pay later, apple Requires at least: 5.3 Tested up to: 6.5 Requires PHP: 7.2 -Stable tag: 2.7.1 +Stable tag: 2.8.0 License: GPLv2 License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -191,6 +191,18 @@ If you encounter issues with the PayPal buttons not appearing after an update, p * Fix - Enable the Shipping Callback handlers #2266 * Enhancement - Use admin theme color #1602 += 2.8.0 - xxxx-xx-xx = +* Fix - Calculate totals after adding shipping to include taxes #2296 +* Fix - Package tracking integration throws error in 2.7.1 #2289 +* Fix - Make PayPal Subscription products unique in cart #2265 +* Fix - PayPal declares subscription support when merchant not enabled for Reference Transactions #2282 +* Fix - Google Pay and Apple Pay Settings button from Connection tab have wrong links #2273 +* Fix - Smart Buttons in Block Checkout not respecting the location setting (2830) #2278 +* Fix - Disable Pay Upon Invoice if billing/shipping country not set #2281 +* Enhancement - Enable shipping callback for WC subscriptions #2259 +* Enhancement - Disable the shipping callback for "venmo" when vaulting is active #2269 +* Enhancement - Improve "Could not retrieve order" error message #2271 + = 2.7.0 - 2024-04-30 = * Fix - Zero sum subscriptions cause CANNOT_BE_ZERO_OR_NEGATIVE when using Vault v3 #2152 * Fix - Incorrect Pricing Issue with Variable Subscriptions in PayPal Subscriptions Mode #2156 diff --git a/woocommerce-paypal-payments.php b/woocommerce-paypal-payments.php index ce5883709..62d4359aa 100644 --- a/woocommerce-paypal-payments.php +++ b/woocommerce-paypal-payments.php @@ -3,14 +3,14 @@ * 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: 2.7.1 + * Version: 2.8.0 * Author: WooCommerce * Author URI: https://woocommerce.com/ * License: GPL-2.0 * Requires PHP: 7.2 * Requires Plugins: woocommerce * WC requires at least: 3.9 - * WC tested up to: 8.8 + * WC tested up to: 8.9 * Text Domain: woocommerce-paypal-payments * * @package WooCommerce\PayPalCommerce @@ -26,7 +26,7 @@ define( 'PAYPAL_API_URL', 'https://api-m.paypal.com' ); define( 'PAYPAL_URL', 'https://www.paypal.com' ); define( 'PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com' ); define( 'PAYPAL_SANDBOX_URL', 'https://www.sandbox.paypal.com' ); -define( 'PAYPAL_INTEGRATION_DATE', '2024-05-13' ); +define( 'PAYPAL_INTEGRATION_DATE', '2024-06-03' ); ! defined( 'CONNECT_WOO_CLIENT_ID' ) && define( 'CONNECT_WOO_CLIENT_ID', 'AcCAsWta_JTL__OfpjspNyH7c1GGHH332fLwonA5CwX4Y10mhybRZmHLA0GdRbwKwjQIhpDQy0pluX_P' ); ! defined( 'CONNECT_WOO_SANDBOX_CLIENT_ID' ) && define( 'CONNECT_WOO_SANDBOX_CLIENT_ID', 'AYmOHbt1VHg-OZ_oihPdzKEVbU3qg0qXonBcAztuzniQRaKE0w1Hr762cSFwd4n8wxOl-TCWohEa0XM_' ); From b64523f2a333d097ad2d2d4881468dd29b663c2e Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 4 Jun 2024 16:10:33 +0200 Subject: [PATCH 45/48] Remove wc subscriptions plugin check --- modules/ppcp-blocks/extensions.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/modules/ppcp-blocks/extensions.php b/modules/ppcp-blocks/extensions.php index 2409d1bbc..b32f5bbc6 100644 --- a/modules/ppcp-blocks/extensions.php +++ b/modules/ppcp-blocks/extensions.php @@ -51,17 +51,7 @@ return array( ); } - $subscription_helper = $container->get( 'wc-subscriptions.helper' ); - - if ( $subscription_helper->plugin_is_active() ) { - $notice_content = __( - 'Important: Cannot be deactivated while the WooCommerce Subscriptions plugin is active.', - 'woocommerce-paypal-payments' - ); - $label .= '

' . $notice_content . '

'; - } - - $should_disable_checkbox = $subscription_helper->plugin_is_active() || apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ); + $should_disable_checkbox = apply_filters( 'woocommerce_paypal_payments_toggle_final_review_checkbox', false ); return $insert_after( $fields, From c8b2f99e658454a629ef0e155967528e0af4b750 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 5 Jun 2024 11:59:04 +0200 Subject: [PATCH 46/48] Fix axo.smart-button-location-notice service not found --- .../src/Settings/Fields/paypal-smart-button-fields.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php b/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php index 9e6038606..460ff3592 100644 --- a/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php +++ b/modules/ppcp-wc-gateway/src/Settings/Fields/paypal-smart-button-fields.php @@ -36,6 +36,8 @@ return function ( ContainerInterface $container, array $fields ): array { '; }; + $axo_smart_button_location_notice = $container->has( 'axo.smart-button-location-notice' ) ? $container->get( 'axo.smart-button-location-notice' ) : ''; + $smart_button_fields = array( 'button_style_heading' => array( 'heading' => __( 'PayPal Smart Buttons', 'woocommerce-paypal-payments' ), @@ -65,7 +67,7 @@ return function ( ContainerInterface $container, array $fields ): array { 'type' => 'ppcp-multiselect', 'input_class' => array( 'wc-enhanced-select' ), 'default' => $container->get( 'wcgateway.button.default-locations' ), - 'description' => __( 'Select where the PayPal smart buttons should be displayed.', 'woocommerce-paypal-payments' ) . $container->get( 'axo.smart-button-location-notice' ), + 'description' => __( 'Select where the PayPal smart buttons should be displayed.', 'woocommerce-paypal-payments' ) . $axo_smart_button_location_notice, 'options' => $container->get( 'wcgateway.button.locations' ), 'screens' => array( State::STATE_START, State::STATE_ONBOARDED ), 'requirements' => array(), From 3c8144de421b2563b08b7628f0e714a03d5d7dc7 Mon Sep 17 00:00:00 2001 From: Philipp Stracker Date: Wed, 5 Jun 2024 15:24:13 +0200 Subject: [PATCH 47/48] =?UTF-8?q?=F0=9F=A9=B9=20Remove=20HTML=20from=20the?= =?UTF-8?q?=20error=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As outlined in the linked issue: HTML code is escaped by the exception handler, instead of displaying a clickable link. --- .../ppcp-wc-gateway/src/Processor/OrderProcessor.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php b/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php index 4d1363361..82183e0d4 100644 --- a/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php +++ b/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php @@ -220,14 +220,9 @@ class OrderProcessor { ); throw new PayPalOrderMissingException( - sprintf( - // translators: %s: Order history URL on My Account section. - esc_attr__( - 'There was an error processing your order. Please check for any charges in your payment method and review your
order history before placing the order again.', - // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Intentionally "woocommerce" to reflect the original message. - 'woocommerce' - ), - esc_url( wc_get_account_endpoint_url( 'orders' ) ) + esc_attr__( + 'There was an error processing your order. Please check for any charges in your payment method and review your order history before placing the order again.', + 'woocommerce-paypal-payments' ) ); } From 08f0b42f1c7b7983927a7148f433cbdf7423c718 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 5 Jun 2024 15:52:54 +0200 Subject: [PATCH 48/48] Update changelog --- changelog.txt | 1 + readme.txt | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/changelog.txt b/changelog.txt index cad6f366e..17c03cb83 100644 --- a/changelog.txt +++ b/changelog.txt @@ -11,6 +11,7 @@ * Enhancement - Enable shipping callback for WC subscriptions #2259 * Enhancement - Disable the shipping callback for "venmo" when vaulting is active #2269 * Enhancement - Improve "Could not retrieve order" error message #2271 +* Enhancement - Add block Checkout compatibility to Advanced Card Processing #2246 = 2.7.1 - 2024-05-28 = * Fix - Ensure package tracking data is sent to original PayPal transaction #2180 diff --git a/readme.txt b/readme.txt index 111dc667c..ac1315805 100644 --- a/readme.txt +++ b/readme.txt @@ -179,18 +179,6 @@ If you encounter issues with the PayPal buttons not appearing after an update, p == Changelog == -= 2.7.1 - 2024-05-28 = -* Fix - Ensure package tracking data is sent to original PayPal transaction #2180 -* Fix - Set the 'Woo_PPCP' as a default value for data-partner-attribution-id #2188 -* Fix - Allow PUI Gateway for refund processor #2192 -* Fix - Notice on newly created block cart checkout #2211 -* Fix - Apple Pay button in the editor #2177 -* Fix - Allow shipping callback and skipping confirmation page from any express button #2236 -* Fix - Pay Later messaging configurator sometimes displays old settings after saving #2249 -* Fix - Update the apple-developer-merchantid-domain-association validation strings for Apple Pay #2251 -* Fix - Enable the Shipping Callback handlers #2266 -* Enhancement - Use admin theme color #1602 - = 2.8.0 - xxxx-xx-xx = * Fix - Calculate totals after adding shipping to include taxes #2296 * Fix - Package tracking integration throws error in 2.7.1 #2289 @@ -202,6 +190,19 @@ If you encounter issues with the PayPal buttons not appearing after an update, p * Enhancement - Enable shipping callback for WC subscriptions #2259 * Enhancement - Disable the shipping callback for "venmo" when vaulting is active #2269 * Enhancement - Improve "Could not retrieve order" error message #2271 +* Enhancement - Add block Checkout compatibility to Advanced Card Processing #2246 + += 2.7.1 - 2024-05-28 = +* Fix - Ensure package tracking data is sent to original PayPal transaction #2180 +* Fix - Set the 'Woo_PPCP' as a default value for data-partner-attribution-id #2188 +* Fix - Allow PUI Gateway for refund processor #2192 +* Fix - Notice on newly created block cart checkout #2211 +* Fix - Apple Pay button in the editor #2177 +* Fix - Allow shipping callback and skipping confirmation page from any express button #2236 +* Fix - Pay Later messaging configurator sometimes displays old settings after saving #2249 +* Fix - Update the apple-developer-merchantid-domain-association validation strings for Apple Pay #2251 +* Fix - Enable the Shipping Callback handlers #2266 +* Enhancement - Use admin theme color #1602 = 2.7.0 - 2024-04-30 = * Fix - Zero sum subscriptions cause CANNOT_BE_ZERO_OR_NEGATIVE when using Vault v3 #2152