From 08fb1d335073e552678bea1c913b9f7106d9c93a Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 21 Jul 2023 10:49:50 +0300 Subject: [PATCH 01/39] Check validation errors when submitting in block --- .../resources/js/checkout-block.js | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index bec1827c3..9a4afda54 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -18,7 +18,7 @@ const PayPalComponent = ({ shippingData, isEditing, }) => { - const {onPaymentSetup, onCheckoutAfterProcessingWithError} = eventRegistration; + const {onPaymentSetup, onCheckoutAfterProcessingWithError, onCheckoutValidation} = eventRegistration; const {responseTypes} = emitResponse; const [paypalOrder, setPaypalOrder] = useState(null); @@ -69,6 +69,14 @@ const PayPalComponent = ({ } }; + const getCheckoutRedirectUrl = () => { + const checkoutUrl = new URL(config.scriptData.redirect); + // sometimes some browsers may load some kind of cached version of the page, + // so adding a parameter to avoid that + checkoutUrl.searchParams.append('ppcp-continuation-redirect', (new Date()).getTime().toString()); + return checkoutUrl.toString(); + } + const handleApprove = async (data, actions) => { try { const res = await fetch(config.scriptData.ajax.approve_order.endpoint, { @@ -105,12 +113,8 @@ const PayPalComponent = ({ billing_address: addresses.billingAddress, shipping_address: addresses.shippingAddress, }); - const checkoutUrl = new URL(config.scriptData.redirect); - // sometimes some browsers may load some kind of cached version of the page, - // so adding a parameter to avoid that - checkoutUrl.searchParams.append('ppcp-continuation-redirect', (new Date()).getTime().toString()); - location.href = checkoutUrl.toString(); + location.href = getCheckoutRedirectUrl(); } else { onSubmit(); } @@ -125,6 +129,19 @@ const PayPalComponent = ({ } }; + useEffect(() => { + const unsubscribe = onCheckoutValidation(() => { + if (config.scriptData.continuation) { + return true; + } + if (wp.data.select('wc/store/validation').hasValidationErrors()) { + location.href = getCheckoutRedirectUrl(); + return false; + } + }); + return unsubscribe; + }, [onCheckoutValidation] ); + const handleClick = (data, actions) => { if (isEditing) { return actions.reject(); From 533c2cc97f33e82b136023e4a2fd1d7722a16279 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 21 Sep 2023 16:54:33 +0200 Subject: [PATCH 02/39] Update changelog for 2.3.0-rc2 --- changelog.txt | 20 ++++++++++++++++++++ readme.txt | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/changelog.txt b/changelog.txt index 758a4ce68..73671f93c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,12 @@ * Fix - Since version > 2.2.0 the PayPal Checkout button on single product pages does not redirect anymore #1664 * Fix - PayPal fee and PayPal Payout do not change on order if we do partial refund #1578 * Fix - Order does not contain intent error when using ACDC payment token while buyer is not present #1506 +* Fix - Error when product description linked with a PayPal subscription exceeds 127 characters #1700 +* Fix - $_POST uses the wrong key to hold the shipping method #1652 +* Fix - WC Payment Token created multiple times when webhook is received #1663 +* Fix - Subtotal mismatch line name shows on Account settings page when merchant is disconnected #1702 +* Fix - Warning prevents payments on Pay for Order page when debugging is enabled #1703 +* Fix - paypal-overlay-uid_ blocks page after closing PayPal popup on Pay for Order page | Terms checkbox validation fails on Pay for Order page #1704 * Enhancement - Add support for HPOS for tracking module #1676 * Enhancement - Billing agreements endpoint called too frequently for Reference Transactions check #1646 * Enhancement - Do not declare subscription support for PayPal when only ACDC vaulting #1669 @@ -21,6 +27,20 @@ * Enhancement - Compatibility with WooCommerce Product Add-Ons plugin #1586 * Enhancement - Remove "no shipment" message after adding tracking #1674 * Enhancement - Improve error & success validation messages #1675 +* Enhancement - Compatibility with third-party "Product Add-Ons" plugins #1601 +* Enhancement - PayPal logo flashes when switching between tabs #1345 +* Enhancement - Include url & image_url in create order call #1649 +* Enhancement - Include item_url & image_url to tracking call #1712 +* Enhancement - Update strings for tracking metabox #1714 +* Enhancement - Validate email address API credentials field #1691 +* Enhancement - Set payment method title for order edit page only if our gateway #1661 +* Enhancement - Fix missing Pay Later messages in cart + refactoring #1683 +* Enhancement - Product page PP button keep loading popup - "wc_add_to_cart_params is not defined" error in WooCommerce #1655 +* Enhancement - Remove PayPal Subscriptions API feature flag #1690 +* Enhancement - Don't send image_url when it is empty #1678 +* Enhancement - Subscription support depending on Vaulting setting instead of subscription mode setting #1697 +* Enhancement - Wrong PayPal subscription id on vaulted subscriptions #1699 +* Enhancement - Remove payment vaulted checker functionality (2030) #1711 * Feature preview - Apple Pay integration #1514 * Feature preview - Google Pay integration #1654 diff --git a/readme.txt b/readme.txt index b92654783..3310a7473 100644 --- a/readme.txt +++ b/readme.txt @@ -187,6 +187,12 @@ If you encounter issues with the PayPal buttons not appearing after an update, p * Fix - Since version > 2.2.0 the PayPal Checkout button on single product pages does not redirect anymore #1664 * Fix - PayPal fee and PayPal Payout do not change on order if we do partial refund #1578 * Fix - Order does not contain intent error when using ACDC payment token while buyer is not present #1506 +* Fix - Error when product description linked with a PayPal subscription exceeds 127 characters #1700 +* Fix - $_POST uses the wrong key to hold the shipping method #1652 +* Fix - WC Payment Token created multiple times when webhook is received #1663 +* Fix - Subtotal mismatch line name shows on Account settings page when merchant is disconnected #1702 +* Fix - Warning prevents payments on Pay for Order page when debugging is enabled #1703 +* Fix - paypal-overlay-uid_ blocks page after closing PayPal popup on Pay for Order page | Terms checkbox validation fails on Pay for Order page #1704 * Enhancement - Add support for HPOS for tracking module #1676 * Enhancement - Billing agreements endpoint called too frequently for Reference Transactions check #1646 * Enhancement - Do not declare subscription support for PayPal when only ACDC vaulting #1669 @@ -201,6 +207,20 @@ If you encounter issues with the PayPal buttons not appearing after an update, p * Enhancement - Compatibility with WooCommerce Product Add-Ons plugin #1586 * Enhancement - Remove "no shipment" message after adding tracking #1674 * Enhancement - Improve error & success validation messages #1675 +* Enhancement - Compatibility with third-party "Product Add-Ons" plugins #1601 +* Enhancement - PayPal logo flashes when switching between tabs #1345 +* Enhancement - Include url & image_url in create order call #1649 +* Enhancement - Include item_url & image_url to tracking call #1712 +* Enhancement - Update strings for tracking metabox #1714 +* Enhancement - Validate email address API credentials field #1691 +* Enhancement - Set payment method title for order edit page only if our gateway #1661 +* Enhancement - Fix missing Pay Later messages in cart + refactoring #1683 +* Enhancement - Product page PP button keep loading popup - "wc_add_to_cart_params is not defined" error in WooCommerce #1655 +* Enhancement - Remove PayPal Subscriptions API feature flag #1690 +* Enhancement - Don't send image_url when it is empty #1678 +* Enhancement - Subscription support depending on Vaulting setting instead of subscription mode setting #1697 +* Enhancement - Wrong PayPal subscription id on vaulted subscriptions #1699 +* Enhancement - Remove payment vaulted checker functionality (2030) #1711 * Feature preview - Apple Pay integration #1514 * Feature preview - Google Pay integration #1654 From 099b50728ebfd3bbe005741e0edaeb0eea9f1e8d Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 25 Sep 2023 09:52:53 +0300 Subject: [PATCH 03/39] Remove unused --- modules/ppcp-blocks/resources/js/checkout-block.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index 8dd1c69f7..2a670ddc0 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -125,10 +125,6 @@ const PayPalComponent = ({ shipping_address: addresses.shippingAddress, }); } - const checkoutUrl = new URL(config.scriptData.redirect); - // sometimes some browsers may load some kind of cached version of the page, - // so adding a parameter to avoid that - checkoutUrl.searchParams.append('ppcp-continuation-redirect', (new Date()).getTime().toString()); location.href = getCheckoutRedirectUrl(); } else { From 47ad89bab9bd4998f7613e900641e98a6818991a Mon Sep 17 00:00:00 2001 From: Alex P Date: Mon, 25 Sep 2023 15:31:38 +0300 Subject: [PATCH 04/39] Check validation errors before submit in block --- .../resources/js/checkout-block.js | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index 2a670ddc0..9a3b2afc2 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -89,6 +89,19 @@ const PayPalComponent = ({ const handleApprove = async (data, actions) => { try { + const order = await actions.order.get(); + + if (order) { + const addresses = paypalOrderToWcAddresses(order); + + await wp.data.dispatch('wc/store/cart').updateCustomerData({ + billing_address: addresses.billingAddress, + shipping_address: addresses.shippingAddress, + }); + } + + setPaypalOrder(order); + const res = await fetch(config.scriptData.ajax.approve_order.endpoint, { method: 'POST', credentials: 'same-origin', @@ -112,20 +125,12 @@ const PayPalComponent = ({ throw new Error(config.scriptData.labels.error.generic) } - const order = await actions.order.get(); - - setPaypalOrder(order); + if (wp.data.select('wc/store/validation').hasValidationErrors()) { + location.href = getCheckoutRedirectUrl(); + return; + } if (config.finalReviewEnabled) { - if (order) { - const addresses = paypalOrderToWcAddresses(order); - - await wp.data.dispatch('wc/store/cart').updateCustomerData({ - billing_address: addresses.billingAddress, - shipping_address: addresses.shippingAddress, - }); - } - location.href = getCheckoutRedirectUrl(); } else { onSubmit(); @@ -141,19 +146,6 @@ const PayPalComponent = ({ } }; - useEffect(() => { - const unsubscribe = onCheckoutValidation(() => { - if (config.scriptData.continuation) { - return true; - } - if (wp.data.select('wc/store/validation').hasValidationErrors()) { - location.href = getCheckoutRedirectUrl(); - return false; - } - }); - return unsubscribe; - }, [onCheckoutValidation] ); - const handleClick = (data, actions) => { if (isEditing) { return actions.reject(); From 40ac8fc54e0605e04d3f8702a4713f20ea6b76e6 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 25 Sep 2023 17:11:27 +0400 Subject: [PATCH 05/39] Disable tracking if transaction ID doesn't exist --- modules/ppcp-compat/src/AdminContextTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-compat/src/AdminContextTrait.php b/modules/ppcp-compat/src/AdminContextTrait.php index 0430f47ba..ed5583774 100644 --- a/modules/ppcp-compat/src/AdminContextTrait.php +++ b/modules/ppcp-compat/src/AdminContextTrait.php @@ -30,7 +30,7 @@ trait AdminContextTrait { return false; } - if ( ! $order->get_meta( PayPalGateway::ORDER_ID_META_KEY ) ) { + if ( ! $order->get_meta( PayPalGateway::ORDER_ID_META_KEY ) || empty( $order->get_transaction_id() ) ) { return false; } From e936c0070b3bc178d35466ab09833db9e7e9d538 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 25 Sep 2023 19:29:54 +0400 Subject: [PATCH 06/39] Validate info only for new shipments --- .../src/Endpoint/OrderTrackingEndpoint.php | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php b/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php index b6b749db3..ae2ca54f0 100644 --- a/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php +++ b/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php @@ -136,6 +136,7 @@ class OrderTrackingEndpoint { $order_id = (int) $data['order_id']; $action = $data['action'] ?? ''; + $this->validate_tracking_info( $data ); $shipment = $this->create_shipment( $order_id, $data ); $action === 'update' @@ -381,45 +382,53 @@ class OrderTrackingEndpoint { $carrier = $data['carrier'] ?? ''; $tracking_info = array( - 'transaction_id' => $data['transaction_id'] ?? '', - 'status' => $data['status'] ?? '', - 'tracking_number' => $data['tracking_number'] ?? '', - 'carrier' => $carrier, + 'transaction_id' => $data['transaction_id'] ?? '', + 'status' => $data['status'] ?? '', + 'tracking_number' => $data['tracking_number'] ?? '', + 'carrier' => $carrier, + 'carrier_name_other' => $data['carrier_name_other'] ?? '', ); if ( ! empty( $data['items'] ) ) { $tracking_info['items'] = array_map( 'intval', $data['items'] ); } - if ( $carrier === 'OTHER' ) { - $tracking_info['carrier_name_other'] = $data['carrier_name_other'] ?? ''; - } - - $this->validate_tracking_info( $tracking_info ); - return $this->shipment_factory->create_shipment( $wc_order_id, $tracking_info['transaction_id'], $tracking_info['tracking_number'], $tracking_info['status'], $tracking_info['carrier'], - $tracking_info['carrier_name_other'] ?? '', + $tracking_info['carrier_name_other'], $tracking_info['items'] ?? array() ); } /** - * Validates the requested tracking info. + * Validates tracking info for given request values. * - * @param array $tracking_info A map of tracking information keys to values. + * @param array $request_values A map of request keys to values. * @return void * @throws RuntimeException If validation failed. */ - protected function validate_tracking_info( array $tracking_info ): void { + protected function validate_tracking_info( array $request_values ): void { $error_message = __( 'Missing required information: ', 'woocommerce-paypal-payments' ); $empty_keys = array(); - foreach ( $tracking_info as $key => $value ) { + $carrier = $request_values['carrier'] ?? ''; + + $data_to_check = array( + 'transaction_id' => $request_values['transaction_id'] ?? '', + 'status' => $request_values['status'] ?? '', + 'tracking_number' => $request_values['tracking_number'] ?? '', + 'carrier' => $carrier, + ); + + if ( $carrier === 'OTHER' ) { + $data_to_check['carrier_name_other'] = $request_values['carrier_name_other'] ?? ''; + } + + foreach ( $data_to_check as $key => $value ) { if ( ! empty( $value ) ) { continue; } From fc22796ae4d0f9e571f1affe3cda2993cc806aa3 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 25 Sep 2023 19:31:18 +0400 Subject: [PATCH 07/39] Revert "Validate info only for new shipments" This reverts commit e936c0070b3bc178d35466ab09833db9e7e9d538. --- .../src/Endpoint/OrderTrackingEndpoint.php | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php b/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php index ae2ca54f0..b6b749db3 100644 --- a/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php +++ b/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php @@ -136,7 +136,6 @@ class OrderTrackingEndpoint { $order_id = (int) $data['order_id']; $action = $data['action'] ?? ''; - $this->validate_tracking_info( $data ); $shipment = $this->create_shipment( $order_id, $data ); $action === 'update' @@ -382,53 +381,45 @@ class OrderTrackingEndpoint { $carrier = $data['carrier'] ?? ''; $tracking_info = array( - 'transaction_id' => $data['transaction_id'] ?? '', - 'status' => $data['status'] ?? '', - 'tracking_number' => $data['tracking_number'] ?? '', - 'carrier' => $carrier, - 'carrier_name_other' => $data['carrier_name_other'] ?? '', + 'transaction_id' => $data['transaction_id'] ?? '', + 'status' => $data['status'] ?? '', + 'tracking_number' => $data['tracking_number'] ?? '', + 'carrier' => $carrier, ); if ( ! empty( $data['items'] ) ) { $tracking_info['items'] = array_map( 'intval', $data['items'] ); } + if ( $carrier === 'OTHER' ) { + $tracking_info['carrier_name_other'] = $data['carrier_name_other'] ?? ''; + } + + $this->validate_tracking_info( $tracking_info ); + return $this->shipment_factory->create_shipment( $wc_order_id, $tracking_info['transaction_id'], $tracking_info['tracking_number'], $tracking_info['status'], $tracking_info['carrier'], - $tracking_info['carrier_name_other'], + $tracking_info['carrier_name_other'] ?? '', $tracking_info['items'] ?? array() ); } /** - * Validates tracking info for given request values. + * Validates the requested tracking info. * - * @param array $request_values A map of request keys to values. + * @param array $tracking_info A map of tracking information keys to values. * @return void * @throws RuntimeException If validation failed. */ - protected function validate_tracking_info( array $request_values ): void { + protected function validate_tracking_info( array $tracking_info ): void { $error_message = __( 'Missing required information: ', 'woocommerce-paypal-payments' ); $empty_keys = array(); - $carrier = $request_values['carrier'] ?? ''; - - $data_to_check = array( - 'transaction_id' => $request_values['transaction_id'] ?? '', - 'status' => $request_values['status'] ?? '', - 'tracking_number' => $request_values['tracking_number'] ?? '', - 'carrier' => $carrier, - ); - - if ( $carrier === 'OTHER' ) { - $data_to_check['carrier_name_other'] = $request_values['carrier_name_other'] ?? ''; - } - - foreach ( $data_to_check as $key => $value ) { + foreach ( $tracking_info as $key => $value ) { if ( ! empty( $value ) ) { continue; } From 9c7e75e86a9a5a6b22a26fad73a6c3e637feb2b7 Mon Sep 17 00:00:00 2001 From: Narek Zakarian Date: Mon, 25 Sep 2023 19:35:48 +0400 Subject: [PATCH 08/39] Validate info only for new shipments --- .../src/Endpoint/OrderTrackingEndpoint.php | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php b/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php index b6b749db3..ae2ca54f0 100644 --- a/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php +++ b/modules/ppcp-order-tracking/src/Endpoint/OrderTrackingEndpoint.php @@ -136,6 +136,7 @@ class OrderTrackingEndpoint { $order_id = (int) $data['order_id']; $action = $data['action'] ?? ''; + $this->validate_tracking_info( $data ); $shipment = $this->create_shipment( $order_id, $data ); $action === 'update' @@ -381,45 +382,53 @@ class OrderTrackingEndpoint { $carrier = $data['carrier'] ?? ''; $tracking_info = array( - 'transaction_id' => $data['transaction_id'] ?? '', - 'status' => $data['status'] ?? '', - 'tracking_number' => $data['tracking_number'] ?? '', - 'carrier' => $carrier, + 'transaction_id' => $data['transaction_id'] ?? '', + 'status' => $data['status'] ?? '', + 'tracking_number' => $data['tracking_number'] ?? '', + 'carrier' => $carrier, + 'carrier_name_other' => $data['carrier_name_other'] ?? '', ); if ( ! empty( $data['items'] ) ) { $tracking_info['items'] = array_map( 'intval', $data['items'] ); } - if ( $carrier === 'OTHER' ) { - $tracking_info['carrier_name_other'] = $data['carrier_name_other'] ?? ''; - } - - $this->validate_tracking_info( $tracking_info ); - return $this->shipment_factory->create_shipment( $wc_order_id, $tracking_info['transaction_id'], $tracking_info['tracking_number'], $tracking_info['status'], $tracking_info['carrier'], - $tracking_info['carrier_name_other'] ?? '', + $tracking_info['carrier_name_other'], $tracking_info['items'] ?? array() ); } /** - * Validates the requested tracking info. + * Validates tracking info for given request values. * - * @param array $tracking_info A map of tracking information keys to values. + * @param array $request_values A map of request keys to values. * @return void * @throws RuntimeException If validation failed. */ - protected function validate_tracking_info( array $tracking_info ): void { + protected function validate_tracking_info( array $request_values ): void { $error_message = __( 'Missing required information: ', 'woocommerce-paypal-payments' ); $empty_keys = array(); - foreach ( $tracking_info as $key => $value ) { + $carrier = $request_values['carrier'] ?? ''; + + $data_to_check = array( + 'transaction_id' => $request_values['transaction_id'] ?? '', + 'status' => $request_values['status'] ?? '', + 'tracking_number' => $request_values['tracking_number'] ?? '', + 'carrier' => $carrier, + ); + + if ( $carrier === 'OTHER' ) { + $data_to_check['carrier_name_other'] = $request_values['carrier_name_other'] ?? ''; + } + + foreach ( $data_to_check as $key => $value ) { if ( ! empty( $value ) ) { continue; } From bea09b2ed487101da16d098323e2a673ba07fae3 Mon Sep 17 00:00:00 2001 From: Mayisha Date: Tue, 26 Sep 2023 14:14:58 +0600 Subject: [PATCH 09/39] woorelease: Product version bump update --- changelog.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 73671f93c..1a561daf6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ *** Changelog *** -= 2.3.0 - XXXX-XX-XX = += 2.3.0 - 2023-09-26 = * Fix - Plus sign in PayPal account email address gets converted to space #771 * Fix - Payment method dropdown option label on edit order screen for ppcp-gateway option displaying wrong name #1639 * Fix - WooCommerce Bookings products don't remain in Cart as a guest when PayPal button active on single product #1645 diff --git a/readme.txt b/readme.txt index 3310a7473..af7501ea7 100644 --- a/readme.txt +++ b/readme.txt @@ -180,7 +180,7 @@ If you encounter issues with the PayPal buttons not appearing after an update, p == Changelog == -= 2.3.0 - XXXX-XX-XX = += 2.3.0 - 2023-09-26 = * Fix - Plus sign in PayPal account email address gets converted to space #771 * Fix - Payment method dropdown option label on edit order screen for ppcp-gateway option displaying wrong name #1639 * Fix - WooCommerce Bookings products don't remain in Cart as a guest when PayPal button active on single product #1645 From b5e156d74c7b6407e2d7740f207944ca3ad977b6 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 26 Sep 2023 11:59:10 +0200 Subject: [PATCH 10/39] Fix subscriptions product class not found --- .../ppcp-subscription/src/SubscriptionModule.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 67c2b5c89..9193768e1 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -194,7 +194,18 @@ class SubscriptionModule implements ModuleInterface { //phpcs:disable WordPress.Security.NonceVerification.Recommended $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); $product = wc_get_product( $post_id ); - if ( ! ( is_a( $product, WC_Product::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { + if ( ! ( is_a( $product, WC_Product::class ) )) { + return; + } + + $subscriptions_helper = $c->get('subscription.helper'); + assert($subscriptions_helper instanceof SubscriptionHelper); + + if( + !$subscriptions_helper->plugin_is_active() + || ! is_a( $product, WC_Product_Subscription_Variation::class ) + || ! WC_Subscriptions_Product::is_subscription( $product ) + ) { return; } From 55c3b4f2c575d98441f43f1fa3376c7ea069a8a7 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 26 Sep 2023 12:09:21 +0200 Subject: [PATCH 11/39] Fix psalm --- modules/ppcp-subscription/src/SubscriptionModule.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 9193768e1..1731bc2e8 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -221,7 +221,6 @@ class SubscriptionModule implements ModuleInterface { $products = array( $this->set_product_config( $product ) ); if ( $product->get_type() === 'variable-subscription' ) { $products = array(); - assert( $product instanceof WC_Product_Variable ); $available_variations = $product->get_available_variations(); foreach ( $available_variations as $variation ) { /** From 30c1f61f3048edd83928c12c32f7db4337972195 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 26 Sep 2023 12:30:58 +0200 Subject: [PATCH 12/39] Fix psalm --- modules/ppcp-subscription/src/SubscriptionModule.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 1731bc2e8..487d9eba3 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -221,6 +221,13 @@ class SubscriptionModule implements ModuleInterface { $products = array( $this->set_product_config( $product ) ); if ( $product->get_type() === 'variable-subscription' ) { $products = array(); + + /** + * @psalm-suppress TypeDoesNotContainType + * + * WC_Product_Variable_Subscription extends WC_Product_Variable. + */ + assert( $product instanceof WC_Product_Variable ); $available_variations = $product->get_available_variations(); foreach ( $available_variations as $variation ) { /** From 7c4605d39bb8d17c82b95d53ae80f7024f86b58f Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 26 Sep 2023 12:39:09 +0200 Subject: [PATCH 13/39] Fix subscriptions product class not found --- modules/ppcp-subscription/src/SubscriptionModule.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 487d9eba3..84c91d88e 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -558,8 +558,13 @@ class SubscriptionModule implements ModuleInterface { */ function( $variation_id ) use ( $c ) { $wcsnonce_save_variations = wc_clean( wp_unslash( $_POST['_wcsnonce_save_variations'] ?? '' ) ); + + $subscriptions_helper = $c->get('subscription.helper'); + assert($subscriptions_helper instanceof SubscriptionHelper); + if ( - ! WC_Subscriptions_Product::is_subscription( $variation_id ) + !$subscriptions_helper->plugin_is_active() + || ! WC_Subscriptions_Product::is_subscription( $variation_id ) || ! is_string( $wcsnonce_save_variations ) || ! wp_verify_nonce( $wcsnonce_save_variations, 'wcs_subscription_variations' ) ) { From a8c2cb90353b02eee9317b0a768c1fe77a802814 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 26 Sep 2023 14:30:59 +0200 Subject: [PATCH 14/39] Check if `WC_Subscriptions_Product` class exist in `plugin_is_active` --- modules/ppcp-subscription/src/Helper/SubscriptionHelper.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index b09566c3e..760293541 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -13,6 +13,7 @@ namespace WooCommerce\PayPalCommerce\Subscription\Helper; use WC_Product; use WC_Product_Subscription_Variation; +use WC_Subscriptions; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; @@ -120,7 +121,7 @@ class SubscriptionHelper { */ public function plugin_is_active(): bool { - return class_exists( \WC_Subscriptions::class ); + return class_exists( WC_Subscriptions::class ) && class_exists(WC_Subscriptions_Product::class); } /** From 3fc228589fa0703c68a19790da9759d2a3eb223b Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Tue, 26 Sep 2023 14:22:25 +0100 Subject: [PATCH 15/39] Fix lint --- .../src/Helper/SubscriptionHelper.php | 2 +- .../src/SubscriptionModule.php | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index 760293541..9f803c5c5 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -121,7 +121,7 @@ class SubscriptionHelper { */ public function plugin_is_active(): bool { - return class_exists( WC_Subscriptions::class ) && class_exists(WC_Subscriptions_Product::class); + return class_exists( WC_Subscriptions::class ) && class_exists( WC_Subscriptions_Product::class ); } /** diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 84c91d88e..505794a6b 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -194,15 +194,15 @@ class SubscriptionModule implements ModuleInterface { //phpcs:disable WordPress.Security.NonceVerification.Recommended $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); $product = wc_get_product( $post_id ); - if ( ! ( is_a( $product, WC_Product::class ) )) { + if ( ! ( is_a( $product, WC_Product::class ) ) ) { return; } - $subscriptions_helper = $c->get('subscription.helper'); - assert($subscriptions_helper instanceof SubscriptionHelper); + $subscriptions_helper = $c->get( 'subscription.helper' ); + assert( $subscriptions_helper instanceof SubscriptionHelper ); - if( - !$subscriptions_helper->plugin_is_active() + if ( + ! $subscriptions_helper->plugin_is_active() || ! is_a( $product, WC_Product_Subscription_Variation::class ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { @@ -223,6 +223,8 @@ class SubscriptionModule implements ModuleInterface { $products = array(); /** + * Suppress pslam. + * * @psalm-suppress TypeDoesNotContainType * * WC_Product_Variable_Subscription extends WC_Product_Variable. @@ -559,11 +561,11 @@ class SubscriptionModule implements ModuleInterface { function( $variation_id ) use ( $c ) { $wcsnonce_save_variations = wc_clean( wp_unslash( $_POST['_wcsnonce_save_variations'] ?? '' ) ); - $subscriptions_helper = $c->get('subscription.helper'); - assert($subscriptions_helper instanceof SubscriptionHelper); + $subscriptions_helper = $c->get( 'subscription.helper' ); + assert( $subscriptions_helper instanceof SubscriptionHelper ); if ( - !$subscriptions_helper->plugin_is_active() + ! $subscriptions_helper->plugin_is_active() || ! WC_Subscriptions_Product::is_subscription( $variation_id ) || ! is_string( $wcsnonce_save_variations ) || ! wp_verify_nonce( $wcsnonce_save_variations, 'wcs_subscription_variations' ) From cfa6dfc5ff950f98cfcd5a184fa79a61a09dba80 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 26 Sep 2023 16:48:04 +0200 Subject: [PATCH 16/39] Bump 2.3.1 version --- changelog.txt | 5 +++++ package.json | 2 +- readme.txt | 7 ++++++- woocommerce-paypal-payments.php | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1a561daf6..7a684589d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ *** Changelog *** += 2.3.1 - xxxx-xx-xx = +* Fix - Fatal error when saving product while WooCommerce Subscriptions plugin is not active #1731 +* Fix - Validate tracking data only for add/update Package Tracking #1729 +* Fix - Disable Package Tracking for order if transaction ID doesn't exist #1727 + = 2.3.0 - 2023-09-26 = * Fix - Plus sign in PayPal account email address gets converted to space #771 * Fix - Payment method dropdown option label on edit order screen for ppcp-gateway option displaying wrong name #1639 diff --git a/package.json b/package.json index 60360b9ad..1f5b13aa8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "woocommerce-paypal-payments", - "version": "2.3.0", + "version": "2.3.1", "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 af7501ea7..ee116c89e 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.3 Requires PHP: 7.2 -Stable tag: 2.3.0 +Stable tag: 2.3.1 License: GPLv2 License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -180,6 +180,11 @@ If you encounter issues with the PayPal buttons not appearing after an update, p == Changelog == += 2.3.1 - xxxx-xx-xx = +* Fix - Fatal error when saving product while WooCommerce Subscriptions plugin is not active #1731 +* Fix - Validate tracking data only for add/update Package Tracking #1729 +* Fix - Disable Package Tracking for order if transaction ID doesn't exist #1727 + = 2.3.0 - 2023-09-26 = * Fix - Plus sign in PayPal account email address gets converted to space #771 * Fix - Payment method dropdown option label on edit order screen for ppcp-gateway option displaying wrong name #1639 diff --git a/woocommerce-paypal-payments.php b/woocommerce-paypal-payments.php index 436879749..81dad2f90 100644 --- a/woocommerce-paypal-payments.php +++ b/woocommerce-paypal-payments.php @@ -3,7 +3,7 @@ * 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.3.0 + * Version: 2.3.1 * Author: WooCommerce * Author URI: https://woocommerce.com/ * License: GPL-2.0 @@ -23,7 +23,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; define( 'PAYPAL_API_URL', 'https://api.paypal.com' ); define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' ); -define( 'PAYPAL_INTEGRATION_DATE', '2023-09-13' ); +define( 'PAYPAL_INTEGRATION_DATE', '2023-09-26' ); ! 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 e530382a7cc31651f236d9e33359311a6701baf6 Mon Sep 17 00:00:00 2001 From: Danae Millan Date: Tue, 26 Sep 2023 14:03:29 -0300 Subject: [PATCH 17/39] woorelease: Product version bump update --- changelog.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7a684589d..518db2346 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ *** Changelog *** -= 2.3.1 - xxxx-xx-xx = += 2.3.1 - 2023-09-26 = * Fix - Fatal error when saving product while WooCommerce Subscriptions plugin is not active #1731 * Fix - Validate tracking data only for add/update Package Tracking #1729 * Fix - Disable Package Tracking for order if transaction ID doesn't exist #1727 diff --git a/readme.txt b/readme.txt index ee116c89e..16701685b 100644 --- a/readme.txt +++ b/readme.txt @@ -180,7 +180,7 @@ If you encounter issues with the PayPal buttons not appearing after an update, p == Changelog == -= 2.3.1 - xxxx-xx-xx = += 2.3.1 - 2023-09-26 = * Fix - Fatal error when saving product while WooCommerce Subscriptions plugin is not active #1731 * Fix - Validate tracking data only for add/update Package Tracking #1729 * Fix - Disable Package Tracking for order if transaction ID doesn't exist #1727 From 631a0186bc05c3de6a32a07a26bd545ae8f25aa4 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 28 Sep 2023 10:19:51 +0100 Subject: [PATCH 18/39] Fix minicart HTML --- modules/ppcp-button/src/Assets/SmartButton.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 426bb9251..5e4533fee 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -482,7 +482,7 @@ class SmartButton implements SmartButtonInterface { echo '

'; echo ''; do_action( 'woocommerce_paypal_payments_minicart_button_render' ); - echo ''; + echo '

'; }, 30 ); From fcfbdbe1fa4891d1638ee648db139c425bec8616 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 28 Sep 2023 15:14:19 +0100 Subject: [PATCH 19/39] Fix SimulateCart to prevent cart race conditions --- modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php b/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php index 6862cc006..ed58eec06 100644 --- a/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php @@ -159,9 +159,7 @@ class SimulateCartEndpoint extends AbstractCartEndpoint { $this->remove_cart_items(); // Restore cart and unset cart clone. - if ( null !== $this->real_cart ) { - WC()->cart = $this->real_cart; - } + unset( WC()->cart ); unset( $this->cart ); } From a35515f5a17a809345959e1ab22085617d4dfa55 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 28 Sep 2023 16:36:25 +0200 Subject: [PATCH 20/39] Ensure description characters between 1-127 --- .../ppcp-subscription/src/SubscriptionsApiHandler.php | 11 +++++++---- tests/Playwright/tests/subscriptions-api.spec.js | 11 +++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php index 09513a340..eea8108a8 100644 --- a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php +++ b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php @@ -114,7 +114,7 @@ class SubscriptionsApiHandler { */ public function create_product( WC_Product $product ) { try { - $subscription_product = $this->products_endpoint->create( $product->get_title(), $product->get_description() ); + $subscription_product = $this->products_endpoint->create( $product->get_title(), $this->prepare_description($product->get_description()) ); $product->update_meta_data( 'ppcp_subscription_product', $subscription_product->to_array() ); $product->save(); } catch ( RuntimeException $exception ) { @@ -168,7 +168,10 @@ class SubscriptionsApiHandler { $catalog_product = $this->products_endpoint->product( $catalog_product_id ); $catalog_product_name = $catalog_product->name() ?: ''; $catalog_product_description = $catalog_product->description() ?: ''; - if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $product->get_description() ) { + + $wc_product_description = $this->prepare_description($product->get_description()) ?: $product->get_title(); + + if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $wc_product_description) { $data = array(); if ( $catalog_product_name !== $product->get_title() ) { $data[] = (object) array( @@ -177,11 +180,11 @@ class SubscriptionsApiHandler { 'value' => $product->get_title(), ); } - if ( $catalog_product_description !== $product->get_description() ) { + if ( $catalog_product_description !== $wc_product_description) { $data[] = (object) array( 'op' => 'replace', 'path' => '/description', - 'value' => $this->prepare_description( $product->get_description() ) ?: '', + 'value' => $wc_product_description, ); } diff --git a/tests/Playwright/tests/subscriptions-api.spec.js b/tests/Playwright/tests/subscriptions-api.spec.js index d575ed8f7..b8ad4b253 100644 --- a/tests/Playwright/tests/subscriptions-api.spec.js +++ b/tests/Playwright/tests/subscriptions-api.spec.js @@ -11,6 +11,16 @@ const { CART_URL, } = process.env; +const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ultricies integer quis auctor elit sed vulputate mi. Aliquam sem et tortor consequat id porta nibh venenatis cras. Massa enim nec dui nunc. Nulla porttitor massa id neque aliquam vestibulum morbi blandit cursus. Eu lobortis elementum nibh tellus molestie nunc. Euismod nisi porta lorem mollis aliquam ut porttitor. Ultrices tincidunt arcu non sodales neque sodales ut etiam. Urna cursus eget nunc scelerisque. Pulvinar sapien et ligula ullamcorper malesuada proin libero. Convallis a cras semper auctor neque vitae tempus quam pellentesque. Phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam. Cras tincidunt lobortis feugiat vivamus. Nec ultrices dui sapien eget mi proin sed libero enim. Neque gravida in fermentum et sollicitudin ac orci phasellus egestas. Aliquam faucibus purus in massa. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. At augue eget arcu dictum varius duis. Commodo ullamcorper a lacus vestibulum sed arcu non odio.\n' + + '\n' + + 'Id cursus metus aliquam eleifend mi in nulla. A diam sollicitudin tempor id eu nisl. Faucibus purus in massa tempor. Lacus luctus accumsan tortor posuere ac ut consequat. Mauris augue neque gravida in fermentum et sollicitudin ac. Venenatis tellus in metus vulputate. Consectetur libero id faucibus nisl tincidunt eget. Pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio. Dolor sed viverra ipsum nunc aliquet bibendum. Turpis in eu mi bibendum neque. Ac tincidunt vitae semper quis lectus nulla at volutpat. Felis imperdiet proin fermentum leo vel orci porta. Sed sed risus pretium quam vulputate dignissim.\n' + + '\n' + + 'Urna et pharetra pharetra massa massa ultricies mi quis. Egestas purus viverra accumsan in nisl nisi. Elit sed vulputate mi sit amet mauris commodo. Cras fermentum odio eu feugiat pretium nibh ipsum consequat. Justo laoreet sit amet cursus sit amet dictum. Nunc id cursus metus aliquam. Tortor at auctor urna nunc id. Quis lectus nulla at volutpat diam ut. Lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque. Tincidunt lobortis feugiat vivamus at augue eget arcu dictum varius.\n' + + '\n' + + 'Mattis nunc sed blandit libero. Vitae ultricies leo integer malesuada nunc vel risus. Dapibus ultrices in iaculis nunc. Interdum varius sit amet mattis. Tortor vitae purus faucibus ornare. Netus et malesuada fames ac turpis. Elit duis tristique sollicitudin nibh sit amet. Lacus suspendisse faucibus interdum posuere lorem. In pellentesque massa placerat duis. Fusce ut placerat orci nulla pellentesque dignissim. Dictum fusce ut placerat orci nulla pellentesque dignissim enim. Nibh sit amet commodo nulla facilisi. Maecenas sed enim ut sem. Non consectetur a erat nam at lectus urna duis convallis. Diam phasellus vestibulum lorem sed risus ultricies tristique nulla. Nunc congue nisi vitae suscipit. Tortor condimentum lacinia quis vel eros donec ac. Eleifend mi in nulla posuere.\n' + + '\n' + + 'Vestibulum lectus mauris ultrices eros. Massa sed elementum tempus egestas sed sed risus. Ut placerat orci nulla pellentesque dignissim enim sit. Duis ut diam quam nulla porttitor. Morbi tincidunt ornare massa eget egestas purus. Commodo sed egestas egestas fringilla phasellus faucibus scelerisque eleifend donec. Arcu odio ut sem nulla pharetra diam sit. Risus sed vulputate odio ut enim. Faucibus et molestie ac feugiat. A scelerisque purus semper eget. Odio facilisis mauris sit amet massa vitae tortor. Condimentum vitae sapien pellentesque habitant morbi tristique senectus. Nec feugiat in fermentum posuere urna. Volutpat est velit egestas dui id ornare arcu odio ut. Ullamcorper malesuada proin libero nunc consequat interdum. Suspendisse in est ante in nibh mauris cursus mattis molestie. Vel eros donec ac odio tempor orci dapibus. Et tortor at risus viverra adipiscing at in tellus. Metus aliquam eleifend mi in.' + async function purchaseSubscriptionFromCart(page) { await loginAsCustomer(page); await page.goto(SUBSCRIPTION_URL); @@ -98,6 +108,7 @@ test.describe.serial('Subscriptions Merchant', () => { await page.fill('#title', `Updated ${productTitle}`); await page.fill('#_subscription_price', '20'); + await page.fill('#content', longText) await Promise.all([ page.waitForNavigation(), From 2722c41a066c98df19dbd08c6284f11e2f1a4b2c Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 28 Sep 2023 16:56:26 +0200 Subject: [PATCH 21/39] Fix phpcs --- modules/ppcp-subscription/src/SubscriptionsApiHandler.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php index eea8108a8..663a8028d 100644 --- a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php +++ b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php @@ -114,7 +114,7 @@ class SubscriptionsApiHandler { */ public function create_product( WC_Product $product ) { try { - $subscription_product = $this->products_endpoint->create( $product->get_title(), $this->prepare_description($product->get_description()) ); + $subscription_product = $this->products_endpoint->create( $product->get_title(), $this->prepare_description( $product->get_description() ) ); $product->update_meta_data( 'ppcp_subscription_product', $subscription_product->to_array() ); $product->save(); } catch ( RuntimeException $exception ) { @@ -169,9 +169,9 @@ class SubscriptionsApiHandler { $catalog_product_name = $catalog_product->name() ?: ''; $catalog_product_description = $catalog_product->description() ?: ''; - $wc_product_description = $this->prepare_description($product->get_description()) ?: $product->get_title(); + $wc_product_description = $this->prepare_description( $product->get_description() ) ?: $product->get_title(); - if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $wc_product_description) { + if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $wc_product_description ) { $data = array(); if ( $catalog_product_name !== $product->get_title() ) { $data[] = (object) array( @@ -180,7 +180,7 @@ class SubscriptionsApiHandler { 'value' => $product->get_title(), ); } - if ( $catalog_product_description !== $wc_product_description) { + if ( $catalog_product_description !== $wc_product_description ) { $data[] = (object) array( 'op' => 'replace', 'path' => '/description', From 6979747caf12261b7af8ea420a5ff391cfb447e3 Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 29 Sep 2023 17:20:47 +0300 Subject: [PATCH 22/39] Use api-m PayPal API URLs Switched to the new API endpoints. Seems to work fine, the same as before. --- tests/PHPUnit/ModularTestCase.php | 4 ++-- .../tests/subscriptions-api.spec.js | 22 +++++++++---------- woocommerce-paypal-payments.php | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/PHPUnit/ModularTestCase.php b/tests/PHPUnit/ModularTestCase.php index a77f359e2..61583c4e1 100644 --- a/tests/PHPUnit/ModularTestCase.php +++ b/tests/PHPUnit/ModularTestCase.php @@ -40,8 +40,8 @@ class ModularTestCase extends TestCase $wpdb->posts = ''; $wpdb->postmeta = ''; - !defined('PAYPAL_API_URL') && define('PAYPAL_API_URL', 'https://api.paypal.com'); - !defined('PAYPAL_SANDBOX_API_URL') && define('PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com'); + !defined('PAYPAL_API_URL') && define('PAYPAL_API_URL', 'https://api-m.paypal.com'); + !defined('PAYPAL_SANDBOX_API_URL') && define('PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com'); !defined('PAYPAL_INTEGRATION_DATE') && define('PAYPAL_INTEGRATION_DATE', '2020-10-15'); !defined('PPCP_FLAG_SUBSCRIPTION') && define('PPCP_FLAG_SUBSCRIPTION', true); diff --git a/tests/Playwright/tests/subscriptions-api.spec.js b/tests/Playwright/tests/subscriptions-api.spec.js index d575ed8f7..0c0098059 100644 --- a/tests/Playwright/tests/subscriptions-api.spec.js +++ b/tests/Playwright/tests/subscriptions-api.spec.js @@ -57,7 +57,7 @@ test.describe.serial('Subscriptions Merchant', () => { const message = await page.locator('.notice-success'); await expect(message).toContainText('Product published.'); - const products = await request.get('https://api.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', { + const products = await request.get('https://api-m.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -73,7 +73,7 @@ test.describe.serial('Subscriptions Merchant', () => { product_id = product.id; - const plans = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans?product_id=${product_id}&page_size=10&page=1&total_required=true`, { + const plans = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans?product_id=${product_id}&page_size=10&page=1&total_required=true`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -107,7 +107,7 @@ test.describe.serial('Subscriptions Merchant', () => { const message = await page.locator('.notice-success'); await expect(message).toContainText('Product updated.'); - const products = await request.get('https://api.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', { + const products = await request.get('https://api-m.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -121,7 +121,7 @@ test.describe.serial('Subscriptions Merchant', () => { }); await expect(product.id).toBeTruthy; - const plan = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans/${plan_id}`, { + const plan = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans/${plan_id}`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -156,7 +156,7 @@ test('Create new free trial subscription product', async ({page, request}) => { const message = await page.locator('.notice-success'); await expect(message).toContainText('Product published.'); - const products = await request.get('https://api.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', { + const products = await request.get('https://api-m.sandbox.paypal.com/v1/catalogs/products?page_size=100&page=1&total_required=true', { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -170,7 +170,7 @@ test('Create new free trial subscription product', async ({page, request}) => { }); await expect(product.id).toBeTruthy; - const plans = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans?product_id=${product.id}&page_size=10&page=1&total_required=true`, { + const plans = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans?product_id=${product.id}&page_size=10&page=1&total_required=true`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -184,7 +184,7 @@ test('Create new free trial subscription product', async ({page, request}) => { }); await expect(plan.id).toBeTruthy; - const planDetail = await request.get(`https://api.sandbox.paypal.com/v1/billing/plans/${plan.id}`, { + const planDetail = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/plans/${plan.id}`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -253,7 +253,7 @@ test.describe('Subscriber my account actions', () => { await page.locator('text=View').first().click(); const subscriptionId = await page.locator('#ppcp-subscription-id').textContent(); - let subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { + let subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -267,7 +267,7 @@ test.describe('Subscriber my account actions', () => { const title = page.locator('.woocommerce-message'); await expect(title).toHaveText('Your subscription has been cancelled.'); - subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { + subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -285,7 +285,7 @@ test.describe('Subscriber my account actions', () => { await page.locator('text=View').first().click(); const subscriptionId = await page.locator('#ppcp-subscription-id').textContent(); - let subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { + let subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' @@ -299,7 +299,7 @@ test.describe('Subscriber my account actions', () => { const title = page.locator('.woocommerce-message'); await expect(title).toHaveText('Your subscription has been cancelled.'); - subscription = await request.get(`https://api.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { + subscription = await request.get(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}`, { headers: { 'Authorization': AUTHORIZATION, 'Content-Type': 'application/json' diff --git a/woocommerce-paypal-payments.php b/woocommerce-paypal-payments.php index 81dad2f90..dd438323f 100644 --- a/woocommerce-paypal-payments.php +++ b/woocommerce-paypal-payments.php @@ -21,8 +21,8 @@ namespace WooCommerce\PayPalCommerce; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; -define( 'PAYPAL_API_URL', 'https://api.paypal.com' ); -define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' ); +define( 'PAYPAL_API_URL', 'https://api-m.paypal.com' ); +define( 'PAYPAL_SANDBOX_API_URL', 'https://api-m.sandbox.paypal.com' ); define( 'PAYPAL_INTEGRATION_DATE', '2023-09-26' ); ! defined( 'CONNECT_WOO_CLIENT_ID' ) && define( 'CONNECT_WOO_CLIENT_ID', 'AcCAsWta_JTL__OfpjspNyH7c1GGHH332fLwonA5CwX4Y10mhybRZmHLA0GdRbwKwjQIhpDQy0pluX_P' ); From e083484ad738b68b055bf92d7eecf7c95739529f Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 5 Oct 2023 10:06:47 +0300 Subject: [PATCH 23/39] Check type --- modules/ppcp-subscription/src/SubscriptionModule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 505794a6b..39ba90cb3 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -656,7 +656,7 @@ class SubscriptionModule implements ModuleInterface { * @psalm-suppress MissingClosureParamType */ function( $actions, $subscription ): array { - if ( ! is_a( $subscription, WC_Subscription::class ) ) { + if ( ! is_array( $actions ) || ! is_a( $subscription, WC_Subscription::class ) ) { return $actions; } From fb1f0250f4b9fa7ef182ccfef419f554c81db196 Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 5 Oct 2023 10:09:03 +0300 Subject: [PATCH 24/39] Fix subscription retrieval in woocommerce_process_shop_subscription_meta --- .../src/SubscriptionModule.php | 85 ++++++++++--------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 39ba90cb3..94c7845f5 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -592,55 +592,60 @@ class SubscriptionModule implements ModuleInterface { * * @psalm-suppress MissingClosureParamType */ - function( $id, $subscription ) use ( $c ) { + function( $id, $post ) use ( $c ) { + $subscription = wcs_get_subscription( $id ); + if ( ! is_a( $subscription, WC_Subscription::class ) ) { + return; + } $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; - if ( $subscription_id ) { - $subscriptions_endpoint = $c->get( 'api.endpoint.billing-subscriptions' ); - assert( $subscriptions_endpoint instanceof BillingSubscriptions ); + if ( ! $subscription_id ) { + return; + } + $subscriptions_endpoint = $c->get( 'api.endpoint.billing-subscriptions' ); + assert( $subscriptions_endpoint instanceof BillingSubscriptions ); - if ( $subscription->get_status() === 'cancelled' ) { - try { - $subscriptions_endpoint->cancel( $subscription_id ); - } catch ( RuntimeException $exception ) { - $error = $exception->getMessage(); - if ( is_a( $exception, PayPalApiException::class ) ) { - $error = $exception->get_details( $error ); - } - - $logger = $c->get( 'woocommerce.logger.woocommerce' ); - $logger->error( 'Could not cancel subscription product on PayPal. ' . $error ); + if ( $subscription->get_status() === 'cancelled' ) { + try { + $subscriptions_endpoint->cancel( $subscription_id ); + } catch ( RuntimeException $exception ) { + $error = $exception->getMessage(); + if ( is_a( $exception, PayPalApiException::class ) ) { + $error = $exception->get_details( $error ); } + + $logger = $c->get( 'woocommerce.logger.woocommerce' ); + $logger->error( 'Could not cancel subscription product on PayPal. ' . $error ); } + } - if ( $subscription->get_status() === 'pending-cancel' ) { - try { - $subscriptions_endpoint->suspend( $subscription_id ); - } catch ( RuntimeException $exception ) { - $error = $exception->getMessage(); - if ( is_a( $exception, PayPalApiException::class ) ) { - $error = $exception->get_details( $error ); - } - - $logger = $c->get( 'woocommerce.logger.woocommerce' ); - $logger->error( 'Could not suspend subscription product on PayPal. ' . $error ); + if ( $subscription->get_status() === 'pending-cancel' ) { + try { + $subscriptions_endpoint->suspend( $subscription_id ); + } catch ( RuntimeException $exception ) { + $error = $exception->getMessage(); + if ( is_a( $exception, PayPalApiException::class ) ) { + $error = $exception->get_details( $error ); } + + $logger = $c->get( 'woocommerce.logger.woocommerce' ); + $logger->error( 'Could not suspend subscription product on PayPal. ' . $error ); } + } - if ( $subscription->get_status() === 'active' ) { - try { - $current_subscription = $subscriptions_endpoint->subscription( $subscription_id ); - if ( $current_subscription->status === 'SUSPENDED' ) { - $subscriptions_endpoint->activate( $subscription_id ); - } - } catch ( RuntimeException $exception ) { - $error = $exception->getMessage(); - if ( is_a( $exception, PayPalApiException::class ) ) { - $error = $exception->get_details( $error ); - } - - $logger = $c->get( 'woocommerce.logger.woocommerce' ); - $logger->error( 'Could not reactivate subscription product on PayPal. ' . $error ); + if ( $subscription->get_status() === 'active' ) { + try { + $current_subscription = $subscriptions_endpoint->subscription( $subscription_id ); + if ( $current_subscription->status === 'SUSPENDED' ) { + $subscriptions_endpoint->activate( $subscription_id ); } + } catch ( RuntimeException $exception ) { + $error = $exception->getMessage(); + if ( is_a( $exception, PayPalApiException::class ) ) { + $error = $exception->get_details( $error ); + } + + $logger = $c->get( 'woocommerce.logger.woocommerce' ); + $logger->error( 'Could not reactivate subscription product on PayPal. ' . $error ); } } }, From 7df1b04a4f658cdf71bc919790894614e446df9f Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 5 Oct 2023 16:19:36 +0300 Subject: [PATCH 25/39] Change default ACDC title --- modules/ppcp-wc-gateway/services.php | 2 +- modules/ppcp-wc-gateway/src/Settings/Settings.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 8a825b0b1..23223d3c6 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -487,7 +487,7 @@ return array( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ), - 'default' => __( 'Credit Cards', 'woocommerce-paypal-payments' ), + 'default' => __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ), 'desc_tip' => true, 'screens' => array( State::STATE_ONBOARDED, diff --git a/modules/ppcp-wc-gateway/src/Settings/Settings.php b/modules/ppcp-wc-gateway/src/Settings/Settings.php index aa0981a03..1eca02587 100644 --- a/modules/ppcp-wc-gateway/src/Settings/Settings.php +++ b/modules/ppcp-wc-gateway/src/Settings/Settings.php @@ -116,7 +116,7 @@ class Settings implements ContainerInterface { 'pay_later_button_locations' => $this->default_button_locations, 'pay_later_messaging_locations' => $this->default_button_locations, 'brand_name' => get_bloginfo( 'name' ), - 'dcc_gateway_title' => __( 'Credit Cards', 'woocommerce-paypal-payments' ), + 'dcc_gateway_title' => __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ), 'dcc_gateway_description' => __( 'Pay with your credit card.', 'woocommerce-paypal-payments' From 65f60728c77ed5493430ebbf64fba82a40d82143 Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 6 Oct 2023 09:52:24 +0300 Subject: [PATCH 26/39] Refactor ACDC title duplication --- modules/ppcp-wc-gateway/services.php | 12 +++++++++--- modules/ppcp-wc-gateway/src/Settings/Settings.php | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 23223d3c6..cba701931 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -201,8 +201,10 @@ return array( }, 'wcgateway.settings' => static function ( ContainerInterface $container ): Settings { - $default_button_locations = $container->get( 'wcgateway.button.default-locations' ); - return new Settings( $default_button_locations ); + return new Settings( + $container->get( 'wcgateway.button.default-locations' ), + $container->get( 'wcgateway.settings.dcc-gateway-title.default' ) + ); }, 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice { $state = $container->get( 'onboarding.state' ); @@ -487,7 +489,7 @@ return array( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ), - 'default' => __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ), + 'default' => $container->get( 'wcgateway.settings.dcc-gateway-title.default' ), 'desc_tip' => true, 'screens' => array( State::STATE_ONBOARDED, @@ -1186,6 +1188,10 @@ return array( return $vaulting_label; }, + 'wcgateway.settings.dcc-gateway-title.default' => static function ( ContainerInterface $container ): string { + return __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ); + }, + 'wcgateway.settings.card_billing_data_mode.default' => static function ( ContainerInterface $container ): string { return $container->get( 'api.shop.is-latin-america' ) ? CardBillingMode::MINIMAL_INPUT : CardBillingMode::USE_WC; }, diff --git a/modules/ppcp-wc-gateway/src/Settings/Settings.php b/modules/ppcp-wc-gateway/src/Settings/Settings.php index 1eca02587..9abca804d 100644 --- a/modules/ppcp-wc-gateway/src/Settings/Settings.php +++ b/modules/ppcp-wc-gateway/src/Settings/Settings.php @@ -35,13 +35,22 @@ class Settings implements ContainerInterface { */ protected $default_button_locations; + /** + * The default ACDC gateway title. + * + * @var string + */ + protected $default_dcc_gateway_title; + /** * Settings constructor. * * @param string[] $default_button_locations The list of selected default button locations. + * @param string $default_dcc_gateway_title The default ACDC gateway title. */ - public function __construct( array $default_button_locations ) { - $this->default_button_locations = $default_button_locations; + public function __construct( array $default_button_locations, string $default_dcc_gateway_title ) { + $this->default_button_locations = $default_button_locations; + $this->default_dcc_gateway_title = $default_dcc_gateway_title; } /** @@ -116,7 +125,7 @@ class Settings implements ContainerInterface { 'pay_later_button_locations' => $this->default_button_locations, 'pay_later_messaging_locations' => $this->default_button_locations, 'brand_name' => get_bloginfo( 'name' ), - 'dcc_gateway_title' => __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ), + 'dcc_gateway_title' => $this->default_dcc_gateway_title, 'dcc_gateway_description' => __( 'Pay with your credit card.', 'woocommerce-paypal-payments' From ccb874b0b946cec38ac50a925da23cbaca7ef90e Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 6 Oct 2023 18:04:36 +0300 Subject: [PATCH 27/39] Make Settings singleton --- modules/ppcp-wc-gateway/services.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 8a825b0b1..bc5dbf3a2 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -200,10 +200,12 @@ return array( return $ppcp_tab ? $ppcp_tab : $section; }, - 'wcgateway.settings' => static function ( ContainerInterface $container ): Settings { - $default_button_locations = $container->get( 'wcgateway.button.default-locations' ); - return new Settings( $default_button_locations ); - }, + 'wcgateway.settings' => SingletonDecorator::make( + static function ( ContainerInterface $container ): Settings { + $default_button_locations = $container->get( 'wcgateway.button.default-locations' ); + return new Settings( $default_button_locations ); + } + ), 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice { $state = $container->get( 'onboarding.state' ); $settings = $container->get( 'wcgateway.settings' ); From 6f6b3ac1c1c41e0003d83b9ac7c8444a9bc345c3 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Mon, 9 Oct 2023 10:07:17 +0100 Subject: [PATCH 28/39] Update comments --- modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php b/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php index ed58eec06..171dc6c81 100644 --- a/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php @@ -151,6 +151,7 @@ class SimulateCartEndpoint extends AbstractCartEndpoint { /** * Restores the real cart. + * Currently, unsets the WC cart to prevent race conditions arising from it being persisted. * * @return void */ @@ -158,7 +159,7 @@ class SimulateCartEndpoint extends AbstractCartEndpoint { // Remove from cart because some plugins reserve resources internally when adding to cart. $this->remove_cart_items(); - // Restore cart and unset cart clone. + // Unset cart to prevent it being updated/persisted. unset( WC()->cart ); unset( $this->cart ); } From c3fc37d1a5c5f9ec3093c431ae6713b1e9775926 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 9 Oct 2023 13:06:05 +0200 Subject: [PATCH 29/39] Ensure plan name is not empty when creating plan --- modules/ppcp-subscription/src/SubscriptionsApiHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php index 09513a340..d16d79d76 100644 --- a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php +++ b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php @@ -137,7 +137,7 @@ class SubscriptionsApiHandler { public function create_plan( string $plan_name, WC_Product $product ): void { try { $subscription_plan = $this->billing_plans_endpoint->create( - $plan_name, + $plan_name ?: $product->get_title(), $product->get_meta( 'ppcp_subscription_product' )['id'] ?? '', $this->billing_cycles( $product ), $this->payment_preferences_factory->from_wc_product( $product )->to_array() From 572d1b8f9977d358fc8df6276b03e10f19f632b8 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 9 Oct 2023 14:46:42 +0200 Subject: [PATCH 30/39] Ensure js resource is loaded for subscription products --- modules/ppcp-subscription/src/SubscriptionModule.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 505794a6b..d0301c577 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Subscription; use ActionScheduler_Store; use Exception; use WC_Product; +use WC_Product_Subscription; use WC_Product_Subscription_Variation; use WC_Product_Variable; use WC_Product_Variable_Subscription; @@ -203,7 +204,7 @@ class SubscriptionModule implements ModuleInterface { if ( ! $subscriptions_helper->plugin_is_active() - || ! is_a( $product, WC_Product_Subscription_Variation::class ) + || ! ( is_a( $product, WC_Product_Subscription::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { return; From bc818816ab2cb5ee0649e637fc90c93f91ce4102 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 10 Oct 2023 10:36:42 +0300 Subject: [PATCH 31/39] Fix merge --- modules/ppcp-wc-gateway/services.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 3473a4cd0..0044f7ea1 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -202,8 +202,10 @@ return array( 'wcgateway.settings' => SingletonDecorator::make( static function ( ContainerInterface $container ): Settings { - $default_button_locations = $container->get( 'wcgateway.button.default-locations' ); - return new Settings( $default_button_locations ); + return new Settings( + $container->get( 'wcgateway.button.default-locations' ), + $container->get( 'wcgateway.settings.dcc-gateway-title.default' ) + ); } ), 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice { From a49d7b958f96e767ee2eb218f85490ef7736056a Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 10 Oct 2023 09:46:04 +0200 Subject: [PATCH 32/39] Fix merge conflict --- modules/ppcp-wc-gateway/services.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 3473a4cd0..0044f7ea1 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -202,8 +202,10 @@ return array( 'wcgateway.settings' => SingletonDecorator::make( static function ( ContainerInterface $container ): Settings { - $default_button_locations = $container->get( 'wcgateway.button.default-locations' ); - return new Settings( $default_button_locations ); + return new Settings( + $container->get( 'wcgateway.button.default-locations' ), + $container->get( 'wcgateway.settings.dcc-gateway-title.default' ) + ); } ), 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice { From b06a73a8159dadcafb37e8fdb31df662c97383f7 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 10 Oct 2023 11:35:23 +0200 Subject: [PATCH 33/39] Ensure js resource is loaded for variable subscription products --- modules/ppcp-subscription/src/SubscriptionModule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index d0301c577..2f07e8293 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -204,7 +204,7 @@ class SubscriptionModule implements ModuleInterface { if ( ! $subscriptions_helper->plugin_is_active() - || ! ( is_a( $product, WC_Product_Subscription::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) ) + || ! ( is_a( $product, WC_Product_Subscription::class ) || is_a( $product, WC_Product_Variable_Subscription::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { return; From 613665f43e6bf7a7c22201129830dc689818ddd7 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 11 Oct 2023 10:10:45 +0300 Subject: [PATCH 34/39] Revert "check validation before submit", also check in onPaymentSetup --- .../resources/js/checkout-block.js | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index 9a3b2afc2..ab4fbd3f9 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -125,11 +125,6 @@ const PayPalComponent = ({ throw new Error(config.scriptData.labels.error.generic) } - if (wp.data.select('wc/store/validation').hasValidationErrors()) { - location.href = getCheckoutRedirectUrl(); - return; - } - if (config.finalReviewEnabled) { location.href = getCheckoutRedirectUrl(); } else { @@ -146,6 +141,21 @@ const PayPalComponent = ({ } }; + useEffect(() => { + const unsubscribe = onCheckoutValidation(() => { + if (config.scriptData.continuation) { + return true; + } + if (wp.data.select('wc/store/validation').hasValidationErrors()) { + location.href = getCheckoutRedirectUrl(); + return false; + } + + return true; + }); + return unsubscribe; + }, [onCheckoutValidation] ); + const handleClick = (data, actions) => { if (isEditing) { return actions.reject(); @@ -201,6 +211,12 @@ const PayPalComponent = ({ } const unsubscribeProcessing = onPaymentSetup(() => { + if (wp.data.select('wc/store/validation').hasValidationErrors()) { + return { + type: responseTypes.ERROR, + }; + } + if (config.scriptData.continuation) { return { type: responseTypes.SUCCESS, From 62e824fd921b44392eaa9238fb8cf9fd2510432d Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 11 Oct 2023 09:22:55 +0200 Subject: [PATCH 35/39] Fix psalm --- .psalm/wcs.php | 13 +++++++++++++ .../ppcp-subscription/src/SubscriptionModule.php | 6 +++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.psalm/wcs.php b/.psalm/wcs.php index cc33e0103..1698c98c0 100644 --- a/.psalm/wcs.php +++ b/.psalm/wcs.php @@ -2107,3 +2107,16 @@ function wc_get_page_screen_id( $for ) {} * */ class WC_Product_Subscription_Variation extends WC_Product_Variation {} + +/** + * Variable Subscription Product Class + * + * This class extends the WC Variable product class to create variable products with recurring payments. + * + * @class WC_Product_Variable_Subscription + * @package WooCommerce Subscriptions + * @category Class + * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3 + * + */ +class WC_Product_Variable_Subscription extends WC_Product_Variable {} diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 2f07e8293..bf090efb8 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -204,7 +204,11 @@ class SubscriptionModule implements ModuleInterface { if ( ! $subscriptions_helper->plugin_is_active() - || ! ( is_a( $product, WC_Product_Subscription::class ) || is_a( $product, WC_Product_Variable_Subscription::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) ) + || ! ( + is_a( $product, WC_Product_Subscription::class ) + || is_a( $product, WC_Product_Variable_Subscription::class ) + || is_a( $product, WC_Product_Subscription_Variation::class ) + ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { return; From 18f8b83b61bdf0347a20566ae53ebbecc779439c Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 11 Oct 2023 10:43:33 +0300 Subject: [PATCH 36/39] Fix failed validation response the 2nd check seems to not needed now --- modules/ppcp-blocks/resources/js/checkout-block.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index ab4fbd3f9..99cd94799 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -148,7 +148,7 @@ const PayPalComponent = ({ } if (wp.data.select('wc/store/validation').hasValidationErrors()) { location.href = getCheckoutRedirectUrl(); - return false; + return { type: responseTypes.ERROR }; } return true; @@ -211,12 +211,6 @@ const PayPalComponent = ({ } const unsubscribeProcessing = onPaymentSetup(() => { - if (wp.data.select('wc/store/validation').hasValidationErrors()) { - return { - type: responseTypes.ERROR, - }; - } - if (config.scriptData.continuation) { return { type: responseTypes.SUCCESS, From 9059ef7f2506c5f0a31e065ac7a6cbdbf140e5d5 Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 12 Oct 2023 10:18:58 +0300 Subject: [PATCH 37/39] Fill form locally before submit when no-review mode --- .../resources/js/checkout-block.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js index 99cd94799..2ec60bfb3 100644 --- a/modules/ppcp-blocks/resources/js/checkout-block.js +++ b/modules/ppcp-blocks/resources/js/checkout-block.js @@ -94,10 +94,21 @@ const PayPalComponent = ({ if (order) { const addresses = paypalOrderToWcAddresses(order); - await wp.data.dispatch('wc/store/cart').updateCustomerData({ - billing_address: addresses.billingAddress, - shipping_address: addresses.shippingAddress, - }); + let promises = [ + // save address on server + wp.data.dispatch('wc/store/cart').updateCustomerData({ + billing_address: addresses.billingAddress, + shipping_address: addresses.shippingAddress, + }), + ]; + if (!config.finalReviewEnabled) { + // set address in UI + promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress)); + if (shippingData.needsShipping) { + promises.push(wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress)) + } + } + await Promise.all(promises); } setPaypalOrder(order); From b29da6a62749b6bc7d493ffbcd3bd116cfa75be3 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 12 Oct 2023 18:22:55 +0100 Subject: [PATCH 38/39] Add simulate cart hooks --- .../ContextBootstrap/SingleProductBootstap.js | 7 ++++++- modules/ppcp-button/src/Assets/SmartButton.php | 4 ++++ .../src/Endpoint/SimulateCartEndpoint.php | 13 +++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 5ff7f2a80..c8b7e386f 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -17,7 +17,7 @@ class SingleProductBootstap { this.formSelector = 'form.cart'; // Prevent simulate cart being called too many times in a burst. - this.simulateCartThrottled = throttle(this.simulateCart, 5000); + this.simulateCartThrottled = throttle(this.simulateCart, this.gateway.simulate_cart.throttling || 5000); this.renderer.onButtonsInit(this.gateway.button.wrapper, () => { this.handleChange(); @@ -217,6 +217,11 @@ class SingleProductBootstap { } simulateCart() { + // Check of cart simulation is enabled. + if (!this.gateway.simulate_cart.enabled) { + return; + } + const actionHandler = new SingleProductActionHandler( null, null, diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 426bb9251..6b29d1dc7 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -963,6 +963,10 @@ class SmartButton implements SmartButtonInterface { // phpcs:ignore WordPress.WP.I18n 'shipping_field' => _x( 'Shipping %s', 'checkout-validation', 'woocommerce' ), ), + 'simulate_cart' => array( + 'enabled' => apply_filters( 'woocommerce_paypal_payments_simulate_cart_enabled', true ), + 'throttling' => apply_filters( 'woocommerce_paypal_payments_simulate_cart_throttling', 5000 ), + ), 'order_id' => 'pay-now' === $this->context() ? $this->get_order_pay_id() : 0, 'single_product_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'product' ), 'mini_cart_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' ), diff --git a/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php b/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php index 171dc6c81..25ac4ba91 100644 --- a/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/SimulateCartEndpoint.php @@ -159,8 +159,17 @@ class SimulateCartEndpoint extends AbstractCartEndpoint { // Remove from cart because some plugins reserve resources internally when adding to cart. $this->remove_cart_items(); - // Unset cart to prevent it being updated/persisted. - unset( WC()->cart ); + if ( apply_filters( 'woocommerce_paypal_payments_simulate_cart_prevent_updates', true ) ) { + // Removes shutdown actions to prevent persisting session, transients and save cookies. + remove_all_actions( 'shutdown' ); + unset( WC()->cart ); + } else { + // Restores cart, may lead to race conditions. + if ( null !== $this->real_cart ) { + WC()->cart = $this->real_cart; + } + } + unset( $this->cart ); } From bd1c683fabc5cce9dea90183b88f30c0a6f2c830 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Fri, 13 Oct 2023 10:05:56 +0100 Subject: [PATCH 39/39] Remove comment --- .../js/modules/ContextBootstrap/SingleProductBootstap.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index c8b7e386f..c9978306e 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -217,7 +217,6 @@ class SingleProductBootstap { } simulateCart() { - // Check of cart simulation is enabled. if (!this.gateway.simulate_cart.enabled) { return; }