Skip to content

Commit

Permalink
Merge release/8.0.2 into trunk
Browse files Browse the repository at this point in the history
  • Loading branch information
cesarcosta99 committed Aug 7, 2024
2 parents 06621e1 + d8bbbe7 commit 106db15
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 68 deletions.
5 changes: 5 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
*** WooPayments Changelog ***

= 8.0.2 - 2024-08-07 =
* Fix - Add opt-in checks to prevent blocking customers using other payment methods.
* Fix - Fix error in Express Checkout Element use with coupons.
* Fix - Only enable Direct Checkout when WooPayments gateway is enabled.

= 8.0.1 - 2024-07-31 =
* Fix - Reverts changes related to Direct Checkout that broke the PayPal extension.

Expand Down
99 changes: 54 additions & 45 deletions client/components/woopay/save-user/checkout-page-save-user.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable max-len */
/* global jQuery */
/**
* External dependencies
*/
Expand Down Expand Up @@ -131,55 +132,51 @@ const CheckoutPageSaveUser = ( { isBlocksCheckout } ) => {
}, [ isPhoneValid ] );

useEffect( () => {
const formSubmitButton = isBlocksCheckout
? document.querySelector(
'button.wc-block-components-checkout-place-order-button'
)
: document.querySelector(
'form.woocommerce-checkout button[type="submit"]'
);
const checkoutForm = jQuery( 'form.woocommerce-checkout' );

if ( ! formSubmitButton ) {
checkoutForm.on( 'checkout_place_order', function () {
jQuery( '#validate-error-invalid-woopay-phone-number' ).show();
} );
}, [] );

const updatePhoneNumberValidationError = useCallback( () => {
if ( ! isSaveDetailsChecked ) {
clearValidationError( errorId );
if ( isPhoneValid !== null ) {
onPhoneValidationChange( null );
}
return;
}

const updateFormSubmitButton = () => {
if ( isSaveDetailsChecked && isPhoneValid ) {
clearValidationError( errorId );

// Set extension data if checkbox is selected and phone number is valid in blocks checkout.
if ( isBlocksCheckout ) {
sendExtensionData( false );
}
}
if ( isSaveDetailsChecked && isPhoneValid ) {
clearValidationError( errorId );

if ( isSaveDetailsChecked && ! isPhoneValid ) {
setValidationErrors( {
[ errorId ]: {
message: __(
'Please enter a valid mobile phone number.',
'woocommerce-payments'
),
// Hides errors when the number has not been typed yet but shows when trying to place the order.
hidden: isPhoneValid === null,
},
} );
// Set extension data if checkbox is selected and phone number is valid in blocks checkout.
if ( isBlocksCheckout ) {
sendExtensionData( false );
}
};

updateFormSubmitButton();
return;
}

return () => {
clearValidationError( errorId );
};
if ( isSaveDetailsChecked && ! isPhoneValid ) {
setValidationErrors( {
[ errorId ]: {
message: __(
'Please enter a valid mobile phone number.',
'woocommerce-payments'
),
// Hides errors when the number has not been typed yet but shows when trying to place the order.
hidden: isPhoneValid === null,
},
} );
}
}, [
setValidationErrors,
errorId,
clearValidationError,
isBlocksCheckout,
isPhoneValid,
isSaveDetailsChecked,
sendExtensionData,
setValidationErrors,
] );

// In classic checkout the saved tokens are under WCPay, so we need to check if new token is selected or not,
Expand All @@ -198,9 +195,12 @@ const CheckoutPageSaveUser = ( { isBlocksCheckout } ) => {
if ( isBlocksCheckout && userDataSent ) {
sendExtensionData( true );
}
clearValidationError( errorId );
return null;
}

updatePhoneNumberValidationError();

return (
<Container
isBlocksCheckout={ isBlocksCheckout }
Expand Down Expand Up @@ -270,11 +270,7 @@ const CheckoutPageSaveUser = ( { isBlocksCheckout } ) => {
name="woopay_viewport"
value={ `${ viewportWidth }x${ viewportHeight }` }
/>
<div
className={
isPhoneValid === false ? 'has-error' : ''
}
>
<div className={ isPhoneValid ? '' : 'has-error' }>
<PhoneNumberInput
value={ phoneNumber }
onValueChange={ setPhoneNumber }
Expand All @@ -289,10 +285,23 @@ const CheckoutPageSaveUser = ( { isBlocksCheckout } ) => {
isBlocksCheckout={ isBlocksCheckout }
/>
</div>
<ValidationInputError
elementId={ errorId }
propertyName={ errorId }
/>
{ isBlocksCheckout && (
<ValidationInputError
elementId={ errorId }
propertyName={ errorId }
/>
) }
{ ! isBlocksCheckout && ! isPhoneValid && (
<p
id="validate-error-invalid-woopay-phone-number"
hidden={ isPhoneValid !== false }
>
{ __(
'Please enter a valid mobile phone number.',
'woocommerce-payments'
) }
</p>
) }
<AdditionalInformation />
<Agreement />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
// eslint-disable-next-line import/no-unresolved
import { extensionCartUpdate } from '@woocommerce/blocks-checkout';
import { addAction } from '@wordpress/hooks';

/**
* Internal dependencies
Expand All @@ -16,6 +17,30 @@ import useSelectedPaymentMethod from '../../hooks/use-selected-payment-method';
import { getConfig } from 'utils/checkout';
import { useDispatch } from '@wordpress/data';

const jQueryMock = ( selector ) => {
if ( typeof selector === 'function' ) {
return selector( jQueryMock );
}

return {
on: ( event, callbackOrSelector, callback2 ) =>
addAction(
`payment-request-test.jquery-event.${ selector }${
typeof callbackOrSelector === 'string'
? `.${ callbackOrSelector }`
: ''
}.${ event }`,
'tests',
typeof callbackOrSelector === 'string'
? callback2
: callbackOrSelector
),
val: () => null,
is: () => null,
remove: () => null,
};
};

jest.mock( '../../hooks/use-woopay-user', () => jest.fn() );
jest.mock( '../../hooks/use-selected-payment-method', () => jest.fn() );
jest.mock( 'utils/checkout', () => ( {
Expand Down Expand Up @@ -79,6 +104,8 @@ const BlocksCheckoutEnvironmentMock = ( { children } ) => (

describe( 'CheckoutPageSaveUser', () => {
beforeEach( () => {
global.$ = jQueryMock;
global.jQuery = jQueryMock;
useDispatch.mockImplementation( () => {
return {
setValidationErrors: jest.fn(),
Expand Down
17 changes: 10 additions & 7 deletions client/express-checkout/utils/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
* @return {Array} An array of PaymentItems
*/
export const normalizeLineItems = ( displayItems ) => {
return displayItems.map( ( displayItem ) =>
// The amount prop is already present on the item.
( {
...displayItem,
return displayItems.map( ( displayItem ) => {
let amount = displayItem?.amount ?? displayItem?.value;
if ( displayItem.key === 'total_discount' ) {
amount = -amount;
}

return {
name: displayItem.label,
amount: displayItem?.amount ?? displayItem?.value,
} )
);
amount,
};
} );
};

/**
Expand Down
53 changes: 44 additions & 9 deletions client/express-checkout/utils/test/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,15 @@ describe( 'Express checkout normalization', () => {
const expected = [
{
name: 'Item 1',
label: 'Item 1',
amount: 100,
value: 100,
},
{
name: 'Item 2',
label: 'Item 2',
amount: 200,
value: 200,
},
{
name: 'Item 3',
label: 'Item 3',
amount: 200,
valueWithTax: 300,
value: 200,
},
];

Expand Down Expand Up @@ -74,19 +67,61 @@ describe( 'Express checkout normalization', () => {
const expected = [
{
name: 'Item 1',
label: 'Item 1',
amount: 100,
},
{
name: 'Item 2',
label: 'Item 2',
amount: 200,
},
{
name: 'Item 3',
amount: 300,
},
];

expect( normalizeLineItems( displayItems ) ).toStrictEqual(
expected
);
} );

test( 'normalizes discount line item properly', () => {
const displayItems = [
{
label: 'Item 1',
amount: 100,
},
{
label: 'Item 2',
amount: 200,
},
{
label: 'Item 3',
amount: 300,
},
{
key: 'total_discount',
label: 'Discount',
amount: 50,
},
];

const expected = [
{
name: 'Item 1',
amount: 100,
},
{
name: 'Item 2',
amount: 200,
},
{
name: 'Item 3',
amount: 300,
},
{
name: 'Discount',
amount: -50,
},
];

expect( normalizeLineItems( displayItems ) ).toStrictEqual(
Expand Down
14 changes: 13 additions & 1 deletion includes/class-wc-payments-features.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ public static function is_woopay_direct_checkout_enabled() {
$is_direct_checkout_eligible = is_array( $account_cache ) && ( $account_cache['platform_direct_checkout_eligible'] ?? false );
$is_direct_checkout_flag_enabled = '1' === get_option( self::WOOPAY_DIRECT_CHECKOUT_FLAG_NAME, '1' );

return $is_direct_checkout_eligible && $is_direct_checkout_flag_enabled && self::is_woopay_enabled();
return $is_direct_checkout_eligible && $is_direct_checkout_flag_enabled && self::is_woopayments_gateway_enabled() && self::is_woopay_enabled();
}

/**
Expand Down Expand Up @@ -392,4 +392,16 @@ public static function to_array() {
]
);
}

/**
* Checks if WooCommerce Payments gateway is enabled.
*
* @return bool True if WooCommerce Payments gateway is enabled, false otherwise.
*/
private static function is_woopayments_gateway_enabled() {
$woopayments_settings = get_option( 'woocommerce_woocommerce_payments_settings' );
$woopayments_enabled_setting = $woopayments_settings['enabled'] ?? 'no';

return 'yes' === $woopayments_enabled_setting;
}
}
14 changes: 14 additions & 0 deletions includes/class-wc-payments.php
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,7 @@ public static function init_woopay() {
// Update email field location.
add_action( 'woocommerce_checkout_billing', [ __CLASS__, 'woopay_fields_before_billing_details' ], -50 );
add_filter( 'woocommerce_form_field_email', [ __CLASS__, 'filter_woocommerce_form_field_woopay_email' ], 20, 4 );
add_action( 'woocommerce_checkout_process', [ __CLASS__, 'maybe_show_woopay_phone_number_error' ] );

include_once __DIR__ . '/woopay-user/class-woopay-save-user.php';

Expand Down Expand Up @@ -2027,4 +2028,17 @@ public static function maybe_disable_wcpay_subscriptions_on_update() {
update_option( WC_Payments_Features::WCPAY_SUBSCRIPTIONS_FLAG_NAME, '0' );
}
}

/**
* Show error when WooPay opt-in is checked but no phone number was typed.
*/
public static function maybe_show_woopay_phone_number_error() {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( isset( $_POST['save_user_in_woopay'] ) && 'true' === $_POST['save_user_in_woopay'] ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['woopay_user_phone_field'] ) || ! isset( $_POST['woopay_user_phone_field']['no-country-code'] ) || empty( $_POST['woopay_user_phone_field']['no-country-code'] ) ) {
wc_add_notice( '<strong>' . __( 'Mobile Number', 'woocommerce-payments' ) . '</strong> ' . __( 'is required to create an WooPay account.', 'woocommerce-payments' ), 'error' );
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public function build_display_items( $itemized_display_items = false ) {

if ( WC()->cart->has_discount() ) {
$items[] = [
'key' => 'total_discount',
'label' => esc_html( __( 'Discount', 'woocommerce-payments' ) ),
'amount' => WC_Payments_Utils::prepare_amount( $discounts, $currency ),
];
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 106db15

Please sign in to comment.