diff --git a/.psalm/stubs.php b/.psalm/stubs.php index 9f0cdaf55..00ece2e4e 100644 --- a/.psalm/stubs.php +++ b/.psalm/stubs.php @@ -2,3 +2,6 @@ if (!defined('EP_PAGES')) { define('EP_PAGES', 4096); } +if (!defined('MONTH_IN_SECONDS')) { + define('MONTH_IN_SECONDS', 30 * DAY_IN_SECONDS); +} diff --git a/modules/ppcp-api-client/src/Helper/Cache.php b/modules/ppcp-api-client/src/Helper/Cache.php index e31dd14a3..c5b79dc5c 100644 --- a/modules/ppcp-api-client/src/Helper/Cache.php +++ b/modules/ppcp-api-client/src/Helper/Cache.php @@ -67,10 +67,11 @@ class Cache { * * @param string $key The key under which the value should be cached. * @param mixed $value The value to cache. + * @param int $expiration Time until expiration in seconds. * * @return bool */ - public function set( string $key, $value ): bool { - return (bool) set_transient( $this->prefix . $key, $value ); + public function set( string $key, $value, int $expiration = 0 ): bool { + return (bool) set_transient( $this->prefix . $key, $value, $expiration ); } } diff --git a/modules/ppcp-onboarding/assets/js/onboarding.js b/modules/ppcp-onboarding/assets/js/onboarding.js index 31dfe9745..5671938e4 100644 --- a/modules/ppcp-onboarding/assets/js/onboarding.js +++ b/modules/ppcp-onboarding/assets/js/onboarding.js @@ -87,7 +87,19 @@ const ppcp_onboarding = { }).then((res)=>{ return res.json(); }).then((data)=>{ - location.reload(); + if (!data.success) { + alert('Could not update signup buttons: ' + JSON.stringify(data)); + return; + } + + buttons.forEach((element) => { + for (let [key, value] of Object.entries(data.data.signup_links)) { + key = 'connect-to' + key.replace(/-/g, ''); + if(key === element.id) { + element.setAttribute('href', value); + } + } + }); }); }) }, diff --git a/modules/ppcp-onboarding/services.php b/modules/ppcp-onboarding/services.php index d92446054..82f26e26c 100644 --- a/modules/ppcp-onboarding/services.php +++ b/modules/ppcp-onboarding/services.php @@ -191,6 +191,9 @@ return array( return new PayUponInvoiceEndpoint( $container->get( 'wcgateway.settings' ), $container->get( 'button.request-data' ), + $container->get( 'onboarding.signup-link-cache' ), + $container->get( 'onboarding.render' ), + $container->get( 'onboarding.signup-link-ids' ), $container->get( 'woocommerce.logger.woocommerce' ) ); }, @@ -210,17 +213,29 @@ return array( $container->get( 'woocommerce.logger.woocommerce' ) ); }, + 'onboarding.signup-link-cache' => static function( ContainerInterface $container ): Cache { + return new Cache( 'ppcp-paypal-signup-link' ); + }, + 'onboarding.signup-link-ids' => static function ( ContainerInterface $container ): array { + return array( + 'production-ppcp', + 'production-express_checkout', + 'sandbox-ppcp', + 'sandbox-express_checkout', + ); + }, 'onboarding.render' => static function ( ContainerInterface $container ) : OnboardingRenderer { - $partner_referrals = $container->get( 'api.endpoint.partner-referrals-production' ); $partner_referrals_sandbox = $container->get( 'api.endpoint.partner-referrals-sandbox' ); $partner_referrals_data = $container->get( 'api.repository.partner-referrals-data' ); $settings = $container->get( 'wcgateway.settings' ); + $signup_link_cache = $container->get( 'onboarding.signup-link-cache' ); return new OnboardingRenderer( $settings, $partner_referrals, $partner_referrals_sandbox, - $partner_referrals_data + $partner_referrals_data, + $signup_link_cache ); }, 'onboarding.render-options' => static function ( ContainerInterface $container ) : OnboardingOptionsRenderer { diff --git a/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php b/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php index 1793f84c8..5f81ca8a7 100644 --- a/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php +++ b/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php @@ -11,8 +11,10 @@ namespace WooCommerce\PayPalCommerce\Onboarding\Endpoint; use Exception; use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface; use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData; +use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; @@ -35,6 +37,27 @@ class PayUponInvoiceEndpoint implements EndpointInterface { */ protected $request_data; + /** + * The signup link cache. + * + * @var Cache + */ + protected $signup_link_cache; + + /** + * The onboarding renderer. + * + * @var OnboardingRenderer + */ + protected $onboarding_renderer; + + /** + * Signup link ids. + * + * @var array + */ + protected $signup_link_ids; + /** * The logger. * @@ -45,14 +68,27 @@ class PayUponInvoiceEndpoint implements EndpointInterface { /** * PayUponInvoiceEndpoint constructor. * - * @param Settings $settings The settings. - * @param RequestData $request_data The request data. - * @param LoggerInterface $logger The logger. + * @param Settings $settings The settings. + * @param RequestData $request_data The request data. + * @param Cache $signup_link_cache The signup link cache. + * @param OnboardingRenderer $onboarding_renderer The onboarding renderer. + * @param array $signup_link_ids Signup link ids. + * @param LoggerInterface $logger The logger. */ - public function __construct( Settings $settings, RequestData $request_data, LoggerInterface $logger ) { - $this->settings = $settings; - $this->request_data = $request_data; - $this->logger = $logger; + public function __construct( + Settings $settings, + RequestData $request_data, + Cache $signup_link_cache, + OnboardingRenderer $onboarding_renderer, + array $signup_link_ids, + LoggerInterface $logger + ) { + $this->settings = $settings; + $this->request_data = $request_data; + $this->signup_link_cache = $signup_link_cache; + $this->onboarding_renderer = $onboarding_renderer; + $this->logger = $logger; + $this->signup_link_ids = $signup_link_ids; } /** @@ -71,18 +107,33 @@ class PayUponInvoiceEndpoint implements EndpointInterface { * @throws NotFoundException When order not found or handling failed. */ public function handle_request(): bool { + $signup_links = array(); + try { $data = $this->request_data->read_request( $this->nonce() ); $this->settings->set( 'ppcp-onboarding-pui', $data['checked'] ); $this->settings->persist(); + foreach ( $this->signup_link_ids as $key ) { + if ( $this->signup_link_cache->has( $key ) ) { + $this->signup_link_cache->delete( $key ); + } + } + + foreach ( $this->signup_link_ids as $key ) { + $parts = explode( '-', $key ); + $is_production = 'production' === $parts[0]; + $products = 'ppcp' === $parts[1] ? array( 'PPCP' ) : array( 'EXPRESS_CHECKOUT' ); + $signup_links[ $key ] = $this->onboarding_renderer->get_signup_link( $is_production, $products ); + } } catch ( Exception $exception ) { $this->logger->error( $exception->getMessage() ); } wp_send_json_success( array( - $this->settings->get( 'ppcp-onboarding-pui' ), + 'onboarding_pui' => $this->settings->get( 'ppcp-onboarding-pui' ), + 'signup_links' => $signup_links, ) ); diff --git a/modules/ppcp-onboarding/src/Render/OnboardingRenderer.php b/modules/ppcp-onboarding/src/Render/OnboardingRenderer.php index 95c0c46a4..8bbbc238a 100644 --- a/modules/ppcp-onboarding/src/Render/OnboardingRenderer.php +++ b/modules/ppcp-onboarding/src/Render/OnboardingRenderer.php @@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Onboarding\Render; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnerReferrals; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; +use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; @@ -47,6 +48,13 @@ class OnboardingRenderer { */ private $partner_referrals_data; + /** + * The cache + * + * @var Cache + */ + protected $cache; + /** * OnboardingRenderer constructor. * @@ -54,17 +62,20 @@ class OnboardingRenderer { * @param PartnerReferrals $production_partner_referrals The PartnerReferrals for production. * @param PartnerReferrals $sandbox_partner_referrals The PartnerReferrals for sandbox. * @param PartnerReferralsData $partner_referrals_data The default partner referrals data. + * @param Cache $cache The cache. */ public function __construct( Settings $settings, PartnerReferrals $production_partner_referrals, PartnerReferrals $sandbox_partner_referrals, - PartnerReferralsData $partner_referrals_data + PartnerReferralsData $partner_referrals_data, + Cache $cache ) { $this->settings = $settings; $this->production_partner_referrals = $production_partner_referrals; $this->sandbox_partner_referrals = $sandbox_partner_referrals; $this->partner_referrals_data = $partner_referrals_data; + $this->cache = $cache; } /** @@ -83,9 +94,17 @@ class OnboardingRenderer { ->with_products( $products ) ->data(); + $environment = $is_production ? 'production' : 'sandbox'; + $product = 'PPCP' === $data['products'][0] ? 'ppcp' : 'express_checkout'; + if ( $this->cache->has( $environment . '-' . $product ) ) { + return $this->cache->get( $environment . '-' . $product ); + } + $url = $is_production ? $this->production_partner_referrals->signup_link( $data ) : $this->sandbox_partner_referrals->signup_link( $data ); $url = add_query_arg( $args, $url ); + $this->cache->set( $environment . '-' . $product, $url, 3 * MONTH_IN_SECONDS ); + return $url; } diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index f953b839d..63a5a4814 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -219,7 +219,19 @@ return array( $cache = new Cache( 'ppcp-paypal-bearer' ); $bearer = $container->get( 'api.bearer' ); $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' ); - return new SettingsListener( $settings, $fields, $webhook_registrar, $cache, $state, $bearer, $page_id ); + $signup_link_cache = $container->get( 'onboarding.signup-link-cache' ); + $signup_link_ids = $container->get( 'onboarding.signup-link-ids' ); + return new SettingsListener( + $settings, + $fields, + $webhook_registrar, + $cache, + $state, + $bearer, + $page_id, + $signup_link_cache, + $signup_link_ids + ); }, 'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor { @@ -2217,7 +2229,7 @@ return array( ); }, - 'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool { + 'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool { try { $token = $container->get( 'api.bearer' )->bearer(); return $token->vaulting_available(); @@ -2226,7 +2238,7 @@ return array( } }, - 'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string { + 'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string { $vaulting_label = __( 'Enable saved cards and subscription features on your store.', 'woocommerce-paypal-payments' ); if ( ! $container->get( 'wcgateway.helper.vaulting-scope' ) ) { @@ -2248,7 +2260,7 @@ return array( return $vaulting_label; }, - 'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string { + 'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string { $pay_later_label = '%s'; $pay_later_label .= ''; $pay_later_label .= __( "You have PayPal vaulting enabled, that's why Pay Later Messaging options are unavailable now. You cannot use both features at the same time.", 'woocommerce-paypal-payments' ); diff --git a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php index 4bd403378..d93b05504 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php +++ b/modules/ppcp-wc-gateway/src/Settings/SettingsListener.php @@ -81,6 +81,20 @@ class SettingsListener { */ protected $page_id; + /** + * The signup link cache. + * + * @var Cache + */ + protected $signup_link_cache; + + /** + * Signup link ids + * + * @var array + */ + protected $signup_link_ids; + /** * SettingsListener constructor. * @@ -91,6 +105,8 @@ class SettingsListener { * @param State $state The state. * @param Bearer $bearer The bearer. * @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. */ public function __construct( Settings $settings, @@ -99,7 +115,9 @@ class SettingsListener { Cache $cache, State $state, Bearer $bearer, - string $page_id + string $page_id, + Cache $signup_link_cache, + array $signup_link_ids ) { $this->settings = $settings; @@ -109,6 +127,8 @@ class SettingsListener { $this->state = $state; $this->bearer = $bearer; $this->page_id = $page_id; + $this->signup_link_cache = $signup_link_cache; + $this->signup_link_ids = $signup_link_ids; } /** @@ -260,6 +280,12 @@ class SettingsListener { true ) ) { $this->webhook_registrar->unregister(); + + foreach ( $this->signup_link_ids as $key ) { + if ( $this->signup_link_cache->has( $key ) ) { + $this->signup_link_cache->delete( $key ); + } + } } } diff --git a/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php b/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php index 050b87e40..d4499e874 100644 --- a/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php +++ b/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php @@ -32,12 +32,12 @@ class SettingsListenerTest extends ModularTestCase $webhook_registrar = Mockery::mock(WebhookRegistrar::class); $webhook_registrar->shouldReceive('unregister')->andReturnTrue(); $webhook_registrar->shouldReceive('register')->andReturnTrue(); - $cache = Mockery::mock(Cache::class); - $state = Mockery::mock(State::class); $state->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED); $bearer = Mockery::mock(Bearer::class); + $signup_link_cache = Mockery::mock(Cache::class); + $signup_link_ids = array(); $testee = new SettingsListener( $settings, @@ -46,7 +46,9 @@ class SettingsListenerTest extends ModularTestCase $cache, $state, $bearer, - PayPalGateway::ID + PayPalGateway::ID, + $signup_link_cache, + $signup_link_ids ); $_GET['section'] = PayPalGateway::ID; @@ -74,6 +76,8 @@ class SettingsListenerTest extends ModularTestCase $settings->shouldReceive('persist'); $cache->shouldReceive('has') ->andReturn(false); + $signup_link_cache->shouldReceive('has') + ->andReturn(false); $testee->listen(); }