Fix merge conflict

This commit is contained in:
dinamiko 2021-09-16 12:34:05 +02:00
commit 17de4ac1de
33 changed files with 946 additions and 341 deletions

56
bootstrap.php Normal file
View file

@ -0,0 +1,56 @@
<?php
/**
* Bootstraps the modular app.
*
* @package WooCommerce\PayPalCommerce
*/
use Dhii\Container\CachingContainer;
use Dhii\Container\CompositeCachingServiceProvider;
use Dhii\Container\CompositeContainer;
use Dhii\Container\DelegatingContainer;
use Dhii\Container\ProxyContainer;
use Dhii\Modular\Module\ModuleInterface;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
return function (
string $root_dir,
ContainerInterface ...$additional_containers
): ContainerInterface {
$modules = ( require "$root_dir/modules.php" )( $root_dir );
// Use this filter to add custom module or remove some of existing ones.
// Modules able to access container, add services and modify existing ones.
$modules = apply_filters( 'woocommerce_paypal_payments_modules', $modules );
$providers = array_map(
function ( ModuleInterface $module ): ServiceProviderInterface {
return $module->setup();
},
$modules
);
$provider = new CompositeCachingServiceProvider( $providers );
$proxy_container = new ProxyContainer();
// TODO: caching does not work currently,
// may want to consider fixing it later (pass proxy as parent to DelegatingContainer)
// for now not fixed since we were using this behavior for long time and fixing it now may break things.
$container = new DelegatingContainer( $provider );
$app_container = new CachingContainer(
new CompositeContainer(
array_merge(
$additional_containers,
array( $container )
)
)
);
$proxy_container->setInnerContainer( $app_container );
foreach ( $modules as $module ) {
/* @var $module ModuleInterface module */
$module->run( $app_container );
}
return $app_container;
};

29
modules.php Normal file
View file

@ -0,0 +1,29 @@
<?php
/**
* The list of modules.
*
* @package WooCommerce\PayPalCommerce
*/
use WooCommerce\PayPalCommerce\PluginModule;
return function ( string $root_dir ): iterable {
$modules_dir = "$root_dir/modules";
$modules = array(
new PluginModule(),
( require "$modules_dir/woocommerce-logging/module.php" )(),
( require "$modules_dir/ppcp-admin-notices/module.php" )(),
( require "$modules_dir/ppcp-api-client/module.php" )(),
( require "$modules_dir/ppcp-button/module.php" )(),
( require "$modules_dir/ppcp-compat/module.php" )(),
( require "$modules_dir/ppcp-onboarding/module.php" )(),
( require "$modules_dir/ppcp-session/module.php" )(),
( require "$modules_dir/ppcp-status-report/module.php" )(),
( require "$modules_dir/ppcp-subscription/module.php" )(),
( require "$modules_dir/ppcp-wc-gateway/module.php" )(),
( require "$modules_dir/ppcp-webhooks/module.php" )(),
);
return $modules;
};

View file

@ -36,6 +36,48 @@ trait RequestTrait {
$args['headers']['PayPal-Partner-Attribution-Id'] = 'Woo_PPCP';
}
return wp_remote_get( $url, $args );
$response = wp_remote_get( $url, $args );
$this->logger->debug( $this->request_response_string( $url, $args, $response ) );
return $response;
}
/**
* Returns request and response information as string.
*
* @param string $url The request URL.
* @param array $args The request arguments.
* @param array $response The response.
* @return string
*/
private function request_response_string( string $url, array $args, array $response ): string {
$method = $args['method'] ?? '';
$output = $method . ' ' . $url . "\n";
if ( isset( $args['body'] ) ) {
if ( ! in_array(
$url,
array(
trailingslashit( $this->host ) . 'v1/oauth2/token/',
trailingslashit( $this->host ) . 'v1/oauth2/token?grant_type=client_credentials',
),
true
) ) {
$output .= 'Request Body: ' . wc_print_r( $args['body'], true ) . "\n";
}
}
if ( isset( $response['headers']->getAll()['paypal-debug-id'] ) ) {
$output .= 'Response Debug ID: ' . $response['headers']->getAll()['paypal-debug-id'] . "\n";
}
if ( isset( $response['response'] ) ) {
$output .= 'Response: ' . wc_print_r( $response['response'], true ) . "\n";
if ( isset( $response['body'] )
&& isset( $response['response']['code'] )
&& ! in_array( $response['response']['code'], array( 200, 201, 202, 204 ), true ) ) {
$output .= 'Response Body: ' . wc_print_r( $response['body'], true ) . "\n";
}
}
return $output;
}
}

View file

@ -79,14 +79,14 @@ class WebhookEndpoint {
*
* @return Webhook
* @throws RuntimeException If the request fails.
* @throws PayPalApiException If the request fails.
*/
public function create( Webhook $hook ): Webhook {
/**
* An hook, which has an ID has already been created.
*/
// The hook was already created.
if ( $hook->id() ) {
return $hook;
}
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v1/notifications/webhooks';
$args = array(
@ -100,36 +100,18 @@ class WebhookEndpoint {
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
throw new RuntimeException(
__( 'Not able to create a webhook.', 'woocommerce-paypal-payments' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$json = json_decode( $response['body'] );
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
$error = new PayPalApiException(
throw new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$hook = $this->webhook_factory->from_paypal_response( $json );
@ -160,18 +142,9 @@ class WebhookEndpoint {
$response = $this->request( $url, $args );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
throw new RuntimeException(
__( 'Not able to delete the webhook.', 'woocommerce-paypal-payments' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
return wp_remote_retrieve_response_code( $response ) === 204;
}

View file

@ -743,8 +743,7 @@ class SmartButton implements SmartButtonInterface {
'currency' => get_woocommerce_currency(),
'integration-date' => PAYPAL_INTEGRATION_DATE,
'components' => implode( ',', $this->components() ),
'vault' => $this->can_save_vault_token() ?
'true' : 'false',
'vault' => $this->can_save_vault_token() ? 'true' : 'false',
'commit' => is_checkout() ? 'true' : 'false',
'intent' => ( $this->settings->has( 'intent' ) ) ?
$this->settings->get( 'intent' ) : 'capture',
@ -757,11 +756,20 @@ class SmartButton implements SmartButtonInterface {
) {
$params['buyer-country'] = WC()->customer->get_billing_country();
}
$disable_funding = $this->settings->has( 'disable_funding' ) ?
$this->settings->get( 'disable_funding' ) : array();
$disable_funding = $this->settings->has( 'disable_funding' )
? $this->settings->get( 'disable_funding' )
: array();
if ( ! is_checkout() ) {
$disable_funding[] = 'card';
}
if ( is_checkout() && $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) ) {
$key = array_search( 'card', $disable_funding, true );
if ( false !== $key ) {
unset( $disable_funding[ $key ] );
}
}
if ( count( $disable_funding ) > 0 ) {
$params['disable-funding'] = implode( ',', array_unique( $disable_funding ) );

View file

@ -136,7 +136,7 @@ class LoginSellerEndpoint implements EndpointInterface {
$this->cache->delete( PayPalBearer::CACHE_KEY );
}
wp_schedule_single_event(
time() - 1,
time() + 5,
WebhookRegistrar::EVENT_HOOK
);
wp_send_json_success();

View file

@ -5,6 +5,8 @@
* @package WooCommerce\PayPalCommerce\WcGateway
*/
// phpcs:disable WordPress.Security.NonceVerification.Recommended
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway;
@ -28,6 +30,7 @@ use Woocommerce\PayPalCommerce\WcGateway\Helper\DccProductStatus;
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
@ -48,6 +51,7 @@ return array(
$state = $container->get( 'onboarding.state' );
$transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' );
$subscription_helper = $container->get( 'subscription.helper' );
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
return new PayPalGateway(
$settings_renderer,
$order_processor,
@ -58,7 +62,8 @@ return array(
$refund_processor,
$state,
$transaction_url_provider,
$subscription_helper
$subscription_helper,
$page_id
);
},
'wcgateway.credit-card-gateway' => static function ( $container ): CreditCardGateway {
@ -100,6 +105,33 @@ return array(
$settings = $container->get( 'wcgateway.settings' );
return new DisableGateways( $session_handler, $settings );
},
'wcgateway.is-wc-payments-page' => static function ( $container ): bool {
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
$tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
return 'wc-settings' === $page && 'checkout' === $tab;
},
'wcgateway.is-ppcp-settings-page' => static function ( $container ): bool {
if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) {
return false;
}
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID ), true );
},
'wcgateway.current-ppcp-settings-page-id' => static function ( $container ): string {
if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) {
return '';
}
$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 ] ) ) : '';
return $ppcp_tab ? $ppcp_tab : $section;
},
'wcgateway.settings' => static function ( $container ): Settings {
return new Settings();
},
@ -108,12 +140,19 @@ return array(
$settings = $container->get( 'wcgateway.settings' );
return new ConnectAdminNotice( $state, $settings );
},
'wcgateway.notice.dcc-without-paypal' => static function ( $container ): DccWithoutPayPalAdminNotice {
$state = $container->get( 'onboarding.state' );
$settings = $container->get( 'wcgateway.settings' );
$is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' );
$is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' );
return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page );
},
'wcgateway.notice.authorize-order-action' =>
static function ( $container ): AuthorizeOrderActionNotice {
return new AuthorizeOrderActionNotice();
},
'wcgateway.settings.sections-renderer' => static function ( $container ): SectionsRenderer {
return new SectionsRenderer();
return new SectionsRenderer( $container->get( 'wcgateway.current-ppcp-settings-page-id' ) );
},
'wcgateway.settings.status' => static function ( $container ): SettingsStatus {
$settings = $container->get( 'wcgateway.settings' );
@ -127,6 +166,7 @@ return array(
$messages_apply = $container->get( 'button.helper.messages-apply' );
$dcc_product_status = $container->get( 'wcgateway.helper.dcc-product-status' );
$settings_status = $container->get( 'wcgateway.settings.status' );
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
return new SettingsRenderer(
$settings,
$state,
@ -134,7 +174,8 @@ return array(
$dcc_applies,
$messages_apply,
$dcc_product_status,
$settings_status
$settings_status,
$page_id
);
},
'wcgateway.settings.listener' => static function ( $container ): SettingsListener {
@ -144,7 +185,8 @@ return array(
$state = $container->get( 'onboarding.state' );
$cache = new Cache( 'ppcp-paypal-bearer' );
$bearer = $container->get( 'api.bearer' );
return new SettingsListener( $settings, $fields, $webhook_registrar, $cache, $state, $bearer );
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
return new SettingsListener( $settings, $fields, $webhook_registrar, $cache, $state, $bearer, $page_id );
},
'wcgateway.order-processor' => static function ( $container ): OrderProcessor {
@ -1876,15 +1918,6 @@ return array(
unset( $fields['ppcp_disconnect_sandbox'] );
}
/**
* Disable card for UK.
*/
$region = wc_get_base_location();
$country = $region['country'];
if ( 'GB' === $country ) {
unset( $fields['disable_funding']['options']['card'] );
}
/**
* Depending on your store location, some credit cards can't be used.
* Here, we filter them out.

View file

@ -197,13 +197,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'label' => __( 'Enable Credit Card Payments', 'woocommerce-paypal-payments' ),
'default' => 'no',
),
'ppcp' => array(
'ppcp' => array(
'type' => 'ppcp',
),
);
@ -218,6 +212,20 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
}
/**
* Renders the settings.
*
* @return string
*/
public function generate_ppcp_html(): string {
ob_start();
$this->settings_renderer->render();
$content = ob_get_contents();
ob_end_clean();
return $content;
}
/**
* Replace WooCommerce credit card field label.
*
@ -314,7 +322,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
* @return bool
*/
public function is_available() : bool {
return $this->config->has( 'dcc_enabled' ) && $this->config->get( 'dcc_enabled' );
return $this->is_enabled();
}
@ -349,4 +357,60 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
return parent::get_transaction_url( $order );
}
/**
* Initialize settings for WC.
*
* @return void
*/
public function init_settings() {
parent::init_settings();
// looks like in some cases WC uses this field instead of get_option.
$this->enabled = $this->is_enabled();
}
/**
* Get the option value for WC.
*
* @param string $key The option key.
* @param mixed $empty_value Value when empty.
* @return mixed
*/
public function get_option( $key, $empty_value = null ) {
if ( 'enabled' === $key ) {
return $this->is_enabled();
}
return parent::get_option( $key, $empty_value );
}
/**
* Handle update of WC settings.
*
* @param string $key The option key.
* @param string $value The option value.
* @return bool was anything saved?
*/
public function update_option( $key, $value = '' ) {
$ret = parent::update_option( $key, $value );
if ( 'enabled' === $key ) {
$this->config->set( 'dcc_enabled', 'yes' === $value );
$this->config->persist();
return true;
}
return $ret;
}
/**
* Returns if the gateway is enabled.
*
* @return bool
*/
private function is_enabled(): bool {
return $this->config->has( 'dcc_enabled' ) && $this->config->get( 'dcc_enabled' );
}
}

View file

@ -103,6 +103,13 @@ class PayPalGateway extends \WC_Payment_Gateway {
*/
private $onboarded;
/**
* ID of the current PPCP gateway settings page, or empty if it is not such page.
*
* @var string
*/
protected $page_id;
/**
* PayPalGateway constructor.
*
@ -116,6 +123,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
* @param State $state The state.
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
* @param SubscriptionHelper $subscription_helper The subscription helper.
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
*/
public function __construct(
SettingsRenderer $settings_renderer,
@ -127,7 +135,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
RefundProcessor $refund_processor,
State $state,
TransactionUrlProvider $transaction_url_provider,
SubscriptionHelper $subscription_helper
SubscriptionHelper $subscription_helper,
string $page_id
) {
$this->id = self::ID;
@ -139,6 +148,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
$this->session_handler = $session_handler;
$this->refund_processor = $refund_processor;
$this->transaction_url_provider = $transaction_url_provider;
$this->page_id = $page_id;
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
if ( $this->onboarded ) {
@ -332,8 +342,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
*/
private function is_credit_card_tab() : bool {
return is_admin()
&& isset( $_GET[ SectionsRenderer::KEY ] )
&& CreditCardGateway::ID === sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) );
&& CreditCardGateway::ID === $this->page_id;
}
@ -345,8 +354,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
private function is_paypal_tab() : bool {
return ! $this->is_credit_card_tab()
&& is_admin()
&& isset( $_GET['section'] )
&& self::ID === sanitize_text_field( wp_unslash( $_GET['section'] ) );
&& self::ID === $this->page_id;
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
@ -387,14 +395,18 @@ class PayPalGateway extends \WC_Payment_Gateway {
*
* @param string $key The option key.
* @param string $value The option value.
* @return bool|void
* @return bool was anything saved?
*/
public function update_option( $key, $value = '' ) {
parent::update_option( $key, $value );
$ret = parent::update_option( $key, $value );
if ( 'enabled' === $key ) {
$this->config->set( 'enabled', 'yes' === $value );
$this->config->persist();
return true;
}
return $ret;
}
}

View file

@ -0,0 +1,101 @@
<?php
/**
* Creates the admin message about the DCC gateway being enabled without the PayPal gateway.
*
* @package WooCommerce\PayPalCommerce\WcGateway\Notice
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Notice;
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
use WooCommerce\PayPalCommerce\Onboarding\State;
use Psr\Container\ContainerInterface;
/**
* Creates the admin message about the DCC gateway being enabled without the PayPal gateway.
*/
class DccWithoutPayPalAdminNotice {
/**
* The state.
*
* @var State
*/
private $state;
/**
* The settings.
*
* @var ContainerInterface
*/
private $settings;
/**
* Whether the current page is the WC payment page.
*
* @var bool
*/
private $is_payments_page;
/**
* Whether the current page is the PPCP settings page.
*
* @var bool
*/
private $is_ppcp_settings_page;
/**
* ConnectAdminNotice constructor.
*
* @param State $state The state.
* @param ContainerInterface $settings The settings.
* @param bool $is_payments_page Whether the current page is the WC payment page.
* @param bool $is_ppcp_settings_page Whether the current page is the PPCP settings page.
*/
public function __construct(
State $state,
ContainerInterface $settings,
bool $is_payments_page,
bool $is_ppcp_settings_page
) {
$this->state = $state;
$this->settings = $settings;
$this->is_payments_page = $is_payments_page;
$this->is_ppcp_settings_page = $is_ppcp_settings_page;
}
/**
* Returns the message.
*
* @return Message|null
*/
public function message(): ?Message {
if ( ! $this->should_display() ) {
return null;
}
$message = sprintf(
/* translators: %1$s the gateway name. */
__(
'PayPal Card Processing cannot be used without the PayPal gateway. <a href="%1$s">Enable the PayPal Gateway</a>.',
'woocommerce-paypal-payments'
),
admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway' )
);
return new Message( $message, 'warning' );
}
/**
* Whether the message should be displayed.
*
* @return bool
*/
protected function should_display(): bool {
return State::STATE_ONBOARDED === $this->state->current_state()
&& ( $this->is_payments_page || $this->is_ppcp_settings_page )
&& ( $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) )
&& ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) );
}
}

View file

@ -19,15 +19,29 @@ class SectionsRenderer {
const KEY = 'ppcp-tab';
/**
* ID of the current PPCP gateway settings page, or empty if it is not such page.
*
* @var string
*/
protected $page_id;
/**
* SectionsRenderer constructor.
*
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
*/
public function __construct( string $page_id ) {
$this->page_id = $page_id;
}
/**
* Whether the sections tab should be rendered.
*
* @return bool
*/
public function should_render() : bool {
global $current_section;
return PayPalGateway::ID === $current_section;
return ! empty( $this->page_id );
}
/**
@ -38,8 +52,6 @@ class SectionsRenderer {
return;
}
//phpcs:ignore WordPress.Security.NonceVerification.Recommended
$current = ! isset( $_GET[ self::KEY ] ) ? PayPalGateway::ID : sanitize_text_field( wp_unslash( $_GET[ self::KEY ] ) );
$sections = array(
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
@ -51,7 +63,7 @@ class SectionsRenderer {
foreach ( $sections as $id => $label ) {
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway&' . self::KEY . '=' . $id );
echo '<li><a href="' . esc_url( $url ) . '" class="' . ( $current === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
echo '<li><a href="' . esc_url( $url ) . '" class="' . ( $this->page_id === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
}
echo '</ul><br class="clear" />';

View file

@ -25,6 +25,11 @@ class SettingsListener {
const NONCE = 'ppcp-settings';
private const CREDENTIALS_ADDED = 'credentials_added';
private const CREDENTIALS_REMOVED = 'credentials_removed';
private const CREDENTIALS_CHANGED = 'credentials_changed';
private const CREDENTIALS_UNCHANGED = 'credentials_unchanged';
/**
* The Settings.
*
@ -67,6 +72,13 @@ class SettingsListener {
*/
private $bearer;
/**
* ID of the current PPCP gateway settings page, or empty if it is not such page.
*
* @var string
*/
protected $page_id;
/**
* SettingsListener constructor.
*
@ -76,6 +88,7 @@ class SettingsListener {
* @param Cache $cache The Cache.
* @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.
*/
public function __construct(
Settings $settings,
@ -83,7 +96,8 @@ class SettingsListener {
WebhookRegistrar $webhook_registrar,
Cache $cache,
State $state,
Bearer $bearer
Bearer $bearer,
string $page_id
) {
$this->settings = $settings;
@ -92,6 +106,7 @@ class SettingsListener {
$this->cache = $cache;
$this->state = $state;
$this->bearer = $bearer;
$this->page_id = $page_id;
}
/**
@ -218,18 +233,46 @@ class SettingsListener {
$settings = $this->read_active_credentials_from_settings( $settings );
if ( ! isset( $_GET[ SectionsRenderer::KEY ] ) || PayPalGateway::ID === $_GET[ SectionsRenderer::KEY ] ) {
$credentials_change_status = null; // Cannot detect on Card Processing page.
if ( PayPalGateway::ID === $this->page_id ) {
$settings['enabled'] = isset( $_POST['woocommerce_ppcp-gateway_enabled'] )
&& 1 === absint( $_POST['woocommerce_ppcp-gateway_enabled'] );
$this->maybe_register_webhooks( $settings );
$credentials_change_status = $this->determine_credentials_change_status( $settings );
}
// phpcs:enable phpcs:disable WordPress.Security.NonceVerification.Missing
// phpcs:enable phpcs:disable WordPress.Security.NonceVerification.Missing
if ( $credentials_change_status ) {
if ( self::CREDENTIALS_UNCHANGED !== $credentials_change_status ) {
$this->settings->set( 'products_dcc_enabled', null );
}
if ( in_array(
$credentials_change_status,
array( self::CREDENTIALS_REMOVED, self::CREDENTIALS_CHANGED ),
true
) ) {
$this->webhook_registrar->unregister();
}
}
foreach ( $settings as $id => $value ) {
$this->settings->set( $id, $value );
}
$this->settings->persist();
if ( $credentials_change_status ) {
if ( in_array(
$credentials_change_status,
array( self::CREDENTIALS_ADDED, self::CREDENTIALS_CHANGED ),
true
) ) {
$this->webhook_registrar->register();
}
}
if ( $this->cache->has( PayPalBearer::CACHE_KEY ) ) {
$this->cache->delete( PayPalBearer::CACHE_KEY );
}
@ -265,30 +308,36 @@ class SettingsListener {
}
/**
* Depending on the settings change, we might need to register or unregister the Webhooks at PayPal.
* Checks whether on the credentials changed.
*
* @param array $settings The settings.
*
* @throws \WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting hasn't been found.
* @param array $new_settings New settings.
* @return string One of the CREDENTIALS_ constants.
*/
private function maybe_register_webhooks( array $settings ) {
private function determine_credentials_change_status( array $new_settings ): string {
$current_id = $this->settings->has( 'client_id' ) ? $this->settings->get( 'client_id' ) : '';
$current_secret = $this->settings->has( 'client_secret' ) ? $this->settings->get( 'client_secret' ) : '';
$new_id = $new_settings['client_id'] ?? '';
$new_secret = $new_settings['client_secret'] ?? '';
if ( ! $this->settings->has( 'client_id' ) && $settings['client_id'] ) {
$this->settings->set( 'products_dcc_enabled', null );
$this->webhook_registrar->register();
$had_credentials = $current_id && $current_secret;
$submitted_credentials = $new_id && $new_secret;
if ( ! $had_credentials && $submitted_credentials ) {
return self::CREDENTIALS_ADDED;
}
if ( $this->settings->has( 'client_id' ) && $this->settings->get( 'client_id' ) ) {
$current_secret = $this->settings->has( 'client_secret' ) ?
$this->settings->get( 'client_secret' ) : '';
if ( $had_credentials ) {
if ( ! $submitted_credentials ) {
return self::CREDENTIALS_REMOVED;
}
if (
$settings['client_id'] !== $this->settings->get( 'client_id' )
|| $settings['client_secret'] !== $current_secret
$current_id !== $new_id
|| $current_secret !== $new_secret
) {
$this->settings->set( 'products_dcc_enabled', null );
$this->webhook_registrar->unregister();
$this->webhook_registrar->register();
return self::CREDENTIALS_CHANGED;
}
}
return self::CREDENTIALS_UNCHANGED;
}
/**
@ -313,17 +362,13 @@ class SettingsListener {
}
if (
'dcc' === $config['gateway']
&& (
! isset( $_GET[ SectionsRenderer::KEY ] )
|| sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) !== CreditCardGateway::ID
)
&& CreditCardGateway::ID !== $this->page_id
) {
continue;
}
if (
'paypal' === $config['gateway']
&& isset( $_GET[ SectionsRenderer::KEY ] )
&& sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) !== PayPalGateway::ID
&& PayPalGateway::ID !== $this->page_id
) {
continue;
}
@ -406,14 +451,7 @@ class SettingsListener {
* phpcs:disable WordPress.Security.NonceVerification.Missing
* phpcs:disable WordPress.Security.NonceVerification.Recommended
*/
if (
! isset( $_REQUEST['section'] )
|| ! in_array(
sanitize_text_field( wp_unslash( $_REQUEST['section'] ) ),
array( 'ppcp-gateway', 'ppcp-credit-card-gateway' ),
true
)
) {
if ( empty( $this->page_id ) ) {
return false;
}

View file

@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use Woocommerce\PayPalCommerce\WcGateway\Helper\DccProductStatus;
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
@ -72,6 +73,13 @@ class SettingsRenderer {
*/
private $dcc_product_status;
/**
* ID of the current PPCP gateway settings page, or empty if it is not such page.
*
* @var string
*/
protected $page_id;
/**
* SettingsRenderer constructor.
*
@ -82,6 +90,7 @@ class SettingsRenderer {
* @param MessagesApply $messages_apply Whether messages can be shown.
* @param DccProductStatus $dcc_product_status The product status.
* @param SettingsStatus $settings_status The Settings status helper.
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
*/
public function __construct(
ContainerInterface $settings,
@ -90,7 +99,8 @@ class SettingsRenderer {
DccApplies $dcc_applies,
MessagesApply $messages_apply,
DccProductStatus $dcc_product_status,
SettingsStatus $settings_status
SettingsStatus $settings_status,
string $page_id
) {
$this->settings = $settings;
@ -100,6 +110,7 @@ class SettingsRenderer {
$this->messages_apply = $messages_apply;
$this->dcc_product_status = $dcc_product_status;
$this->settings_status = $settings_status;
$this->page_id = $page_id;
}
/**
@ -166,21 +177,7 @@ class SettingsRenderer {
* @return bool Whether is PayPal checkout screen or not.
*/
private function is_paypal_checkout_screen(): bool {
$current_screen = get_current_screen();
//phpcs:disable WordPress.Security.NonceVerification.Recommended
//phpcs:disable WordPress.Security.NonceVerification.Missing
if ( isset( $current_screen->id ) && 'woocommerce_page_wc-settings' === $current_screen->id
&& isset( $_GET['section'] ) && 'ppcp-gateway' === $_GET['section'] ) {
if ( isset( $_GET['ppcp-tab'] ) && 'ppcp-gateway' !== $_GET['ppcp-tab'] ) {
return false;
}
return true;
}
//phpcs:enable
return false;
return PayPalGateway::ID === $this->page_id;
}
/**
@ -317,9 +314,7 @@ class SettingsRenderer {
*/
public function render() {
//phpcs:disable WordPress.Security.NonceVerification.Recommended
//phpcs:disable WordPress.Security.NonceVerification.Missing
$is_dcc = isset( $_GET[ SectionsRenderer::KEY ] ) && CreditCardGateway::ID === sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) );
$is_dcc = CreditCardGateway::ID === $this->page_id;
//phpcs:enable WordPress.Security.NonceVerification.Recommended
//phpcs:enable WordPress.Security.NonceVerification.Missing
$nonce = wp_create_nonce( SettingsListener::NONCE );
@ -506,8 +501,8 @@ class SettingsRenderer {
return false;
}
return $this->is_paypal_checkout_screen() && $this->paypal_vaulting_is_enabled()
|| $this->is_paypal_checkout_screen() && $this->settings_status->pay_later_messaging_is_enabled();
return $this->is_paypal_checkout_screen()
&& ( $this->paypal_vaulting_is_enabled() || $this->settings_status->pay_later_messaging_is_enabled() );
}
}

View file

@ -24,6 +24,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
@ -58,7 +59,6 @@ class WcGatewayModule implements ModuleInterface {
$this->register_order_functionality( $container );
$this->register_columns( $container );
$this->register_checkout_paypal_address_preset( $container );
$this->ajax_gateway_enabler( $container );
add_action(
'woocommerce_sections_checkout',
@ -86,15 +86,19 @@ class WcGatewayModule implements ModuleInterface {
Repository::NOTICES_FILTER,
static function ( $notices ) use ( $container ): array {
$notice = $container->get( 'wcgateway.notice.connect' );
/**
* The Connect Admin Notice object.
*
* @var ConnectAdminNotice $notice
*/
assert( $notice instanceof ConnectAdminNotice );
$connect_message = $notice->connect_message();
if ( $connect_message ) {
$notices[] = $connect_message;
}
$dcc_without_paypal_notice = $container->get( 'wcgateway.notice.dcc-without-paypal' );
assert( $dcc_without_paypal_notice instanceof DccWithoutPayPalAdminNotice );
$dcc_without_paypal_message = $dcc_without_paypal_notice->message();
if ( $dcc_without_paypal_message ) {
$notices[] = $dcc_without_paypal_message;
}
$authorize_order_action = $container->get( 'wcgateway.notice.authorize-order-action' );
$authorized_message = $authorize_order_action->message();
if ( $authorized_message ) {
@ -102,11 +106,7 @@ class WcGatewayModule implements ModuleInterface {
}
$settings_renderer = $container->get( 'wcgateway.settings.render' );
/**
* The settings renderer.
*
* @var SettingsRenderer $settings_renderer
*/
assert( $settings_renderer instanceof SettingsRenderer );
$messages = $settings_renderer->messages();
$notices = array_merge( $notices, $messages );
@ -149,50 +149,6 @@ class WcGatewayModule implements ModuleInterface {
);
}
/**
* Adds the functionality to listen to the ajax enable gateway switch.
*
* @param ContainerInterface $container The container.
*/
private function ajax_gateway_enabler( ContainerInterface $container ) {
add_action(
'wp_ajax_woocommerce_toggle_gateway_enabled',
static function () use ( $container ) {
if (
! current_user_can( 'manage_woocommerce' )
|| ! check_ajax_referer(
'woocommerce-toggle-payment-gateway-enabled',
'security'
)
|| ! isset( $_POST['gateway_id'] )
) {
return;
}
/**
* The settings.
*
* @var Settings $settings
*/
$settings = $container->get( 'wcgateway.settings' );
$key = PayPalGateway::ID === $_POST['gateway_id'] ? 'enabled' : '';
if ( CreditCardGateway::ID === $_POST['gateway_id'] ) {
$key = 'dcc_enabled';
}
if ( ! $key ) {
return;
}
$enabled = $settings->has( $key ) ? $settings->get( $key ) : false;
if ( ! $enabled ) {
return;
}
$settings->set( $key, false );
$settings->persist();
},
9
);
}
/**
* Registers the payment gateways.
*
@ -206,16 +162,12 @@ class WcGatewayModule implements ModuleInterface {
$methods[] = $container->get( 'wcgateway.paypal-gateway' );
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
$screen = ! function_exists( 'get_current_screen' ) ? (object) array( 'id' => 'front' ) : get_current_screen();
if ( ! $screen ) {
$screen = (object) array( 'id' => 'front' );
}
/**
* The DCC Applies object.
*
* @var DccApplies $dcc_applies
*/
if ( 'woocommerce_page_wc-settings' !== $screen->id && $dcc_applies->for_country_currency() ) {
if ( $dcc_applies->for_country_currency() ) {
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
}
return (array) $methods;

View file

@ -22,10 +22,12 @@ return array(
$factory = $container->get( 'api.factory.webhook' );
$endpoint = $container->get( 'api.endpoint.webhook' );
$rest_endpoint = $container->get( 'webhook.endpoint.controller' );
$logger = $container->get( 'woocommerce.logger.woocommerce' );
return new WebhookRegistrar(
$factory,
$endpoint,
$rest_endpoint
$rest_endpoint,
$logger
);
},
'webhook.endpoint.controller' => function( $container ) : IncomingWebhookEndpoint {

View file

@ -9,6 +9,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Webhooks;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
@ -43,22 +44,32 @@ class WebhookRegistrar {
*/
private $rest_endpoint;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* WebhookRegistrar constructor.
*
* @param WebhookFactory $webhook_factory The Webhook factory.
* @param WebhookEndpoint $endpoint The Webhook endpoint.
* @param IncomingWebhookEndpoint $rest_endpoint The WordPress Rest API endpoint.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
WebhookFactory $webhook_factory,
WebhookEndpoint $endpoint,
IncomingWebhookEndpoint $rest_endpoint
IncomingWebhookEndpoint $rest_endpoint,
LoggerInterface $logger
) {
$this->webhook_factory = $webhook_factory;
$this->endpoint = $endpoint;
$this->rest_endpoint = $rest_endpoint;
$this->logger = $logger;
}
/**
@ -81,8 +92,10 @@ class WebhookRegistrar {
self::KEY,
$created->to_array()
);
$this->logger->info( 'Webhooks registered.' );
return true;
} catch ( RuntimeException $error ) {
$this->logger->error( 'Failed to register webhooks: ' . $error->getMessage() );
return false;
}
}
@ -101,11 +114,13 @@ class WebhookRegistrar {
$webhook = $this->webhook_factory->from_array( $data );
$success = $this->endpoint->delete( $webhook );
} catch ( RuntimeException $error ) {
$this->logger->error( 'Failed to delete webhooks: ' . $error->getMessage() );
return false;
}
if ( $success ) {
delete_option( self::KEY );
$this->logger->info( 'Webhooks deleted.' );
}
return $success;
}

View file

@ -23,6 +23,8 @@
<file>./src</file>
<file>./modules</file>
<file>./woocommerce-paypal-payments.php</file>
<file>./modules.php</file>
<file>./bootstrap.php</file>
<exclude-pattern>*/node_modules/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>

View file

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Authentication;
use Requests_Utility_CaseInsensitiveDictionary;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
@ -28,10 +29,12 @@ class PayPalBearerTest extends TestCase
$key = 'key';
$secret = 'secret';
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$settings = Mockery::mock(Settings::class);
$settings->shouldReceive('has')->andReturn(true);
$settings->shouldReceive('get')->andReturn('');
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
@ -40,7 +43,7 @@ class PayPalBearerTest extends TestCase
->andReturn($host . '/');
expect('wp_remote_get')
->andReturnUsing(
function ($url, $args) use ($json, $key, $secret, $host) {
function ($url, $args) use ($json, $key, $secret, $host, $headers) {
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
return false;
}
@ -53,6 +56,7 @@ class PayPalBearerTest extends TestCase
return [
'body' => $json,
'headers' => $headers
];
}
);
@ -80,10 +84,12 @@ class PayPalBearerTest extends TestCase
$key = 'key';
$secret = 'secret';
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$settings = Mockery::mock(Settings::class);
$settings->shouldReceive('has')->andReturn(true);
$settings->shouldReceive('get')->andReturn('');
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
@ -92,7 +98,7 @@ class PayPalBearerTest extends TestCase
->andReturn($host . '/');
expect('wp_remote_get')
->andReturnUsing(
function ($url, $args) use ($json, $key, $secret, $host) {
function ($url, $args) use ($json, $key, $secret, $host, $headers) {
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
return false;
}
@ -105,6 +111,7 @@ class PayPalBearerTest extends TestCase
return [
'body' => $json,
'headers' => $headers,
];
}
);
@ -153,9 +160,12 @@ class PayPalBearerTest extends TestCase
$secret = 'secret';
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$settings = Mockery::mock(Settings::class);
$settings->shouldReceive('has')->andReturn(true);
$settings->shouldReceive('get')->andReturn('');
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
@ -164,7 +174,7 @@ class PayPalBearerTest extends TestCase
->andReturn($host . '/');
expect('wp_remote_get')
->andReturnUsing(
function ($url, $args) use ($json, $key, $secret, $host) {
function ($url, $args) use ($json, $key, $secret, $host, $headers) {
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
return false;
}
@ -177,6 +187,7 @@ class PayPalBearerTest extends TestCase
return [
'body' => $json,
'headers' => $headers,
];
}
);
@ -199,9 +210,12 @@ class PayPalBearerTest extends TestCase
$secret = 'secret';
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$settings = Mockery::mock(Settings::class);
$settings->shouldReceive('has')->andReturn(true);
$settings->shouldReceive('get')->andReturn('');
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
@ -210,7 +224,7 @@ class PayPalBearerTest extends TestCase
->andReturn($host . '/');
expect('wp_remote_get')
->andReturnUsing(
function ($url, $args) use ($json, $key, $secret, $host) {
function ($url, $args) use ($json, $key, $secret, $host, $headers) {
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
return false;
}
@ -223,6 +237,7 @@ class PayPalBearerTest extends TestCase
return [
'body' => $json,
'headers' => $headers,
];
}
);

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
use Psr\Log\LoggerInterface;
use Requests_Utility_CaseInsensitiveDictionary;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
@ -11,6 +12,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use function Brain\Monkey\Functions\expect;
use function Brain\Monkey\Functions\when;
class IdentityTokenTest extends TestCase
{
@ -40,10 +42,18 @@ class IdentityTokenTest extends TestCase
$this->bearer
->expects('bearer')->andReturn($token);
$rawResponse = ['body' => '{"client_token":"abc123", "expires_in":3600}'];
$host = $this->host;
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$this->logger->shouldReceive('debug');
$rawResponse = [
'body' => '{"client_token":"abc123", "expires_in":3600}',
'headers' => $headers,
];
expect('wp_remote_get')
->andReturnUsing(function ($url, $args) use ($rawResponse, $host) {
->andReturnUsing(function ($url, $args) use ($rawResponse, $host, $headers) {
if ($url !== $host . 'v1/identity/generate-token') {
return false;
}
@ -65,6 +75,7 @@ class IdentityTokenTest extends TestCase
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200);
when('wc_print_r')->returnArg();
$result = $this->sut->generate_for_customer(1);
$this->assertInstanceOf(Token::class, $result);
@ -78,9 +89,13 @@ class IdentityTokenTest extends TestCase
$this->bearer
->expects('bearer')->andReturn($token);
expect('wp_remote_get')->andReturn();
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
expect('wp_remote_get')->andReturn(['headers' => $headers,]);
expect('is_wp_error')->andReturn(true);
when('wc_print_r')->returnArg();
$this->logger->shouldReceive('log');
$this->logger->shouldReceive('debug');
$this->expectException(RuntimeException::class);
$this->sut->generate_for_customer(1);
@ -94,10 +109,17 @@ class IdentityTokenTest extends TestCase
$this->bearer
->expects('bearer')->andReturn($token);
expect('wp_remote_get')->andReturn(['body' => '',]);
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
expect('wp_remote_get')->andReturn([
'body' => '',
'headers' => $headers,
]);
expect('is_wp_error')->andReturn(false);
expect('wp_remote_retrieve_response_code')->andReturn(500);
when('wc_print_r')->returnArg();
$this->logger->shouldReceive('log');
$this->logger->shouldReceive('debug');
$this->expectException(PayPalApiException::class);
$this->sut->generate_for_customer(1);

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
use Hamcrest\Matchers;
use Requests_Utility_CaseInsensitiveDictionary;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
use Woocommerce\PayPalCommerce\ApiClient\Entity\Capture;
@ -22,14 +23,20 @@ use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use Psr\Log\LoggerInterface;
use function Brain\Monkey\Functions\expect;
use function Brain\Monkey\Functions\when;
class OrderEndpointTest extends TestCase
{
public function testOrderDefault()
public function setUp(): void
{
parent::setUp();
when('wc_print_r')->returnArg();
}
public function testOrderDefault()
{
expect('wp_json_encode')->andReturnUsing('json_encode');
$orderId = 'id';
@ -51,10 +58,14 @@ class OrderEndpointTest extends TestCase
$intent = 'CAPTURE';
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
->expects('get_for_order_id')->with($orderId)->andReturn('uniqueRequestId');
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$testee = new OrderEndpoint(
$host,
$bearer,
@ -66,7 +77,10 @@ class OrderEndpointTest extends TestCase
$paypalRequestIdRepository
);
$rawResponse = ['body' => '{"is_correct":true}'];
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
expect('wp_remote_get')
->andReturnUsing(function ($url, $args) use ($rawResponse, $host, $orderId) {
if ($url !== $host . 'v2/checkout/orders/' . $orderId) {
@ -103,10 +117,14 @@ class OrderEndpointTest extends TestCase
$intent = 'CAPTURE';
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
->expects('get_for_order_id')->with($orderId)->andReturn('uniqueRequestId');
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$testee = new OrderEndpoint(
$host,
$bearer,
@ -118,7 +136,10 @@ class OrderEndpointTest extends TestCase
$paypalRequestIdRepository
);
$rawResponse = ['body' => '{"is_correct":true}'];
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
expect('wp_remote_get')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(true);
@ -140,9 +161,15 @@ class OrderEndpointTest extends TestCase
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$rawResponse = ['body' => '{"some_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"some_error":true}',
'headers' => $headers,
];
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
@ -176,8 +203,12 @@ class OrderEndpointTest extends TestCase
$orderToCapture = Mockery::mock(Order::class);
$orderToCapture->expects('status')->andReturn($orderToCaptureStatus);
$orderToCapture->expects('id')->andReturn($orderId);
$rawResponse = ['body' => '{"is_correct":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
$expectedOrder = Mockery::mock(Order::class);
$host = 'https://example.com/';
$token = Mockery::mock(Token::class);
@ -202,6 +233,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
@ -307,6 +339,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
@ -321,8 +354,12 @@ class OrderEndpointTest extends TestCase
$applicationContextRepository,
$paypalRequestIdRepository
);
$rawResponse = ['body' => '{"is_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_error":true}',
'headers' => $headers,
];
expect('wp_remote_get')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(true);
$this->expectException(RuntimeException::class);
@ -351,6 +388,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
@ -366,7 +404,12 @@ class OrderEndpointTest extends TestCase
$paypalRequestIdRepository
);
$rawResponse = ['body' => '{"some_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"some_error":true}',
'headers' => $headers
];
expect('wp_remote_get')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
@ -396,6 +439,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
@ -415,8 +459,12 @@ class OrderEndpointTest extends TestCase
)->makePartial();
$orderToExpect = Mockery::mock(Order::class);
$testee->expects('order')->with($orderId)->andReturn($orderToExpect);
$rawResponse = ['body' => '{"some_error": "' . ErrorResponse::ORDER_ALREADY_CAPTURED . '"}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"some_error": "' . ErrorResponse::ORDER_ALREADY_CAPTURED . '"}',
'headers' => $headers,
];
expect('wp_remote_get')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
@ -436,8 +484,12 @@ class OrderEndpointTest extends TestCase
->shouldReceive('purchase_units')
->andReturn([]);
$orderToCompare = Mockery::mock(Order::class);
$rawResponse = ['body' => '{"is_correct":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
$expectedOrder = Mockery::mock(Order::class);
$host = 'https://example.com/';
$token = Mockery::mock(Token::class);
@ -464,6 +516,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
@ -533,8 +586,12 @@ class OrderEndpointTest extends TestCase
->shouldReceive('purchase_units')
->andReturn([]);
$orderToCompare = Mockery::mock(Order::class);
$rawResponse = ['body' => '{"has_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"has_error":true}',
'headers' => $headers,
];
$expectedOrder = Mockery::mock(Order::class);
$host = 'https://example.com/';
$token = Mockery::mock(Token::class);
@ -561,6 +618,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
$paypalRequestIdRepository
@ -624,8 +682,12 @@ class OrderEndpointTest extends TestCase
->shouldReceive('purchase_units')
->andReturn([]);
$orderToCompare = Mockery::mock(Order::class);
$rawResponse = ['body' => '{"is_correct":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
$expectedOrder = Mockery::mock(Order::class);
$host = 'https://example.com/';
$token = Mockery::mock(Token::class);
@ -652,6 +714,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
@ -748,7 +811,12 @@ class OrderEndpointTest extends TestCase
public function testCreateForPurchaseUnitsDefault()
{
expect('wp_json_encode')->andReturnUsing('json_encode');
$rawResponse = ['body' => '{"success":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"success":true}',
'headers' => $headers,
];
$host = 'https://example.com/';
$bearer = Mockery::mock(Bearer::class);
$token = Mockery::mock(Token::class);
@ -772,6 +840,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$applicationContext = Mockery::mock(ApplicationContext::class);
$applicationContext
->expects('to_array')
@ -844,7 +913,12 @@ class OrderEndpointTest extends TestCase
public function testCreateForPurchaseUnitsWithPayer()
{
expect('wp_json_encode')->andReturnUsing('json_encode');
$rawResponse = ['body' => '{"success":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"success":true}',
'headers' => $headers,
];
$host = 'https://example.com/';
$token = Mockery::mock(Token::class);
$token
@ -868,6 +942,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$applicationContext = Mockery::mock(ApplicationContext::class);
$applicationContext
->expects('to_array')
@ -928,7 +1003,12 @@ class OrderEndpointTest extends TestCase
public function testCreateForPurchaseUnitsIsWpError()
{
expect('wp_json_encode')->andReturnUsing('json_encode');
$rawResponse = ['body' => '{"success":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"success":true}',
'headers' => $headers,
];
$host = 'https://example.com/';
$token = Mockery::mock(Token::class);
$token
@ -943,6 +1023,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContext = Mockery::mock(ApplicationContext::class);
$applicationContext
->expects('to_array')
@ -1006,7 +1087,12 @@ class OrderEndpointTest extends TestCase
public function testCreateForPurchaseUnitsIsNot201()
{
expect('wp_json_encode')->andReturnUsing('json_encode');
$rawResponse = ['body' => '{"has_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"has_error":true}',
'headers' => $headers,
];
$host = 'https://example.com/';
$token = Mockery::mock(Token::class);
$token
@ -1021,6 +1107,7 @@ class OrderEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$applicationContext = Mockery::mock(ApplicationContext::class);
$applicationContext
->expects('to_array')

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
use Psr\Log\LoggerInterface;
use Requests_Utility_CaseInsensitiveDictionary;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
@ -48,7 +49,12 @@ class PaymentTokenEndpointTest extends TestCase
{
$id = 1;
$token = Mockery::mock(Token::class);
$rawResponse = ['body' => '{"payment_tokens":[{"id": "123abc"}]}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"payment_tokens":[{"id": "123abc"}]}',
'headers' => $headers,
];
$paymentToken = Mockery::mock(PaymentToken::class);
$paymentToken->shouldReceive('id')
->andReturn('foo');
@ -65,6 +71,8 @@ class PaymentTokenEndpointTest extends TestCase
$this->factory->shouldReceive('from_paypal_response')
->andReturn($paymentToken);
$this->logger->shouldReceive('debug');
$result = $this->sut->for_user($id);
$this->assertInstanceOf(PaymentToken::class, $result[0]);
@ -74,7 +82,9 @@ class PaymentTokenEndpointTest extends TestCase
{
$id = 1;
$token = Mockery::mock(Token::class);
$rawResponse = [];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = ['headers' => $headers,];
$this->bearer->shouldReceive('bearer')
->andReturn($token);
$token->shouldReceive('token')
@ -84,6 +94,7 @@ class PaymentTokenEndpointTest extends TestCase
expect('wp_remote_get')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(true);
$this->logger->shouldReceive('log');
$this->logger->shouldReceive('debug');
$this->expectException(RuntimeException::class);
$this->sut->for_user($id);
@ -93,7 +104,12 @@ class PaymentTokenEndpointTest extends TestCase
{
$id = 1;
$token = Mockery::mock(Token::class);
$rawResponse = ['body' => '{"some_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"some_error":true}',
'headers' => $headers,
];
$this->bearer->shouldReceive('bearer')
->andReturn($token);
$token->shouldReceive('token')
@ -105,6 +121,7 @@ class PaymentTokenEndpointTest extends TestCase
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
$this->logger->shouldReceive('log');
$this->logger->shouldReceive('debug');
$this->expectException(PayPalApiException::class);
$this->sut->for_user($id);
@ -112,7 +129,7 @@ class PaymentTokenEndpointTest extends TestCase
public function testDeleteToken()
{
$paymentToken = $paymentToken = Mockery::mock(PaymentToken::class);
$paymentToken = Mockery::mock(PaymentToken::class);
$paymentToken->shouldReceive('id')
->andReturn('foo');
$token = Mockery::mock(Token::class);
@ -121,9 +138,14 @@ class PaymentTokenEndpointTest extends TestCase
$token->shouldReceive('token')
->andReturn('bearer');
expect('wp_remote_get')->andReturn();
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
expect('wp_remote_get')->andReturn([
'headers' => $headers,
]);
expect('is_wp_error')->andReturn(false);
expect('wp_remote_retrieve_response_code')->andReturn(204);
$this->logger->shouldReceive('debug');
$this->sut->delete_token($paymentToken);
}
@ -139,9 +161,14 @@ class PaymentTokenEndpointTest extends TestCase
$token->shouldReceive('token')
->andReturn('bearer');
expect('wp_remote_get')->andReturn();
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
expect('wp_remote_get')->andReturn([
'headers' => $headers,
]);
expect('is_wp_error')->andReturn(true);
$this->logger->shouldReceive('log');
$this->logger->shouldReceive('debug');
$this->expectException(RuntimeException::class);
$this->sut->delete_token($paymentToken);

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
use Requests_Utility_CaseInsensitiveDictionary;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ErrorResponseCollection;
@ -40,8 +41,14 @@ class PaymentsEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$rawResponse = ['body' => '{"is_correct":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
$testee = new PaymentsEndpoint(
$host,
@ -88,8 +95,14 @@ class PaymentsEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$rawResponse = ['body' => '{"is_correct":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
$testee = new PaymentsEndpoint(
$host,
@ -119,10 +132,16 @@ class PaymentsEndpointTest extends TestCase
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$rawResponse = ['body' => '{"some_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"some_error":true}',
'headers' => $headers,
];
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('log');
$logger->shouldReceive('debug');
$testee = new PaymentsEndpoint(
$host,
@ -161,8 +180,14 @@ class PaymentsEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->shouldNotReceive('log');
$logger->shouldReceive('debug');
$rawResponse = ['body' => '{"is_correct":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
$testee = new PaymentsEndpoint(
$host,
@ -212,8 +237,14 @@ class PaymentsEndpointTest extends TestCase
$logger = Mockery::mock(LoggerInterface::class);
$logger->expects('log');
$logger->expects('debug');
$rawResponse = ['body' => '{"is_correct":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"is_correct":true}',
'headers' => $headers,
];
$testee = new PaymentsEndpoint(
$host,
@ -243,10 +274,16 @@ class PaymentsEndpointTest extends TestCase
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$rawResponse = ['body' => '{"some_error":true}'];
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
$headers->shouldReceive('getAll');
$rawResponse = [
'body' => '{"some_error":true}',
'headers' => $headers,
];
$logger = Mockery::mock(LoggerInterface::class);
$logger->expects('log');
$logger->expects('debug');
$testee = new PaymentsEndpoint(
$host,

View file

@ -32,7 +32,7 @@ class CreateOrderEndpointTest extends TestCase
{
list($payer_factory, $testee) = $this->mockTestee();
$method = $this->testPrivateMethod(CreateOrderEndpoint::class, 'payer');
$method = $this->makePrivateMethod(CreateOrderEndpoint::class, 'payer');
$dataString = wp_json_encode($expectedResult['payer']);
$dataObj = json_decode(wp_json_encode($expectedResult['payer']));
@ -173,7 +173,7 @@ class CreateOrderEndpointTest extends TestCase
* @return \ReflectionMethod
* @throws \ReflectionException
*/
protected function testPrivateMethod($class, $method)
protected function makePrivateMethod($class, $method)
{
$reflector = new ReflectionClass($class);
$method = $reflector->getMethod($method);

View file

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce;
use Dhii\Container\CompositeCachingServiceProvider;
use Dhii\Container\DelegatingContainer;
use Dhii\Container\ServiceProvider;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use Psr\Container\ContainerInterface;
use function Brain\Monkey\Functions\when;
class ModularTestCase extends TestCase
{
use MockeryPHPUnitIntegration;
public function setUp(): void
{
parent::setUp();
when('get_option')->justReturn(null);
when('plugins_url')->returnArg();
when('plugin_dir_path')->alias(function ($file) { return trailingslashit(dirname($file)); });
when('get_current_blog_id')->justReturn(42);
when('get_site_url')->justReturn('example.com');
when('get_bloginfo')->justReturn('My Shop');
when('wc_get_base_location')->justReturn(['country' => 'US']);
when('get_woocommerce_currency')->justReturn('USD');
when('WC')->justReturn((object) [
'session' => null,
]);
global $wpdb;
$wpdb = \Mockery::mock(\stdClass::class);
$wpdb->shouldReceive('get_var')->andReturn(null);
$wpdb->shouldReceive('prepare')->andReturn(null);
$wpdb->posts = '';
$wpdb->postmeta = '';
!defined('PAYPAL_API_URL') && define('PAYPAL_API_URL', 'https://api.paypal.com');
!defined('PAYPAL_SANDBOX_API_URL') && define('PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com');
!defined('PAYPAL_INTEGRATION_DATE') && define('PAYPAL_INTEGRATION_DATE', '2020-10-15');
!defined('PPCP_FLAG_SUBSCRIPTION') && define('PPCP_FLAG_SUBSCRIPTION', true);
!defined('CONNECT_WOO_CLIENT_ID') && define('CONNECT_WOO_CLIENT_ID', 'woo-id');
!defined('CONNECT_WOO_SANDBOX_CLIENT_ID') && define('CONNECT_WOO_SANDBOX_CLIENT_ID', 'woo-id2');
!defined('CONNECT_WOO_MERCHANT_ID') && define('CONNECT_WOO_MERCHANT_ID', 'merchant-id');
!defined('CONNECT_WOO_SANDBOX_MERCHANT_ID') && define('CONNECT_WOO_SANDBOX_MERCHANT_ID', 'merchant-id2');
!defined('CONNECT_WOO_URL') && define('CONNECT_WOO_URL', 'https://connect.woocommerce.com/ppc');
!defined('CONNECT_WOO_SANDBOX_URL') && define('CONNECT_WOO_SANDBOX_URL', 'https://connect.woocommerce.com/ppcsandbox');
}
/**
* @param array<string, callable> $overriddenServices
* @return ContainerInterface
*/
protected function bootstrapModule(array $overriddenServices = []): ContainerInterface
{
$overridingContainer = new DelegatingContainer(new CompositeCachingServiceProvider([
new ServiceProvider($overriddenServices, []),
]));
$rootDir = ROOT_DIR;
$bootstrap = require ("$rootDir/bootstrap.php");
$appContainer = $bootstrap($rootDir, $overridingContainer);
return $appContainer;
}
}

View file

@ -3,26 +3,36 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce;
use function Brain\Monkey\Functions\when;
use function Brain\Monkey\setUp;
use function Brain\Monkey\tearDown;
use function Brain\Monkey\Functions\expect;
use Mockery;
class TestCase extends \PHPUnit\Framework\TestCase
{
public function setUp(): void
{
parent::setUp();
expect('__')->andReturnUsing(function (string $text) {
return $text;
});
setUp();
}
public function setUp(): void
{
parent::setUp();
public function tearDown(): void
{
tearDown();
Mockery::close();
parent::tearDown();
}
when('__')->returnArg();
when('_x')->returnArg();
when('esc_url')->returnArg();
when('esc_attr')->returnArg();
when('esc_attr__')->returnArg();
when('esc_html')->returnArg();
when('esc_html__')->returnArg();
when('esc_textarea')->returnArg();
when('sanitize_text_field')->returnArg();
when('wp_kses_post')->returnArg();
when('wp_unslash')->returnArg();
setUp();
}
public function tearDown(): void
{
tearDown();
Mockery::close();
parent::tearDown();
}
}

View file

@ -68,7 +68,8 @@ class WcGatewayTest extends TestCase
$refundProcessor,
$state,
$transactionUrlProvider,
$subscriptionHelper
$subscriptionHelper,
PayPalGateway::ID
);
expect('wc_get_order')
@ -116,7 +117,8 @@ class WcGatewayTest extends TestCase
$refundProcessor,
$state,
$transactionUrlProvider,
$subscriptionHelper
$subscriptionHelper,
PayPalGateway::ID
);
expect('wc_get_order')
@ -181,7 +183,8 @@ class WcGatewayTest extends TestCase
$refundProcessor,
$state,
$transactionUrlProvider,
$subscriptionHelper
$subscriptionHelper,
PayPalGateway::ID
);
expect('wc_get_order')
@ -254,7 +257,8 @@ class WcGatewayTest extends TestCase
$refundProcessor,
$state,
$transactionUrlProvider,
$subscriptionHelper
$subscriptionHelper,
PayPalGateway::ID
);
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
@ -311,7 +315,8 @@ class WcGatewayTest extends TestCase
$refundProcessor,
$state,
$transactionUrlProvider,
$subscriptionHelper
$subscriptionHelper,
PayPalGateway::ID
);
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
@ -362,7 +367,8 @@ class WcGatewayTest extends TestCase
$refundProcessor,
$state,
$transactionUrlProvider,
$subscriptionHelper
$subscriptionHelper,
PayPalGateway::ID
);
$this->assertFalse($testee->capture_authorized_payment($wcOrder));
@ -401,7 +407,8 @@ class WcGatewayTest extends TestCase
$refundProcessor,
$onboardingState,
$transactionUrlProvider,
$subscriptionHelper
$subscriptionHelper,
PayPalGateway::ID
);
$this->assertSame($needSetup, $testee->needs_setup());

View file

@ -4,63 +4,77 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\ModularTestCase;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
use function Brain\Monkey\Functions\when;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
class SettingsListenerTest extends TestCase
class SettingsListenerTest extends ModularTestCase
{
use MockeryPHPUnitIntegration;
private $appContainer;
public function testListen()
{
$settings = Mockery::mock(Settings::class);
$setting_fields = [];
$webhook_registrar = Mockery::mock(WebhookRegistrar::class);
$cache = Mockery::mock(Cache::class);
$state = Mockery::mock(State::class);
$bearer = Mockery::mock(Bearer::class);
public function setUp(): void
{
parent::setUp();
$testee = new SettingsListener(
$settings,
$setting_fields,
$webhook_registrar,
$cache,
$state,
$bearer
);
$this->appContainer = $this->bootstrapModule();
}
$_REQUEST['section'] = 'ppcp-gateway';
$_POST['ppcp-nonce'] = 'foo';
$_POST['ppcp'] = [
'client_id' => 'client_id',
];
$_GET['ppcp-tab'] = 'just-a-tab';
public function testListen()
{
$settings = Mockery::mock(Settings::class);
$settings->shouldReceive('set');
when('sanitize_text_field')->justReturn('ppcp-gateway');
when('wp_unslash')->justReturn('ppcp-gateway');
when('current_user_can')->justReturn(true);
when('wp_verify_nonce')->justReturn(true);
$setting_fields = $this->appContainer->get('wcgateway.settings.fields');
$settings->shouldReceive('has')
->with('client_id')
->andReturn('client_id');
$settings->shouldReceive('get')
->with('client_id')
->andReturn('client_id');
$settings->shouldReceive('has')
->with('client_secret')
->andReturn('client_secret');
$settings->shouldReceive('get')
->with('client_secret')
->andReturn('client_secret');
$settings->shouldReceive('persist');
$cache->shouldReceive('has')
->andReturn(false);
$webhook_registrar = Mockery::mock(WebhookRegistrar::class);
$webhook_registrar->shouldReceive('unregister')->andReturnTrue();
$webhook_registrar->shouldReceive('register')->andReturnTrue();
$testee->listen();
}
$cache = Mockery::mock(Cache::class);
$state = Mockery::mock(State::class);
$state->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
$bearer = Mockery::mock(Bearer::class);
$testee = new SettingsListener(
$settings,
$setting_fields,
$webhook_registrar,
$cache,
$state,
$bearer,
PayPalGateway::ID
);
$_GET['section'] = PayPalGateway::ID;
$_POST['ppcp-nonce'] = 'foo';
$_POST['ppcp'] = [
'client_id' => 'client_id',
];
$_GET['ppcp-tab'] = PayPalGateway::ID;
when('current_user_can')->justReturn(true);
when('wp_verify_nonce')->justReturn(true);
$settings->shouldReceive('has')
->with('client_id')
->andReturn('client_id');
$settings->shouldReceive('get')
->with('client_id')
->andReturn('client_id');
$settings->shouldReceive('has')
->with('client_secret')
->andReturn('client_secret');
$settings->shouldReceive('get')
->with('client_secret')
->andReturn('client_secret');
$settings->shouldReceive('persist');
$cache->shouldReceive('has')
->andReturn(false);
$testee->listen();
}
}

View file

@ -1,6 +1,10 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../stubs/WC_Payment_Gateway.php';
require_once __DIR__ . '/../stubs/WC_Payment_Gateway_CC.php';
require_once __DIR__ . '/../stubs/WC_Ajax.php';
define('TESTS_ROOT_DIR', dirname(__DIR__));
define('ROOT_DIR', dirname(TESTS_ROOT_DIR));
require_once ROOT_DIR . '/vendor/autoload.php';
require_once TESTS_ROOT_DIR . '/stubs/WC_Payment_Gateway.php';
require_once TESTS_ROOT_DIR . '/stubs/WC_Payment_Gateway_CC.php';
require_once TESTS_ROOT_DIR . '/stubs/WC_Ajax.php';

View file

@ -19,12 +19,6 @@ declare( strict_types = 1 );
namespace WooCommerce\PayPalCommerce;
use Dhii\Container\CachingContainer;
use Dhii\Container\CompositeCachingServiceProvider;
use Dhii\Container\DelegatingContainer;
use Dhii\Container\ProxyContainer;
use Dhii\Modular\Module\ModuleInterface;
define( 'PAYPAL_API_URL', 'https://api.paypal.com' );
define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' );
define( 'PAYPAL_INTEGRATION_DATE', '2020-10-15' );
@ -45,6 +39,8 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
* Initialize the plugin and its modules.
*/
function init() {
$root_dir = __DIR__;
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . '/wp-admin/includes/plugin.php';
}
@ -72,30 +68,12 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
static $initialized;
if ( ! $initialized ) {
$modules = array( new PluginModule() );
foreach ( glob( plugin_dir_path( __FILE__ ) . 'modules/*/module.php' ) as $module_file ) {
$modules[] = ( require $module_file )();
}
$providers = array();
$bootstrap = require "$root_dir/bootstrap.php";
// Use this filter to add custom module or remove some of existing ones.
// Modules able to access container, add services and modify existing ones.
$modules = apply_filters( 'woocommerce_paypal_payments_modules', $modules );
$app_container = $bootstrap( $root_dir );
foreach ( $modules as $module ) {
/* @var $module ModuleInterface module */
$providers[] = $module->setup();
}
$proxy = new ProxyContainer();
$provider = new CompositeCachingServiceProvider( $providers );
$container = new CachingContainer( new DelegatingContainer( $provider ) );
$proxy->setInnerContainer( $container );
foreach ( $modules as $module ) {
/* @var $module ModuleInterface module */
$module->run( $container );
}
$initialized = true;
do_action( 'woocommerce_paypal_payments_built_container', $proxy );
do_action( 'woocommerce_paypal_payments_built_container', $app_container );
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before After
Before After