Skip to content

Commit

Permalink
Merge branch 'develop' into fix/8026-deposit-schedule-notice-add-tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
haszari authored Feb 28, 2024
2 parents 29979d0 + 835df7f commit 86e6d51
Show file tree
Hide file tree
Showing 18 changed files with 205 additions and 81 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/check-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:
branches:
- develop
- 'release/**'
paths-ignore:
- '.github/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Expand Down
4 changes: 4 additions & 0 deletions changelog/add-timeouts-to-direct-to-woopay-checkout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Handle timeouts in direct to WooPay checkout flow.
5 changes: 5 additions & 0 deletions changelog/fix-7263-hooks-in-prb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: dev
Comment: Removed hooks from payment request button classes


4 changes: 4 additions & 0 deletions changelog/fix-refunds-with-pms-disabled-on-checkout
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: fix

Ensure gateways accessibility for use cases which don't require the gateway to be enabled
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: dev

Reverts removed REST controller class to prevent error on update from older versions of the plugin.
5 changes: 3 additions & 2 deletions client/checkout/woopay/direct-checkout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ window.addEventListener( 'load', async () => {
const checkoutElements = WooPayDirectCheckout.getCheckoutRedirectElements();
if ( isThirdPartyCookieEnabled ) {
if ( await WooPayDirectCheckout.isUserLoggedIn() ) {
WooPayDirectCheckout.redirectToWooPaySession( checkoutElements );
WooPayDirectCheckout.redirectToWooPay( checkoutElements, false );
}

return;
}

WooPayDirectCheckout.redirectToWooPay( checkoutElements );
// Pass true to append '&checkout_redirect=1' and let WooPay decide the checkout flow.
WooPayDirectCheckout.redirectToWooPay( checkoutElements, true );
} );
102 changes: 67 additions & 35 deletions client/checkout/woopay/direct-checkout/woopay-direct-checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,49 @@ class WoopayDirectCheckout {
}

/**
* Sends the session data to the WooPayConnectIframe.
* Resolves the redirect URL to the WooPay checkout page or throws an error if the request fails.
*
* @return {Promise<*>} Resolves to the redirect URL.
* @return {string} The redirect URL.
* @throws {Error} If the session data could not be sent to WooPay.
*/
static async sendRedirectSessionDataToWooPay() {
const woopaySession = await this.getWooPaySessionFromMerchant();
const woopaySessionData = await this.getSessionConnect().sendRedirectSessionDataToWooPay(
woopaySession
);
static async resolveWooPayRedirectUrl() {
// We're intentionally adding a try-catch block to catch any errors
// that might occur other than the known validation errors.
try {
const encryptedSessionData = await this.getEncryptedSessionData();
if ( ! this.isValidEncryptedSessionData( encryptedSessionData ) ) {
throw new Error(
'Could not retrieve encrypted session data from store.'
);
}

const { redirect_url: redirectUrl } = await woopaySessionData;
const woopaySessionData = await this.getSessionConnect().sendRedirectSessionDataToWooPay(
encryptedSessionData
);
if ( ! woopaySessionData?.redirect_url ) {
throw new Error( 'Could not retrieve WooPay checkout URL.' );
}

return redirectUrl;
return woopaySessionData.redirect_url;
} catch ( error ) {
throw new Error( error.message );
}
}

/**
* Checks if the encrypted session object is valid.
*
* @param {Object} encryptedSessionData The encrypted session data.
* @return {boolean} True if the session is valid.
*/
static isValidEncryptedSessionData( encryptedSessionData ) {
return (
encryptedSessionData &&
encryptedSessionData?.blog_id &&
encryptedSessionData?.data?.session &&
encryptedSessionData?.data?.iv &&
encryptedSessionData?.data?.hash
);
}

/**
Expand All @@ -120,46 +150,48 @@ class WoopayDirectCheckout {
addElementBySelector( '.wc-proceed-to-checkout .checkout-button' );
// Blocks 'Proceed to Checkout' button.
addElementBySelector(
'.wp-block-woocommerce-proceed-to-checkout-block'
'.wp-block-woocommerce-proceed-to-checkout-block a'
);

return elements;
}

/**
* Adds a click-event listener that redirects to the WooPay checkout page to the given elements.
* Adds a click-event listener to the given elements that redirects to the WooPay checkout page.
*
* @param {*[]} elements The elements to add a click-event listener to.
* @param {boolean} useCheckoutRedirect Whether to use the `checkout_redirect` flag to let WooPay handle the checkout flow.
*/
static redirectToWooPaySession( elements ) {
static redirectToWooPay( elements, useCheckoutRedirect ) {
elements.forEach( ( element ) => {
element.addEventListener( 'click', async ( event ) => {
event.preventDefault();
// Store href before the async call to not lose the reference.
const currTargetHref = event.currentTarget.href;

const woopayRedirectUrl = await this.sendRedirectSessionDataToWooPay();
this.teardown();
// If there's no link where to redirect the user, do not break the expected behavior.
if ( ! currTargetHref ) {
this.teardown();
return;
}

window.location.href = woopayRedirectUrl;
} );
} );
}

/**
* Adds a click-event listener that redirects to WooPay and lets WooPay handle the checkout flow
* to the given elements.
*
* @param {*[]} elements The elements to add a click-event listener to.
*/
static redirectToWooPay( elements ) {
elements.forEach( ( element ) => {
element.addEventListener( 'click', async ( event ) => {
event.preventDefault();

const woopayRedirectUrl = await this.sendRedirectSessionDataToWooPay();
this.teardown();

window.location.href =
woopayRedirectUrl + '&woopay_checkout_redirect=1';
try {
let woopayRedirectUrl = await this.resolveWooPayRedirectUrl();
if ( useCheckoutRedirect ) {
woopayRedirectUrl += '&checkout_redirect=1';
}

this.teardown();
// TODO: Add telemetry as to _how long_ it took to get to this step.
window.location.href = woopayRedirectUrl;
} catch ( error ) {
// TODO: Add telemetry as to _why_ we've short-circuited the WooPay checkout flow.
console.warn( error ); // eslint-disable-line no-console

this.teardown();
window.location.href = currTargetHref;
}
} );
} );
}
Expand All @@ -169,7 +201,7 @@ class WoopayDirectCheckout {
*
* @return {Promise<Promise<*>|*>} Resolves to the WooPay session response.
*/
static async getWooPaySessionFromMerchant() {
static async getEncryptedSessionData() {
return request(
buildAjaxURL( getConfig( 'wcAjaxUrl' ), 'get_woopay_session' ),
{
Expand Down
4 changes: 0 additions & 4 deletions dev/phpcs/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
<exclude-pattern>*/includes/woopay-user/*</exclude-pattern>
<exclude-pattern>*/includes/class-wc-payments-order-success-page.php</exclude-pattern>

<!-- https://github.com/Automattic/woocommerce-payments/issues/7263 -->
<exclude-pattern>*/includes/class-wc-payments-apple-pay-registration.php</exclude-pattern>
<exclude-pattern>*/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php</exclude-pattern>

<!-- https://github.com/Automattic/woocommerce-payments/issues/7264 -->
<exclude-pattern>*/includes/class-wc-payments-customer-service.php</exclude-pattern>
<exclude-pattern>*/includes/class-wc-payments-token-service.php</exclude-pattern>
Expand Down
18 changes: 18 additions & 0 deletions includes/admin/class-wc-rest-payments-survey-controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
/**
* Class WC_REST_Payments_Survey_Controller
*
* @package WooCommerce\Payments\Admin
*/

defined( 'ABSPATH' ) || exit;

/**
* REST dummy controller for settings. Needs to remain to prevent errors on update from v7.2 and earlier.
*/
class WC_REST_Payments_Survey_Controller extends WP_REST_Controller {
/**
* Dummy register routes.
*/
public function register_routes() {}
}
6 changes: 6 additions & 0 deletions includes/class-wc-payment-gateway-wcpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,12 @@ public function is_available() {
return false;
}

// Disable the gateway if it should not be displayed on the checkout page.
$is_gateway_enabled = in_array( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout(), true ) ? true : false;
if ( ! $is_gateway_enabled ) {
return false;
}

return parent::is_available() && ! $this->needs_setup();
}

Expand Down
9 changes: 8 additions & 1 deletion includes/class-wc-payments-apple-pay-registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,14 @@ public function __construct( WC_Payments_API_Client $payments_api_client, WC_Pay
$this->payments_api_client = $payments_api_client;
$this->account = $account;
$this->gateway = $gateway;
}

/**
* Initializes this class's hooks.
*
* @return void
*/
public function init_hooks() {
add_action( 'init', [ $this, 'add_domain_association_rewrite_rule' ], 5 );
add_action( 'woocommerce_woocommerce_payments_updated', [ $this, 'verify_domain_on_update' ] );
add_action( 'init', [ $this, 'init' ] );
Expand Down Expand Up @@ -433,6 +440,6 @@ public function display_error_notice() {
<?php endif; ?>
<p><?php echo $check_log_text; /* @codingStandardsIgnoreLine */ ?></p>
</div>
<?php
<?php
}
}
4 changes: 3 additions & 1 deletion includes/class-wc-payments.php
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ public static function init() {
self::maybe_register_woopay_hooks();

self::$apple_pay_registration = new WC_Payments_Apple_Pay_Registration( self::$api_client, self::$account, self::get_gateway() );
self::$apple_pay_registration->init_hooks();

self::maybe_display_express_checkout_buttons();

Expand Down Expand Up @@ -734,7 +735,7 @@ public static function get_plugin_headers() {
* @return array The list of payment gateways that will be available, including WooPayments' Gateway class.
*/
public static function register_gateway( $gateways ) {
$payment_methods = self::$card_gateway->get_payment_method_ids_enabled_at_checkout();
$payment_methods = array_keys( self::get_payment_method_map() );

$key = array_search( 'link', $payment_methods, true );

Expand Down Expand Up @@ -1484,6 +1485,7 @@ public static function maybe_display_express_checkout_buttons() {
$payment_request_button_handler = new WC_Payments_Payment_Request_Button_Handler( self::$account, self::get_gateway(), $express_checkout_helper );
$woopay_button_handler = new WC_Payments_WooPay_Button_Handler( self::$account, self::get_gateway(), self::$woopay_util, $express_checkout_helper );
$express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( self::get_gateway(), $payment_request_button_handler, $woopay_button_handler, $express_checkout_helper );
$express_checkout_button_display_handler->init();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ public function __construct( WC_Payment_Gateway_WCPay $gateway, WC_Payments_Paym
$this->payment_request_button_handler = $payment_request_button_handler;
$this->platform_checkout_button_handler = $platform_checkout_button_handler;
$this->express_checkout_helper = $express_checkout_helper;
}

/**
* Initializes this class, its dependencies, and its hooks.
*
* @return void
*/
public function init() {
$this->platform_checkout_button_handler->init();
$this->payment_request_button_handler->init();

Expand Down Expand Up @@ -106,9 +113,9 @@ public function display_express_checkout_buttons() {
?>
<div class='wcpay-payment-request-wrapper' >
<?php
if ( ! $this->express_checkout_helper->is_pay_for_order_page() || $this->is_pay_for_order_flow_supported() ) {
$this->platform_checkout_button_handler->display_woopay_button_html();
}
if ( ! $this->express_checkout_helper->is_pay_for_order_page() || $this->is_pay_for_order_flow_supported() ) {
$this->platform_checkout_button_handler->display_woopay_button_html();
}
$this->payment_request_button_handler->display_payment_request_button_html();
?>
</div >
Expand Down Expand Up @@ -148,7 +155,7 @@ public function add_pay_for_order_params_to_js_config() {

$order = wc_get_order( $order_id );

// phpcs:disable WordPress.Security.NonceVerification.Recommended
// phpcs:disable WordPress.Security.NonceVerification
if ( isset( $_GET['pay_for_order'] ) && isset( $_GET['key'] ) && current_user_can( 'pay_for_order', $order_id ) ) {
add_filter(
'wcpay_payment_fields_js_config',
Expand All @@ -162,7 +169,7 @@ function( $js_config ) use ( $order ) {
}

// Silence the filter_input warning because we are sanitizing the input with sanitize_email().
// nosemgrep: audit.php.lang.misc.filter-input-no-filter
// nosemgrep: audit.php.lang.misc.filter-input-no-filter.
$user_email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( filter_input( INPUT_POST, 'email' ) ) ) : $session_email;

$js_config['order_id'] = $order->get_id();
Expand All @@ -177,6 +184,6 @@ function( $js_config ) use ( $order ) {
}
);
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
// phpcs:enable WordPress.Security.NonceVerification
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,6 @@ public function set_up() {
'get_payment_method_ids_enabled_at_checkout',
'wc_payments_get_payment_gateway_by_id',
'get_selected_payment_method',
'get_upe_enabled_payment_method_ids',
]
)
->getMock();
Expand Down Expand Up @@ -381,12 +380,7 @@ public function test_should_not_use_stripe_platform_on_checkout_page_for_upe() {
public function test_link_payment_method_requires_mandate_data() {
$mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];

$mock_upe_gateway
->expects( $this->once() )
->method( 'get_upe_enabled_payment_method_ids' )
->will(
$this->returnValue( [ 'link' ] )
);
$mock_upe_gateway->update_option( 'upe_enabled_payment_method_ids', [ 'link' ] );

$this->assertTrue( $mock_upe_gateway->is_mandate_data_required() );
}
Expand Down Expand Up @@ -422,11 +416,7 @@ public function test_process_payment_returns_correct_redirect_when_using_saved_p
->will(
$this->returnValue( [ $user, $customer_id ] )
);
$mock_card_payment_gateway->expects( $this->any() )
->method( 'get_upe_enabled_payment_method_ids' )
->will(
$this->returnValue( [ Payment_Method::CARD ] )
);
$mock_card_payment_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD ] );
$this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1 )
->expects( $this->once() )
->method( 'format_response' )
Expand Down Expand Up @@ -1216,7 +1206,6 @@ public function test_get_payment_methods_from_gateway_id_upe() {
)
->onlyMethods(
[
'get_upe_enabled_payment_method_ids',
'get_payment_method_ids_enabled_at_checkout',
]
)
Expand All @@ -1225,11 +1214,7 @@ public function test_get_payment_methods_from_gateway_id_upe() {
$gateway = WC_Payments::get_gateway();
WC_Payments::set_gateway( $mock_upe_gateway );

$mock_upe_gateway->expects( $this->any() )
->method( 'get_upe_enabled_payment_method_ids' )
->will(
$this->returnValue( [ Payment_Method::CARD, Payment_Method::LINK ] )
);
$mock_upe_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD, Payment_Method::LINK ] );

$payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID . '_' . Payment_Method::BANCONTACT );
$this->assertSame( [ Payment_Method::BANCONTACT ], $payment_methods );
Expand Down
Loading

0 comments on commit 86e6d51

Please sign in to comment.