diff --git a/changelog.txt b/changelog.txt index fbeb13826..37ca53711 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,16 @@ *** Changelog *** += 1.8.2 - TBD = +* Fix - Order not approved: payment via vaulted PayPal account fails #677 +* Fix - Something went wrong error in Virtual products when using vaulted payment #673 +* Fix - PayPal smart buttons are not displayed for product variations when parent product is set to out of stock #669 +* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667 +* Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665 +* Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661 +* Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654 +* Fix - Checkout using an email address containing a + symbol results in a "[INVALID_REQUEST]" error #523 +* Enhancement - Improve checkout validation & order creation #513 + = 1.8.1 - 2022-05-31 = * Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530 * Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605 diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index 24bcd1a21..6be5355be 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -47,6 +47,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory; use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies; +use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper; use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository; use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository; use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository; @@ -671,4 +672,7 @@ return array( 'SE', ); }, + 'api.order-helper' => static function( ContainerInterface $container ): OrderHelper { + return new OrderHelper(); + }, ); diff --git a/modules/ppcp-api-client/src/Factory/PayerFactory.php b/modules/ppcp-api-client/src/Factory/PayerFactory.php index 6bec8fe80..5716d99cc 100644 --- a/modules/ppcp-api-client/src/Factory/PayerFactory.php +++ b/modules/ppcp-api-client/src/Factory/PayerFactory.php @@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerName; use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerTaxInfo; use WooCommerce\PayPalCommerce\ApiClient\Entity\Phone; use WooCommerce\PayPalCommerce\ApiClient\Entity\PhoneWithType; +use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; /** * Class PayerFactory @@ -158,6 +159,7 @@ class PayerFactory { * * @param array $form_fields The checkout form fields. * @return Payer + * @throws RuntimeException When invalid data. */ public function from_checkout_form( array $form_fields ): Payer { @@ -189,6 +191,14 @@ class PayerFactory { } } + if ( ! is_email( $billing_email ) ) { + /* + phpcs:disable WordPress.WP.I18n.TextDomainMismatch + translators: %s: email address + */ + throw new RuntimeException( sprintf( __( '%s is not a valid email address.', 'woocommerce' ), esc_html( $billing_email ) ) ); + } + return new Payer( new PayerName( $first_name, $last_name ), $billing_email, diff --git a/modules/ppcp-api-client/src/Helper/OrderHelper.php b/modules/ppcp-api-client/src/Helper/OrderHelper.php new file mode 100644 index 000000000..25e5124e2 --- /dev/null +++ b/modules/ppcp-api-client/src/Helper/OrderHelper.php @@ -0,0 +1,34 @@ +purchase_units() as $unit ) { + if ( $unit->contains_physical_goods() ) { + return true; + } + } + + return false; + } +} diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js index 1ecda5a95..c416521a0 100644 --- a/modules/ppcp-button/resources/js/button.js +++ b/modules/ppcp-button/resources/js/button.js @@ -31,6 +31,19 @@ const bootstrap = () => { const onSmartButtonClick = (data, actions) => { window.ppcpFundingSource = data.fundingSource; + // TODO: quick fix to get the error about empty form before attempting PayPal order + // it should solve #513 for most of the users, but proper solution should be implemented later. + const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input'); + requiredFields.each((i, input) => { + jQuery(input).trigger('validate'); + }); + if (jQuery('form.woocommerce-checkout .woocommerce-invalid').length) { + errorHandler.clear(); + errorHandler.message(PayPalCommerceGateway.labels.error.js_validation); + + return actions.reject(); + } + const form = document.querySelector('form.woocommerce-checkout'); if (form) { jQuery('#ppcp-funding-source-form-input').remove(); diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js index 625fd369b..733b5e339 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js @@ -20,7 +20,9 @@ class CheckoutActionHandler { const errorHandler = this.errorHandler; const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review'; - const formValues = jQuery(formSelector).serialize(); + const formData = new FormData(document.querySelector(formSelector)); + // will not handle fields with multiple values (checkboxes,