Use continuation mode when APM does not redirect back

This commit is contained in:
Alex P 2023-06-14 08:59:30 +03:00
parent 8a6437b558
commit e29ef9c7d6
No known key found for this signature in database
GPG key ID: 54487A734A204D71
7 changed files with 105 additions and 16 deletions

View file

@ -125,6 +125,7 @@ return array(
$container->get( 'button.basic-checkout-validation-enabled' ),
$container->get( 'button.early-wc-checkout-validation-enabled' ),
$container->get( 'button.pay-now-contexts' ),
$container->get( 'wcgateway.funding-sources-without-redirect' ),
$container->get( 'woocommerce.logger.woocommerce' )
);
},
@ -176,6 +177,7 @@ return array(
$container->get( 'button.early-wc-checkout-validation-enabled' ),
$container->get( 'button.pay-now-contexts' ),
$container->get( 'button.handle-shipping-in-paypal' ),
$container->get( 'wcgateway.funding-sources-without-redirect' ),
$logger
);
},

View file

@ -152,6 +152,13 @@ class CreateOrderEndpoint implements EndpointInterface {
*/
private $handle_shipping_in_paypal;
/**
* The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back.
*
* @var string[]
*/
private $funding_sources_without_redirect;
/**
* The logger.
*
@ -175,6 +182,7 @@ class CreateOrderEndpoint implements EndpointInterface {
* @param bool $early_validation_enabled Whether to execute WC validation of the checkout form.
* @param string[] $pay_now_contexts The contexts that should have the Pay Now button.
* @param bool $handle_shipping_in_paypal If true, the shipping methods are sent to PayPal allowing the customer to select it inside the popup.
* @param string[] $funding_sources_without_redirect The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
@ -191,23 +199,25 @@ class CreateOrderEndpoint implements EndpointInterface {
bool $early_validation_enabled,
array $pay_now_contexts,
bool $handle_shipping_in_paypal,
array $funding_sources_without_redirect,
LoggerInterface $logger
) {
$this->request_data = $request_data;
$this->purchase_unit_factory = $purchase_unit_factory;
$this->shipping_preference_factory = $shipping_preference_factory;
$this->api_endpoint = $order_endpoint;
$this->payer_factory = $payer_factory;
$this->session_handler = $session_handler;
$this->settings = $settings;
$this->early_order_handler = $early_order_handler;
$this->registration_needed = $registration_needed;
$this->card_billing_data_mode = $card_billing_data_mode;
$this->early_validation_enabled = $early_validation_enabled;
$this->pay_now_contexts = $pay_now_contexts;
$this->handle_shipping_in_paypal = $handle_shipping_in_paypal;
$this->logger = $logger;
$this->request_data = $request_data;
$this->purchase_unit_factory = $purchase_unit_factory;
$this->shipping_preference_factory = $shipping_preference_factory;
$this->api_endpoint = $order_endpoint;
$this->payer_factory = $payer_factory;
$this->session_handler = $session_handler;
$this->settings = $settings;
$this->early_order_handler = $early_order_handler;
$this->registration_needed = $registration_needed;
$this->card_billing_data_mode = $card_billing_data_mode;
$this->early_validation_enabled = $early_validation_enabled;
$this->pay_now_contexts = $pay_now_contexts;
$this->handle_shipping_in_paypal = $handle_shipping_in_paypal;
$this->funding_sources_without_redirect = $funding_sources_without_redirect;
$this->logger = $logger;
}
/**
@ -288,6 +298,11 @@ class CreateOrderEndpoint implements EndpointInterface {
}
if ( 'checkout' === $data['context'] ) {
if ( ! in_array( $funding_source, $this->funding_sources_without_redirect, true ) ) {
$this->session_handler->replace_order( $order );
$this->session_handler->replace_funding_source( $funding_source );
}
if (
! $this->early_order_handler->should_create_early_order()
|| $this->registration_needed

View file

@ -9,6 +9,8 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Button\Helper;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
trait ContextTrait {
/**
@ -56,6 +58,12 @@ trait ContextTrait {
return false;
}
if ( ! $order->status()->is( OrderStatus::APPROVED )
&& ! $order->status()->is( OrderStatus::COMPLETED )
) {
return false;
}
$source = $order->payment_source();
if ( $source && $source->card() ) {
return false; // Ignore for DCC.

View file

@ -55,6 +55,8 @@ class SessionHandler {
public function order() {
$this->load_session();
do_action( 'ppcp_session_get_order', $this->order, $this );
return $this->order;
}

View file

@ -9,6 +9,11 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Session;
use Psr\Log\LoggerInterface;
use Throwable;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
use WooCommerce\PayPalCommerce\Session\Cancellation\CancelController;
@ -19,6 +24,12 @@ use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
* Class SessionModule
*/
class SessionModule implements ModuleInterface {
/**
* A flag to avoid multiple requests to reload order.
*
* @var bool
*/
private $reloaded_order = false;
/**
* {@inheritDoc}
@ -46,6 +57,45 @@ class SessionModule implements ModuleInterface {
$controller->run();
}
);
add_action(
'ppcp_session_get_order',
function ( ?Order $order, SessionHandler $session_handler ) use ( $c ): void {
if ( ! isset( WC()->session ) ) {
return;
}
if ( $this->reloaded_order ) {
return;
}
if ( ! $order ) {
return;
}
if ( $order->status()->is( OrderStatus::APPROVED )
|| $order->status()->is( OrderStatus::COMPLETED )
) {
return;
}
$order_endpoint = $c->get( 'api.endpoint.order' );
assert( $order_endpoint instanceof OrderEndpoint );
$this->reloaded_order = true;
try {
$session_handler->replace_order( $order_endpoint->order( $order->id() ) );
} catch ( Throwable $exception ) {
$logger = $c->get( 'woocommerce.logger.woocommerce' );
assert( $logger instanceof LoggerInterface );
$logger->warning( 'Failed to reload PayPal order in the session: ' . $exception->getMessage() );
}
},
10,
2
);
}
/**

View file

@ -903,6 +903,12 @@ return array(
'paylater' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
);
},
/**
* The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back.
*/
'wcgateway.funding-sources-without-redirect' => static function( ContainerInterface $container ): array {
return array( 'paypal', 'paylater', 'venmo', 'card' );
},
'wcgateway.settings.funding-sources' => static function( ContainerInterface $container ): array {
return array_diff_key(
$container->get( 'wcgateway.all-funding-sources' ),

View file

@ -13,6 +13,7 @@ use Exception;
use Psr\Log\LoggerInterface;
use WC_Order;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
@ -253,8 +254,13 @@ class PayPalGateway extends \WC_Payment_Gateway {
$funding_source = $this->session_handler->funding_source();
if ( $funding_source ) {
$this->title = $this->funding_source_renderer->render_name( $funding_source );
$this->description = $this->funding_source_renderer->render_description( $funding_source );
$order = $this->session_handler->order();
if ( $order &&
( $order->status()->is( OrderStatus::APPROVED ) || $order->status()->is( OrderStatus::COMPLETED ) )
) {
$this->title = $this->funding_source_renderer->render_name( $funding_source );
$this->description = $this->funding_source_renderer->render_description( $funding_source );
}
}
$this->init_form_fields();