mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-07 19:54:15 +08:00
Merge branch 'trunk' into PCP-901-onboarding-buttons-must-be-clicked-multiple-times-after-using-checkbox
This commit is contained in:
commit
a58f94de46
19 changed files with 393 additions and 144 deletions
|
@ -132,13 +132,14 @@ const ppcp_onboarding = {
|
|||
},
|
||||
};
|
||||
|
||||
function ppcp_onboarding_sandboxCallback(...args) {
|
||||
return ppcp_onboarding.loginSeller('sandbox', ...args);
|
||||
}
|
||||
|
||||
function ppcp_onboarding_productionCallback(...args) {
|
||||
return ppcp_onboarding.loginSeller('production', ...args);
|
||||
}
|
||||
window.ppcp_onboarding_sandboxCallback = function(...args) {
|
||||
return ppcp_onboarding.loginSeller('sandbox', ...args);
|
||||
};
|
||||
|
||||
window.ppcp_onboarding_productionCallback = function(...args) {
|
||||
return ppcp_onboarding.loginSeller('production', ...args);
|
||||
};
|
||||
|
||||
(() => {
|
||||
const productionCredentialElementsSelectors = [
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
@ -170,6 +169,13 @@ return array(
|
|||
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
|
||||
$ppcp_tab = isset( $_GET[ SectionsRenderer::KEY ] ) ? sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) : '';
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
assert( $state instanceof State );
|
||||
|
||||
if ( ! $ppcp_tab && PayPalGateway::ID === $section && $state->current_state() !== State::STATE_ONBOARDED ) {
|
||||
return Settings::CONNECTION_TAB_ID;
|
||||
}
|
||||
|
||||
return $ppcp_tab ? $ppcp_tab : $section;
|
||||
},
|
||||
|
||||
|
@ -224,14 +230,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 +281,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 +292,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 +360,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 );
|
||||
|
||||
|
@ -1894,7 +1923,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 {
|
||||
|
@ -1958,7 +1987,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 {
|
||||
|
@ -2211,4 +2241,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' );
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -60,7 +60,7 @@ class ConnectAdminNotice {
|
|||
'PayPal Payments is almost ready. To get started, <a href="%1$s">connect your account</a>.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' )
|
||||
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=' . Settings::CONNECTION_TAB_ID )
|
||||
);
|
||||
return new Message( $message, 'warning' );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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§ion=' . $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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,7 +196,7 @@ class SettingsListener {
|
|||
/**
|
||||
* The URL opened at the end of onboarding after saving the merchant ID/email.
|
||||
*/
|
||||
$redirect_url = apply_filters( 'woocommerce_paypal_payments_onboarding_redirect_url', admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-connection' ) );
|
||||
$redirect_url = apply_filters( 'woocommerce_paypal_payments_onboarding_redirect_url', admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=' . Settings::CONNECTION_TAB_ID ) );
|
||||
if ( ! $this->settings->has( 'client_id' ) || ! $this->settings->get( 'client_id' ) ) {
|
||||
$redirect_url = add_query_arg( 'ppcp-onboarding-error', '1', $redirect_url );
|
||||
}
|
||||
|
@ -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 );
|
||||
|
|
|
@ -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' ),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -19,6 +19,7 @@ use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulateEndpoint;
|
|||
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutPaymentApprovalReversed;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureDenied;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCapturePending;
|
||||
|
@ -75,6 +76,7 @@ return array(
|
|||
return array(
|
||||
new CheckoutOrderApproved( $logger, $prefix, $order_endpoint ),
|
||||
new CheckoutOrderCompleted( $logger, $prefix ),
|
||||
new CheckoutPaymentApprovalReversed( $logger ),
|
||||
new PaymentCaptureRefunded( $logger, $prefix ),
|
||||
new PaymentCaptureReversed( $logger, $prefix ),
|
||||
new PaymentCaptureCompleted( $logger, $prefix, $order_endpoint ),
|
||||
|
|
|
@ -11,13 +11,15 @@ namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
/**
|
||||
* Class CheckoutOrderCompleted
|
||||
*/
|
||||
class CheckoutOrderCompleted implements RequestHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
use PrefixTrait, RequestHandlerTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
|
@ -51,97 +53,45 @@ class CheckoutOrderCompleted implements RequestHandler {
|
|||
/**
|
||||
* Whether a handler is responsible for a given request or not.
|
||||
*
|
||||
* @param \WP_REST_Request $request The request.
|
||||
* @param WP_REST_Request $request The request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function responsible_for_request( \WP_REST_Request $request ): bool {
|
||||
public function responsible_for_request( WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->event_types(), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for handling the request.
|
||||
*
|
||||
* @param \WP_REST_Request $request The request.
|
||||
* @param WP_REST_Request $request The request.
|
||||
*
|
||||
* @return \WP_REST_Response
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function handle_request( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
$response = array( 'success' => false );
|
||||
$custom_ids = array_filter(
|
||||
array_map(
|
||||
static function ( array $purchase_unit ): string {
|
||||
return isset( $purchase_unit['custom_id'] ) ?
|
||||
(string) $purchase_unit['custom_id'] : '';
|
||||
},
|
||||
isset( $request['resource']['purchase_units'] ) ?
|
||||
(array) $request['resource']['purchase_units'] : array()
|
||||
),
|
||||
static function ( string $order_id ): bool {
|
||||
return ! empty( $order_id );
|
||||
}
|
||||
);
|
||||
public function handle_request( WP_REST_Request $request ): WP_REST_Response {
|
||||
$response = array( 'success' => false );
|
||||
|
||||
$custom_ids = $this->get_custom_ids_from_request( $request );
|
||||
if ( empty( $custom_ids ) ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
'No order for webhook event %s was found.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
isset( $request['id'] ) ? $request['id'] : ''
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$message,
|
||||
array(
|
||||
'request' => $request,
|
||||
)
|
||||
);
|
||||
$response['message'] = $message;
|
||||
return rest_ensure_response( $response );
|
||||
return $this->no_custom_ids_from_request( $request, $response );
|
||||
}
|
||||
|
||||
$order_ids = array_map(
|
||||
array(
|
||||
$this,
|
||||
'sanitize_custom_id',
|
||||
),
|
||||
$custom_ids
|
||||
);
|
||||
$args = array(
|
||||
'post__in' => $order_ids,
|
||||
'limit' => -1,
|
||||
);
|
||||
$wc_orders = wc_get_orders( $args );
|
||||
$wc_orders = $this->get_wc_orders_from_custom_ids( $custom_ids );
|
||||
if ( ! $wc_orders ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal order Id.
|
||||
__( 'Order for PayPal order %s not found.', 'woocommerce-paypal-payments' ),
|
||||
isset( $request['resource']['id'] ) ? $request['resource']['id'] : ''
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$message,
|
||||
array(
|
||||
'request' => $request,
|
||||
)
|
||||
);
|
||||
$response['message'] = $message;
|
||||
return rest_ensure_response( $response );
|
||||
return $this->no_wc_orders_from_custom_ids( $request, $response );
|
||||
}
|
||||
|
||||
foreach ( $wc_orders as $wc_order ) {
|
||||
if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
$this->logger->log(
|
||||
'info',
|
||||
|
||||
$this->logger->info(
|
||||
sprintf(
|
||||
// translators: %s is the order ID.
|
||||
__(
|
||||
|
@ -149,15 +99,11 @@ class CheckoutOrderCompleted implements RequestHandler {
|
|||
'woocommerce-paypal-payments'
|
||||
),
|
||||
(string) $wc_order->get_id()
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
'order' => $wc_order,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$response['success'] = true;
|
||||
return rest_ensure_response( $response );
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles CHECKOUT.PAYMENT-APPROVAL.REVERSED Webhook.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
/**
|
||||
* Class CheckoutPaymentApprovalReversed
|
||||
*/
|
||||
class CheckoutPaymentApprovalReversed implements RequestHandler {
|
||||
|
||||
use RequestHandlerTrait, PrefixTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* CheckoutPaymentApprovalReversed constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct( LoggerInterface $logger ) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array(
|
||||
'CHECKOUT.PAYMENT-APPROVAL.REVERSED',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a handler is responsible for a given request or not.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function responsible_for_request( WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->event_types(), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for handling the request.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function handle_request( WP_REST_Request $request ): WP_REST_Response {
|
||||
$response = array( 'success' => false );
|
||||
|
||||
$custom_ids = $this->get_custom_ids_from_request( $request );
|
||||
if ( empty( $custom_ids ) ) {
|
||||
return $this->no_custom_ids_from_request( $request, $response );
|
||||
}
|
||||
|
||||
$wc_orders = $this->get_wc_orders_from_custom_ids( $custom_ids );
|
||||
if ( ! $wc_orders ) {
|
||||
return $this->no_wc_orders_from_custom_ids( $request, $response );
|
||||
}
|
||||
|
||||
foreach ( $wc_orders as $wc_order ) {
|
||||
if ( in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
|
||||
$error_message = sprintf(
|
||||
// translators: %1$s is the order id.
|
||||
__(
|
||||
'Failed to capture order %1$s through PayPal.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
(string) $wc_order->get_id()
|
||||
);
|
||||
|
||||
$this->logger->warning( 'CHECKOUT.PAYMENT-APPROVAL.REVERSED received. ' . $error_message );
|
||||
|
||||
$wc_order->update_status( 'failed', $error_message );
|
||||
}
|
||||
}
|
||||
|
||||
$response['success'] = true;
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
}
|
111
modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php
Normal file
111
modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
/**
|
||||
* Trait which helps to handle the request.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Webhooks\Handler;
|
||||
|
||||
use stdClass;
|
||||
use WC_Order;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
trait RequestHandlerTrait {
|
||||
|
||||
/**
|
||||
* Get available custom ids from the given request
|
||||
*
|
||||
* @param \WP_REST_Request $request The request.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_custom_ids_from_request( WP_REST_Request $request ): array {
|
||||
return array_filter(
|
||||
array_map(
|
||||
static function ( array $purchase_unit ): string {
|
||||
return isset( $purchase_unit['custom_id'] ) ?
|
||||
(string) $purchase_unit['custom_id'] : '';
|
||||
},
|
||||
$request['resource'] !== null && isset( $request['resource']['purchase_units'] ) ?
|
||||
(array) $request['resource']['purchase_units'] : array()
|
||||
),
|
||||
static function ( string $order_id ): bool {
|
||||
return ! empty( $order_id );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WC orders from the given custom ids.
|
||||
*
|
||||
* @param array $custom_ids The custom ids.
|
||||
* @return WC_Order[]
|
||||
*/
|
||||
protected function get_wc_orders_from_custom_ids( array $custom_ids ): array {
|
||||
$order_ids = array_map(
|
||||
array(
|
||||
$this,
|
||||
'sanitize_custom_id',
|
||||
),
|
||||
$custom_ids
|
||||
);
|
||||
$args = array(
|
||||
'post__in' => $order_ids,
|
||||
'limit' => -1,
|
||||
);
|
||||
|
||||
$orders = wc_get_orders( $args );
|
||||
return is_array( $orders ) ? $orders : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return and log response for no custom ids found in request.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
* @param array $response The response.
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
protected function no_custom_ids_from_request( WP_REST_Request $request, array $response ): WP_REST_Response {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__( 'No order for webhook event %s was found.', 'woocommerce-paypal-payments' ),
|
||||
$request['id'] !== null && isset( $request['id'] ) ? $request['id'] : ''
|
||||
);
|
||||
|
||||
return $this->log_and_return_response( $message, $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return and log response for no WC orders found in response.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
* @param array $response The response.
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
protected function no_wc_orders_from_custom_ids( WP_REST_Request $request, array $response ): WP_REST_Response {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal order Id.
|
||||
__( 'WC order for PayPal order %s not found.', 'woocommerce-paypal-payments' ),
|
||||
$request['resource'] !== null && isset( $request['resource']['id'] ) ? $request['resource']['id'] : ''
|
||||
);
|
||||
|
||||
return $this->log_and_return_response( $message, $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return and log response with the given message.
|
||||
*
|
||||
* @param string $message The message.
|
||||
* @param array $response The response.
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
private function log_and_return_response( string $message, array $response ): WP_REST_Response {
|
||||
$this->logger->warning( $message );
|
||||
$response['message'] = $message;
|
||||
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
}
|
|
@ -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',
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ declare( strict_types = 1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
define( 'PAYPAL_API_URL', 'https://api.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2022-04-13' );
|
||||
|
@ -134,7 +136,7 @@ define( 'PPCP_FLAG_SEPARATE_APM_BUTTONS', apply_filters( 'woocommerce_paypal_pay
|
|||
$links,
|
||||
sprintf(
|
||||
'<a href="%1$s">%2$s</a>',
|
||||
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' ),
|
||||
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=' . Settings::CONNECTION_TAB_ID ),
|
||||
__( 'Settings', 'woocommerce-paypal-payments' )
|
||||
)
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue