Merge branch 'trunk' into PCP-688-add-functionality-to-choose-subscription-failure-behavior

This commit is contained in:
dinamiko 2022-09-16 11:04:45 +02:00
commit 6a5cc5d129
12 changed files with 142 additions and 63 deletions

View file

@ -20,6 +20,12 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
return function ( ContainerInterface $container, array $fields ): array {
$current_page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
if ( $current_page_id !== Settings::CONNECTION_TAB_ID ) {
return $fields;
}
$state = $container->get( 'onboarding.state' );
assert( $state instanceof State );

View file

@ -59,7 +59,6 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
return array(
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
@ -159,7 +158,7 @@ return array(
}
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
return in_array( $section, array( Settings::CONNECTION_TAB_ID, PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID, CardButtonGateway::ID, OXXOGateway::ID ), true );
return in_array( $section, array( Settings::CONNECTION_TAB_ID, PayPalGateway::ID, CreditCardGateway::ID, PayUponInvoiceGateway::ID, CardButtonGateway::ID, OXXOGateway::ID ), true );
},
'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
@ -224,14 +223,13 @@ return array(
CardButtonGateway::ID => __( 'PayPal Card Button', 'woocommerce-paypal-payments' ),
OXXOGateway::ID => __( 'OXXO', 'woocommerce-paypal-payments' ),
PayUponInvoiceGateway::ID => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ),
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
);
// Remove for all not registered in WC gateways that cannot render anything in this case.
$gateways = WC()->payment_gateways->payment_gateways();
foreach ( array_diff(
array_keys( $sections ),
array( Settings::CONNECTION_TAB_ID, PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID )
array( Settings::CONNECTION_TAB_ID, PayPalGateway::ID, CreditCardGateway::ID )
) as $id ) {
if ( ! isset( $gateways[ $id ] ) ) {
unset( $sections[ $id ] );
@ -276,6 +274,8 @@ return array(
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
$signup_link_cache = $container->get( 'onboarding.signup-link-cache' );
$signup_link_ids = $container->get( 'onboarding.signup-link-ids' );
$pui_status_cache = $container->get( 'pui.status-cache' );
$dcc_status_cache = $container->get( 'dcc.status-cache' );
return new SettingsListener(
$settings,
$fields,
@ -285,7 +285,9 @@ return array(
$bearer,
$page_id,
$signup_link_cache,
$signup_link_ids
$signup_link_ids,
$pui_status_cache,
$dcc_status_cache
);
},
'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
@ -351,8 +353,28 @@ return array(
return new FeesRenderer();
},
'wcgateway.settings.should-render-settings' => static function ( ContainerInterface $container ): bool {
$sections = array(
Settings::CONNECTION_TAB_ID => __( 'Connection', 'woocommerce-paypal-payments' ),
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
CardButtonGateway::ID => __( 'PayPal Card Button', 'woocommerce-paypal-payments' ),
);
$current_page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
return array_key_exists( $current_page_id, $sections );
},
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
$should_render_settings = $container->get( 'wcgateway.settings.should-render-settings' );
if ( ! $should_render_settings ) {
return array();
}
$state = $container->get( 'onboarding.state' );
assert( $state instanceof State );
@ -1913,7 +1935,7 @@ return array(
$settings = $container->get( 'wcgateway.settings' );
$partner_endpoint = $container->get( 'api.endpoint.partners' );
return new DCCProductStatus( $settings, $partner_endpoint );
return new DCCProductStatus( $settings, $partner_endpoint, $container->get( 'dcc.status-cache' ) );
},
'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
@ -1977,7 +1999,8 @@ return array(
'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
return new PayUponInvoiceProductStatus(
$container->get( 'wcgateway.settings' ),
$container->get( 'api.endpoint.partners' )
$container->get( 'api.endpoint.partners' ),
$container->get( 'pui.status-cache' )
);
},
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
@ -2248,4 +2271,10 @@ return array(
esc_html( $pui_button_text )
);
},
'pui.status-cache' => static function( ContainerInterface $container ): Cache {
return new Cache( 'ppcp-paypal-pui-status-cache' );
},
'dcc.status-cache' => static function( ContainerInterface $container ): Cache {
return new Cache( 'ppcp-paypal-dcc-status-cache' );
},
);

View file

@ -29,7 +29,6 @@ use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class PayPalGateway
@ -297,9 +296,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
if ( $this->is_credit_card_tab() ) {
return __( 'PayPal Card Processing', 'woocommerce-paypal-payments' );
}
if ( $this->is_webhooks_tab() ) {
return __( 'Webhooks Status', 'woocommerce-paypal-payments' );
}
if ( $this->is_paypal_tab() ) {
return __( 'PayPal Checkout', 'woocommerce-paypal-payments' );
}
@ -326,12 +322,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
'woocommerce-paypal-payments'
);
}
if ( $this->is_webhooks_tab() ) {
return __(
'Status of the webhooks subscription.',
'woocommerce-paypal-payments'
);
}
if ( is_admin() ) {
return __(
@ -372,16 +362,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
return is_admin() && PayUponInvoiceGateway::ID === $this->page_id;
}
/**
* Whether we are on the Webhooks Status tab.
*
* @return bool
*/
private function is_webhooks_tab() : bool {
return is_admin()
&& WebhooksStatusPage::ID === $this->page_id;
}
/**
* Whether we are on the connection tab.
*

View file

@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
use Throwable;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
@ -19,6 +20,15 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
*/
class DCCProductStatus {
const DCC_STATUS_CACHE_KEY = 'dcc_status_cache';
/**
* The Cache.
*
* @var Cache
*/
protected $cache;
/**
* Caches the status for the current load.
*
@ -44,13 +54,16 @@ class DCCProductStatus {
*
* @param Settings $settings The Settings.
* @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
* @param Cache $cache The cache.
*/
public function __construct(
Settings $settings,
PartnersEndpoint $partners_endpoint
PartnersEndpoint $partners_endpoint,
Cache $cache
) {
$this->settings = $settings;
$this->partners_endpoint = $partners_endpoint;
$this->cache = $cache;
}
/**
@ -59,6 +72,10 @@ class DCCProductStatus {
* @return bool
*/
public function dcc_is_active() : bool {
if ( $this->cache->has( self::DCC_STATUS_CACHE_KEY ) ) {
return (bool) $this->cache->get( self::DCC_STATUS_CACHE_KEY );
}
if ( is_bool( $this->current_status_cache ) ) {
return $this->current_status_cache;
}
@ -92,9 +109,11 @@ class DCCProductStatus {
$this->settings->set( 'products_dcc_enabled', true );
$this->settings->persist();
$this->current_status_cache = true;
$this->cache->set( self::DCC_STATUS_CACHE_KEY, true, 3 * MONTH_IN_SECONDS );
return true;
}
}
$this->cache->set( self::DCC_STATUS_CACHE_KEY, false, 3 * MONTH_IN_SECONDS );
$this->current_status_cache = false;
return false;

View file

@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
use Throwable;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/**
@ -19,6 +20,15 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
*/
class PayUponInvoiceProductStatus {
const PUI_STATUS_CACHE_KEY = 'pui_status_cache';
/**
* The Cache.
*
* @var Cache
*/
protected $cache;
/**
* Caches the status for the current load.
*
@ -44,13 +54,16 @@ class PayUponInvoiceProductStatus {
*
* @param Settings $settings The Settings.
* @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
* @param Cache $cache The cache.
*/
public function __construct(
Settings $settings,
PartnersEndpoint $partners_endpoint
PartnersEndpoint $partners_endpoint,
Cache $cache
) {
$this->settings = $settings;
$this->partners_endpoint = $partners_endpoint;
$this->cache = $cache;
}
/**
@ -59,6 +72,10 @@ class PayUponInvoiceProductStatus {
* @return bool
*/
public function pui_is_active() : bool {
if ( $this->cache->has( self::PUI_STATUS_CACHE_KEY ) ) {
return (bool) $this->cache->get( self::PUI_STATUS_CACHE_KEY );
}
if ( is_bool( $this->current_status_cache ) ) {
return $this->current_status_cache;
}
@ -95,9 +112,11 @@ class PayUponInvoiceProductStatus {
$this->settings->set( 'products_pui_enabled', true );
$this->settings->persist();
$this->current_status_cache = true;
$this->cache->set( self::PUI_STATUS_CACHE_KEY, true, 3 * MONTH_IN_SECONDS );
return true;
}
}
$this->cache->set( self::PUI_STATUS_CACHE_KEY, false, 3 * MONTH_IN_SECONDS );
$this->current_status_cache = false;
return false;

View file

@ -12,7 +12,6 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class PageMatcherTrait.
@ -37,7 +36,6 @@ trait PageMatcherTrait {
PayPalGateway::ID => 'paypal',
CreditCardGateway::ID => 'dcc', // TODO: consider using just the gateway ID for PayPal and DCC too.
CardButtonGateway::ID => CardButtonGateway::ID,
WebhooksStatusPage::ID => WebhooksStatusPage::ID,
);
return array_key_exists( $current_page_id, $gateway_page_id_map )
&& in_array( $gateway_page_id_map[ $current_page_id ], $allowed_gateways, true );

View file

@ -11,7 +11,6 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class SectionsRenderer
@ -77,7 +76,7 @@ class SectionsRenderer {
foreach ( $this->sections as $id => $label ) {
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . $id );
if ( in_array( $id, array( Settings::CONNECTION_TAB_ID, CreditCardGateway::ID, WebhooksStatusPage::ID ), true ) ) {
if ( in_array( $id, array( Settings::CONNECTION_TAB_ID, CreditCardGateway::ID ), true ) ) {
// We need section=ppcp-gateway for the webhooks page because it is not a gateway,
// and for DCC because otherwise it will not render the page if gateway is not available (country/currency).
// Other gateways render fields differently, and their pages are not expected to work when gateway is not available.

View file

@ -15,6 +15,8 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
@ -95,6 +97,20 @@ class SettingsListener {
*/
protected $signup_link_ids;
/**
* The PUI status cache.
*
* @var Cache
*/
protected $pui_status_cache;
/**
* The DCC status cache.
*
* @var Cache
*/
protected $dcc_status_cache;
/**
* SettingsListener constructor.
*
@ -107,6 +123,8 @@ class SettingsListener {
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
* @param Cache $signup_link_cache The signup link cache.
* @param array $signup_link_ids Signup link ids.
* @param Cache $pui_status_cache The PUI status cache.
* @param Cache $dcc_status_cache The DCC status cache.
*/
public function __construct(
Settings $settings,
@ -117,7 +135,9 @@ class SettingsListener {
Bearer $bearer,
string $page_id,
Cache $signup_link_cache,
array $signup_link_ids
array $signup_link_ids,
Cache $pui_status_cache,
Cache $dcc_status_cache
) {
$this->settings = $settings;
@ -129,6 +149,8 @@ class SettingsListener {
$this->page_id = $page_id;
$this->signup_link_cache = $signup_link_cache;
$this->signup_link_ids = $signup_link_ids;
$this->pui_status_cache = $pui_status_cache;
$this->dcc_status_cache = $dcc_status_cache;
}
/**
@ -307,6 +329,14 @@ class SettingsListener {
$this->cache->delete( PayPalBearer::CACHE_KEY );
}
if ( $this->pui_status_cache->has( PayUponInvoiceProductStatus::PUI_STATUS_CACHE_KEY ) ) {
$this->pui_status_cache->delete( PayUponInvoiceProductStatus::PUI_STATUS_CACHE_KEY );
}
if ( $this->dcc_status_cache->has( DCCProductStatus::DCC_STATUS_CACHE_KEY ) ) {
$this->dcc_status_cache->delete( DCCProductStatus::DCC_STATUS_CACHE_KEY );
}
if ( isset( $_GET['ppcp-onboarding-error'] ) ) {
$url = remove_query_arg( 'ppcp-onboarding-error' );
wp_safe_redirect( $url, 302 );

View file

@ -10,25 +10,35 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
return array(
'wcgateway.settings.fields' => static function ( $container, array $fields ): array {
$status_page_fields = array(
'webhooks_list' => array(
'webhook_status_heading' => array(
'heading' => __( 'Webhook Status', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-heading',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Status of the webhooks subscription.', 'woocommerce-paypal-payments' ),
),
'webhooks_list' => array(
'title' => __( 'Subscribed webhooks', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-table',
'screens' => array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => WebhooksStatusPage::ID,
'gateway' => Settings::CONNECTION_TAB_ID,
'classes' => array( 'ppcp-webhooks-table' ),
'value' => function () use ( $container ) : array {
return $container->get( 'webhook.status.registered-webhooks-data' );
},
),
'webhooks_resubscribe' => array(
'webhooks_resubscribe' => array(
'title' => __( 'Resubscribe webhooks', 'woocommerce-paypal-payments' ),
'type' => 'ppcp-text',
'text' => '<button type="button" class="button ppcp-webhooks-resubscribe">' . esc_html__( 'Resubscribe', 'woocommerce-paypal-payments' ) . '</button>',
@ -36,7 +46,7 @@ return array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => WebhooksStatusPage::ID,
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Click to remove the current webhook subscription and subscribe again, for example, if the website domain or URL structure changed.', 'woocommerce-paypal-payments' ),
),
);
@ -54,7 +64,7 @@ return array(
State::STATE_ONBOARDED,
),
'requirements' => array(),
'gateway' => WebhooksStatusPage::ID,
'gateway' => Settings::CONNECTION_TAB_ID,
'description' => __( 'Click to request a sample webhook payload from PayPal, allowing to check that your server can successfully receive webhooks.', 'woocommerce-paypal-payments' ),
),
)

View file

@ -1,18 +0,0 @@
<?php
/**
* Status page.
*
* @package WooCommerce\PayPalCommerce\Webhooks\Status
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks\Status;
/**
* Class WebhooksStatusPage
*/
class WebhooksStatusPage {
const ID = 'ppcp-webhooks-status-page';
}

View file

@ -15,11 +15,11 @@ use Exception;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulateEndpoint;
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint;
use WooCommerce\PayPalCommerce\Webhooks\Status\Assets\WebhooksStatusPageAssets;
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
/**
* Class WebhookModule
@ -112,9 +112,8 @@ class WebhookModule implements ModuleInterface {
);
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
if ( WebhooksStatusPage::ID === $page_id ) {
$GLOBALS['hide_save_button'] = true;
$asset_loader = $container->get( 'webhook.status.assets' );
if ( Settings::CONNECTION_TAB_ID === $page_id ) {
$asset_loader = $container->get( 'webhook.status.assets' );
assert( $asset_loader instanceof WebhooksStatusPageAssets );
add_action(
'init',

View file

@ -36,6 +36,8 @@ class SettingsListenerTest extends ModularTestCase
$bearer = Mockery::mock(Bearer::class);
$signup_link_cache = Mockery::mock(Cache::class);
$signup_link_ids = array();
$pui_status_cache = Mockery::mock(Cache::class);
$dcc_status_cache = Mockery::mock(Cache::class);
$testee = new SettingsListener(
$settings,
@ -46,7 +48,9 @@ class SettingsListenerTest extends ModularTestCase
$bearer,
PayPalGateway::ID,
$signup_link_cache,
$signup_link_ids
$signup_link_ids,
$pui_status_cache,
$dcc_status_cache
);
$_GET['section'] = PayPalGateway::ID;
@ -76,6 +80,10 @@ class SettingsListenerTest extends ModularTestCase
->andReturn(false);
$signup_link_cache->shouldReceive('has')
->andReturn(false);
$pui_status_cache->shouldReceive('has')
->andReturn(false);
$dcc_status_cache->shouldReceive('has')
->andReturn(false);
$testee->listen();
}