mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Fix merge conflicts
This commit is contained in:
commit
57ff2cc649
106 changed files with 10786 additions and 7645 deletions
23
.travis.yml
23
.travis.yml
|
@ -1,23 +0,0 @@
|
||||||
language: php
|
|
||||||
os: linux
|
|
||||||
dist: xenial
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
|
|
||||||
php:
|
|
||||||
- 7.0
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- trunk
|
|
||||||
- compat/ppxo
|
|
||||||
|
|
||||||
script: |
|
|
||||||
CHANGED_FILES=`git diff --name-only --diff-filter=ACMR $TRAVIS_COMMIT_RANGE | grep \\\\.php | awk '{print}' ORS=' '`
|
|
||||||
|
|
||||||
if [ "$CHANGED_FILES" != "" ]; then
|
|
||||||
composer global require woocommerce/woocommerce-sniffs --update-with-all-dependencies
|
|
||||||
$HOME/.config/composer/vendor/bin/phpcs -p $CHANGED_FILES
|
|
||||||
fi
|
|
31
README.md
31
README.md
|
@ -29,8 +29,8 @@ You can also use the Docker environment which includes WP, WC and all developmen
|
||||||
0. Install Docker and Docker Compose.
|
0. Install Docker and Docker Compose.
|
||||||
1. `$ cp .env.example .env` and edit the configuration in the `.env` file if needed.
|
1. `$ cp .env.example .env` and edit the configuration in the `.env` file if needed.
|
||||||
2. `$ yarn run docker:build` (or copy the commands from [package.json](/package.json) if you do not have `yarn`).
|
2. `$ yarn run docker:build` (or copy the commands from [package.json](/package.json) if you do not have `yarn`).
|
||||||
3. `$ yarn docker:install`
|
3. `$ yarn run docker:install`
|
||||||
4. `$ yarn docker:start`
|
4. `$ yarn run docker:start`
|
||||||
5. Add `127.0.0.1 wc-pp.myhost` to your `hosts` file and open http://wc-pp.myhost (the default value of `WP_DOMAIN` in `.env`).
|
5. Add `127.0.0.1 wc-pp.myhost` to your `hosts` file and open http://wc-pp.myhost (the default value of `WP_DOMAIN` in `.env`).
|
||||||
|
|
||||||
Tests and code style:
|
Tests and code style:
|
||||||
|
@ -44,30 +44,21 @@ After some changes in `.env` (such as PHP, WP versions) you may need to rebuild
|
||||||
|
|
||||||
See [package.json](/package.json) for other useful commands.
|
See [package.json](/package.json) for other useful commands.
|
||||||
|
|
||||||
## Preparation for wordpress.org release
|
## Building a release package
|
||||||
|
|
||||||
If you want to deploy a new version, you need to do some preparation:
|
If you want to build a release package
|
||||||
|
(that can be used for deploying a new version on wordpress.org or manual installation on a WP website via ZIP uploading),
|
||||||
|
follow these steps:
|
||||||
|
|
||||||
### Clone
|
1. Clone the repository and `cd` into it.
|
||||||
|
2. Make sure you have the version in the plugin root file updated.
|
||||||
Clone the repository and `cd` into it
|
3. Update the PayPal JavaScript SDK integration date by using the current date for the `PAYPAL_INTEGRATION_DATE` constant.
|
||||||
|
4. The following command should get you a ZIP file ready to be used on a WordPress site:
|
||||||
### Build
|
|
||||||
|
|
||||||
The following command should get you a ZIP file ready to be used on a WordPress site.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build
|
$ yarn run build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update version
|
|
||||||
|
|
||||||
Make sure you have the version in the plugin root file updated.
|
|
||||||
|
|
||||||
### Fixate integration date
|
|
||||||
|
|
||||||
Fix the PayPal JavaScript SDK integration date by using the current date for the `PAYPAL_INTEGRATION_DATE` constant.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[GPL-2.0 License](LICENSE)
|
[GPL-2.0 License](LICENSE)
|
||||||
|
|
56
bootstrap.php
Normal file
56
bootstrap.php
Normal 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;
|
||||||
|
};
|
|
@ -1,5 +1,19 @@
|
||||||
*** Changelog ***
|
*** Changelog ***
|
||||||
|
|
||||||
|
= 1.6.0 - 2021-09-29 =
|
||||||
|
* Add - Webhook status. #246 #273
|
||||||
|
* Add - Show CC gateway in admin payments list. #236
|
||||||
|
* Add - Add 3d secure contingency settings. #230
|
||||||
|
* Add - Improve logging. #252 #275
|
||||||
|
* Add - Do not send payee email. #231
|
||||||
|
* Add - Allow customers to see and delete their saved payments in My Account. #274
|
||||||
|
* Fix - PayPal Payments generates multiple orders. #244
|
||||||
|
* Fix - Saved credit card does not auto fill. #242
|
||||||
|
* Fix - Incorrect webhooks registration. #254
|
||||||
|
* Fix - Disable funding credit cards affecting hosted fields, unset for GB. #249
|
||||||
|
* Fix - REFUND_CAPTURE_CURRENCY_MISMATCH on multicurrency sites. #225
|
||||||
|
* Fix - Can't checkout to certain countries with optional postcode. #224
|
||||||
|
|
||||||
= 1.5.1 - 2021-08-19 =
|
= 1.5.1 - 2021-08-19 =
|
||||||
* Fix - Set 3DS contingencies to "SCA_WHEN_REQUIRED". #178
|
* Fix - Set 3DS contingencies to "SCA_WHEN_REQUIRED". #178
|
||||||
* Fix - Plugin conflict blocking line item details. #221
|
* Fix - Plugin conflict blocking line item details. #221
|
||||||
|
|
30
modules.php
Normal file
30
modules.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?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" )(),
|
||||||
|
( require "$modules_dir/ppcp-vaulting/module.php" )(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $modules;
|
||||||
|
};
|
|
@ -36,6 +36,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerStatusFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerStatusFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingFactory;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||||
|
@ -72,19 +73,19 @@ return array(
|
||||||
return 'WC-';
|
return 'WC-';
|
||||||
},
|
},
|
||||||
'api.bearer' => static function ( ContainerInterface $container ): Bearer {
|
'api.bearer' => static function ( ContainerInterface $container ): Bearer {
|
||||||
|
|
||||||
$cache = new Cache( 'ppcp-paypal-bearer' );
|
$cache = new Cache( 'ppcp-paypal-bearer' );
|
||||||
$key = $container->get( 'api.key' );
|
$key = $container->get( 'api.key' );
|
||||||
$secret = $container->get( 'api.secret' );
|
$secret = $container->get( 'api.secret' );
|
||||||
|
|
||||||
$host = $container->get( 'api.host' );
|
$host = $container->get( 'api.host' );
|
||||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
|
$settings = $container->get( 'wcgateway.settings' );
|
||||||
return new PayPalBearer(
|
return new PayPalBearer(
|
||||||
$cache,
|
$cache,
|
||||||
$host,
|
$host,
|
||||||
$key,
|
$key,
|
||||||
$secret,
|
$secret,
|
||||||
$logger
|
$logger,
|
||||||
|
$settings
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'api.endpoint.partners' => static function ( ContainerInterface $container ) : PartnersEndpoint {
|
'api.endpoint.partners' => static function ( ContainerInterface $container ) : PartnersEndpoint {
|
||||||
|
@ -115,6 +116,7 @@ return array(
|
||||||
$container->get( 'api.host' ),
|
$container->get( 'api.host' ),
|
||||||
$container->get( 'api.bearer' ),
|
$container->get( 'api.bearer' ),
|
||||||
$container->get( 'api.factory.webhook' ),
|
$container->get( 'api.factory.webhook' ),
|
||||||
|
$container->get( 'api.factory.webhook-event' ),
|
||||||
$container->get( 'woocommerce.logger.woocommerce' )
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -215,7 +217,10 @@ return array(
|
||||||
'api.factory.webhook' => static function ( ContainerInterface $container ): WebhookFactory {
|
'api.factory.webhook' => static function ( ContainerInterface $container ): WebhookFactory {
|
||||||
return new WebhookFactory();
|
return new WebhookFactory();
|
||||||
},
|
},
|
||||||
'api.factory.capture' => static function ( ContainerInterface $container ): CaptureFactory {
|
'api.factory.webhook-event' => static function ( $container ): WebhookEventFactory {
|
||||||
|
return new WebhookEventFactory();
|
||||||
|
},
|
||||||
|
'api.factory.capture' => static function ( $container ): CaptureFactory {
|
||||||
|
|
||||||
$amount_factory = $container->get( 'api.factory.amount' );
|
$amount_factory = $container->get( 'api.factory.amount' );
|
||||||
return new CaptureFactory( $amount_factory );
|
return new CaptureFactory( $amount_factory );
|
||||||
|
|
|
@ -390,7 +390,7 @@ class OrderEndpoint {
|
||||||
}
|
}
|
||||||
$json = json_decode( $response['body'] );
|
$json = json_decode( $response['body'] );
|
||||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||||
if ( 201 !== $status_code ) {
|
if ( ! in_array( $status_code, array( 200, 201 ), true ) ) {
|
||||||
if ( false !== strpos( $response['body'], ErrorResponse::ORDER_ALREADY_AUTHORIZED ) ) {
|
if ( false !== strpos( $response['body'], ErrorResponse::ORDER_ALREADY_AUTHORIZED ) ) {
|
||||||
return $this->order( $order->id() );
|
return $this->order( $order->id() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,24 +139,7 @@ class PaymentTokenEndpoint {
|
||||||
foreach ( $json->payment_tokens as $token_value ) {
|
foreach ( $json->payment_tokens as $token_value ) {
|
||||||
$tokens[] = $this->factory->from_paypal_response( $token_value );
|
$tokens[] = $this->factory->from_paypal_response( $token_value );
|
||||||
}
|
}
|
||||||
if ( empty( $tokens ) ) {
|
|
||||||
$error = new RuntimeException(
|
|
||||||
sprintf(
|
|
||||||
// translators: %d is the customer id.
|
|
||||||
__( 'No token stored for customer %d.', 'woocommerce-paypal-payments' ),
|
|
||||||
$id
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$this->logger->log(
|
|
||||||
'warning',
|
|
||||||
$error->getMessage(),
|
|
||||||
array(
|
|
||||||
'args' => $args,
|
|
||||||
'response' => $response,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
throw $error;
|
|
||||||
}
|
|
||||||
return $tokens;
|
return $tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,48 @@ trait RequestTrait {
|
||||||
$args['headers']['PayPal-Partner-Attribution-Id'] = 'Woo_PPCP';
|
$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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,10 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||||
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Webhook;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Webhook;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\WebhookEvent;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
@ -44,6 +46,13 @@ class WebhookEndpoint {
|
||||||
*/
|
*/
|
||||||
private $webhook_factory;
|
private $webhook_factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The webhook event factory.
|
||||||
|
*
|
||||||
|
* @var WebhookEventFactory
|
||||||
|
*/
|
||||||
|
private $webhook_event_factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*
|
*
|
||||||
|
@ -54,22 +63,25 @@ class WebhookEndpoint {
|
||||||
/**
|
/**
|
||||||
* WebhookEndpoint constructor.
|
* WebhookEndpoint constructor.
|
||||||
*
|
*
|
||||||
* @param string $host The host.
|
* @param string $host The host.
|
||||||
* @param Bearer $bearer The bearer.
|
* @param Bearer $bearer The bearer.
|
||||||
* @param WebhookFactory $webhook_factory The webhook factory.
|
* @param WebhookFactory $webhook_factory The webhook factory.
|
||||||
* @param LoggerInterface $logger The logger.
|
* @param WebhookEventFactory $webhook_event_factory The webhook event factory.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
string $host,
|
string $host,
|
||||||
Bearer $bearer,
|
Bearer $bearer,
|
||||||
WebhookFactory $webhook_factory,
|
WebhookFactory $webhook_factory,
|
||||||
|
WebhookEventFactory $webhook_event_factory,
|
||||||
LoggerInterface $logger
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->host = $host;
|
$this->host = $host;
|
||||||
$this->bearer = $bearer;
|
$this->bearer = $bearer;
|
||||||
$this->webhook_factory = $webhook_factory;
|
$this->webhook_factory = $webhook_factory;
|
||||||
$this->logger = $logger;
|
$this->webhook_event_factory = $webhook_event_factory;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,14 +91,14 @@ class WebhookEndpoint {
|
||||||
*
|
*
|
||||||
* @return Webhook
|
* @return Webhook
|
||||||
* @throws RuntimeException If the request fails.
|
* @throws RuntimeException If the request fails.
|
||||||
|
* @throws PayPalApiException If the request fails.
|
||||||
*/
|
*/
|
||||||
public function create( Webhook $hook ): Webhook {
|
public function create( Webhook $hook ): Webhook {
|
||||||
/**
|
// The hook was already created.
|
||||||
* An hook, which has an ID has already been created.
|
|
||||||
*/
|
|
||||||
if ( $hook->id() ) {
|
if ( $hook->id() ) {
|
||||||
return $hook;
|
return $hook;
|
||||||
}
|
}
|
||||||
|
|
||||||
$bearer = $this->bearer->bearer();
|
$bearer = $this->bearer->bearer();
|
||||||
$url = trailingslashit( $this->host ) . 'v1/notifications/webhooks';
|
$url = trailingslashit( $this->host ) . 'v1/notifications/webhooks';
|
||||||
$args = array(
|
$args = array(
|
||||||
|
@ -100,42 +112,64 @@ class WebhookEndpoint {
|
||||||
$response = $this->request( $url, $args );
|
$response = $this->request( $url, $args );
|
||||||
|
|
||||||
if ( is_wp_error( $response ) ) {
|
if ( is_wp_error( $response ) ) {
|
||||||
$error = new RuntimeException(
|
throw new RuntimeException(
|
||||||
__( 'Not able to create a webhook.', 'woocommerce-paypal-payments' )
|
__( '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'] );
|
$json = json_decode( $response['body'] );
|
||||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||||
if ( 201 !== $status_code ) {
|
if ( 201 !== $status_code ) {
|
||||||
$error = new PayPalApiException(
|
throw new PayPalApiException(
|
||||||
$json,
|
$json,
|
||||||
$status_code
|
$status_code
|
||||||
);
|
);
|
||||||
$this->logger->log(
|
|
||||||
'warning',
|
|
||||||
$error->getMessage(),
|
|
||||||
array(
|
|
||||||
'args' => $args,
|
|
||||||
'response' => $response,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
throw $error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$hook = $this->webhook_factory->from_paypal_response( $json );
|
$hook = $this->webhook_factory->from_paypal_response( $json );
|
||||||
return $hook;
|
return $hook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the webhooks list for the current auth token.
|
||||||
|
*
|
||||||
|
* @return Webhook[]
|
||||||
|
* @throws RuntimeException If the request fails.
|
||||||
|
* @throws PayPalApiException If the request fails.
|
||||||
|
*/
|
||||||
|
public function list(): array {
|
||||||
|
$bearer = $this->bearer->bearer();
|
||||||
|
$url = trailingslashit( $this->host ) . 'v1/notifications/webhooks';
|
||||||
|
$args = array(
|
||||||
|
'method' => 'GET',
|
||||||
|
'headers' => array(
|
||||||
|
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$response = $this->request( $url, $args );
|
||||||
|
|
||||||
|
if ( is_wp_error( $response ) ) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
__( 'Not able to load webhooks list.', 'woocommerce-paypal-payments' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = json_decode( $response['body'] );
|
||||||
|
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||||
|
if ( 200 !== $status_code ) {
|
||||||
|
throw new PayPalApiException(
|
||||||
|
$json,
|
||||||
|
$status_code
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_map(
|
||||||
|
array( $this->webhook_factory, 'from_paypal_response' ),
|
||||||
|
$json->webhooks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a webhook.
|
* Deletes a webhook.
|
||||||
*
|
*
|
||||||
|
@ -160,22 +194,61 @@ class WebhookEndpoint {
|
||||||
$response = $this->request( $url, $args );
|
$response = $this->request( $url, $args );
|
||||||
|
|
||||||
if ( is_wp_error( $response ) ) {
|
if ( is_wp_error( $response ) ) {
|
||||||
$error = new RuntimeException(
|
throw new RuntimeException(
|
||||||
__( 'Not able to delete the webhook.', 'woocommerce-paypal-payments' )
|
__( '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;
|
return wp_remote_retrieve_response_code( $response ) === 204;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a simulated webhook to be sent.
|
||||||
|
*
|
||||||
|
* @param Webhook $hook The webhook subscription to use.
|
||||||
|
* @param string $event_type The event type, such as CHECKOUT.ORDER.APPROVED.
|
||||||
|
* @param string|null $resource_version The event resource version, such as 2.0.
|
||||||
|
*
|
||||||
|
* @return WebhookEvent
|
||||||
|
* @throws RuntimeException If the request fails.
|
||||||
|
* @throws PayPalApiException If the request fails.
|
||||||
|
*/
|
||||||
|
public function simulate( Webhook $hook, string $event_type, ?string $resource_version ): WebhookEvent {
|
||||||
|
$bearer = $this->bearer->bearer();
|
||||||
|
$url = trailingslashit( $this->host ) . 'v1/notifications/simulate-event';
|
||||||
|
$data = array(
|
||||||
|
'webhook_id' => $hook->id(),
|
||||||
|
'event_type' => $event_type,
|
||||||
|
);
|
||||||
|
if ( $resource_version ) {
|
||||||
|
$data['resource_version'] = $resource_version;
|
||||||
|
}
|
||||||
|
$args = array(
|
||||||
|
'method' => 'POST',
|
||||||
|
'headers' => array(
|
||||||
|
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
),
|
||||||
|
'body' => wp_json_encode( $data ),
|
||||||
|
);
|
||||||
|
$response = $this->request( $url, $args );
|
||||||
|
|
||||||
|
if ( is_wp_error( $response ) ) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
__( 'Not able to simulate webhook.', 'woocommerce-paypal-payments' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$json = json_decode( $response['body'] );
|
||||||
|
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||||
|
if ( 202 !== $status_code ) {
|
||||||
|
throw new PayPalApiException(
|
||||||
|
$json,
|
||||||
|
$status_code
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->webhook_event_factory->from_paypal_response( $json );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies if a webhook event is legitimate.
|
* Verifies if a webhook event is legitimate.
|
||||||
*
|
*
|
||||||
|
|
|
@ -112,7 +112,7 @@ class CardAuthenticationResult {
|
||||||
$data['liability_shift'] = $this->liability_shift();
|
$data['liability_shift'] = $this->liability_shift();
|
||||||
$data['three_d_secure'] = array(
|
$data['three_d_secure'] = array(
|
||||||
'enrollment_status' => $this->enrollment_status(),
|
'enrollment_status' => $this->enrollment_status(),
|
||||||
'authentication_result' => $this->authentication_result(),
|
'authentication_status' => $this->authentication_result(),
|
||||||
);
|
);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,11 +68,11 @@ class Payee {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function to_array(): array {
|
public function to_array(): array {
|
||||||
$data = array(
|
$data = array();
|
||||||
'email_address' => $this->email(),
|
|
||||||
);
|
|
||||||
if ( $this->merchant_id ) {
|
if ( $this->merchant_id ) {
|
||||||
$data['merchant_id'] = $this->merchant_id();
|
$data['merchant_id'] = $this->merchant_id();
|
||||||
|
} else {
|
||||||
|
$data['email_address'] = $this->email();
|
||||||
}
|
}
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Webhook
|
* Class Webhook
|
||||||
*/
|
*/
|
||||||
|
@ -71,13 +73,38 @@ class Webhook {
|
||||||
/**
|
/**
|
||||||
* Returns the event types.
|
* Returns the event types.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return stdClass[]
|
||||||
*/
|
*/
|
||||||
public function event_types(): array {
|
public function event_types(): array {
|
||||||
|
|
||||||
return $this->event_types;
|
return $this->event_types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the human-friendly names of the event types.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function humanfriendly_event_names(): array {
|
||||||
|
|
||||||
|
return array_map(
|
||||||
|
function ( $event ): string {
|
||||||
|
return Webhook::get_humanfriendly_event_name( $event->name );
|
||||||
|
},
|
||||||
|
$this->event_types
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts event names to more human-friendly form.
|
||||||
|
*
|
||||||
|
* @param string $name The event name like 'CHECKOUT.ORDER.APPROVED'.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_humanfriendly_event_name( string $name ): string {
|
||||||
|
return strtolower( str_replace( '.', ' ', $name ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the object as array.
|
* Returns the object as array.
|
||||||
*
|
*
|
||||||
|
|
170
modules/ppcp-api-client/src/Entity/class-webhookevent.php
Normal file
170
modules/ppcp-api-client/src/Entity/class-webhookevent.php
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The Webhook event notification object.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class WebhookEvent
|
||||||
|
*/
|
||||||
|
class WebhookEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the event notification.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time when the event notification was created.
|
||||||
|
*
|
||||||
|
* @var DateTime|null
|
||||||
|
*/
|
||||||
|
private $create_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the resource related to the webhook notification event, such as 'checkout-order'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $resource_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event version in the webhook notification, such as '1.0'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $event_version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event that triggered the webhook event notification, such as 'CHECKOUT.ORDER.APPROVED'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $event_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary description for the event notification.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $summary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource version in the webhook notification, such as '1.0'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $resource_version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource that triggered the webhook event notification.
|
||||||
|
*
|
||||||
|
* @var stdClass
|
||||||
|
*/
|
||||||
|
private $resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebhookEvent constructor.
|
||||||
|
*
|
||||||
|
* @param string $id The ID of the event notification.
|
||||||
|
* @param DateTime|null $create_time The date and time when the event notification was created.
|
||||||
|
* @param string $resource_type The name of the resource related to the webhook notification event, such as 'checkout-order'.
|
||||||
|
* @param string $event_version The event version in the webhook notification, such as '1.0'.
|
||||||
|
* @param string $event_type The event that triggered the webhook event notification, such as 'CHECKOUT.ORDER.APPROVED'.
|
||||||
|
* @param string $summary A summary description for the event notification.
|
||||||
|
* @param string $resource_version The resource version in the webhook notification, such as '1.0'.
|
||||||
|
* @param stdClass $resource The resource that triggered the webhook event notification.
|
||||||
|
*/
|
||||||
|
public function __construct( string $id, ?DateTime $create_time, string $resource_type, string $event_version, string $event_type, string $summary, string $resource_version, stdClass $resource ) {
|
||||||
|
$this->id = $id;
|
||||||
|
$this->create_time = $create_time;
|
||||||
|
$this->resource_type = $resource_type;
|
||||||
|
$this->event_version = $event_version;
|
||||||
|
$this->event_type = $event_type;
|
||||||
|
$this->summary = $summary;
|
||||||
|
$this->resource_version = $resource_version;
|
||||||
|
$this->resource = $resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the event notification.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function id(): string {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time when the event notification was created.
|
||||||
|
*
|
||||||
|
* @return DateTime|null
|
||||||
|
*/
|
||||||
|
public function create_time(): ?DateTime {
|
||||||
|
return $this->create_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the resource related to the webhook notification event, such as 'checkout-order'.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function resource_type(): string {
|
||||||
|
return $this->resource_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event version in the webhook notification, such as '1.0'.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function event_version(): string {
|
||||||
|
return $this->event_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event that triggered the webhook event notification, such as 'CHECKOUT.ORDER.APPROVED'.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function event_type(): string {
|
||||||
|
return $this->event_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary description for the event notification.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function summary(): string {
|
||||||
|
return $this->summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource version in the webhook notification, such as '1.0'.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function resource_version(): string {
|
||||||
|
return $this->resource_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource that triggered the webhook event notification.
|
||||||
|
*
|
||||||
|
* @return stdClass
|
||||||
|
*/
|
||||||
|
public function resource(): stdClass {
|
||||||
|
return $this->resource;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,13 +26,8 @@ class PayeeFactory {
|
||||||
* @throws RuntimeException When JSON object is malformed.
|
* @throws RuntimeException When JSON object is malformed.
|
||||||
*/
|
*/
|
||||||
public function from_paypal_response( \stdClass $data ) {
|
public function from_paypal_response( \stdClass $data ) {
|
||||||
if ( ! isset( $data->email_address ) ) {
|
$email = ( isset( $data->email_address ) ) ? $data->email_address : '';
|
||||||
throw new RuntimeException(
|
|
||||||
__( 'No email for payee given.', 'woocommerce-paypal-payments' )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$merchant_id = ( isset( $data->merchant_id ) ) ? $data->merchant_id : '';
|
$merchant_id = ( isset( $data->merchant_id ) ) ? $data->merchant_id : '';
|
||||||
return new Payee( $data->email_address, $merchant_id );
|
return new Payee( $email, $merchant_id );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@ class PaymentSourceFactory {
|
||||||
(string) $data->card->authentication_result->liability_shift : '',
|
(string) $data->card->authentication_result->liability_shift : '',
|
||||||
isset( $data->card->authentication_result->three_d_secure->enrollment_status ) ?
|
isset( $data->card->authentication_result->three_d_secure->enrollment_status ) ?
|
||||||
(string) $data->card->authentication_result->three_d_secure->enrollment_status : '',
|
(string) $data->card->authentication_result->three_d_secure->enrollment_status : '',
|
||||||
isset( $data->card->authentication_result->three_d_secure->authentication_result ) ?
|
isset( $data->card->authentication_result->three_d_secure->authentication_status ) ?
|
||||||
(string) $data->card->authentication_result->three_d_secure->authentication_result : ''
|
(string) $data->card->authentication_result->three_d_secure->authentication_status : ''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$card = new PaymentSourceCard(
|
$card = new PaymentSourceCard(
|
||||||
|
|
|
@ -158,6 +158,8 @@ class PurchaseUnitFactory {
|
||||||
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer );
|
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer );
|
||||||
if (
|
if (
|
||||||
2 !== strlen( $shipping->address()->country_code() )
|
2 !== strlen( $shipping->address()->country_code() )
|
||||||
|
|| ( ! $shipping->address()->postal_code() )
|
||||||
|
|| $this->country_without_postal_code( $shipping->address()->country_code() )
|
||||||
) {
|
) {
|
||||||
$shipping = null;
|
$shipping = null;
|
||||||
}
|
}
|
||||||
|
@ -264,4 +266,18 @@ class PurchaseUnitFactory {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if country does not have postal code.
|
||||||
|
*
|
||||||
|
* @param string $country_code The country code.
|
||||||
|
* @return bool Whether country has postal code or not.
|
||||||
|
*/
|
||||||
|
private function country_without_postal_code( string $country_code ): bool {
|
||||||
|
$countries = array( 'AE', 'AF', 'AG', 'AI', 'AL', 'AN', 'AO', 'AW', 'BB', 'BF', 'BH', 'BI', 'BJ', 'BM', 'BO', 'BS', 'BT', 'BW', 'BZ', 'CD', 'CF', 'CG', 'CI', 'CK', 'CL', 'CM', 'CO', 'CR', 'CV', 'DJ', 'DM', 'DO', 'EC', 'EG', 'ER', 'ET', 'FJ', 'FK', 'GA', 'GD', 'GH', 'GI', 'GM', 'GN', 'GQ', 'GT', 'GW', 'GY', 'HK', 'HN', 'HT', 'IE', 'IQ', 'IR', 'JM', 'JO', 'KE', 'KH', 'KI', 'KM', 'KN', 'KP', 'KW', 'KY', 'LA', 'LB', 'LC', 'LK', 'LR', 'LS', 'LY', 'ML', 'MM', 'MO', 'MR', 'MS', 'MT', 'MU', 'MW', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NP', 'NR', 'NU', 'OM', 'PA', 'PE', 'PF', 'PY', 'QA', 'RW', 'SA', 'SB', 'SC', 'SD', 'SL', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SY', 'TC', 'TD', 'TG', 'TL', 'TO', 'TT', 'TV', 'TZ', 'UG', 'UY', 'VC', 'VE', 'VG', 'VN', 'VU', 'WS', 'XA', 'XB', 'XC', 'XE', 'XL', 'XM', 'XN', 'XS', 'YE', 'ZM', 'ZW' );
|
||||||
|
if ( in_array( $country_code, $countries, true ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Creates WebhookEvent.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use stdClass;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\WebhookEvent;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class WebhookEventFactory
|
||||||
|
*/
|
||||||
|
class WebhookEventFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a webhook from a given data array.
|
||||||
|
*
|
||||||
|
* @param array $data The data array.
|
||||||
|
*
|
||||||
|
* @return WebhookEvent
|
||||||
|
*/
|
||||||
|
public function from_array( array $data ): WebhookEvent {
|
||||||
|
return $this->from_paypal_response( (object) $data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Webhook based of a PayPal JSON response.
|
||||||
|
*
|
||||||
|
* @param stdClass $data The JSON object.
|
||||||
|
*
|
||||||
|
* @return WebhookEvent
|
||||||
|
* @throws RuntimeException When JSON object is malformed.
|
||||||
|
*/
|
||||||
|
public function from_paypal_response( stdClass $data ): WebhookEvent {
|
||||||
|
if ( ! isset( $data->id ) ) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
__( 'ID for webhook event not found.', 'woocommerce-paypal-payments' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( ! isset( $data->event_type ) ) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
__( 'Event type for webhook event not found.', 'woocommerce-paypal-payments' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$create_time = ( isset( $data->create_time ) ) ?
|
||||||
|
DateTime::createFromFormat( 'Y-m-d\TH:i:sO', $data->create_time )
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Sometimes the time may be in weird format 2018-12-19T22:20:32.000Z (at least in simulation),
|
||||||
|
// we do not care much about time, so just ignore on failure.
|
||||||
|
if ( false === $create_time ) {
|
||||||
|
$create_time = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WebhookEvent(
|
||||||
|
(string) $data->id,
|
||||||
|
$create_time,
|
||||||
|
(string) $data->resource_type ?? '',
|
||||||
|
(string) $data->event_version ?? '',
|
||||||
|
(string) $data->event_type,
|
||||||
|
(string) $data->summary ?? '',
|
||||||
|
(string) $data->resource_version ?? '',
|
||||||
|
(object) $data->resource ?? ( new stdClass() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,13 +7,13 @@
|
||||||
"@babel/core": "^7.9.0",
|
"@babel/core": "^7.9.0",
|
||||||
"@babel/preset-env": "^7.9.5",
|
"@babel/preset-env": "^7.9.5",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"cross-env": "^5.0.1",
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
"file-loader": "^4.2.0",
|
"cross-env": "^7.0.3",
|
||||||
"node-sass": "^4.13.0",
|
"file-loader": "^6.2.0",
|
||||||
"sass-loader": "^8.0.0",
|
"sass": "^1.42.1",
|
||||||
"webpack": "^4.42.1",
|
"sass-loader": "^12.1.0",
|
||||||
"webpack-cli": "^3.1.2",
|
"webpack": "^5.55.0",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.26.0"
|
"webpack-cli": "^4.8.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||||
|
|
|
@ -7,3 +7,7 @@
|
||||||
.payments-sdk-contingency-handler {
|
.payments-sdk-contingency-handler {
|
||||||
z-index: 1000 !important;
|
z-index: 1000 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ppcp-credit-card-gateway-form-field-disabled {
|
||||||
|
opacity: .5 !important;
|
||||||
|
}
|
||||||
|
|
|
@ -24,9 +24,11 @@ class CheckoutBootstap {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
jQuery('#saved-credit-card').on('change', () => {
|
jQuery(document).on('hosted_fields_loaded', () => {
|
||||||
this.displayPlaceOrderButtonForSavedCreditCards()
|
jQuery('#saved-credit-card').on('change', () => {
|
||||||
})
|
this.displayPlaceOrderButtonForSavedCreditCards()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
this.switchBetweenPayPalandOrderButton()
|
this.switchBetweenPayPalandOrderButton()
|
||||||
this.displayPlaceOrderButtonForSavedCreditCards()
|
this.displayPlaceOrderButtonForSavedCreditCards()
|
||||||
|
@ -100,13 +102,41 @@ class CheckoutBootstap {
|
||||||
this.renderer.hideButtons(this.gateway.messages.wrapper)
|
this.renderer.hideButtons(this.gateway.messages.wrapper)
|
||||||
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper)
|
this.renderer.hideButtons(this.gateway.hosted_fields.wrapper)
|
||||||
jQuery('#place_order').show()
|
jQuery('#place_order').show()
|
||||||
|
this.disableCreditCardFields()
|
||||||
} else {
|
} else {
|
||||||
jQuery('#place_order').hide()
|
jQuery('#place_order').hide()
|
||||||
this.renderer.hideButtons(this.gateway.button.wrapper)
|
this.renderer.hideButtons(this.gateway.button.wrapper)
|
||||||
this.renderer.hideButtons(this.gateway.messages.wrapper)
|
this.renderer.hideButtons(this.gateway.messages.wrapper)
|
||||||
this.renderer.showButtons(this.gateway.hosted_fields.wrapper)
|
this.renderer.showButtons(this.gateway.hosted_fields.wrapper)
|
||||||
|
this.enableCreditCardFields()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disableCreditCardFields() {
|
||||||
|
jQuery('label[for="ppcp-credit-card-gateway-card-number"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-gateway-card-number').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('label[for="ppcp-credit-card-gateway-card-expiry"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-gateway-card-expiry').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('label[for="ppcp-credit-card-gateway-card-cvc"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-gateway-card-cvc').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('label[for="vault"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-vault').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-vault').attr("disabled", true)
|
||||||
|
this.renderer.disableCreditCardFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
enableCreditCardFields() {
|
||||||
|
jQuery('label[for="ppcp-credit-card-gateway-card-number"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-gateway-card-number').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('label[for="ppcp-credit-card-gateway-card-expiry"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-gateway-card-expiry').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('label[for="ppcp-credit-card-gateway-card-cvc"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-gateway-card-cvc').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('label[for="vault"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-vault').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||||
|
jQuery('#ppcp-credit-card-vault').attr("disabled", false)
|
||||||
|
this.renderer.enableCreditCardFields()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CheckoutBootstap
|
export default CheckoutBootstap
|
||||||
|
|
|
@ -8,6 +8,8 @@ class CreditCardRenderer {
|
||||||
this.spinner = spinner;
|
this.spinner = spinner;
|
||||||
this.cardValid = false;
|
this.cardValid = false;
|
||||||
this.formValid = false;
|
this.formValid = false;
|
||||||
|
this.currentHostedFieldsInstance = null;
|
||||||
|
this.formSubmissionSubscribed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(wrapper, contextConfig) {
|
render(wrapper, contextConfig) {
|
||||||
|
@ -31,6 +33,12 @@ class CreditCardRenderer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.currentHostedFieldsInstance) {
|
||||||
|
this.currentHostedFieldsInstance.teardown()
|
||||||
|
.catch(err => console.error(`Hosted fields teardown error: ${err}`));
|
||||||
|
this.currentHostedFieldsInstance = null;
|
||||||
|
}
|
||||||
|
|
||||||
const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway');
|
const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway');
|
||||||
const oldDisplayStyle = gateWayBox.style.display;
|
const oldDisplayStyle = gateWayBox.style.display;
|
||||||
gateWayBox.style.display = 'block';
|
gateWayBox.style.display = 'block';
|
||||||
|
@ -92,36 +100,11 @@ class CreditCardRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(hostedFields => {
|
}).then(hostedFields => {
|
||||||
const submitEvent = (event) => {
|
document.dispatchEvent(new CustomEvent("hosted_fields_loaded"));
|
||||||
this.spinner.block();
|
this.currentHostedFieldsInstance = hostedFields;
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
this.errorHandler.clear();
|
|
||||||
|
|
||||||
if (this.formValid && this.cardValid) {
|
hostedFields.on('inputSubmitRequest', () => {
|
||||||
const save_card = this.defaultConfig.save_card ? true : false;
|
this._submit(contextConfig);
|
||||||
const vault = document.getElementById('ppcp-credit-card-vault') ?
|
|
||||||
document.getElementById('ppcp-credit-card-vault').checked : save_card;
|
|
||||||
hostedFields.submit({
|
|
||||||
contingencies: ['SCA_WHEN_REQUIRED'],
|
|
||||||
vault: vault
|
|
||||||
}).then((payload) => {
|
|
||||||
payload.orderID = payload.orderId;
|
|
||||||
this.spinner.unblock();
|
|
||||||
return contextConfig.onApprove(payload);
|
|
||||||
}).catch(() => {
|
|
||||||
this.errorHandler.genericError();
|
|
||||||
this.spinner.unblock();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.spinner.unblock();
|
|
||||||
const message = ! this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
|
||||||
this.errorHandler.message(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hostedFields.on('inputSubmitRequest', function () {
|
|
||||||
submitEvent(null);
|
|
||||||
});
|
});
|
||||||
hostedFields.on('cardTypeChange', (event) => {
|
hostedFields.on('cardTypeChange', (event) => {
|
||||||
if ( ! event.cards.length ) {
|
if ( ! event.cards.length ) {
|
||||||
|
@ -137,11 +120,18 @@ class CreditCardRenderer {
|
||||||
});
|
});
|
||||||
this.formValid = formValid;
|
this.formValid = formValid;
|
||||||
|
|
||||||
})
|
});
|
||||||
document.querySelector(wrapper + ' button').addEventListener(
|
|
||||||
'click',
|
if (!this.formSubmissionSubscribed) {
|
||||||
submitEvent
|
document.querySelector(wrapper + ' button').addEventListener(
|
||||||
);
|
'click',
|
||||||
|
event => {
|
||||||
|
event.preventDefault();
|
||||||
|
this._submit(contextConfig);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.formSubmissionSubscribed = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#payment_method_ppcp-credit-card-gateway').addEventListener(
|
document.querySelector('#payment_method_ppcp-credit-card-gateway').addEventListener(
|
||||||
|
@ -151,5 +141,69 @@ class CreditCardRenderer {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disableFields() {
|
||||||
|
if( this.currentHostedFieldsInstance) {
|
||||||
|
this.currentHostedFieldsInstance.setAttribute({
|
||||||
|
field: 'number',
|
||||||
|
attribute: 'disabled'
|
||||||
|
})
|
||||||
|
this.currentHostedFieldsInstance.setAttribute({
|
||||||
|
field: 'cvv',
|
||||||
|
attribute: 'disabled'
|
||||||
|
})
|
||||||
|
this.currentHostedFieldsInstance.setAttribute({
|
||||||
|
field: 'expirationDate',
|
||||||
|
attribute: 'disabled'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enableFields() {
|
||||||
|
if( this.currentHostedFieldsInstance) {
|
||||||
|
this.currentHostedFieldsInstance.removeAttribute({
|
||||||
|
field: 'number',
|
||||||
|
attribute: 'disabled'
|
||||||
|
})
|
||||||
|
this.currentHostedFieldsInstance.removeAttribute({
|
||||||
|
field: 'cvv',
|
||||||
|
attribute: 'disabled'
|
||||||
|
})
|
||||||
|
this.currentHostedFieldsInstance.removeAttribute({
|
||||||
|
field: 'expirationDate',
|
||||||
|
attribute: 'disabled'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_submit(contextConfig) {
|
||||||
|
this.spinner.block();
|
||||||
|
this.errorHandler.clear();
|
||||||
|
|
||||||
|
if (this.formValid && this.cardValid) {
|
||||||
|
const save_card = this.defaultConfig.save_card ? true : false;
|
||||||
|
const vault = document.getElementById('ppcp-credit-card-vault') ?
|
||||||
|
document.getElementById('ppcp-credit-card-vault').checked : save_card;
|
||||||
|
const contingency = this.defaultConfig.hosted_fields.contingency;
|
||||||
|
const hostedFieldsData = {
|
||||||
|
vault: vault
|
||||||
|
};
|
||||||
|
if (contingency !== 'NO_3D_SECURE') {
|
||||||
|
hostedFieldsData.contingencies = [contingency];
|
||||||
|
}
|
||||||
|
this.currentHostedFieldsInstance.submit(hostedFieldsData).then((payload) => {
|
||||||
|
payload.orderID = payload.orderId;
|
||||||
|
this.spinner.unblock();
|
||||||
|
return contextConfig.onApprove(payload);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
this.spinner.unblock();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.spinner.unblock();
|
||||||
|
const message = ! this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
||||||
|
this.errorHandler.message(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export default CreditCardRenderer;
|
export default CreditCardRenderer;
|
||||||
|
|
|
@ -43,6 +43,14 @@ class Renderer {
|
||||||
domElement.style.display = 'block';
|
domElement.style.display = 'block';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disableCreditCardFields() {
|
||||||
|
this.creditCardRenderer.disableFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
enableCreditCardFields() {
|
||||||
|
this.creditCardRenderer.enableFields();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Renderer;
|
export default Renderer;
|
||||||
|
|
|
@ -68,7 +68,7 @@ return array(
|
||||||
$subscription_helper = $container->get( 'subscription.helper' );
|
$subscription_helper = $container->get( 'subscription.helper' );
|
||||||
$messages_apply = $container->get( 'button.helper.messages-apply' );
|
$messages_apply = $container->get( 'button.helper.messages-apply' );
|
||||||
$environment = $container->get( 'onboarding.environment' );
|
$environment = $container->get( 'onboarding.environment' );
|
||||||
$payment_token_repository = $container->get( 'subscription.repository.payment-token' );
|
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||||
$settings_status = $container->get( 'wcgateway.settings.status' );
|
$settings_status = $container->get( 'wcgateway.settings.status' );
|
||||||
return new SmartButton(
|
return new SmartButton(
|
||||||
$container->get( 'button.url' ),
|
$container->get( 'button.url' ),
|
||||||
|
@ -103,7 +103,8 @@ return array(
|
||||||
$request_data = $container->get( 'button.request-data' );
|
$request_data = $container->get( 'button.request-data' );
|
||||||
$repository = $container->get( 'api.repository.cart' );
|
$repository = $container->get( 'api.repository.cart' );
|
||||||
$data_store = \WC_Data_Store::load( 'product' );
|
$data_store = \WC_Data_Store::load( 'product' );
|
||||||
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
|
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store, $logger );
|
||||||
},
|
},
|
||||||
'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
|
'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
|
||||||
$request_data = $container->get( 'button.request-data' );
|
$request_data = $container->get( 'button.request-data' );
|
||||||
|
@ -114,6 +115,7 @@ return array(
|
||||||
$session_handler = $container->get( 'session.handler' );
|
$session_handler = $container->get( 'session.handler' );
|
||||||
$settings = $container->get( 'wcgateway.settings' );
|
$settings = $container->get( 'wcgateway.settings' );
|
||||||
$early_order_handler = $container->get( 'button.helper.early-order-handler' );
|
$early_order_handler = $container->get( 'button.helper.early-order-handler' );
|
||||||
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
return new CreateOrderEndpoint(
|
return new CreateOrderEndpoint(
|
||||||
$request_data,
|
$request_data,
|
||||||
$cart_repository,
|
$cart_repository,
|
||||||
|
@ -122,7 +124,8 @@ return array(
|
||||||
$payer_factory,
|
$payer_factory,
|
||||||
$session_handler,
|
$session_handler,
|
||||||
$settings,
|
$settings,
|
||||||
$early_order_handler
|
$early_order_handler,
|
||||||
|
$logger
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'button.helper.early-order-handler' => static function ( ContainerInterface $container ) : EarlyOrderHandler {
|
'button.helper.early-order-handler' => static function ( ContainerInterface $container ) : EarlyOrderHandler {
|
||||||
|
@ -154,13 +157,16 @@ return array(
|
||||||
'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint {
|
'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint {
|
||||||
$request_data = $container->get( 'button.request-data' );
|
$request_data = $container->get( 'button.request-data' );
|
||||||
$identity_token = $container->get( 'api.endpoint.identity-token' );
|
$identity_token = $container->get( 'api.endpoint.identity-token' );
|
||||||
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
return new DataClientIdEndpoint(
|
return new DataClientIdEndpoint(
|
||||||
$request_data,
|
$request_data,
|
||||||
$identity_token
|
$identity_token,
|
||||||
|
$logger
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
|
'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
|
||||||
return new ThreeDSecure();
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
|
return new ThreeDSecure( $logger );
|
||||||
},
|
},
|
||||||
'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply {
|
'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply {
|
||||||
return new MessagesApply();
|
return new MessagesApply();
|
||||||
|
|
|
@ -20,7 +20,7 @@ use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||||
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||||
|
@ -601,6 +601,19 @@ class SmartButton implements SmartButtonInterface {
|
||||||
return $this->subscription_helper->cart_contains_subscription();
|
return $this->subscription_helper->cart_contains_subscription();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the 3D Secure contingency settings.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function get_3ds_contingency(): string {
|
||||||
|
if ( $this->settings->has( '3d_secure_contingency' ) ) {
|
||||||
|
return $this->settings->get( '3d_secure_contingency' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'SCA_WHEN_REQUIRED';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The localized data for the smart button.
|
* The localized data for the smart button.
|
||||||
*
|
*
|
||||||
|
@ -677,6 +690,7 @@ class SmartButton implements SmartButtonInterface {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'valid_cards' => $this->dcc_applies->valid_cards(),
|
'valid_cards' => $this->dcc_applies->valid_cards(),
|
||||||
|
'contingency' => $this->get_3ds_contingency(),
|
||||||
),
|
),
|
||||||
'messages' => $this->message_values(),
|
'messages' => $this->message_values(),
|
||||||
'labels' => array(
|
'labels' => array(
|
||||||
|
@ -729,8 +743,7 @@ class SmartButton implements SmartButtonInterface {
|
||||||
'currency' => get_woocommerce_currency(),
|
'currency' => get_woocommerce_currency(),
|
||||||
'integration-date' => PAYPAL_INTEGRATION_DATE,
|
'integration-date' => PAYPAL_INTEGRATION_DATE,
|
||||||
'components' => implode( ',', $this->components() ),
|
'components' => implode( ',', $this->components() ),
|
||||||
'vault' => $this->can_save_vault_token() ?
|
'vault' => $this->can_save_vault_token() ? 'true' : 'false',
|
||||||
'true' : 'false',
|
|
||||||
'commit' => is_checkout() ? 'true' : 'false',
|
'commit' => is_checkout() ? 'true' : 'false',
|
||||||
'intent' => ( $this->settings->has( 'intent' ) ) ?
|
'intent' => ( $this->settings->has( 'intent' ) ) ?
|
||||||
$this->settings->get( 'intent' ) : 'capture',
|
$this->settings->get( 'intent' ) : 'capture',
|
||||||
|
@ -743,11 +756,20 @@ class SmartButton implements SmartButtonInterface {
|
||||||
) {
|
) {
|
||||||
$params['buyer-country'] = WC()->customer->get_billing_country();
|
$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() ) {
|
if ( ! is_checkout() ) {
|
||||||
$disable_funding[] = 'card';
|
$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 ) {
|
if ( count( $disable_funding ) > 0 ) {
|
||||||
$params['disable-funding'] = implode( ',', array_unique( $disable_funding ) );
|
$params['disable-funding'] = implode( ',', array_unique( $disable_funding ) );
|
||||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||||
|
@ -195,7 +196,9 @@ class ApproveOrderEndpoint implements EndpointInterface {
|
||||||
$this->session_handler->replace_order( $order );
|
$this->session_handler->replace_order( $order );
|
||||||
wp_send_json_success( $order );
|
wp_send_json_success( $order );
|
||||||
return true;
|
return true;
|
||||||
} catch ( \RuntimeException $error ) {
|
} catch ( Exception $error ) {
|
||||||
|
$this->logger->error( 'Order approve failed: ' . $error->getMessage() );
|
||||||
|
|
||||||
wp_send_json_error(
|
wp_send_json_error(
|
||||||
array(
|
array(
|
||||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||||
|
@ -57,21 +59,30 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
*/
|
*/
|
||||||
private $product_data_store;
|
private $product_data_store;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChangeCartEndpoint constructor.
|
* ChangeCartEndpoint constructor.
|
||||||
*
|
*
|
||||||
* @param \WC_Cart $cart The current WC cart object.
|
* @param \WC_Cart $cart The current WC cart object.
|
||||||
* @param \WC_Shipping $shipping The current WC shipping object.
|
* @param \WC_Shipping $shipping The current WC shipping object.
|
||||||
* @param RequestData $request_data The request data helper.
|
* @param RequestData $request_data The request data helper.
|
||||||
* @param CartRepository $repository The repository for the current purchase items.
|
* @param CartRepository $repository The repository for the current purchase items.
|
||||||
* @param \WC_Data_Store $product_data_store The data store for products.
|
* @param \WC_Data_Store $product_data_store The data store for products.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
\WC_Cart $cart,
|
\WC_Cart $cart,
|
||||||
\WC_Shipping $shipping,
|
\WC_Shipping $shipping,
|
||||||
RequestData $request_data,
|
RequestData $request_data,
|
||||||
CartRepository $repository,
|
CartRepository $repository,
|
||||||
\WC_Data_Store $product_data_store
|
\WC_Data_Store $product_data_store,
|
||||||
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->cart = $cart;
|
$this->cart = $cart;
|
||||||
|
@ -79,6 +90,7 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
$this->request_data = $request_data;
|
$this->request_data = $request_data;
|
||||||
$this->repository = $repository;
|
$this->repository = $repository;
|
||||||
$this->product_data_store = $product_data_store;
|
$this->product_data_store = $product_data_store;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -94,12 +106,13 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
* Handles the request.
|
* Handles the request.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception On error.
|
|
||||||
*/
|
*/
|
||||||
public function handle_request(): bool {
|
public function handle_request(): bool {
|
||||||
try {
|
try {
|
||||||
return $this->handle_data();
|
return $this->handle_data();
|
||||||
} catch ( RuntimeException $error ) {
|
} catch ( Exception $error ) {
|
||||||
|
$this->logger->error( 'Cart updating failed: ' . $error->getMessage() );
|
||||||
|
|
||||||
wp_send_json_error(
|
wp_send_json_error(
|
||||||
array(
|
array(
|
||||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||||
|
@ -116,7 +129,7 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
* Handles the request data.
|
* Handles the request data.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception On error.
|
* @throws Exception On error.
|
||||||
*/
|
*/
|
||||||
private function handle_data(): bool {
|
private function handle_data(): bool {
|
||||||
$data = $this->request_data->read_request( $this->nonce() );
|
$data = $this->request_data->read_request( $this->nonce() );
|
||||||
|
@ -234,7 +247,7 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
* @param int $quantity The Quantity.
|
* @param int $quantity The Quantity.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception When product could not be added.
|
* @throws Exception When product could not be added.
|
||||||
*/
|
*/
|
||||||
private function add_product( \WC_Product $product, int $quantity ): bool {
|
private function add_product( \WC_Product $product, int $quantity ): bool {
|
||||||
return false !== $this->cart->add_to_cart( $product->get_id(), $quantity );
|
return false !== $this->cart->add_to_cart( $product->get_id(), $quantity );
|
||||||
|
@ -249,7 +262,7 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
* @param array $post_variations The variations.
|
* @param array $post_variations The variations.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws \Exception When product could not be added.
|
* @throws Exception When product could not be added.
|
||||||
*/
|
*/
|
||||||
private function add_variable_product(
|
private function add_variable_product(
|
||||||
\WC_Product $product,
|
\WC_Product $product,
|
||||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||||
|
@ -102,6 +104,13 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
*/
|
*/
|
||||||
private $purchase_units;
|
private $purchase_units;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CreateOrderEndpoint constructor.
|
* CreateOrderEndpoint constructor.
|
||||||
*
|
*
|
||||||
|
@ -113,6 +122,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
* @param SessionHandler $session_handler The SessionHandler object.
|
* @param SessionHandler $session_handler The SessionHandler object.
|
||||||
* @param Settings $settings The Settings object.
|
* @param Settings $settings The Settings object.
|
||||||
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
RequestData $request_data,
|
RequestData $request_data,
|
||||||
|
@ -122,7 +132,8 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
PayerFactory $payer_factory,
|
PayerFactory $payer_factory,
|
||||||
SessionHandler $session_handler,
|
SessionHandler $session_handler,
|
||||||
Settings $settings,
|
Settings $settings,
|
||||||
EarlyOrderHandler $early_order_handler
|
EarlyOrderHandler $early_order_handler,
|
||||||
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->request_data = $request_data;
|
$this->request_data = $request_data;
|
||||||
|
@ -133,6 +144,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
$this->session_handler = $session_handler;
|
$this->session_handler = $session_handler;
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->early_order_handler = $early_order_handler;
|
$this->early_order_handler = $early_order_handler;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,6 +202,8 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
wp_send_json_success( $order->to_array() );
|
wp_send_json_success( $order->to_array() );
|
||||||
return true;
|
return true;
|
||||||
} catch ( \RuntimeException $error ) {
|
} catch ( \RuntimeException $error ) {
|
||||||
|
$this->logger->error( 'Order creation failed: ' . $error->getMessage() );
|
||||||
|
|
||||||
wp_send_json_error(
|
wp_send_json_error(
|
||||||
array(
|
array(
|
||||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||||
|
@ -198,7 +212,9 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch ( \Exception $exception ) {
|
} catch ( Exception $exception ) {
|
||||||
|
$this->logger->error( 'Order creation failed: ' . $exception->getMessage() );
|
||||||
|
|
||||||
wc_add_notice( $exception->getMessage(), 'error' );
|
wc_add_notice( $exception->getMessage(), 'error' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,11 +228,16 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
* @param \WP_Error $errors The errors, which occurred.
|
* @param \WP_Error $errors The errors, which occurred.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
* @throws Exception On Error.
|
||||||
*/
|
*/
|
||||||
public function after_checkout_validation( array $data, \WP_Error $errors ): array {
|
public function after_checkout_validation( array $data, \WP_Error $errors ): array {
|
||||||
if ( ! $errors->errors ) {
|
if ( ! $errors->errors ) {
|
||||||
|
try {
|
||||||
$order = $this->create_paypal_order();
|
$order = $this->create_paypal_order();
|
||||||
|
} catch ( Exception $exception ) {
|
||||||
|
$this->logger->error( 'Order creation failed: ' . $exception->getMessage() );
|
||||||
|
throw $exception;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In case we are onboarded and everything is fine with the \WC_Order
|
* In case we are onboarded and everything is fine with the \WC_Order
|
||||||
|
@ -231,6 +252,8 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger->error( 'Checkout validation failed: ' . $errors->get_error_message() );
|
||||||
|
|
||||||
wp_send_json_error(
|
wp_send_json_error(
|
||||||
array(
|
array(
|
||||||
'name' => '',
|
'name' => '',
|
||||||
|
@ -336,7 +359,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
*
|
*
|
||||||
* @param string $form_values The values of the form.
|
* @param string $form_values The values of the form.
|
||||||
*
|
*
|
||||||
* @throws \Exception On Error.
|
* @throws Exception On Error.
|
||||||
*/
|
*/
|
||||||
private function process_checkout_form( string $form_values ) {
|
private function process_checkout_form( string $form_values ) {
|
||||||
$form_values = explode( '&', $form_values );
|
$form_values = explode( '&', $form_values );
|
||||||
|
@ -386,7 +409,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
*
|
*
|
||||||
* @param string $form_values The values of the form.
|
* @param string $form_values The values of the form.
|
||||||
* @param \WC_Order|null $wc_order WC order to get data from.
|
* @param \WC_Order|null $wc_order WC order to get data from.
|
||||||
* @throws \Exception On Error.
|
* @throws Exception On Error.
|
||||||
*/
|
*/
|
||||||
private function process_checkout_form_when_creating_account( string $form_values, \WC_Order $wc_order = null ) {
|
private function process_checkout_form_when_creating_account( string $form_values, \WC_Order $wc_order = null ) {
|
||||||
$form_values = explode( '&', $form_values );
|
$form_values = explode( '&', $form_values );
|
||||||
|
@ -406,7 +429,12 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
'woocommerce_after_checkout_validation',
|
'woocommerce_after_checkout_validation',
|
||||||
function ( array $data, \WP_Error $errors ) use ( $wc_order ) {
|
function ( array $data, \WP_Error $errors ) use ( $wc_order ) {
|
||||||
if ( ! $errors->errors ) {
|
if ( ! $errors->errors ) {
|
||||||
$order = $this->create_paypal_order( $wc_order );
|
try {
|
||||||
|
$order = $this->create_paypal_order( $wc_order );
|
||||||
|
} catch ( Exception $exception ) {
|
||||||
|
$this->logger->error( 'Order creation failed: ' . $exception->getMessage() );
|
||||||
|
throw $exception;
|
||||||
|
}
|
||||||
wp_send_json_success( $order->to_array() );
|
wp_send_json_success( $order->to_array() );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\IdentityToken;
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\IdentityToken;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
@ -35,19 +37,29 @@ class DataClientIdEndpoint implements EndpointInterface {
|
||||||
*/
|
*/
|
||||||
private $identity_token;
|
private $identity_token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataClientIdEndpoint constructor.
|
* DataClientIdEndpoint constructor.
|
||||||
*
|
*
|
||||||
* @param RequestData $request_data The Request Data Helper.
|
* @param RequestData $request_data The Request Data Helper.
|
||||||
* @param IdentityToken $identity_token The Identity Token.
|
* @param IdentityToken $identity_token The Identity Token.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
RequestData $request_data,
|
RequestData $request_data,
|
||||||
IdentityToken $identity_token
|
IdentityToken $identity_token,
|
||||||
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->request_data = $request_data;
|
$this->request_data = $request_data;
|
||||||
$this->identity_token = $identity_token;
|
$this->identity_token = $identity_token;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,7 +89,9 @@ class DataClientIdEndpoint implements EndpointInterface {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
} catch ( RuntimeException $error ) {
|
} catch ( Exception $error ) {
|
||||||
|
$this->logger->error( 'Client ID retrieval failed: ' . $error->getMessage() );
|
||||||
|
|
||||||
wp_send_json_error(
|
wp_send_json_error(
|
||||||
array(
|
array(
|
||||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult as AuthResult;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult as AuthResult;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
|
|
||||||
|
@ -17,12 +18,27 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
*/
|
*/
|
||||||
class ThreeDSecure {
|
class ThreeDSecure {
|
||||||
|
|
||||||
|
|
||||||
const NO_DECISION = 0;
|
const NO_DECISION = 0;
|
||||||
const PROCCEED = 1;
|
const PROCCEED = 1;
|
||||||
const REJECT = 2;
|
const REJECT = 2;
|
||||||
const RETRY = 3;
|
const RETRY = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ThreeDSecure constructor.
|
||||||
|
*
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
|
*/
|
||||||
|
public function __construct( LoggerInterface $logger ) {
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine, how we proceed with a given order.
|
* Determine, how we proceed with a given order.
|
||||||
*
|
*
|
||||||
|
@ -42,7 +58,10 @@ class ThreeDSecure {
|
||||||
if ( ! $order->payment_source()->card()->authentication_result() ) {
|
if ( ! $order->payment_source()->card()->authentication_result() ) {
|
||||||
return self::NO_DECISION;
|
return self::NO_DECISION;
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $order->payment_source()->card()->authentication_result();
|
$result = $order->payment_source()->card()->authentication_result();
|
||||||
|
$this->logger->info( '3DS authentication result: ' . wc_print_r( $result->to_array(), true ) );
|
||||||
|
|
||||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_POSSIBLE ) {
|
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_POSSIBLE ) {
|
||||||
return self::PROCCEED;
|
return self::PROCCEED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ const path = require('path');
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
devtool: 'sourcemap',
|
devtool: 'eval-source-map',
|
||||||
mode: isProduction ? 'production' : 'development',
|
mode: isProduction ? 'production' : 'development',
|
||||||
target: 'web',
|
target: 'web',
|
||||||
entry: {
|
entry: {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -170,6 +170,7 @@ return array(
|
||||||
$login_seller_sandbox = $container->get( 'api.endpoint.login-seller-sandbox' );
|
$login_seller_sandbox = $container->get( 'api.endpoint.login-seller-sandbox' );
|
||||||
$partner_referrals_data = $container->get( 'api.repository.partner-referrals-data' );
|
$partner_referrals_data = $container->get( 'api.repository.partner-referrals-data' );
|
||||||
$settings = $container->get( 'wcgateway.settings' );
|
$settings = $container->get( 'wcgateway.settings' );
|
||||||
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
|
|
||||||
$cache = new Cache( 'ppcp-paypal-bearer' );
|
$cache = new Cache( 'ppcp-paypal-bearer' );
|
||||||
return new LoginSellerEndpoint(
|
return new LoginSellerEndpoint(
|
||||||
|
@ -178,7 +179,8 @@ return array(
|
||||||
$login_seller_sandbox,
|
$login_seller_sandbox,
|
||||||
$partner_referrals_data,
|
$partner_referrals_data,
|
||||||
$settings,
|
$settings,
|
||||||
$cache
|
$cache,
|
||||||
|
$logger
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ) : PartnerReferrals {
|
'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ) : PartnerReferrals {
|
||||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Onboarding\Endpoint;
|
namespace WooCommerce\PayPalCommerce\Onboarding\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer;
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\LoginSeller;
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\LoginSeller;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||||
|
@ -67,6 +69,13 @@ class LoginSellerEndpoint implements EndpointInterface {
|
||||||
*/
|
*/
|
||||||
private $cache;
|
private $cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LoginSellerEndpoint constructor.
|
* LoginSellerEndpoint constructor.
|
||||||
*
|
*
|
||||||
|
@ -76,6 +85,7 @@ class LoginSellerEndpoint implements EndpointInterface {
|
||||||
* @param PartnerReferralsData $partner_referrals_data The Partner Referrals Data.
|
* @param PartnerReferralsData $partner_referrals_data The Partner Referrals Data.
|
||||||
* @param Settings $settings The Settings.
|
* @param Settings $settings The Settings.
|
||||||
* @param Cache $cache The Cache.
|
* @param Cache $cache The Cache.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
RequestData $request_data,
|
RequestData $request_data,
|
||||||
|
@ -83,7 +93,8 @@ class LoginSellerEndpoint implements EndpointInterface {
|
||||||
LoginSeller $login_seller_sandbox,
|
LoginSeller $login_seller_sandbox,
|
||||||
PartnerReferralsData $partner_referrals_data,
|
PartnerReferralsData $partner_referrals_data,
|
||||||
Settings $settings,
|
Settings $settings,
|
||||||
Cache $cache
|
Cache $cache,
|
||||||
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->request_data = $request_data;
|
$this->request_data = $request_data;
|
||||||
|
@ -92,6 +103,7 @@ class LoginSellerEndpoint implements EndpointInterface {
|
||||||
$this->partner_referrals_data = $partner_referrals_data;
|
$this->partner_referrals_data = $partner_referrals_data;
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,12 +148,13 @@ class LoginSellerEndpoint implements EndpointInterface {
|
||||||
$this->cache->delete( PayPalBearer::CACHE_KEY );
|
$this->cache->delete( PayPalBearer::CACHE_KEY );
|
||||||
}
|
}
|
||||||
wp_schedule_single_event(
|
wp_schedule_single_event(
|
||||||
time() - 1,
|
time() + 5,
|
||||||
WebhookRegistrar::EVENT_HOOK
|
WebhookRegistrar::EVENT_HOOK
|
||||||
);
|
);
|
||||||
wp_send_json_success();
|
wp_send_json_success();
|
||||||
return true;
|
return true;
|
||||||
} catch ( \RuntimeException $error ) {
|
} catch ( Exception $error ) {
|
||||||
|
$this->logger->error( 'Onboarding completion handling error: ' . $error->getMessage() );
|
||||||
wp_send_json_error( $error->getMessage() );
|
wp_send_json_error( $error->getMessage() );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,14 @@ declare(strict_types=1);
|
||||||
namespace WooCommerce\PayPalCommerce\Subscription;
|
namespace WooCommerce\PayPalCommerce\Subscription;
|
||||||
|
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
|
||||||
use Psr\Container\ContainerInterface;
|
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'subscription.helper' => static function ( ContainerInterface $container ): SubscriptionHelper {
|
'subscription.helper' => static function ( ContainerInterface $container ): SubscriptionHelper {
|
||||||
return new SubscriptionHelper();
|
return new SubscriptionHelper();
|
||||||
},
|
},
|
||||||
'subscription.renewal-handler' => static function ( ContainerInterface $container ): RenewalHandler {
|
'subscription.renewal-handler' => static function ( ContainerInterface $container ): RenewalHandler {
|
||||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
$repository = $container->get( 'subscription.repository.payment-token' );
|
$repository = $container->get( 'vaulting.repository.payment-token' );
|
||||||
$endpoint = $container->get( 'api.endpoint.order' );
|
$endpoint = $container->get( 'api.endpoint.order' );
|
||||||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||||
$payer_factory = $container->get( 'api.factory.payer' );
|
$payer_factory = $container->get( 'api.factory.payer' );
|
||||||
|
|
|
@ -15,7 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* The payment token repository returns or deletes payment tokens for users.
|
|
||||||
*
|
|
||||||
* @package WooCommerce\PayPalCommerce\Subscription\Repository
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Subscription\Repository;
|
|
||||||
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokenEndpoint;
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class PaymentTokenRepository
|
|
||||||
*/
|
|
||||||
class PaymentTokenRepository {
|
|
||||||
|
|
||||||
|
|
||||||
const USER_META = 'ppcp-vault-token';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The payment token factory.
|
|
||||||
*
|
|
||||||
* @var PaymentTokenFactory
|
|
||||||
*/
|
|
||||||
private $factory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The payment token endpoint.
|
|
||||||
*
|
|
||||||
* @var PaymentTokenEndpoint
|
|
||||||
*/
|
|
||||||
private $endpoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PaymentTokenRepository constructor.
|
|
||||||
*
|
|
||||||
* @param PaymentTokenFactory $factory The payment token factory.
|
|
||||||
* @param PaymentTokenEndpoint $endpoint The payment token endpoint.
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
PaymentTokenFactory $factory,
|
|
||||||
PaymentTokenEndpoint $endpoint
|
|
||||||
) {
|
|
||||||
|
|
||||||
$this->factory = $factory;
|
|
||||||
$this->endpoint = $endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a token for a user.
|
|
||||||
*
|
|
||||||
* @param int $id The user id.
|
|
||||||
*
|
|
||||||
* @return PaymentToken|null
|
|
||||||
*/
|
|
||||||
public function for_user_id( int $id ) {
|
|
||||||
try {
|
|
||||||
$token = (array) get_user_meta( $id, self::USER_META, true );
|
|
||||||
if ( ! $token || ! isset( $token['id'] ) ) {
|
|
||||||
return $this->fetch_for_user_id( $id );
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = $this->factory->from_array( $token );
|
|
||||||
return $token;
|
|
||||||
} catch ( RuntimeException $error ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all tokens for a user.
|
|
||||||
*
|
|
||||||
* @param int $id The user id.
|
|
||||||
* @return PaymentToken[]
|
|
||||||
*/
|
|
||||||
public function all_for_user_id( int $id ) {
|
|
||||||
try {
|
|
||||||
$tokens = $this->endpoint->for_user( $id );
|
|
||||||
update_user_meta( $id, self::USER_META, $tokens );
|
|
||||||
return $tokens;
|
|
||||||
} catch ( RuntimeException $exception ) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a token for a user.
|
|
||||||
*
|
|
||||||
* @param int $user_id The user id.
|
|
||||||
* @param PaymentToken $token The token.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function delete_token( int $user_id, PaymentToken $token ): bool {
|
|
||||||
delete_user_meta( $user_id, self::USER_META );
|
|
||||||
return $this->endpoint->delete_token( $token );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if tokens has card source.
|
|
||||||
*
|
|
||||||
* @param PaymentToken[] $tokens The tokens.
|
|
||||||
* @return bool Whether tokens contains card or not.
|
|
||||||
*/
|
|
||||||
public function tokens_contains_card( $tokens ): bool {
|
|
||||||
foreach ( $tokens as $token ) {
|
|
||||||
if ( isset( $token->source()->card ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if tokens has PayPal source.
|
|
||||||
*
|
|
||||||
* @param PaymentToken[] $tokens The tokens.
|
|
||||||
* @return bool Whether tokens contains card or not.
|
|
||||||
*/
|
|
||||||
public function tokens_contains_paypal( $tokens ): bool {
|
|
||||||
foreach ( $tokens as $token ) {
|
|
||||||
if ( isset( $token->source()->paypal ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch PaymentToken from PayPal for a user.
|
|
||||||
*
|
|
||||||
* @param int $id The user id.
|
|
||||||
* @return PaymentToken
|
|
||||||
*/
|
|
||||||
private function fetch_for_user_id( int $id ): PaymentToken {
|
|
||||||
|
|
||||||
$tokens = $this->endpoint->for_user( $id );
|
|
||||||
$token = current( $tokens );
|
|
||||||
$token_array = $token->to_array();
|
|
||||||
update_user_meta( $id, self::USER_META, $token_array );
|
|
||||||
return $token;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,7 +14,7 @@ use Dhii\Modular\Module\ModuleInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||||
use Interop\Container\ServiceProviderInterface;
|
use Interop\Container\ServiceProviderInterface;
|
||||||
|
@ -62,7 +62,7 @@ class SubscriptionModule implements ModuleInterface {
|
||||||
add_action(
|
add_action(
|
||||||
'woocommerce_subscription_payment_complete',
|
'woocommerce_subscription_payment_complete',
|
||||||
function ( $subscription ) use ( $c ) {
|
function ( $subscription ) use ( $c ) {
|
||||||
$payment_token_repository = $c->get( 'subscription.repository.payment-token' );
|
$payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
|
||||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||||
|
|
||||||
$this->add_payment_token_id( $subscription, $payment_token_repository, $logger );
|
$this->add_payment_token_id( $subscription, $payment_token_repository, $logger );
|
||||||
|
@ -72,7 +72,7 @@ class SubscriptionModule implements ModuleInterface {
|
||||||
add_filter(
|
add_filter(
|
||||||
'woocommerce_gateway_description',
|
'woocommerce_gateway_description',
|
||||||
function ( $description, $id ) use ( $c ) {
|
function ( $description, $id ) use ( $c ) {
|
||||||
$payment_token_repository = $c->get( 'subscription.repository.payment-token' );
|
$payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
|
||||||
$settings = $c->get( 'wcgateway.settings' );
|
$settings = $c->get( 'wcgateway.settings' );
|
||||||
$subscription_helper = $c->get( 'subscription.helper' );
|
$subscription_helper = $c->get( 'subscription.helper' );
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class SubscriptionModule implements ModuleInterface {
|
||||||
add_filter(
|
add_filter(
|
||||||
'woocommerce_credit_card_form_fields',
|
'woocommerce_credit_card_form_fields',
|
||||||
function ( $default_fields, $id ) use ( $c ) {
|
function ( $default_fields, $id ) use ( $c ) {
|
||||||
$payment_token_repository = $c->get( 'subscription.repository.payment-token' );
|
$payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
|
||||||
$settings = $c->get( 'wcgateway.settings' );
|
$settings = $c->get( 'wcgateway.settings' );
|
||||||
$subscription_helper = $c->get( 'subscription.helper' );
|
$subscription_helper = $c->get( 'subscription.helper' );
|
||||||
|
|
||||||
|
|
2
modules/ppcp-vaulting/.gitignore
vendored
Normal file
2
modules/ppcp-vaulting/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
/assets
|
12
modules/ppcp-vaulting/extensions.php
Normal file
12
modules/ppcp-vaulting/extensions.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The vaulting module extensions.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||||
|
|
||||||
|
return array();
|
16
modules/ppcp-vaulting/module.php
Normal file
16
modules/ppcp-vaulting/module.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The vaulting module.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||||
|
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
|
||||||
|
return static function (): ModuleInterface {
|
||||||
|
return new VaultingModule();
|
||||||
|
};
|
23
modules/ppcp-vaulting/package.json
Normal file
23
modules/ppcp-vaulting/package.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "ppcp-vaulting",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"main": "resources/js/myaccount-payments.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.9.0",
|
||||||
|
"@babel/preset-env": "^7.9.5",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"sass": "^1.42.1",
|
||||||
|
"sass-loader": "^12.1.0",
|
||||||
|
"webpack": "^5.55.1",
|
||||||
|
"webpack-cli": "^4.8.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||||
|
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
|
||||||
|
"dev": "cross-env BABEL_ENV=default webpack --watch"
|
||||||
|
}
|
||||||
|
}
|
41
modules/ppcp-vaulting/resources/js/myaccount-payments.js
Normal file
41
modules/ppcp-vaulting/resources/js/myaccount-payments.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
document.addEventListener(
|
||||||
|
'DOMContentLoaded',
|
||||||
|
() => {
|
||||||
|
jQuery('.ppcp-delete-payment-button').click(async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
jQuery(this).prop('disabled', true);
|
||||||
|
const token = event.target.id;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
PayPalCommerceGatewayVaulting.delete.endpoint,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
nonce: PayPalCommerceGatewayVaulting.delete.nonce,
|
||||||
|
token,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const reportError = error => {
|
||||||
|
alert(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
try {
|
||||||
|
const result = await response.json();
|
||||||
|
reportError(result.data);
|
||||||
|
} catch (exc) {
|
||||||
|
console.error(exc);
|
||||||
|
reportError(response.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
});
|
42
modules/ppcp-vaulting/services.php
Normal file
42
modules/ppcp-vaulting/services.php
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The vaulting module services.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||||
|
|
||||||
|
use WooCommerce\PayPalCommerce\Vaulting\Assets\MyAccountPaymentsAssets;
|
||||||
|
use WooCommerce\PayPalCommerce\Vaulting\Endpoint\DeletePaymentTokenEndpoint;
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'vaulting.module-url' => static function ( $container ): string {
|
||||||
|
return plugins_url(
|
||||||
|
'/modules/ppcp-vaulting/',
|
||||||
|
dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'vaulting.assets.myaccount-payments' => function( $container ) : MyAccountPaymentsAssets {
|
||||||
|
return new MyAccountPaymentsAssets(
|
||||||
|
$container->get( 'vaulting.module-url' )
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'vaulting.payment-tokens-renderer' => static function (): PaymentTokensRenderer {
|
||||||
|
return new PaymentTokensRenderer();
|
||||||
|
},
|
||||||
|
'vaulting.repository.payment-token' => static function ( $container ): PaymentTokenRepository {
|
||||||
|
$factory = $container->get( 'api.factory.payment-token' );
|
||||||
|
$endpoint = $container->get( 'api.endpoint.payment-token' );
|
||||||
|
return new PaymentTokenRepository( $factory, $endpoint );
|
||||||
|
},
|
||||||
|
'vaulting.endpoint.delete' => function( $container ) : DeletePaymentTokenEndpoint {
|
||||||
|
return new DeletePaymentTokenEndpoint(
|
||||||
|
$container->get( 'vaulting.repository.payment-token' ),
|
||||||
|
$container->get( 'button.request-data' ),
|
||||||
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Register and configure assets for My account PayPal payments page.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Vaulting\Assets
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Vaulting\Assets;
|
||||||
|
|
||||||
|
use WooCommerce\PayPalCommerce\Vaulting\Endpoint\DeletePaymentTokenEndpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class MyAccountPaymentsAssets
|
||||||
|
*/
|
||||||
|
class MyAccountPaymentsAssets {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL to the module.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $module_url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebhooksStatusPageAssets constructor.
|
||||||
|
*
|
||||||
|
* @param string $module_url The URL to the module.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
string $module_url
|
||||||
|
) {
|
||||||
|
$this->module_url = untrailingslashit( $module_url );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues the necessary scripts.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function enqueue(): void {
|
||||||
|
wp_enqueue_script(
|
||||||
|
'ppcp-vaulting-myaccount-payments',
|
||||||
|
$this->module_url . '/assets/js/myaccount-payments.js',
|
||||||
|
array( 'jquery' ),
|
||||||
|
'1',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Localize script.
|
||||||
|
*/
|
||||||
|
public function localize() {
|
||||||
|
wp_localize_script(
|
||||||
|
'ppcp-vaulting-myaccount-payments',
|
||||||
|
'PayPalCommerceGatewayVaulting',
|
||||||
|
array(
|
||||||
|
'delete' => array(
|
||||||
|
'endpoint' => home_url( \WC_AJAX::get_endpoint( DeletePaymentTokenEndpoint::ENDPOINT ) ),
|
||||||
|
'nonce' => wp_create_nonce( DeletePaymentTokenEndpoint::nonce() ),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The endpoint for deleting payment tokens.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Vaulting\Endpoint
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Vaulting\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||||
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DeletePayment
|
||||||
|
*/
|
||||||
|
class DeletePaymentTokenEndpoint {
|
||||||
|
|
||||||
|
const ENDPOINT = 'ppc-vaulting-delete';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The repository.
|
||||||
|
*
|
||||||
|
* @var PaymentTokenRepository
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request data.
|
||||||
|
*
|
||||||
|
* @var RequestData
|
||||||
|
*/
|
||||||
|
protected $request_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeletePaymentTokenEndpoint constructor.
|
||||||
|
*
|
||||||
|
* @param PaymentTokenRepository $repository The repository.
|
||||||
|
* @param RequestData $request_data The request data.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
|
*/
|
||||||
|
public function __construct( PaymentTokenRepository $repository, RequestData $request_data, LoggerInterface $logger ) {
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->request_data = $request_data;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the nonce for the endpoint.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function nonce(): string {
|
||||||
|
return self::ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the incoming request.
|
||||||
|
*/
|
||||||
|
public function handle_request() {
|
||||||
|
try {
|
||||||
|
$data = $this->request_data->read_request( $this->nonce() );
|
||||||
|
|
||||||
|
$tokens = $this->repository->all_for_user_id( get_current_user_id() );
|
||||||
|
if ( $tokens ) {
|
||||||
|
foreach ( $tokens as $token ) {
|
||||||
|
if ( isset( $data['token'] ) && $token->id() === $data['token'] ) {
|
||||||
|
if ( $this->repository->delete_token( get_current_user_id(), $token ) ) {
|
||||||
|
wp_send_json_success();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_error( 'Could not delete payment token.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch ( Exception $error ) {
|
||||||
|
$this->logger->error( 'Failed to delete payment: ' . $error->getMessage() );
|
||||||
|
wp_send_json_error( $error->getMessage(), 403 );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
83
modules/ppcp-vaulting/src/class-paymenttokensrenderer.php
Normal file
83
modules/ppcp-vaulting/src/class-paymenttokensrenderer.php
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The payment tokens renderer.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||||
|
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PaymentTokensRendered
|
||||||
|
*/
|
||||||
|
class PaymentTokensRenderer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render payment tokens.
|
||||||
|
*
|
||||||
|
* @param PaymentToken[] $tokens The tokens.
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
public function render( array $tokens ) {
|
||||||
|
ob_start();
|
||||||
|
?>
|
||||||
|
<table class="shop_table shop_table_responsive">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?php echo esc_html__( 'Payment sources', 'woocommerce-paypal-payments' ); ?></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
foreach ( $tokens as $token ) {
|
||||||
|
$source = $token->source() ?? null;
|
||||||
|
if ( $source && isset( $source->card ) ) {
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo esc_attr( $source->card->brand ) . ' ...' . esc_attr( $source->card->last_digits ); ?></td>
|
||||||
|
<td>
|
||||||
|
<a class="ppcp-delete-payment-button" id="<?php echo esc_attr( $token->id() ); ?>" href=""><?php echo esc_html__( 'Delete', 'woocommerce-paypal-payments' ); ?></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
if ( $source && isset( $source->paypal ) ) {
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo esc_attr( $source->paypal->payer->email_address ); ?></td>
|
||||||
|
<td>
|
||||||
|
<a class="ppcp-delete-payment-button" id="<?php echo esc_attr( $token->id() ); ?>" href=""><?php echo esc_html__( 'Delete', 'woocommerce-paypal-payments' ); ?></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render no payments message.
|
||||||
|
*
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
public function render_no_tokens() {
|
||||||
|
ob_start();
|
||||||
|
?>
|
||||||
|
<div class="woocommerce-Message woocommerce-Message--info woocommerce-info">
|
||||||
|
<?php echo esc_html__( 'No payments available yet.', 'woocommerce-paypal-payments' ); ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
}
|
116
modules/ppcp-vaulting/src/class-vaultingmodule.php
Normal file
116
modules/ppcp-vaulting/src/class-vaultingmodule.php
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The vaulting module.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||||
|
|
||||||
|
use Dhii\Container\ServiceProvider;
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
use Interop\Container\ServiceProviderInterface;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\Vaulting\Endpoint\DeletePaymentTokenEndpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class StatusReportModule
|
||||||
|
*/
|
||||||
|
class VaultingModule implements ModuleInterface {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function setup(): ServiceProviderInterface {
|
||||||
|
return new ServiceProvider(
|
||||||
|
require __DIR__ . '/../services.php',
|
||||||
|
require __DIR__ . '/../extensions.php'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @param ContainerInterface $container A services container instance.
|
||||||
|
*/
|
||||||
|
public function run( ContainerInterface $container ): void {
|
||||||
|
|
||||||
|
add_filter(
|
||||||
|
'woocommerce_account_menu_items',
|
||||||
|
function( $menu_links ) {
|
||||||
|
$menu_links = array_slice( $menu_links, 0, 5, true )
|
||||||
|
+ array( 'ppcp-paypal-payment-tokens' => 'PayPal payments' )
|
||||||
|
+ array_slice( $menu_links, 5, null, true );
|
||||||
|
|
||||||
|
return $menu_links;
|
||||||
|
},
|
||||||
|
40
|
||||||
|
);
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'init',
|
||||||
|
function () {
|
||||||
|
add_rewrite_endpoint( 'ppcp-paypal-payment-tokens', EP_PAGES );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'woocommerce_account_ppcp-paypal-payment-tokens_endpoint',
|
||||||
|
function () use ( $container ) {
|
||||||
|
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||||
|
$renderer = $container->get( 'vaulting.payment-tokens-renderer' );
|
||||||
|
|
||||||
|
$tokens = $payment_token_repository->all_for_user_id( get_current_user_id() );
|
||||||
|
if ( $tokens ) {
|
||||||
|
echo wp_kses_post( $renderer->render( $tokens ) );
|
||||||
|
} else {
|
||||||
|
echo wp_kses_post( $renderer->render_no_tokens() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$asset_loader = $container->get( 'vaulting.assets.myaccount-payments' );
|
||||||
|
add_action(
|
||||||
|
'wp_enqueue_scripts',
|
||||||
|
function () use ( $asset_loader ) {
|
||||||
|
if ( is_account_page() && $this->is_payments_page() ) {
|
||||||
|
$asset_loader->enqueue();
|
||||||
|
$asset_loader->localize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'wc_ajax_' . DeletePaymentTokenEndpoint::ENDPOINT,
|
||||||
|
static function () use ( $container ) {
|
||||||
|
$endpoint = $container->get( 'vaulting.endpoint.delete' );
|
||||||
|
assert( $endpoint instanceof DeletePaymentTokenEndpoint );
|
||||||
|
|
||||||
|
$endpoint->handle_request();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getKey() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if is payments page.
|
||||||
|
*
|
||||||
|
* @return bool Whethen page is payments or not.
|
||||||
|
*/
|
||||||
|
private function is_payments_page(): bool {
|
||||||
|
global $wp;
|
||||||
|
$request = explode( '/', wp_parse_url( $wp->request, PHP_URL_PATH ) );
|
||||||
|
if ( end( $request ) === 'ppcp-paypal-payment-tokens' ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
22
modules/ppcp-vaulting/webpack.config.js
Normal file
22
modules/ppcp-vaulting/webpack.config.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
const path = require('path');
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
devtool: 'eval-source-map',
|
||||||
|
mode: isProduction ? 'production' : 'development',
|
||||||
|
target: 'web',
|
||||||
|
entry: {
|
||||||
|
'myaccount-payments': path.resolve('./resources/js/myaccount-payments.js'),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'assets/'),
|
||||||
|
filename: 'js/[name].js',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.js?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
2219
modules/ppcp-vaulting/yarn.lock
Normal file
2219
modules/ppcp-vaulting/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,11 +7,11 @@
|
||||||
"@babel/core": "^7.9.0",
|
"@babel/core": "^7.9.0",
|
||||||
"@babel/preset-env": "^7.9.5",
|
"@babel/preset-env": "^7.9.5",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"cross-env": "^5.0.1",
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
"file-loader": "^4.2.0",
|
"cross-env": "^7.0.3",
|
||||||
"webpack": "^4.42.1",
|
"file-loader": "^6.2.0",
|
||||||
"webpack-cli": "^3.1.2",
|
"webpack": "^5.55.0",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.26.0"
|
"webpack-cli": "^4.8.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* @package WooCommerce\PayPalCommerce\WcGateway
|
* @package WooCommerce\PayPalCommerce\WcGateway
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\WcGateway;
|
namespace WooCommerce\PayPalCommerce\WcGateway;
|
||||||
|
@ -29,6 +31,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
||||||
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||||
|
@ -37,6 +40,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||||
use WpOop\TransientCache\CachePoolFactory;
|
use WpOop\TransientCache\CachePoolFactory;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
||||||
|
@ -50,6 +54,7 @@ return array(
|
||||||
$state = $container->get( 'onboarding.state' );
|
$state = $container->get( 'onboarding.state' );
|
||||||
$transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' );
|
$transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' );
|
||||||
$subscription_helper = $container->get( 'subscription.helper' );
|
$subscription_helper = $container->get( 'subscription.helper' );
|
||||||
|
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||||
return new PayPalGateway(
|
return new PayPalGateway(
|
||||||
$settings_renderer,
|
$settings_renderer,
|
||||||
$order_processor,
|
$order_processor,
|
||||||
|
@ -60,7 +65,8 @@ return array(
|
||||||
$refund_processor,
|
$refund_processor,
|
||||||
$state,
|
$state,
|
||||||
$transaction_url_provider,
|
$transaction_url_provider,
|
||||||
$subscription_helper
|
$subscription_helper,
|
||||||
|
$page_id
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
||||||
|
@ -74,11 +80,12 @@ return array(
|
||||||
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
||||||
$state = $container->get( 'onboarding.state' );
|
$state = $container->get( 'onboarding.state' );
|
||||||
$transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' );
|
$transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' );
|
||||||
$payment_token_repository = $container->get( 'subscription.repository.payment-token' );
|
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||||
$payer_factory = $container->get( 'api.factory.payer' );
|
$payer_factory = $container->get( 'api.factory.payer' );
|
||||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||||
$subscription_helper = $container->get( 'subscription.helper' );
|
$subscription_helper = $container->get( 'subscription.helper' );
|
||||||
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
return new CreditCardGateway(
|
return new CreditCardGateway(
|
||||||
$settings_renderer,
|
$settings_renderer,
|
||||||
$order_processor,
|
$order_processor,
|
||||||
|
@ -94,7 +101,8 @@ return array(
|
||||||
$purchase_unit_factory,
|
$purchase_unit_factory,
|
||||||
$payer_factory,
|
$payer_factory,
|
||||||
$order_endpoint,
|
$order_endpoint,
|
||||||
$subscription_helper
|
$subscription_helper,
|
||||||
|
$logger
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
|
'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
|
||||||
|
@ -102,6 +110,32 @@ return array(
|
||||||
$settings = $container->get( 'wcgateway.settings' );
|
$settings = $container->get( 'wcgateway.settings' );
|
||||||
return new DisableGateways( $session_handler, $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, WebhooksStatusPage::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 ( ContainerInterface $container ): Settings {
|
'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
|
||||||
return new Settings();
|
return new Settings();
|
||||||
},
|
},
|
||||||
|
@ -110,14 +144,21 @@ return array(
|
||||||
$settings = $container->get( 'wcgateway.settings' );
|
$settings = $container->get( 'wcgateway.settings' );
|
||||||
return new ConnectAdminNotice( $state, $settings );
|
return new ConnectAdminNotice( $state, $settings );
|
||||||
},
|
},
|
||||||
|
'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $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' =>
|
'wcgateway.notice.authorize-order-action' =>
|
||||||
static function ( $container ): AuthorizeOrderActionNotice {
|
static function ( $container ): AuthorizeOrderActionNotice {
|
||||||
return new AuthorizeOrderActionNotice();
|
return new AuthorizeOrderActionNotice();
|
||||||
},
|
},
|
||||||
'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
|
'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
|
||||||
return new SectionsRenderer();
|
return new SectionsRenderer( $container->get( 'wcgateway.current-ppcp-settings-page-id' ) );
|
||||||
},
|
},
|
||||||
'wcgateway.settings.status' => static function ( $container ): SettingsStatus {
|
'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
|
||||||
$settings = $container->get( 'wcgateway.settings' );
|
$settings = $container->get( 'wcgateway.settings' );
|
||||||
return new SettingsStatus( $settings );
|
return new SettingsStatus( $settings );
|
||||||
},
|
},
|
||||||
|
@ -129,6 +170,7 @@ return array(
|
||||||
$messages_apply = $container->get( 'button.helper.messages-apply' );
|
$messages_apply = $container->get( 'button.helper.messages-apply' );
|
||||||
$dcc_product_status = $container->get( 'wcgateway.helper.dcc-product-status' );
|
$dcc_product_status = $container->get( 'wcgateway.helper.dcc-product-status' );
|
||||||
$settings_status = $container->get( 'wcgateway.settings.status' );
|
$settings_status = $container->get( 'wcgateway.settings.status' );
|
||||||
|
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||||
return new SettingsRenderer(
|
return new SettingsRenderer(
|
||||||
$settings,
|
$settings,
|
||||||
$state,
|
$state,
|
||||||
|
@ -136,7 +178,8 @@ return array(
|
||||||
$dcc_applies,
|
$dcc_applies,
|
||||||
$messages_apply,
|
$messages_apply,
|
||||||
$dcc_product_status,
|
$dcc_product_status,
|
||||||
$settings_status
|
$settings_status,
|
||||||
|
$page_id
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
|
'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
|
||||||
|
@ -146,7 +189,8 @@ return array(
|
||||||
$state = $container->get( 'onboarding.state' );
|
$state = $container->get( 'onboarding.state' );
|
||||||
$cache = new Cache( 'ppcp-paypal-bearer' );
|
$cache = new Cache( 'ppcp-paypal-bearer' );
|
||||||
$bearer = $container->get( 'api.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 ( ContainerInterface $container ): OrderProcessor {
|
'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
|
||||||
|
|
||||||
|
@ -660,7 +704,7 @@ return array(
|
||||||
State::STATE_ONBOARDED,
|
State::STATE_ONBOARDED,
|
||||||
),
|
),
|
||||||
'requirements' => array(),
|
'requirements' => array(),
|
||||||
'gateway' => 'all',
|
'gateway' => array( 'paypal', 'dcc' ),
|
||||||
),
|
),
|
||||||
'logging_enabled' => array(
|
'logging_enabled' => array(
|
||||||
'title' => __( 'Logging', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Logging', 'woocommerce-paypal-payments' ),
|
||||||
|
@ -1806,6 +1850,62 @@ return array(
|
||||||
),
|
),
|
||||||
'gateway' => 'dcc',
|
'gateway' => 'dcc',
|
||||||
),
|
),
|
||||||
|
'3d_secure_heading' => array(
|
||||||
|
'heading' => __( '3D Secure', 'woocommerce-paypal-payments' ),
|
||||||
|
'type' => 'ppcp-heading',
|
||||||
|
'description' => wp_kses_post(
|
||||||
|
sprintf(
|
||||||
|
// translators: %1$s and %2$s is a link tag.
|
||||||
|
__(
|
||||||
|
'3D Secure benefits cardholders and merchants by providing
|
||||||
|
an additional layer of verification using Verified by Visa,
|
||||||
|
MasterCard SecureCode and American Express SafeKey.
|
||||||
|
%1$sLearn more about 3D Secure.%2$s',
|
||||||
|
'woocommerce-paypal-payments'
|
||||||
|
),
|
||||||
|
'<a
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
href="https://woocommerce.com/posts/introducing-strong-customer-authentication-sca/"
|
||||||
|
>',
|
||||||
|
'</a>'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'screens' => array(
|
||||||
|
State::STATE_ONBOARDED,
|
||||||
|
),
|
||||||
|
'requirements' => array(
|
||||||
|
'dcc',
|
||||||
|
),
|
||||||
|
'gateway' => 'dcc',
|
||||||
|
),
|
||||||
|
'3d_secure_contingency' => array(
|
||||||
|
'title' => __( 'Contingency for 3D Secure', 'woocommerce-paypal-payments' ),
|
||||||
|
'type' => 'select',
|
||||||
|
'description' => sprintf(
|
||||||
|
// translators: %1$s and %2$s opening and closing ul tag, %3$s and %4$s opening and closing li tag.
|
||||||
|
__( '%1$s%3$sNo 3D Secure will cause transactions to be denied if 3D Secure is required by the bank of the cardholder.%4$s%3$sSCA_WHEN_REQUIRED returns a 3D Secure contingency when it is a mandate in the region where you operate.%4$s%3$sSCA_ALWAYS triggers 3D Secure for every transaction, regardless of SCA requirements.%4$s%2$s', 'woocommerce-paypal-payments' ),
|
||||||
|
'<ul>',
|
||||||
|
'</ul>',
|
||||||
|
'<li>',
|
||||||
|
'</li>'
|
||||||
|
),
|
||||||
|
'class' => array(),
|
||||||
|
'input_class' => array( 'wc-enhanced-select' ),
|
||||||
|
'default' => 'SCA_WHEN_REQUIRED',
|
||||||
|
'desc_tip' => true,
|
||||||
|
'options' => array(
|
||||||
|
'NO_3D_SECURE' => __( 'No 3D Secure (transaction will be denied if 3D Secure is required)', 'woocommerce-paypal-payments' ),
|
||||||
|
'SCA_WHEN_REQUIRED' => __( '3D Secure when required', 'woocommerce-paypal-payments' ),
|
||||||
|
'3D_SECURE' => __( 'Always trigger 3D Secure', 'woocommerce-paypal-payments' ),
|
||||||
|
),
|
||||||
|
'screens' => array(
|
||||||
|
State::STATE_ONBOARDED,
|
||||||
|
),
|
||||||
|
'requirements' => array(
|
||||||
|
'dcc',
|
||||||
|
),
|
||||||
|
'gateway' => 'dcc',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
if ( ! defined( 'PPCP_FLAG_SUBSCRIPTION' ) || ! PPCP_FLAG_SUBSCRIPTION ) {
|
if ( ! defined( 'PPCP_FLAG_SUBSCRIPTION' ) || ! PPCP_FLAG_SUBSCRIPTION ) {
|
||||||
unset( $fields['vault_enabled'] );
|
unset( $fields['vault_enabled'] );
|
||||||
|
@ -1822,15 +1922,6 @@ return array(
|
||||||
unset( $fields['ppcp_disconnect_sandbox'] );
|
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.
|
* Depending on your store location, some credit cards can't be used.
|
||||||
* Here, we filter them out.
|
* Here, we filter them out.
|
||||||
|
|
|
@ -9,13 +9,14 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||||
|
@ -46,6 +47,13 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
*/
|
*/
|
||||||
protected $subscription_helper;
|
protected $subscription_helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL to the module.
|
* The URL to the module.
|
||||||
*
|
*
|
||||||
|
@ -104,8 +112,9 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||||
* @param PayerFactory $payer_factory The payer factory.
|
* @param PayerFactory $payer_factory The payer factory.
|
||||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
SettingsRenderer $settings_renderer,
|
SettingsRenderer $settings_renderer,
|
||||||
|
@ -122,7 +131,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
PurchaseUnitFactory $purchase_unit_factory,
|
PurchaseUnitFactory $purchase_unit_factory,
|
||||||
PayerFactory $payer_factory,
|
PayerFactory $payer_factory,
|
||||||
OrderEndpoint $order_endpoint,
|
OrderEndpoint $order_endpoint,
|
||||||
SubscriptionHelper $subscription_helper
|
SubscriptionHelper $subscription_helper,
|
||||||
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->id = self::ID;
|
$this->id = self::ID;
|
||||||
|
@ -190,6 +200,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
$this->order_endpoint = $order_endpoint;
|
$this->order_endpoint = $order_endpoint;
|
||||||
$this->transaction_url_provider = $transaction_url_provider;
|
$this->transaction_url_provider = $transaction_url_provider;
|
||||||
$this->subscription_helper = $subscription_helper;
|
$this->subscription_helper = $subscription_helper;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,13 +208,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
*/
|
*/
|
||||||
public function init_form_fields() {
|
public function init_form_fields() {
|
||||||
$this->form_fields = array(
|
$this->form_fields = array(
|
||||||
'enabled' => array(
|
'ppcp' => array(
|
||||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
|
||||||
'type' => 'checkbox',
|
|
||||||
'label' => __( 'Enable Credit Card Payments', 'woocommerce-paypal-payments' ),
|
|
||||||
'default' => 'no',
|
|
||||||
),
|
|
||||||
'ppcp' => array(
|
|
||||||
'type' => 'ppcp',
|
'type' => 'ppcp',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -218,6 +223,20 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
|
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.
|
* Replace WooCommerce credit card field label.
|
||||||
*
|
*
|
||||||
|
@ -314,7 +333,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function is_available() : bool {
|
public function is_available() : bool {
|
||||||
return $this->config->has( 'dcc_enabled' ) && $this->config->get( 'dcc_enabled' );
|
return $this->is_enabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -349,4 +368,60 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||||
|
|
||||||
return parent::get_transaction_url( $order );
|
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' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class PayPalGateway
|
* Class PayPalGateway
|
||||||
|
@ -103,6 +104,13 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
*/
|
*/
|
||||||
private $onboarded;
|
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.
|
* PayPalGateway constructor.
|
||||||
*
|
*
|
||||||
|
@ -116,6 +124,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
* @param State $state The state.
|
* @param State $state The state.
|
||||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
* @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(
|
public function __construct(
|
||||||
SettingsRenderer $settings_renderer,
|
SettingsRenderer $settings_renderer,
|
||||||
|
@ -127,7 +136,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
RefundProcessor $refund_processor,
|
RefundProcessor $refund_processor,
|
||||||
State $state,
|
State $state,
|
||||||
TransactionUrlProvider $transaction_url_provider,
|
TransactionUrlProvider $transaction_url_provider,
|
||||||
SubscriptionHelper $subscription_helper
|
SubscriptionHelper $subscription_helper,
|
||||||
|
string $page_id
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->id = self::ID;
|
$this->id = self::ID;
|
||||||
|
@ -139,6 +149,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
$this->session_handler = $session_handler;
|
$this->session_handler = $session_handler;
|
||||||
$this->refund_processor = $refund_processor;
|
$this->refund_processor = $refund_processor;
|
||||||
$this->transaction_url_provider = $transaction_url_provider;
|
$this->transaction_url_provider = $transaction_url_provider;
|
||||||
|
$this->page_id = $page_id;
|
||||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||||
|
|
||||||
if ( $this->onboarded ) {
|
if ( $this->onboarded ) {
|
||||||
|
@ -214,7 +225,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$should_show_enabled_checkbox = ! $this->is_credit_card_tab() && ( $this->config->has( 'merchant_email' ) && $this->config->get( 'merchant_email' ) );
|
$should_show_enabled_checkbox = $this->is_paypal_tab() && ( $this->config->has( 'merchant_email' ) && $this->config->get( 'merchant_email' ) );
|
||||||
if ( ! $should_show_enabled_checkbox ) {
|
if ( ! $should_show_enabled_checkbox ) {
|
||||||
unset( $this->form_fields['enabled'] );
|
unset( $this->form_fields['enabled'] );
|
||||||
}
|
}
|
||||||
|
@ -298,6 +309,9 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
if ( $this->is_credit_card_tab() ) {
|
if ( $this->is_credit_card_tab() ) {
|
||||||
return __( 'PayPal Card Processing', 'woocommerce-paypal-payments' );
|
return __( 'PayPal Card Processing', 'woocommerce-paypal-payments' );
|
||||||
}
|
}
|
||||||
|
if ( $this->is_webhooks_tab() ) {
|
||||||
|
return __( 'Webhooks Status', 'woocommerce-paypal-payments' );
|
||||||
|
}
|
||||||
if ( $this->is_paypal_tab() ) {
|
if ( $this->is_paypal_tab() ) {
|
||||||
return __( 'PayPal Checkout', 'woocommerce-paypal-payments' );
|
return __( 'PayPal Checkout', 'woocommerce-paypal-payments' );
|
||||||
}
|
}
|
||||||
|
@ -316,6 +330,12 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
'woocommerce-paypal-payments'
|
'woocommerce-paypal-payments'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if ( $this->is_webhooks_tab() ) {
|
||||||
|
return __(
|
||||||
|
'Status of the webhooks subscription.',
|
||||||
|
'woocommerce-paypal-payments'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return __(
|
return __(
|
||||||
'Accept PayPal, Pay Later and alternative payment types.',
|
'Accept PayPal, Pay Later and alternative payment types.',
|
||||||
|
@ -332,11 +352,20 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
*/
|
*/
|
||||||
private function is_credit_card_tab() : bool {
|
private function is_credit_card_tab() : bool {
|
||||||
return is_admin()
|
return is_admin()
|
||||||
&& isset( $_GET[ SectionsRenderer::KEY ] )
|
&& CreditCardGateway::ID === $this->page_id;
|
||||||
&& CreditCardGateway::ID === sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 PayPal settings tab.
|
* Whether we are on the PayPal settings tab.
|
||||||
*
|
*
|
||||||
|
@ -345,8 +374,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
private function is_paypal_tab() : bool {
|
private function is_paypal_tab() : bool {
|
||||||
return ! $this->is_credit_card_tab()
|
return ! $this->is_credit_card_tab()
|
||||||
&& is_admin()
|
&& is_admin()
|
||||||
&& isset( $_GET['section'] )
|
&& self::ID === $this->page_id;
|
||||||
&& self::ID === sanitize_text_field( wp_unslash( $_GET['section'] ) );
|
|
||||||
}
|
}
|
||||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||||
|
|
||||||
|
@ -387,14 +415,18 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
*
|
*
|
||||||
* @param string $key The option key.
|
* @param string $key The option key.
|
||||||
* @param string $value The option value.
|
* @param string $value The option value.
|
||||||
* @return bool|void
|
* @return bool was anything saved?
|
||||||
*/
|
*/
|
||||||
public function update_option( $key, $value = '' ) {
|
public function update_option( $key, $value = '' ) {
|
||||||
parent::update_option( $key, $value );
|
$ret = parent::update_option( $key, $value );
|
||||||
|
|
||||||
if ( 'enabled' === $key ) {
|
if ( 'enabled' === $key ) {
|
||||||
$this->config->set( 'enabled', 'yes' === $value );
|
$this->config->set( 'enabled', 'yes' === $value );
|
||||||
$this->config->persist();
|
$this->config->persist();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,27 @@ trait ProcessPaymentTrait {
|
||||||
'redirect' => $this->get_return_url( $wc_order ),
|
'redirect' => $this->get_return_url( $wc_order ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( $order->status()->is( OrderStatus::COMPLETED ) && $order->intent() === 'AUTHORIZE' ) {
|
||||||
|
$this->order_endpoint->authorize( $order );
|
||||||
|
$wc_order->update_meta_data( PayPalGateway::CAPTURED_META_KEY, 'false' );
|
||||||
|
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
|
||||||
|
$wc_order->update_status(
|
||||||
|
'on-hold',
|
||||||
|
__( 'Awaiting payment.', 'woocommerce-paypal-payments' )
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->session_handler->destroy_session_data();
|
||||||
|
return array(
|
||||||
|
'result' => 'success',
|
||||||
|
'redirect' => $this->get_return_url( $wc_order ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->warning( "Could neither capture nor authorize order {$order->id()} using a saved credit card:" . 'Status: ' . $order->status()->name() . ' Intent: ' . $order->intent() );
|
||||||
|
|
||||||
} catch ( RuntimeException $error ) {
|
} catch ( RuntimeException $error ) {
|
||||||
|
$this->logger->error( $error->getMessage() );
|
||||||
$this->session_handler->destroy_session_data();
|
$this->session_handler->destroy_session_data();
|
||||||
wc_add_notice( $error->getMessage(), 'error' );
|
wc_add_notice( $error->getMessage(), 'error' );
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -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§ion=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' ) );
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
||||||
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||||
|
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class SectionsRenderer
|
* Class SectionsRenderer
|
||||||
|
@ -19,15 +20,29 @@ class SectionsRenderer {
|
||||||
|
|
||||||
const KEY = 'ppcp-tab';
|
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.
|
* Whether the sections tab should be rendered.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function should_render() : bool {
|
public function should_render() : bool {
|
||||||
|
return ! empty( $this->page_id );
|
||||||
global $current_section;
|
|
||||||
return PayPalGateway::ID === $current_section;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,11 +53,10 @@ class SectionsRenderer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
||||||
$current = ! isset( $_GET[ self::KEY ] ) ? PayPalGateway::ID : sanitize_text_field( wp_unslash( $_GET[ self::KEY ] ) );
|
|
||||||
$sections = array(
|
$sections = array(
|
||||||
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
|
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
|
||||||
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
|
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
|
||||||
|
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
|
||||||
);
|
);
|
||||||
|
|
||||||
echo '<ul class="subsubsub">';
|
echo '<ul class="subsubsub">';
|
||||||
|
@ -51,7 +65,7 @@ class SectionsRenderer {
|
||||||
|
|
||||||
foreach ( $sections as $id => $label ) {
|
foreach ( $sections as $id => $label ) {
|
||||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&' . self::KEY . '=' . $id );
|
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=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" />';
|
echo '</ul><br class="clear" />';
|
||||||
|
|
|
@ -23,8 +23,15 @@ use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
|
||||||
*/
|
*/
|
||||||
class SettingsListener {
|
class SettingsListener {
|
||||||
|
|
||||||
|
use PageMatcherTrait;
|
||||||
|
|
||||||
const NONCE = 'ppcp-settings';
|
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.
|
* The Settings.
|
||||||
*
|
*
|
||||||
|
@ -67,6 +74,13 @@ class SettingsListener {
|
||||||
*/
|
*/
|
||||||
private $bearer;
|
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.
|
* SettingsListener constructor.
|
||||||
*
|
*
|
||||||
|
@ -76,6 +90,7 @@ class SettingsListener {
|
||||||
* @param Cache $cache The Cache.
|
* @param Cache $cache The Cache.
|
||||||
* @param State $state The state.
|
* @param State $state The state.
|
||||||
* @param Bearer $bearer The bearer.
|
* @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(
|
public function __construct(
|
||||||
Settings $settings,
|
Settings $settings,
|
||||||
|
@ -83,7 +98,8 @@ class SettingsListener {
|
||||||
WebhookRegistrar $webhook_registrar,
|
WebhookRegistrar $webhook_registrar,
|
||||||
Cache $cache,
|
Cache $cache,
|
||||||
State $state,
|
State $state,
|
||||||
Bearer $bearer
|
Bearer $bearer,
|
||||||
|
string $page_id
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
|
@ -92,6 +108,7 @@ class SettingsListener {
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
$this->state = $state;
|
$this->state = $state;
|
||||||
$this->bearer = $bearer;
|
$this->bearer = $bearer;
|
||||||
|
$this->page_id = $page_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -218,18 +235,46 @@ class SettingsListener {
|
||||||
|
|
||||||
$settings = $this->read_active_credentials_from_settings( $settings );
|
$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'] )
|
$settings['enabled'] = isset( $_POST['woocommerce_ppcp-gateway_enabled'] )
|
||||||
&& 1 === absint( $_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
|
||||||
// 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 ) {
|
foreach ( $settings as $id => $value ) {
|
||||||
$this->settings->set( $id, $value );
|
$this->settings->set( $id, $value );
|
||||||
}
|
}
|
||||||
$this->settings->persist();
|
$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 ) ) {
|
if ( $this->cache->has( PayPalBearer::CACHE_KEY ) ) {
|
||||||
$this->cache->delete( PayPalBearer::CACHE_KEY );
|
$this->cache->delete( PayPalBearer::CACHE_KEY );
|
||||||
}
|
}
|
||||||
|
@ -265,30 +310,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.
|
* @param array $new_settings New settings.
|
||||||
*
|
* @return string One of the CREDENTIALS_ constants.
|
||||||
* @throws \WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException If a setting hasn't been found.
|
|
||||||
*/
|
*/
|
||||||
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'] ) {
|
$had_credentials = $current_id && $current_secret;
|
||||||
$this->settings->set( 'products_dcc_enabled', null );
|
$submitted_credentials = $new_id && $new_secret;
|
||||||
$this->webhook_registrar->register();
|
|
||||||
|
if ( ! $had_credentials && $submitted_credentials ) {
|
||||||
|
return self::CREDENTIALS_ADDED;
|
||||||
}
|
}
|
||||||
if ( $this->settings->has( 'client_id' ) && $this->settings->get( 'client_id' ) ) {
|
if ( $had_credentials ) {
|
||||||
$current_secret = $this->settings->has( 'client_secret' ) ?
|
if ( ! $submitted_credentials ) {
|
||||||
$this->settings->get( 'client_secret' ) : '';
|
return self::CREDENTIALS_REMOVED;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$settings['client_id'] !== $this->settings->get( 'client_id' )
|
$current_id !== $new_id
|
||||||
|| $settings['client_secret'] !== $current_secret
|
|| $current_secret !== $new_secret
|
||||||
) {
|
) {
|
||||||
$this->settings->set( 'products_dcc_enabled', null );
|
return self::CREDENTIALS_CHANGED;
|
||||||
$this->webhook_registrar->unregister();
|
|
||||||
$this->webhook_registrar->register();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return self::CREDENTIALS_UNCHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -311,20 +362,7 @@ class SettingsListener {
|
||||||
if ( ! in_array( $this->state->current_state(), $config['screens'], true ) ) {
|
if ( ! in_array( $this->state->current_state(), $config['screens'], true ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (
|
if ( ! $this->field_matches_page( $config, $this->page_id ) ) {
|
||||||
'dcc' === $config['gateway']
|
|
||||||
&& (
|
|
||||||
! isset( $_GET[ SectionsRenderer::KEY ] )
|
|
||||||
|| sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) !== CreditCardGateway::ID
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
'paypal' === $config['gateway']
|
|
||||||
&& isset( $_GET[ SectionsRenderer::KEY ] )
|
|
||||||
&& sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) !== PayPalGateway::ID
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch ( $config['type'] ) {
|
switch ( $config['type'] ) {
|
||||||
|
@ -406,14 +444,7 @@ class SettingsListener {
|
||||||
* phpcs:disable WordPress.Security.NonceVerification.Missing
|
* phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||||
* phpcs:disable WordPress.Security.NonceVerification.Recommended
|
* phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||||
*/
|
*/
|
||||||
if (
|
if ( empty( $this->page_id ) ) {
|
||||||
! isset( $_REQUEST['section'] )
|
|
||||||
|| ! in_array(
|
|
||||||
sanitize_text_field( wp_unslash( $_REQUEST['section'] ) ),
|
|
||||||
array( 'ppcp-gateway', 'ppcp-credit-card-gateway' ),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
use Woocommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
use Woocommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,6 +24,8 @@ use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||||
*/
|
*/
|
||||||
class SettingsRenderer {
|
class SettingsRenderer {
|
||||||
|
|
||||||
|
use PageMatcherTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Settings status helper.
|
* The Settings status helper.
|
||||||
*
|
*
|
||||||
|
@ -72,6 +75,13 @@ class SettingsRenderer {
|
||||||
*/
|
*/
|
||||||
private $dcc_product_status;
|
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.
|
* SettingsRenderer constructor.
|
||||||
*
|
*
|
||||||
|
@ -82,15 +92,17 @@ class SettingsRenderer {
|
||||||
* @param MessagesApply $messages_apply Whether messages can be shown.
|
* @param MessagesApply $messages_apply Whether messages can be shown.
|
||||||
* @param DCCProductStatus $dcc_product_status The product status.
|
* @param DCCProductStatus $dcc_product_status The product status.
|
||||||
* @param SettingsStatus $settings_status The Settings status helper.
|
* @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(
|
public function __construct(
|
||||||
ContainerInterface $settings,
|
ContainerInterface $settings,
|
||||||
State $state,
|
State $state,
|
||||||
array $fields,
|
array $fields,
|
||||||
DccApplies $dcc_applies,
|
DccApplies $dcc_applies,
|
||||||
MessagesApply $messages_apply,
|
MessagesApply $messages_apply,
|
||||||
DCCProductStatus $dcc_product_status,
|
DccProductStatus $dcc_product_status,
|
||||||
SettingsStatus $settings_status
|
SettingsStatus $settings_status,
|
||||||
|
string $page_id
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
|
@ -100,6 +112,7 @@ class SettingsRenderer {
|
||||||
$this->messages_apply = $messages_apply;
|
$this->messages_apply = $messages_apply;
|
||||||
$this->dcc_product_status = $dcc_product_status;
|
$this->dcc_product_status = $dcc_product_status;
|
||||||
$this->settings_status = $settings_status;
|
$this->settings_status = $settings_status;
|
||||||
|
$this->page_id = $page_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,21 +179,7 @@ class SettingsRenderer {
|
||||||
* @return bool Whether is PayPal checkout screen or not.
|
* @return bool Whether is PayPal checkout screen or not.
|
||||||
*/
|
*/
|
||||||
private function is_paypal_checkout_screen(): bool {
|
private function is_paypal_checkout_screen(): bool {
|
||||||
$current_screen = get_current_screen();
|
return PayPalGateway::ID === $this->page_id;
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -312,14 +311,66 @@ class SettingsRenderer {
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the table row.
|
||||||
|
*
|
||||||
|
* @param array $data Values of the row cells.
|
||||||
|
* @param string $tag HTML tag ('td', 'th').
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function render_table_row( array $data, string $tag = 'td' ): string {
|
||||||
|
$cells = array_map(
|
||||||
|
function ( $value ) use ( $tag ): string {
|
||||||
|
return "<$tag>" . (string) $value . "</$tag>";
|
||||||
|
},
|
||||||
|
$data
|
||||||
|
);
|
||||||
|
return '<tr>' . implode( $cells ) . '</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the table field.
|
||||||
|
*
|
||||||
|
* @param string $field The current field HTML.
|
||||||
|
* @param string $key The key.
|
||||||
|
* @param array $config The configuration of the field.
|
||||||
|
* @param array $value The current value.
|
||||||
|
*
|
||||||
|
* @return string HTML.
|
||||||
|
*/
|
||||||
|
public function render_table( $field, $key, $config, $value ): string {
|
||||||
|
if ( 'ppcp-table' !== $config['type'] ) {
|
||||||
|
return $field;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $value['data'];
|
||||||
|
if ( empty( $data ) ) {
|
||||||
|
$empty_placeholder = $value['empty_placeholder'] ?? ( $config['empty_placeholder'] ?? null );
|
||||||
|
if ( $empty_placeholder ) {
|
||||||
|
return $empty_placeholder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$header_row_html = $this->render_table_row( $value['headers'], 'th' );
|
||||||
|
$data_rows_html = implode(
|
||||||
|
array_map(
|
||||||
|
array( $this, 'render_table_row' ),
|
||||||
|
$data
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return "<table>
|
||||||
|
$header_row_html
|
||||||
|
$data_rows_html
|
||||||
|
</table>";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the settings.
|
* Renders the settings.
|
||||||
*/
|
*/
|
||||||
public function render() {
|
public function render() {
|
||||||
|
|
||||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
$is_dcc = CreditCardGateway::ID === $this->page_id;
|
||||||
//phpcs:disable WordPress.Security.NonceVerification.Missing
|
|
||||||
$is_dcc = isset( $_GET[ SectionsRenderer::KEY ] ) && CreditCardGateway::ID === sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) );
|
|
||||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||||
//phpcs:enable WordPress.Security.NonceVerification.Missing
|
//phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||||
$nonce = wp_create_nonce( SettingsListener::NONCE );
|
$nonce = wp_create_nonce( SettingsListener::NONCE );
|
||||||
|
@ -330,10 +381,7 @@ class SettingsRenderer {
|
||||||
if ( ! in_array( $this->state->current_state(), $config['screens'], true ) ) {
|
if ( ! in_array( $this->state->current_state(), $config['screens'], true ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( $is_dcc && ! in_array( $config['gateway'], array( 'all', 'dcc' ), true ) ) {
|
if ( ! $this->field_matches_page( $config, $this->page_id ) ) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( ! $is_dcc && ! in_array( $config['gateway'], array( 'all', 'paypal' ), true ) ) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
@ -354,7 +402,7 @@ class SettingsRenderer {
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$value = $this->settings->has( $field ) ? $this->settings->get( $field ) : null;
|
$value = $this->settings->has( $field ) ? $this->settings->get( $field ) : ( isset( $config['value'] ) ? $config['value']() : null );
|
||||||
$key = 'ppcp[' . $field . ']';
|
$key = 'ppcp[' . $field . ']';
|
||||||
$id = 'ppcp-' . $field;
|
$id = 'ppcp-' . $field;
|
||||||
$config['id'] = $id;
|
$config['id'] = $id;
|
||||||
|
@ -399,8 +447,6 @@ class SettingsRenderer {
|
||||||
if ( $this->dcc_applies->for_country_currency() ) {
|
if ( $this->dcc_applies->for_country_currency() ) {
|
||||||
if ( State::STATE_ONBOARDED > $this->state->current_state() ) {
|
if ( State::STATE_ONBOARDED > $this->state->current_state() ) {
|
||||||
$this->render_dcc_onboarding_info();
|
$this->render_dcc_onboarding_info();
|
||||||
} elseif ( State::STATE_ONBOARDED === $this->state->current_state() && $this->dcc_product_status->dcc_is_active() ) {
|
|
||||||
$this->render_3d_secure_info();
|
|
||||||
} elseif ( ! $this->dcc_product_status->dcc_is_active() ) {
|
} elseif ( ! $this->dcc_product_status->dcc_is_active() ) {
|
||||||
$this->render_dcc_not_active_yet();
|
$this->render_dcc_not_active_yet();
|
||||||
}
|
}
|
||||||
|
@ -450,45 +496,6 @@ class SettingsRenderer {
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the 3d secure info text.
|
|
||||||
*/
|
|
||||||
private function render_3d_secure_info() {
|
|
||||||
?>
|
|
||||||
<tr>
|
|
||||||
<th><?php esc_html_e( '3D Secure', 'woocommerce-paypal-payments' ); ?></th>
|
|
||||||
<td>
|
|
||||||
<p>
|
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* We still need to provide a docs link.
|
|
||||||
*
|
|
||||||
* @todo: Provide link to documentation.
|
|
||||||
*/
|
|
||||||
echo wp_kses_post(
|
|
||||||
sprintf(
|
|
||||||
// translators: %1$s and %2$s is a link tag.
|
|
||||||
__(
|
|
||||||
'3D Secure benefits cardholders and merchants by providing
|
|
||||||
an additional layer of verification using Verified by Visa,
|
|
||||||
MasterCard SecureCode and American Express SafeKey.
|
|
||||||
%1$sLearn more about 3D Secure.%2$s',
|
|
||||||
'woocommerce-paypal-payments'
|
|
||||||
),
|
|
||||||
'<a
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
href="https://woocommerce.com/posts/introducing-strong-customer-authentication-sca/"
|
|
||||||
>',
|
|
||||||
'</a>'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
?>
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the DCC onboarding info.
|
* Renders the DCC onboarding info.
|
||||||
*/
|
*/
|
||||||
|
@ -547,8 +554,8 @@ class SettingsRenderer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->is_paypal_checkout_screen() && $this->paypal_vaulting_is_enabled()
|
return $this->is_paypal_checkout_screen()
|
||||||
|| $this->is_paypal_checkout_screen() && $this->settings_status->pay_later_messaging_is_enabled();
|
&& ( $this->paypal_vaulting_is_enabled() || $this->settings_status->pay_later_messaging_is_enabled() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PageMatcherTrait.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\WcGateway\Settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||||
|
|
||||||
|
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||||
|
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;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PageMatcherTrait.
|
||||||
|
*/
|
||||||
|
trait PageMatcherTrait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the field config matches the current page (can be rendered here).
|
||||||
|
*
|
||||||
|
* @param array $field_config The field config (from wcgateway.settings.fields).
|
||||||
|
* @param string $current_page_id ID of the current PPCP gateway settings page.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function field_matches_page( array $field_config, string $current_page_id ): bool {
|
||||||
|
$allowed_gateways = $field_config['gateway'];
|
||||||
|
if ( ! is_array( $allowed_gateways ) ) {
|
||||||
|
$allowed_gateways = array( $allowed_gateways );
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway_page_id_map = array(
|
||||||
|
PayPalGateway::ID => 'paypal',
|
||||||
|
CreditCardGateway::ID => 'dcc', // TODO: consider using just the gateway ID for PayPal and DCC too.
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
|
||||||
|
@ -54,7 +55,6 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
$this->register_order_functionality( $c );
|
$this->register_order_functionality( $c );
|
||||||
$this->register_columns( $c );
|
$this->register_columns( $c );
|
||||||
$this->register_checkout_paypal_address_preset( $c );
|
$this->register_checkout_paypal_address_preset( $c );
|
||||||
$this->ajax_gateway_enabler( $c );
|
|
||||||
|
|
||||||
add_action(
|
add_action(
|
||||||
'woocommerce_sections_checkout',
|
'woocommerce_sections_checkout',
|
||||||
|
@ -82,15 +82,19 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
Repository::NOTICES_FILTER,
|
Repository::NOTICES_FILTER,
|
||||||
static function ( $notices ) use ( $c ): array {
|
static function ( $notices ) use ( $c ): array {
|
||||||
$notice = $c->get( 'wcgateway.notice.connect' );
|
$notice = $c->get( 'wcgateway.notice.connect' );
|
||||||
/**
|
assert( $notice instanceof ConnectAdminNotice );
|
||||||
* The Connect Admin Notice object.
|
|
||||||
*
|
|
||||||
* @var ConnectAdminNotice $notice
|
|
||||||
*/
|
|
||||||
$connect_message = $notice->connect_message();
|
$connect_message = $notice->connect_message();
|
||||||
if ( $connect_message ) {
|
if ( $connect_message ) {
|
||||||
$notices[] = $connect_message;
|
$notices[] = $connect_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dcc_without_paypal_notice = $c->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 = $c->get( 'wcgateway.notice.authorize-order-action' );
|
$authorize_order_action = $c->get( 'wcgateway.notice.authorize-order-action' );
|
||||||
$authorized_message = $authorize_order_action->message();
|
$authorized_message = $authorize_order_action->message();
|
||||||
if ( $authorized_message ) {
|
if ( $authorized_message ) {
|
||||||
|
@ -98,11 +102,7 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings_renderer = $c->get( 'wcgateway.settings.render' );
|
$settings_renderer = $c->get( 'wcgateway.settings.render' );
|
||||||
/**
|
assert( $settings_renderer instanceof SettingsRenderer );
|
||||||
* The settings renderer.
|
|
||||||
*
|
|
||||||
* @var SettingsRenderer $settings_renderer
|
|
||||||
*/
|
|
||||||
$messages = $settings_renderer->messages();
|
$messages = $settings_renderer->messages();
|
||||||
$notices = array_merge( $notices, $messages );
|
$notices = array_merge( $notices, $messages );
|
||||||
|
|
||||||
|
@ -145,50 +145,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.
|
* Registers the payment gateways.
|
||||||
*
|
*
|
||||||
|
@ -202,16 +158,12 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
$methods[] = $container->get( 'wcgateway.paypal-gateway' );
|
$methods[] = $container->get( 'wcgateway.paypal-gateway' );
|
||||||
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
$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.
|
* The DCC Applies object.
|
||||||
*
|
*
|
||||||
* @var DccApplies $dcc_applies
|
* @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' );
|
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
||||||
}
|
}
|
||||||
return (array) $methods;
|
return (array) $methods;
|
||||||
|
@ -258,6 +210,7 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
$field = $renderer->render_password( $field, $key, $args, $value );
|
$field = $renderer->render_password( $field, $key, $args, $value );
|
||||||
$field = $renderer->render_text_input( $field, $key, $args, $value );
|
$field = $renderer->render_text_input( $field, $key, $args, $value );
|
||||||
$field = $renderer->render_heading( $field, $key, $args, $value );
|
$field = $renderer->render_heading( $field, $key, $args, $value );
|
||||||
|
$field = $renderer->render_table( $field, $key, $args, $value );
|
||||||
return $field;
|
return $field;
|
||||||
},
|
},
|
||||||
10,
|
10,
|
||||||
|
|
|
@ -2,7 +2,7 @@ const path = require('path');
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
devtool: 'sourcemap',
|
devtool: 'eval-source-map',
|
||||||
mode: isProduction ? 'production' : 'development',
|
mode: isProduction ? 'production' : 'development',
|
||||||
target: 'web',
|
target: 'web',
|
||||||
entry: {
|
entry: {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
2
modules/ppcp-webhooks/.gitignore
vendored
Normal file
2
modules/ppcp-webhooks/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
assets
|
|
@ -9,4 +9,61 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Webhooks;
|
namespace WooCommerce\PayPalCommerce\Webhooks;
|
||||||
|
|
||||||
return array();
|
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'wcgateway.settings.fields' => static function ( $container, array $fields ): array {
|
||||||
|
$status_page_fields = array(
|
||||||
|
'webhooks_list' => array(
|
||||||
|
'title' => __( 'Subscribed webhooks', 'woocommerce-paypal-payments' ),
|
||||||
|
'type' => 'ppcp-table',
|
||||||
|
'screens' => array(
|
||||||
|
State::STATE_PROGRESSIVE,
|
||||||
|
State::STATE_ONBOARDED,
|
||||||
|
),
|
||||||
|
'requirements' => array(),
|
||||||
|
'gateway' => WebhooksStatusPage::ID,
|
||||||
|
'classes' => array( 'ppcp-webhooks-table' ),
|
||||||
|
'value' => function () use ( $container ) : array {
|
||||||
|
return $container->get( 'webhook.status.registered-webhooks-data' );
|
||||||
|
},
|
||||||
|
),
|
||||||
|
'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>',
|
||||||
|
'screens' => array(
|
||||||
|
State::STATE_PROGRESSIVE,
|
||||||
|
State::STATE_ONBOARDED,
|
||||||
|
),
|
||||||
|
'requirements' => array(),
|
||||||
|
'gateway' => WebhooksStatusPage::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' ),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$is_registered = $container->get( 'webhook.is-registered' );
|
||||||
|
if ( $is_registered ) {
|
||||||
|
$status_page_fields = array_merge(
|
||||||
|
$status_page_fields,
|
||||||
|
array(
|
||||||
|
'webhooks_simulate' => array(
|
||||||
|
'title' => __( 'Webhook simulation', 'woocommerce-paypal-payments' ),
|
||||||
|
'type' => 'ppcp-text',
|
||||||
|
'text' => '<button type="button" class="button ppcp-webhooks-simulate">' . esc_html__( 'Simulate', 'woocommerce-paypal-payments' ) . '</button>',
|
||||||
|
'screens' => array(
|
||||||
|
State::STATE_PROGRESSIVE,
|
||||||
|
State::STATE_ONBOARDED,
|
||||||
|
),
|
||||||
|
'requirements' => array(),
|
||||||
|
'gateway' => WebhooksStatusPage::ID,
|
||||||
|
'description' => __( 'Click to request a sample webhook payload from PayPal, allowing to check that your server can successfully receive webhooks.', 'woocommerce-paypal-payments' ),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge( $fields, $status_page_fields );
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
23
modules/ppcp-webhooks/package.json
Normal file
23
modules/ppcp-webhooks/package.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "ppcp-webhooks",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"main": "resources/js/status-page.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.9.0",
|
||||||
|
"@babel/preset-env": "^7.9.5",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"sass": "^1.42.1",
|
||||||
|
"sass-loader": "^12.1.0",
|
||||||
|
"webpack": "^5.55.0",
|
||||||
|
"webpack-cli": "^4.8.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||||
|
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
|
||||||
|
"dev": "cross-env BABEL_ENV=default webpack --watch"
|
||||||
|
}
|
||||||
|
}
|
34
modules/ppcp-webhooks/resources/css/status-page.scss
Normal file
34
modules/ppcp-webhooks/resources/css/status-page.scss
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
.ppcp-webhooks-table, .ppcp-webhooks-status-text {
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
color: green;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ppcp-webhooks-table {
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
th {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:first-child {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 450px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ppcp-webhooks-status-text {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
148
modules/ppcp-webhooks/resources/js/status-page.js
Normal file
148
modules/ppcp-webhooks/resources/js/status-page.js
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
document.addEventListener(
|
||||||
|
'DOMContentLoaded',
|
||||||
|
() => {
|
||||||
|
const resubscribeBtn = jQuery(PayPalCommerceGatewayWebhooksStatus.resubscribe.button);
|
||||||
|
|
||||||
|
resubscribeBtn.click(async () => {
|
||||||
|
resubscribeBtn.prop('disabled', true);
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
PayPalCommerceGatewayWebhooksStatus.resubscribe.endpoint,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
nonce: PayPalCommerceGatewayWebhooksStatus.resubscribe.nonce,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const reportError = error => {
|
||||||
|
const msg = PayPalCommerceGatewayWebhooksStatus.resubscribe.failureMessage + ' ' + error;
|
||||||
|
alert(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
try {
|
||||||
|
const result = await response.json();
|
||||||
|
reportError(result.data);
|
||||||
|
} catch (exc) {
|
||||||
|
console.error(exc);
|
||||||
|
reportError(response.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
const simulateBtn = jQuery(PayPalCommerceGatewayWebhooksStatus.simulation.start.button);
|
||||||
|
simulateBtn.click(async () => {
|
||||||
|
simulateBtn.prop('disabled', true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
PayPalCommerceGatewayWebhooksStatus.simulation.start.endpoint,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
nonce: PayPalCommerceGatewayWebhooksStatus.simulation.start.nonce,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const reportError = error => {
|
||||||
|
const msg = PayPalCommerceGatewayWebhooksStatus.simulation.start.failureMessage + ' ' + error;
|
||||||
|
alert(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
try {
|
||||||
|
const result = await response.json();
|
||||||
|
reportError(result.data);
|
||||||
|
} catch (exc) {
|
||||||
|
console.error(exc);
|
||||||
|
reportError(response.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const showStatus = html => {
|
||||||
|
let statusBlock = simulateBtn.siblings('.ppcp-webhooks-status-text');
|
||||||
|
if (!statusBlock.length) {
|
||||||
|
statusBlock = jQuery('<div class="ppcp-webhooks-status-text"></div>').insertAfter(simulateBtn);
|
||||||
|
}
|
||||||
|
statusBlock.html(html);
|
||||||
|
};
|
||||||
|
|
||||||
|
simulateBtn.siblings('.description').hide();
|
||||||
|
|
||||||
|
showStatus(
|
||||||
|
PayPalCommerceGatewayWebhooksStatus.simulation.state.waitingMessage +
|
||||||
|
'<span class="spinner is-active" style="float: none;"></span>'
|
||||||
|
);
|
||||||
|
|
||||||
|
const delay = 2000;
|
||||||
|
const retriesBeforeErrorMessage = 15;
|
||||||
|
const maxRetries = 30;
|
||||||
|
|
||||||
|
for (let i = 0; i < maxRetries; i++) {
|
||||||
|
await sleep(delay);
|
||||||
|
|
||||||
|
const stateResponse = await fetch(
|
||||||
|
PayPalCommerceGatewayWebhooksStatus.simulation.state.endpoint,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await stateResponse.json();
|
||||||
|
|
||||||
|
if (!stateResponse.ok || !result.success) {
|
||||||
|
console.error('Simulation state query failed: ' + result.data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = result.data.state;
|
||||||
|
if (state === PayPalCommerceGatewayWebhooksStatus.simulation.state.successState) {
|
||||||
|
showStatus(
|
||||||
|
'<span class="success">' +
|
||||||
|
'✔️ ' +
|
||||||
|
PayPalCommerceGatewayWebhooksStatus.simulation.state.successMessage +
|
||||||
|
'</span>'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (exc) {
|
||||||
|
console.error(exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i === retriesBeforeErrorMessage) {
|
||||||
|
showStatus(
|
||||||
|
'<span class="error">' +
|
||||||
|
PayPalCommerceGatewayWebhooksStatus.simulation.state.tooLongDelayMessage +
|
||||||
|
'</span>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
simulateBtn.prop('disabled', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
|
@ -9,41 +9,57 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Webhooks;
|
namespace WooCommerce\PayPalCommerce\Webhooks;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Webhook;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Assets\WebhooksStatusPageAssets;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulateEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved;
|
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved;
|
||||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted;
|
use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted;
|
||||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted;
|
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted;
|
||||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureRefunded;
|
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureRefunded;
|
||||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureReversed;
|
use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureReversed;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhookSimulation;
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
|
||||||
'webhook.registrar' => function( ContainerInterface $container ) : WebhookRegistrar {
|
'webhook.registrar' => function( ContainerInterface $container ) : WebhookRegistrar {
|
||||||
$factory = $container->get( 'api.factory.webhook' );
|
$factory = $container->get( 'api.factory.webhook' );
|
||||||
$endpoint = $container->get( 'api.endpoint.webhook' );
|
$endpoint = $container->get( 'api.endpoint.webhook' );
|
||||||
$rest_endpoint = $container->get( 'webhook.endpoint.controller' );
|
$rest_endpoint = $container->get( 'webhook.endpoint.controller' );
|
||||||
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
return new WebhookRegistrar(
|
return new WebhookRegistrar(
|
||||||
$factory,
|
$factory,
|
||||||
$endpoint,
|
$endpoint,
|
||||||
$rest_endpoint
|
$rest_endpoint,
|
||||||
|
$logger
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'webhook.endpoint.controller' => function( ContainerInterface $container ) : IncomingWebhookEndpoint {
|
'webhook.endpoint.controller' => function( ContainerInterface $container ) : IncomingWebhookEndpoint {
|
||||||
$webhook_endpoint = $container->get( 'api.endpoint.webhook' );
|
$webhook_endpoint = $container->get( 'api.endpoint.webhook' );
|
||||||
$webhook_factory = $container->get( 'api.factory.webhook' );
|
$webhook = $container->get( 'webhook.current' );
|
||||||
$handler = $container->get( 'webhook.endpoint.handler' );
|
$handler = $container->get( 'webhook.endpoint.handler' );
|
||||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
$verify_request = ! defined( 'PAYPAL_WEBHOOK_REQUEST_VERIFICATION' ) || PAYPAL_WEBHOOK_REQUEST_VERIFICATION;
|
$verify_request = ! defined( 'PAYPAL_WEBHOOK_REQUEST_VERIFICATION' ) || PAYPAL_WEBHOOK_REQUEST_VERIFICATION;
|
||||||
|
$webhook_event_factory = $container->get( 'api.factory.webhook-event' );
|
||||||
|
$simulation = $container->get( 'webhook.status.simulation' );
|
||||||
|
|
||||||
return new IncomingWebhookEndpoint(
|
return new IncomingWebhookEndpoint(
|
||||||
$webhook_endpoint,
|
$webhook_endpoint,
|
||||||
$webhook_factory,
|
$webhook,
|
||||||
$logger,
|
$logger,
|
||||||
$verify_request,
|
$verify_request,
|
||||||
|
$webhook_event_factory,
|
||||||
|
$simulation,
|
||||||
... $handler
|
... $handler
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'webhook.endpoint.handler' => function( ContainerInterface $container ) : array {
|
'webhook.endpoint.handler' => function( ContainerInterface $container ) : array {
|
||||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
$prefix = $container->get( 'api.prefix' );
|
$prefix = $container->get( 'api.prefix' );
|
||||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||||
|
@ -55,4 +71,122 @@ return array(
|
||||||
new PaymentCaptureCompleted( $logger, $prefix ),
|
new PaymentCaptureCompleted( $logger, $prefix ),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'webhook.current' => function( $container ) : ?Webhook {
|
||||||
|
$data = (array) get_option( WebhookRegistrar::KEY, array() );
|
||||||
|
if ( empty( $data ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$factory = $container->get( 'api.factory.webhook' );
|
||||||
|
assert( $factory instanceof WebhookFactory );
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $factory->from_array( $data );
|
||||||
|
} catch ( Exception $exception ) {
|
||||||
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
|
assert( $logger instanceof LoggerInterface );
|
||||||
|
$logger->error( 'Failed to parse the stored webhook data: ' . $exception->getMessage() );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.is-registered' => function( $container ) : bool {
|
||||||
|
return $container->get( 'webhook.current' ) !== null;
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.status.registered-webhooks' => function( $container ) : array {
|
||||||
|
$endpoint = $container->get( 'api.endpoint.webhook' );
|
||||||
|
assert( $endpoint instanceof WebhookEndpoint );
|
||||||
|
|
||||||
|
return $endpoint->list();
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.status.registered-webhooks-data' => function( $container ) : array {
|
||||||
|
$empty_placeholder = __( 'No webhooks found.', 'woocommerce-paypal-payments' );
|
||||||
|
|
||||||
|
$webhooks = array();
|
||||||
|
try {
|
||||||
|
$webhooks = $container->get( 'webhook.status.registered-webhooks' );
|
||||||
|
} catch ( Exception $exception ) {
|
||||||
|
$empty_placeholder = sprintf(
|
||||||
|
'<span class="error">%s</span>',
|
||||||
|
__( 'Failed to load webhooks.', 'woocommerce-paypal-payments' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'headers' => array(
|
||||||
|
__( 'URL', 'woocommerce-paypal-payments' ),
|
||||||
|
__( 'Tracked events', 'woocommerce-paypal-payments' ),
|
||||||
|
),
|
||||||
|
'data' => array_map(
|
||||||
|
function ( Webhook $webhook ): array {
|
||||||
|
return array(
|
||||||
|
esc_html( $webhook->url() ),
|
||||||
|
implode(
|
||||||
|
',<br/>',
|
||||||
|
array_map(
|
||||||
|
'esc_html',
|
||||||
|
$webhook->humanfriendly_event_names()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
$webhooks
|
||||||
|
),
|
||||||
|
'empty_placeholder' => $empty_placeholder,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.status.simulation' => function( $container ) : WebhookSimulation {
|
||||||
|
$webhook_endpoint = $container->get( 'api.endpoint.webhook' );
|
||||||
|
$webhook = $container->get( 'webhook.current' );
|
||||||
|
return new WebhookSimulation(
|
||||||
|
$webhook_endpoint,
|
||||||
|
$webhook,
|
||||||
|
'CHECKOUT.ORDER.APPROVED',
|
||||||
|
'2.0'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.status.assets' => function( $container ) : WebhooksStatusPageAssets {
|
||||||
|
return new WebhooksStatusPageAssets(
|
||||||
|
$container->get( 'webhook.module-url' )
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.endpoint.resubscribe' => static function ( $container ) : ResubscribeEndpoint {
|
||||||
|
$registrar = $container->get( 'webhook.registrar' );
|
||||||
|
$request_data = $container->get( 'button.request-data' );
|
||||||
|
|
||||||
|
return new ResubscribeEndpoint(
|
||||||
|
$registrar,
|
||||||
|
$request_data
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.endpoint.simulate' => static function ( $container ) : SimulateEndpoint {
|
||||||
|
$simulation = $container->get( 'webhook.status.simulation' );
|
||||||
|
$request_data = $container->get( 'button.request-data' );
|
||||||
|
|
||||||
|
return new SimulateEndpoint(
|
||||||
|
$simulation,
|
||||||
|
$request_data
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'webhook.endpoint.simulation-state' => static function ( $container ) : SimulationStateEndpoint {
|
||||||
|
$simulation = $container->get( 'webhook.status.simulation' );
|
||||||
|
|
||||||
|
return new SimulationStateEndpoint(
|
||||||
|
$simulation
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
'webhook.module-url' => static function ( $container ): string {
|
||||||
|
return plugins_url(
|
||||||
|
'/modules/ppcp-webhooks/',
|
||||||
|
dirname( __FILE__, 3 ) . '/woocommerce-paypal-payments.php'
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The endpoint for resubscribing webhooks.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Webhooks\Endpoint
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Webhooks\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ResubscribeEndpoint
|
||||||
|
*/
|
||||||
|
class ResubscribeEndpoint {
|
||||||
|
|
||||||
|
const ENDPOINT = 'ppc-webhooks-resubscribe';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The webhooks registrar.
|
||||||
|
*
|
||||||
|
* @var WebhookRegistrar
|
||||||
|
*/
|
||||||
|
private $registrar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Request Data helper object.
|
||||||
|
*
|
||||||
|
* @var RequestData
|
||||||
|
*/
|
||||||
|
private $request_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResubscribeEndpoint constructor.
|
||||||
|
*
|
||||||
|
* @param WebhookRegistrar $registrar The webhooks registrar.
|
||||||
|
* @param RequestData $request_data The Request Data helper object.
|
||||||
|
*/
|
||||||
|
public function __construct( WebhookRegistrar $registrar, RequestData $request_data ) {
|
||||||
|
$this->registrar = $registrar;
|
||||||
|
$this->request_data = $request_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the nonce for the endpoint.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function nonce(): string {
|
||||||
|
return self::ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the incoming request.
|
||||||
|
*/
|
||||||
|
public function handle_request() {
|
||||||
|
try {
|
||||||
|
// Validate nonce.
|
||||||
|
$this->request_data->read_request( $this->nonce() );
|
||||||
|
|
||||||
|
$this->registrar->unregister();
|
||||||
|
|
||||||
|
if ( ! $this->registrar->register() ) {
|
||||||
|
wp_send_json_error( 'Webhook subscription failed.', 500 );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success();
|
||||||
|
return true;
|
||||||
|
} catch ( Exception $error ) {
|
||||||
|
wp_send_json_error( $error->getMessage(), 403 );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The endpoint for starting webhooks simulation.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Webhooks\Endpoint
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Webhooks\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhookSimulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SimulateEndpoint
|
||||||
|
*/
|
||||||
|
class SimulateEndpoint {
|
||||||
|
|
||||||
|
const ENDPOINT = 'ppc-webhooks-simulate';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The simulation handler.
|
||||||
|
*
|
||||||
|
* @var WebhookSimulation
|
||||||
|
*/
|
||||||
|
private $simulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Request Data helper object.
|
||||||
|
*
|
||||||
|
* @var RequestData
|
||||||
|
*/
|
||||||
|
private $request_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SimulateEndpoint constructor.
|
||||||
|
*
|
||||||
|
* @param WebhookSimulation $simulation The simulation handler.
|
||||||
|
* @param RequestData $request_data The Request Data helper object.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
WebhookSimulation $simulation,
|
||||||
|
RequestData $request_data
|
||||||
|
) {
|
||||||
|
$this->simulation = $simulation;
|
||||||
|
$this->request_data = $request_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the nonce for the endpoint.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function nonce(): string {
|
||||||
|
return self::ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the incoming request.
|
||||||
|
*/
|
||||||
|
public function handle_request() {
|
||||||
|
try {
|
||||||
|
// Validate nonce.
|
||||||
|
$this->request_data->read_request( $this->nonce() );
|
||||||
|
|
||||||
|
$this->simulation->start();
|
||||||
|
|
||||||
|
wp_send_json_success();
|
||||||
|
return true;
|
||||||
|
} catch ( Exception $error ) {
|
||||||
|
wp_send_json_error( $error->getMessage(), 500 );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The endpoint for getting the current webhooks simulation state.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Webhooks\Endpoint
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Webhooks\Endpoint;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhookSimulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SimulationStateEndpoint
|
||||||
|
*/
|
||||||
|
class SimulationStateEndpoint {
|
||||||
|
|
||||||
|
const ENDPOINT = 'ppc-webhooks-simulation-state';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The simulation handler.
|
||||||
|
*
|
||||||
|
* @var WebhookSimulation
|
||||||
|
*/
|
||||||
|
private $simulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SimulationStateEndpoint constructor.
|
||||||
|
*
|
||||||
|
* @param WebhookSimulation $simulation The simulation handler.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
WebhookSimulation $simulation
|
||||||
|
) {
|
||||||
|
$this->simulation = $simulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the nonce for the endpoint.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function nonce(): string {
|
||||||
|
return self::ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the incoming request.
|
||||||
|
*/
|
||||||
|
public function handle_request() {
|
||||||
|
try {
|
||||||
|
$state = $this->simulation->get_state();
|
||||||
|
|
||||||
|
wp_send_json_success(
|
||||||
|
array(
|
||||||
|
'state' => $state,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
} catch ( Exception $error ) {
|
||||||
|
wp_send_json_error( $error->getMessage(), 500 );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,11 +9,15 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Webhooks;
|
namespace WooCommerce\PayPalCommerce\Webhooks;
|
||||||
|
|
||||||
|
use phpDocumentor\Reflection\Types\This;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Webhook;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\WebhookEvent;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
|
||||||
use WooCommerce\PayPalCommerce\Webhooks\Handler\RequestHandler;
|
use WooCommerce\PayPalCommerce\Webhooks\Handler\RequestHandler;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhookSimulation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class IncomingWebhookEndpoint
|
* Class IncomingWebhookEndpoint
|
||||||
|
@ -31,11 +35,11 @@ class IncomingWebhookEndpoint {
|
||||||
private $webhook_endpoint;
|
private $webhook_endpoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Webhook Factory.
|
* Our registered webhook.
|
||||||
*
|
*
|
||||||
* @var WebhookFactory
|
* @var Webhook|null
|
||||||
*/
|
*/
|
||||||
private $webhook_factory;
|
private $webhook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Request handlers.
|
* The Request handlers.
|
||||||
|
@ -58,28 +62,48 @@ class IncomingWebhookEndpoint {
|
||||||
*/
|
*/
|
||||||
private $verify_request;
|
private $verify_request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The webhook event factory.
|
||||||
|
*
|
||||||
|
* @var WebhookEventFactory
|
||||||
|
*/
|
||||||
|
private $webhook_event_factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The simulation handler.
|
||||||
|
*
|
||||||
|
* @var WebhookSimulation
|
||||||
|
*/
|
||||||
|
private $simulation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IncomingWebhookEndpoint constructor.
|
* IncomingWebhookEndpoint constructor.
|
||||||
*
|
*
|
||||||
* @param WebhookEndpoint $webhook_endpoint The webhook endpoint.
|
* @param WebhookEndpoint $webhook_endpoint The webhook endpoint.
|
||||||
* @param WebhookFactory $webhook_factory The webhook factory.
|
* @param Webhook|null $webhook Our registered webhook.
|
||||||
* @param LoggerInterface $logger The logger.
|
* @param LoggerInterface $logger The logger.
|
||||||
* @param bool $verify_request Whether requests need to be verified or not.
|
* @param bool $verify_request Whether requests need to be verified or not.
|
||||||
* @param RequestHandler ...$handlers The handlers, which process a request in the end.
|
* @param WebhookEventFactory $webhook_event_factory The webhook event factory.
|
||||||
|
* @param WebhookSimulation $simulation The simulation handler.
|
||||||
|
* @param RequestHandler ...$handlers The handlers, which process a request in the end.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
WebhookEndpoint $webhook_endpoint,
|
WebhookEndpoint $webhook_endpoint,
|
||||||
WebhookFactory $webhook_factory,
|
?Webhook $webhook,
|
||||||
LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
bool $verify_request,
|
bool $verify_request,
|
||||||
|
WebhookEventFactory $webhook_event_factory,
|
||||||
|
WebhookSimulation $simulation,
|
||||||
RequestHandler ...$handlers
|
RequestHandler ...$handlers
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->webhook_endpoint = $webhook_endpoint;
|
$this->webhook_endpoint = $webhook_endpoint;
|
||||||
$this->webhook_factory = $webhook_factory;
|
$this->webhook = $webhook;
|
||||||
$this->handlers = $handlers;
|
$this->handlers = $handlers;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->verify_request = $verify_request;
|
$this->verify_request = $verify_request;
|
||||||
|
$this->webhook_event_factory = $webhook_event_factory;
|
||||||
|
$this->simulation = $simulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,35 +134,34 @@ class IncomingWebhookEndpoint {
|
||||||
/**
|
/**
|
||||||
* Verifies the current request.
|
* Verifies the current request.
|
||||||
*
|
*
|
||||||
|
* @param \WP_REST_Request $request The request.
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function verify_request(): bool {
|
public function verify_request( \WP_REST_Request $request ): bool {
|
||||||
if ( ! $this->verify_request ) {
|
if ( ! $this->verify_request ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $this->webhook ) {
|
||||||
|
$this->logger->error( 'Failed to retrieve stored webhook data.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$data = (array) get_option( WebhookRegistrar::KEY, array() );
|
$event = $this->event_from_request( $request );
|
||||||
$webhook = $this->webhook_factory->from_array( $data );
|
|
||||||
$result = $this->webhook_endpoint->verify_current_request_for_webhook( $webhook );
|
if ( $this->simulation->is_simulation_event( $event ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->webhook_endpoint->verify_current_request_for_webhook( $this->webhook );
|
||||||
if ( ! $result ) {
|
if ( ! $result ) {
|
||||||
$this->logger->log(
|
$this->logger->error( 'Webhook verification failed.' );
|
||||||
'error',
|
|
||||||
__( 'Illegit Webhook request detected.', 'woocommerce-paypal-payments' )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
} catch ( RuntimeException $exception ) {
|
} catch ( RuntimeException $exception ) {
|
||||||
$this->logger->log(
|
$this->logger->error( 'Webhook verification failed: ' . $exception->getMessage() );
|
||||||
'error',
|
|
||||||
sprintf(
|
|
||||||
// translators: %s is the error message.
|
|
||||||
__(
|
|
||||||
'Illegit Webhook request detected: %s',
|
|
||||||
'woocommerce-paypal-payments'
|
|
||||||
),
|
|
||||||
$exception->getMessage()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,6 +174,17 @@ class IncomingWebhookEndpoint {
|
||||||
* @return \WP_REST_Response
|
* @return \WP_REST_Response
|
||||||
*/
|
*/
|
||||||
public function handle_request( \WP_REST_Request $request ): \WP_REST_Response {
|
public function handle_request( \WP_REST_Request $request ): \WP_REST_Response {
|
||||||
|
$event = $this->event_from_request( $request );
|
||||||
|
|
||||||
|
if ( $this->simulation->is_simulation_event( $event ) ) {
|
||||||
|
$this->logger->info( 'Received simulated webhook.' );
|
||||||
|
$this->simulation->receive( $event );
|
||||||
|
return rest_ensure_response(
|
||||||
|
array(
|
||||||
|
'success' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ( $this->handlers as $handler ) {
|
foreach ( $this->handlers as $handler ) {
|
||||||
if ( $handler->responsible_for_request( $request ) ) {
|
if ( $handler->responsible_for_request( $request ) ) {
|
||||||
|
@ -211,4 +245,16 @@ class IncomingWebhookEndpoint {
|
||||||
}
|
}
|
||||||
return array_unique( $event_types );
|
return array_unique( $event_types );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates WebhookEvent from request data.
|
||||||
|
*
|
||||||
|
* @param \WP_REST_Request $request The request with event data.
|
||||||
|
*
|
||||||
|
* @return WebhookEvent
|
||||||
|
* @throws RuntimeException When failed to create.
|
||||||
|
*/
|
||||||
|
private function event_from_request( \WP_REST_Request $request ): WebhookEvent {
|
||||||
|
return $this->webhook_event_factory->from_array( $request->get_params() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Register and configure assets for webhooks status page.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Webhooks\Status\Assets
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\WcGateway\Assets;
|
||||||
|
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulateEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhookSimulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class WebhooksStatusPageAssets
|
||||||
|
*/
|
||||||
|
class WebhooksStatusPageAssets {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL to the module.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $module_url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebhooksStatusPageAssets constructor.
|
||||||
|
*
|
||||||
|
* @param string $module_url The URL to the module.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
string $module_url
|
||||||
|
) {
|
||||||
|
$this->module_url = untrailingslashit( $module_url );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the scripts and styles.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register(): void {
|
||||||
|
wp_register_style(
|
||||||
|
'ppcp-webhooks-status-page-style',
|
||||||
|
$this->module_url . '/assets/css/status-page.css',
|
||||||
|
array(),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
wp_register_script(
|
||||||
|
'ppcp-webhooks-status-page',
|
||||||
|
$this->module_url . '/assets/js/status-page.js',
|
||||||
|
array(),
|
||||||
|
1,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
wp_localize_script(
|
||||||
|
'ppcp-webhooks-status-page',
|
||||||
|
'PayPalCommerceGatewayWebhooksStatus',
|
||||||
|
$this->get_script_data()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data for the script.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_script_data() {
|
||||||
|
return array(
|
||||||
|
'resubscribe' => array(
|
||||||
|
'endpoint' => home_url( \WC_AJAX::get_endpoint( ResubscribeEndpoint::ENDPOINT ) ),
|
||||||
|
'nonce' => wp_create_nonce( ResubscribeEndpoint::nonce() ),
|
||||||
|
'button' => '.ppcp-webhooks-resubscribe',
|
||||||
|
'failureMessage' => __( 'Operation failed. Check WooCommerce logs for more details.', 'woocommerce-paypal-payments' ),
|
||||||
|
),
|
||||||
|
'simulation' => array(
|
||||||
|
'start' => array(
|
||||||
|
'endpoint' => home_url( \WC_AJAX::get_endpoint( SimulateEndpoint::ENDPOINT ) ),
|
||||||
|
'nonce' => wp_create_nonce( SimulateEndpoint::nonce() ),
|
||||||
|
'button' => '.ppcp-webhooks-simulate',
|
||||||
|
'failureMessage' => __( 'Operation failed. Check WooCommerce logs for more details.', 'woocommerce-paypal-payments' ),
|
||||||
|
),
|
||||||
|
'state' => array(
|
||||||
|
'endpoint' => home_url( \WC_AJAX::get_endpoint( SimulationStateEndpoint::ENDPOINT ) ),
|
||||||
|
'successState' => WebhookSimulation::STATE_RECEIVED,
|
||||||
|
'waitingMessage' => __( 'Waiting for the webhook to arrive...', 'woocommerce-paypal-payments' ),
|
||||||
|
'successMessage' => __( 'The webhook was received successfully.', 'woocommerce-paypal-payments' ),
|
||||||
|
'tooLongDelayMessage' => __( 'Looks like the webhook cannot be received. Check that your website is accessible from the internet.', 'woocommerce-paypal-payments' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues the necessary scripts.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function enqueue(): void {
|
||||||
|
wp_enqueue_style( 'ppcp-webhooks-status-page-style' );
|
||||||
|
wp_enqueue_script( 'ppcp-webhooks-status-page' );
|
||||||
|
}
|
||||||
|
}
|
180
modules/ppcp-webhooks/src/Status/class-webhooksimulation.php
Normal file
180
modules/ppcp-webhooks/src/Status/class-webhooksimulation.php
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles the webhook simulation.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Webhooks\Status
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Webhooks\Status;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Webhook;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\WebhookEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class WebhookSimulation
|
||||||
|
*/
|
||||||
|
class WebhookSimulation {
|
||||||
|
|
||||||
|
public const STATE_WAITING = 'waiting';
|
||||||
|
public const STATE_RECEIVED = 'received';
|
||||||
|
|
||||||
|
private const OPTION_ID = 'ppcp-webhook-simulation';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The webhooks endpoint.
|
||||||
|
*
|
||||||
|
* @var WebhookEndpoint
|
||||||
|
*/
|
||||||
|
private $webhook_endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our registered webhook.
|
||||||
|
*
|
||||||
|
* @var Webhook|null
|
||||||
|
*/
|
||||||
|
private $webhook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event type that will be simulated, such as CHECKOUT.ORDER.APPROVED.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $event_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event resource version, such as 2.0.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private $resource_version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebhookSimulation constructor.
|
||||||
|
*
|
||||||
|
* @param WebhookEndpoint $webhook_endpoint The webhooks endpoint.
|
||||||
|
* @param Webhook|null $webhook Our registered webhook.
|
||||||
|
* @param string $event_type The event type that will be simulated, such as CHECKOUT.ORDER.APPROVED.
|
||||||
|
* @param string|null $resource_version The event resource version, such as 2.0.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
WebhookEndpoint $webhook_endpoint,
|
||||||
|
?Webhook $webhook,
|
||||||
|
string $event_type,
|
||||||
|
?string $resource_version
|
||||||
|
) {
|
||||||
|
$this->webhook_endpoint = $webhook_endpoint;
|
||||||
|
$this->webhook = $webhook;
|
||||||
|
$this->event_type = $event_type;
|
||||||
|
$this->resource_version = $resource_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the simulation by sending request to PayPal and saving the simulation data with STATE_WAITING.
|
||||||
|
*
|
||||||
|
* @throws Exception If failed to start simulation.
|
||||||
|
*/
|
||||||
|
public function start() {
|
||||||
|
if ( ! $this->webhook ) {
|
||||||
|
throw new Exception( 'Webhooks not registered' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$event = $this->webhook_endpoint->simulate( $this->webhook, $this->event_type, $this->resource_version );
|
||||||
|
|
||||||
|
$this->save(
|
||||||
|
array(
|
||||||
|
'id' => $event->id(),
|
||||||
|
'state' => self::STATE_WAITING,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given event matches the expected simulation event.
|
||||||
|
*
|
||||||
|
* @param WebhookEvent $event The webhook event.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_simulation_event( WebhookEvent $event ): bool {
|
||||||
|
try {
|
||||||
|
$data = $this->load();
|
||||||
|
|
||||||
|
return isset( $data['id'] ) && $event->id() === $data['id'];
|
||||||
|
} catch ( Exception $exception ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the simulation state to STATE_RECEIVED if the given event matches the expected simulation event.
|
||||||
|
*
|
||||||
|
* @param WebhookEvent $event The webhook event.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception If failed to save new state.
|
||||||
|
*/
|
||||||
|
public function receive( WebhookEvent $event ): bool {
|
||||||
|
if ( ! $this->is_simulation_event( $event ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->set_state( self::STATE_RECEIVED );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current simulation state, one of the STATE_ constants.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws Exception If failed to load state.
|
||||||
|
*/
|
||||||
|
public function get_state(): string {
|
||||||
|
$data = $this->load();
|
||||||
|
|
||||||
|
return $data['state'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the new state.
|
||||||
|
*
|
||||||
|
* @param string $state One of the STATE_ constants.
|
||||||
|
*
|
||||||
|
* @throws Exception If failed to load state.
|
||||||
|
*/
|
||||||
|
private function set_state( string $state ): void {
|
||||||
|
$data = $this->load();
|
||||||
|
|
||||||
|
$data['state'] = $state;
|
||||||
|
|
||||||
|
$this->save( $data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the simulation data.
|
||||||
|
*
|
||||||
|
* @param array $data The simulation data.
|
||||||
|
*/
|
||||||
|
private function save( array $data ): void {
|
||||||
|
update_option( self::OPTION_ID, $data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current simulation data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws UnexpectedValueException If failed to load.
|
||||||
|
*/
|
||||||
|
private function load(): array {
|
||||||
|
$data = get_option( self::OPTION_ID );
|
||||||
|
if ( ! $data ) {
|
||||||
|
throw new UnexpectedValueException( 'Webhook simulation data not found.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?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';
|
||||||
|
}
|
|
@ -11,8 +11,15 @@ namespace WooCommerce\PayPalCommerce\Webhooks;
|
||||||
|
|
||||||
use Dhii\Container\ServiceProvider;
|
use Dhii\Container\ServiceProvider;
|
||||||
use Dhii\Modular\Module\ModuleInterface;
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
use Exception;
|
||||||
use Interop\Container\ServiceProviderInterface;
|
use Interop\Container\ServiceProviderInterface;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Assets\WebhooksStatusPageAssets;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulateEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class WebhookModule
|
* Class WebhookModule
|
||||||
|
@ -32,11 +39,14 @@ class WebhookModule implements ModuleInterface {
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public function run( ContainerInterface $c ): void {
|
public function run( ContainerInterface $container ): void {
|
||||||
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
|
assert( $logger instanceof LoggerInterface );
|
||||||
|
|
||||||
add_action(
|
add_action(
|
||||||
'rest_api_init',
|
'rest_api_init',
|
||||||
static function () use ( $c ) {
|
static function () use ( $container ) {
|
||||||
$endpoint = $c->get( 'webhook.endpoint.controller' );
|
$endpoint = $container->get( 'webhook.endpoint.controller' );
|
||||||
/**
|
/**
|
||||||
* The Incoming Webhook Endpoint.
|
* The Incoming Webhook Endpoint.
|
||||||
*
|
*
|
||||||
|
@ -48,8 +58,8 @@ class WebhookModule implements ModuleInterface {
|
||||||
|
|
||||||
add_action(
|
add_action(
|
||||||
WebhookRegistrar::EVENT_HOOK,
|
WebhookRegistrar::EVENT_HOOK,
|
||||||
static function () use ( $c ) {
|
static function () use ( $container ) {
|
||||||
$registrar = $c->get( 'webhook.registrar' );
|
$registrar = $container->get( 'webhook.registrar' );
|
||||||
/**
|
/**
|
||||||
* The Webhook Registrar.
|
* The Webhook Registrar.
|
||||||
*
|
*
|
||||||
|
@ -61,8 +71,8 @@ class WebhookModule implements ModuleInterface {
|
||||||
|
|
||||||
add_action(
|
add_action(
|
||||||
'woocommerce_paypal_payments_gateway_deactivate',
|
'woocommerce_paypal_payments_gateway_deactivate',
|
||||||
static function () use ( $c ) {
|
static function () use ( $container ) {
|
||||||
$registrar = $c->get( 'webhook.registrar' );
|
$registrar = $container->get( 'webhook.registrar' );
|
||||||
/**
|
/**
|
||||||
* The Webhook Registrar.
|
* The Webhook Registrar.
|
||||||
*
|
*
|
||||||
|
@ -71,6 +81,69 @@ class WebhookModule implements ModuleInterface {
|
||||||
$registrar->unregister();
|
$registrar->unregister();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'wc_ajax_' . ResubscribeEndpoint::ENDPOINT,
|
||||||
|
static function () use ( $container ) {
|
||||||
|
$endpoint = $container->get( 'webhook.endpoint.resubscribe' );
|
||||||
|
assert( $endpoint instanceof ResubscribeEndpoint );
|
||||||
|
|
||||||
|
$endpoint->handle_request();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'wc_ajax_' . SimulateEndpoint::ENDPOINT,
|
||||||
|
static function () use ( $container ) {
|
||||||
|
$endpoint = $container->get( 'webhook.endpoint.simulate' );
|
||||||
|
assert( $endpoint instanceof SimulateEndpoint );
|
||||||
|
|
||||||
|
$endpoint->handle_request();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add_action(
|
||||||
|
'wc_ajax_' . SimulationStateEndpoint::ENDPOINT,
|
||||||
|
static function () use ( $container ) {
|
||||||
|
$endpoint = $container->get( 'webhook.endpoint.simulation-state' );
|
||||||
|
assert( $endpoint instanceof SimulationStateEndpoint );
|
||||||
|
|
||||||
|
$endpoint->handle_request();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$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' );
|
||||||
|
assert( $asset_loader instanceof WebhooksStatusPageAssets );
|
||||||
|
add_action(
|
||||||
|
'init',
|
||||||
|
array( $asset_loader, 'register' )
|
||||||
|
);
|
||||||
|
add_action(
|
||||||
|
'admin_enqueue_scripts',
|
||||||
|
array( $asset_loader, 'enqueue' )
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$webhooks = $container->get( 'webhook.status.registered-webhooks' );
|
||||||
|
|
||||||
|
if ( empty( $webhooks ) ) {
|
||||||
|
$registrar = $container->get( 'webhook.registrar' );
|
||||||
|
assert( $registrar instanceof WebhookRegistrar );
|
||||||
|
|
||||||
|
// Looks like we cannot call rest_url too early.
|
||||||
|
add_action(
|
||||||
|
'init',
|
||||||
|
function () use ( $registrar ) {
|
||||||
|
$registrar->register();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch ( Exception $exception ) {
|
||||||
|
$logger->error( 'Failed to load webhooks list: ' . $exception->getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\Webhooks;
|
namespace WooCommerce\PayPalCommerce\Webhooks;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||||
|
@ -43,22 +44,32 @@ class WebhookRegistrar {
|
||||||
*/
|
*/
|
||||||
private $rest_endpoint;
|
private $rest_endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
private $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebhookRegistrar constructor.
|
* WebhookRegistrar constructor.
|
||||||
*
|
*
|
||||||
* @param WebhookFactory $webhook_factory The Webhook factory.
|
* @param WebhookFactory $webhook_factory The Webhook factory.
|
||||||
* @param WebhookEndpoint $endpoint The Webhook endpoint.
|
* @param WebhookEndpoint $endpoint The Webhook endpoint.
|
||||||
* @param IncomingWebhookEndpoint $rest_endpoint The WordPress Rest API endpoint.
|
* @param IncomingWebhookEndpoint $rest_endpoint The WordPress Rest API endpoint.
|
||||||
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
WebhookFactory $webhook_factory,
|
WebhookFactory $webhook_factory,
|
||||||
WebhookEndpoint $endpoint,
|
WebhookEndpoint $endpoint,
|
||||||
IncomingWebhookEndpoint $rest_endpoint
|
IncomingWebhookEndpoint $rest_endpoint,
|
||||||
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->webhook_factory = $webhook_factory;
|
$this->webhook_factory = $webhook_factory;
|
||||||
$this->endpoint = $endpoint;
|
$this->endpoint = $endpoint;
|
||||||
$this->rest_endpoint = $rest_endpoint;
|
$this->rest_endpoint = $rest_endpoint;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,8 +92,10 @@ class WebhookRegistrar {
|
||||||
self::KEY,
|
self::KEY,
|
||||||
$created->to_array()
|
$created->to_array()
|
||||||
);
|
);
|
||||||
|
$this->logger->info( 'Webhooks subscribed.' );
|
||||||
return true;
|
return true;
|
||||||
} catch ( RuntimeException $error ) {
|
} catch ( RuntimeException $error ) {
|
||||||
|
$this->logger->error( 'Failed to subscribe webhooks: ' . $error->getMessage() );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,11 +114,13 @@ class WebhookRegistrar {
|
||||||
$webhook = $this->webhook_factory->from_array( $data );
|
$webhook = $this->webhook_factory->from_array( $data );
|
||||||
$success = $this->endpoint->delete( $webhook );
|
$success = $this->endpoint->delete( $webhook );
|
||||||
} catch ( RuntimeException $error ) {
|
} catch ( RuntimeException $error ) {
|
||||||
|
$this->logger->error( 'Failed to delete webhooks: ' . $error->getMessage() );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $success ) {
|
if ( $success ) {
|
||||||
delete_option( self::KEY );
|
delete_option( self::KEY );
|
||||||
|
$this->logger->info( 'Webhooks deleted.' );
|
||||||
}
|
}
|
||||||
return $success;
|
return $success;
|
||||||
}
|
}
|
||||||
|
|
36
modules/ppcp-webhooks/webpack.config.js
Normal file
36
modules/ppcp-webhooks/webpack.config.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
const path = require('path');
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
devtool: 'eval-source-map',
|
||||||
|
mode: isProduction ? 'production' : 'development',
|
||||||
|
target: 'web',
|
||||||
|
entry: {
|
||||||
|
'status-page': path.resolve('./resources/js/status-page.js'),
|
||||||
|
'status-page-style': path.resolve('./resources/css/status-page.scss'),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'assets/'),
|
||||||
|
filename: 'js/[name].js',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.js?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: 'css/[name].css',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{loader:'sass-loader'}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
2219
modules/ppcp-webhooks/yarn.lock
Normal file
2219
modules/ppcp-webhooks/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
19
package.json
19
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "woocommerce-paypal-payments",
|
"name": "woocommerce-paypal-payments",
|
||||||
"version": "1.5.1",
|
"version": "1.6.0",
|
||||||
"description": "WooCommerce PayPal Payments",
|
"description": "WooCommerce PayPal Payments",
|
||||||
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
|
"repository": "https://github.com/woocommerce/woocommerce-paypal-payments",
|
||||||
"license": "GPL-2.0",
|
"license": "GPL-2.0",
|
||||||
|
@ -8,10 +8,14 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"install:modules:ppcp-button": "cd modules/ppcp-button && yarn install && cd -",
|
"install:modules:ppcp-button": "cd modules/ppcp-button && yarn install && cd -",
|
||||||
"install:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn install && cd -",
|
"install:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn install && cd -",
|
||||||
"install:modules": "yarn run install:modules:ppcp-button && yarn run install:modules:ppcp-wc-gateway",
|
"install:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn install && cd -",
|
||||||
|
"install:modules:ppcp-vaulting": "cd modules/ppcp-vaulting && yarn install && cd -",
|
||||||
|
"install:modules": "yarn run install:modules:ppcp-button && yarn run install:modules:ppcp-wc-gateway && yarn run install:modules:ppcp-webhooks && yarn run install:modules:ppcp-vaulting",
|
||||||
"build:modules:ppcp-button": "cd modules/ppcp-button && yarn run build && cd -",
|
"build:modules:ppcp-button": "cd modules/ppcp-button && yarn run build && cd -",
|
||||||
"build:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run build && cd -",
|
"build:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run build && cd -",
|
||||||
"build:modules": "yarn run build:modules:ppcp-button && yarn build:modules:ppcp-wc-gateway",
|
"build:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run build && cd -",
|
||||||
|
"build:modules:ppcp-vaulting": "cd modules/ppcp-vaulting && yarn run build && cd -",
|
||||||
|
"build:modules": "yarn run build:modules:ppcp-button && yarn build:modules:ppcp-wc-gateway && yarn build:modules:ppcp-webhooks && yarn build:modules:ppcp-vaulting",
|
||||||
"build:dev": "yarn run install:modules && yarn run build:modules",
|
"build:dev": "yarn run install:modules && yarn run build:modules",
|
||||||
|
|
||||||
"docker:build": "docker-compose build",
|
"docker:build": "docker-compose build",
|
||||||
|
@ -24,14 +28,15 @@
|
||||||
"docker:build-js": "docker-compose run --rm build yarn run build:dev",
|
"docker:build-js": "docker-compose run --rm build yarn run build:dev",
|
||||||
"docker:composer-update": "docker-compose run --rm composer composer update",
|
"docker:composer-update": "docker-compose run --rm composer composer update",
|
||||||
"docker:test": "docker-compose run --rm test vendor/bin/phpunit",
|
"docker:test": "docker-compose run --rm test vendor/bin/phpunit",
|
||||||
"docker:lint": "docker-compose run --rm test vendor/bin/phpcs --parallel=8 -n -s",
|
"docker:lint": "docker-compose run --rm test vendor/bin/phpcs --parallel=8 -s",
|
||||||
"docker:fix-lint": "docker-compose run --rm test vendor/bin/phpcbf",
|
"docker:fix-lint": "docker-compose run --rm test vendor/bin/phpcbf",
|
||||||
|
|
||||||
"prebuild": "rm -rf ./vendor",
|
|
||||||
"build": "composer install --no-dev && npm run build:dev && npm run archive",
|
"prebuild": "rm -rf ./vendor && find . -name 'node_modules' -type d -maxdepth 3 -exec rm -rf {} +",
|
||||||
|
"build": "composer install --no-dev && yarn run build:dev && yarn run archive",
|
||||||
"prearchive": "rm -rf $npm_package_name.zip",
|
"prearchive": "rm -rf $npm_package_name.zip",
|
||||||
"archive": "zip -r $npm_package_name.zip . -x **.git/\\* **node_modules/\\*",
|
"archive": "zip -r $npm_package_name.zip . -x **.git/\\* **node_modules/\\*",
|
||||||
"postarchive": "npm run archive:cleanup && rm -rf $npm_package_name && unzip $npm_package_name.zip -d $npm_package_name && rm $npm_package_name.zip && zip -r $npm_package_name.zip $npm_package_name && rm -rf $npm_package_name",
|
"postarchive": "yarn run archive:cleanup && rm -rf $npm_package_name && unzip $npm_package_name.zip -d $npm_package_name && rm $npm_package_name.zip && zip -r $npm_package_name.zip $npm_package_name && rm -rf $npm_package_name",
|
||||||
"archive:cleanup": "zip -d $npm_package_name.zip .env* docker/\\* docker-compose.yml .editorconfig tests/\\* .github/\\* wordpress_org_assets/\\* \\*.DS_Store README.md .gitattributes .gitignore .travis.yml composer.json composer.lock package.json package-lock.json patchwork.json yarn.lock phpunit.xml.dist .phpunit.result.cache phpcs.xml.dist modules/ppcp-button/.babelrc modules/ppcp-button/package.json modules/ppcp-button/webpack.config.js modules/ppcp-button/yarn.lock vendor/\\*/.idea/\\* vendor/\\*/.gitignore vendor/\\*/.gitattributes vendor/\\*/.travis.yml"
|
"archive:cleanup": "zip -d $npm_package_name.zip .env* docker/\\* docker-compose.yml .editorconfig tests/\\* .github/\\* wordpress_org_assets/\\* \\*.DS_Store README.md .gitattributes .gitignore .travis.yml composer.json composer.lock package.json package-lock.json patchwork.json yarn.lock phpunit.xml.dist .phpunit.result.cache phpcs.xml.dist modules/ppcp-button/.babelrc modules/ppcp-button/package.json modules/ppcp-button/webpack.config.js modules/ppcp-button/yarn.lock vendor/\\*/.idea/\\* vendor/\\*/.gitignore vendor/\\*/.gitattributes vendor/\\*/.travis.yml"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
<file>src</file>
|
<file>src</file>
|
||||||
<file>modules</file>
|
<file>modules</file>
|
||||||
<file>woocommerce-paypal-payments.php</file>
|
<file>woocommerce-paypal-payments.php</file>
|
||||||
|
<file>modules.php</file>
|
||||||
|
<file>bootstrap.php</file>
|
||||||
|
|
||||||
<exclude-pattern>*/node_modules/*</exclude-pattern>
|
<exclude-pattern>*/node_modules/*</exclude-pattern>
|
||||||
<exclude-pattern>*/vendor/*</exclude-pattern>
|
<exclude-pattern>*/vendor/*</exclude-pattern>
|
||||||
|
|
16
readme.txt
16
readme.txt
|
@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell,
|
||||||
Requires at least: 5.3
|
Requires at least: 5.3
|
||||||
Tested up to: 5.8
|
Tested up to: 5.8
|
||||||
Requires PHP: 7.1
|
Requires PHP: 7.1
|
||||||
Stable tag: 1.5.1
|
Stable tag: 1.6.0
|
||||||
License: GPLv2
|
License: GPLv2
|
||||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||||
|
|
||||||
|
@ -81,6 +81,20 @@ Follow the steps below to connect the plugin to your PayPal account:
|
||||||
|
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 1.6.0 =
|
||||||
|
* Add - Webhook status. #246 #273
|
||||||
|
* Add - Show CC gateway in admin payments list. #236
|
||||||
|
* Add - Add 3d secure contingency settings. #230
|
||||||
|
* Add - Improve logging. #252 #275
|
||||||
|
* Add - Do not send payee email. #231
|
||||||
|
* Add - Allow customers to see and delete their saved payments in My Account. #274
|
||||||
|
* Fix - PayPal Payments generates multiple orders. #244
|
||||||
|
* Fix - Saved credit card does not auto fill. #242
|
||||||
|
* Fix - Incorrect webhooks registration. #254
|
||||||
|
* Fix - Disable funding credit cards affecting hosted fields, unset for GB. #249
|
||||||
|
* Fix - REFUND_CAPTURE_CURRENCY_MISMATCH on multicurrency sites. #225
|
||||||
|
* Fix - Can't checkout to certain countries with optional postcode. #224
|
||||||
|
|
||||||
= 1.5.1 =
|
= 1.5.1 =
|
||||||
* Fix - Set 3DS contingencies to "SCA_WHEN_REQUIRED". #178
|
* Fix - Set 3DS contingencies to "SCA_WHEN_REQUIRED". #178
|
||||||
* Fix - Plugin conflict blocking line item details. #221
|
* Fix - Plugin conflict blocking line item details. #221
|
||||||
|
|
|
@ -3,6 +3,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\ApiClient\Authentication;
|
namespace WooCommerce\PayPalCommerce\ApiClient\Authentication;
|
||||||
|
|
||||||
|
use Requests_Utility_CaseInsensitiveDictionary;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
|
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
|
||||||
|
@ -28,10 +29,12 @@ class PayPalBearerTest extends TestCase
|
||||||
$key = 'key';
|
$key = 'key';
|
||||||
$secret = 'secret';
|
$secret = 'secret';
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldReceive('debug');
|
||||||
$settings = Mockery::mock(Settings::class);
|
$settings = Mockery::mock(Settings::class);
|
||||||
$settings->shouldReceive('has')->andReturn(true);
|
$settings->shouldReceive('has')->andReturn(true);
|
||||||
$settings->shouldReceive('get')->andReturn('');
|
$settings->shouldReceive('get')->andReturn('');
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
|
$headers->shouldReceive('getAll');
|
||||||
|
|
||||||
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
||||||
|
|
||||||
|
@ -40,7 +43,7 @@ class PayPalBearerTest extends TestCase
|
||||||
->andReturn($host . '/');
|
->andReturn($host . '/');
|
||||||
expect('wp_remote_get')
|
expect('wp_remote_get')
|
||||||
->andReturnUsing(
|
->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') {
|
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +56,7 @@ class PayPalBearerTest extends TestCase
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'body' => $json,
|
'body' => $json,
|
||||||
|
'headers' => $headers
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -80,10 +84,12 @@ class PayPalBearerTest extends TestCase
|
||||||
$key = 'key';
|
$key = 'key';
|
||||||
$secret = 'secret';
|
$secret = 'secret';
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldReceive('debug');
|
||||||
$settings = Mockery::mock(Settings::class);
|
$settings = Mockery::mock(Settings::class);
|
||||||
$settings->shouldReceive('has')->andReturn(true);
|
$settings->shouldReceive('has')->andReturn(true);
|
||||||
$settings->shouldReceive('get')->andReturn('');
|
$settings->shouldReceive('get')->andReturn('');
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
|
$headers->shouldReceive('getAll');
|
||||||
|
|
||||||
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
||||||
|
|
||||||
|
@ -92,7 +98,7 @@ class PayPalBearerTest extends TestCase
|
||||||
->andReturn($host . '/');
|
->andReturn($host . '/');
|
||||||
expect('wp_remote_get')
|
expect('wp_remote_get')
|
||||||
->andReturnUsing(
|
->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') {
|
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -105,6 +111,7 @@ class PayPalBearerTest extends TestCase
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'body' => $json,
|
'body' => $json,
|
||||||
|
'headers' => $headers,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -153,9 +160,12 @@ class PayPalBearerTest extends TestCase
|
||||||
$secret = 'secret';
|
$secret = 'secret';
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$settings = Mockery::mock(Settings::class);
|
$settings = Mockery::mock(Settings::class);
|
||||||
$settings->shouldReceive('has')->andReturn(true);
|
$settings->shouldReceive('has')->andReturn(true);
|
||||||
$settings->shouldReceive('get')->andReturn('');
|
$settings->shouldReceive('get')->andReturn('');
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
|
$headers->shouldReceive('getAll');
|
||||||
|
|
||||||
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
||||||
|
|
||||||
|
@ -164,7 +174,7 @@ class PayPalBearerTest extends TestCase
|
||||||
->andReturn($host . '/');
|
->andReturn($host . '/');
|
||||||
expect('wp_remote_get')
|
expect('wp_remote_get')
|
||||||
->andReturnUsing(
|
->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') {
|
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +187,7 @@ class PayPalBearerTest extends TestCase
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'body' => $json,
|
'body' => $json,
|
||||||
|
'headers' => $headers,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -199,9 +210,12 @@ class PayPalBearerTest extends TestCase
|
||||||
$secret = 'secret';
|
$secret = 'secret';
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$settings = Mockery::mock(Settings::class);
|
$settings = Mockery::mock(Settings::class);
|
||||||
$settings->shouldReceive('has')->andReturn(true);
|
$settings->shouldReceive('has')->andReturn(true);
|
||||||
$settings->shouldReceive('get')->andReturn('');
|
$settings->shouldReceive('get')->andReturn('');
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
|
$headers->shouldReceive('getAll');
|
||||||
|
|
||||||
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
$bearer = new PayPalBearer($cache, $host, $key, $secret, $logger, $settings);
|
||||||
|
|
||||||
|
@ -210,7 +224,7 @@ class PayPalBearerTest extends TestCase
|
||||||
->andReturn($host . '/');
|
->andReturn($host . '/');
|
||||||
expect('wp_remote_get')
|
expect('wp_remote_get')
|
||||||
->andReturnUsing(
|
->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') {
|
if ($url !== $host . '/v1/oauth2/token?grant_type=client_credentials') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -223,6 +237,7 @@ class PayPalBearerTest extends TestCase
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'body' => $json,
|
'body' => $json,
|
||||||
|
'headers' => $headers,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Requests_Utility_CaseInsensitiveDictionary;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||||
|
@ -11,6 +12,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
|
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
use function Brain\Monkey\Functions\expect;
|
use function Brain\Monkey\Functions\expect;
|
||||||
|
use function Brain\Monkey\Functions\when;
|
||||||
|
|
||||||
class IdentityTokenTest extends TestCase
|
class IdentityTokenTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -40,10 +42,18 @@ class IdentityTokenTest extends TestCase
|
||||||
$this->bearer
|
$this->bearer
|
||||||
->expects('bearer')->andReturn($token);
|
->expects('bearer')->andReturn($token);
|
||||||
|
|
||||||
$rawResponse = ['body' => '{"client_token":"abc123", "expires_in":3600}'];
|
|
||||||
$host = $this->host;
|
$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')
|
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') {
|
if ($url !== $host . 'v1/identity/generate-token') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +75,7 @@ class IdentityTokenTest extends TestCase
|
||||||
|
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
||||||
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200);
|
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200);
|
||||||
|
when('wc_print_r')->returnArg();
|
||||||
|
|
||||||
$result = $this->sut->generate_for_customer(1);
|
$result = $this->sut->generate_for_customer(1);
|
||||||
$this->assertInstanceOf(Token::class, $result);
|
$this->assertInstanceOf(Token::class, $result);
|
||||||
|
@ -78,9 +89,13 @@ class IdentityTokenTest extends TestCase
|
||||||
$this->bearer
|
$this->bearer
|
||||||
->expects('bearer')->andReturn($token);
|
->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);
|
expect('is_wp_error')->andReturn(true);
|
||||||
|
when('wc_print_r')->returnArg();
|
||||||
$this->logger->shouldReceive('log');
|
$this->logger->shouldReceive('log');
|
||||||
|
$this->logger->shouldReceive('debug');
|
||||||
|
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(RuntimeException::class);
|
||||||
$this->sut->generate_for_customer(1);
|
$this->sut->generate_for_customer(1);
|
||||||
|
@ -94,10 +109,17 @@ class IdentityTokenTest extends TestCase
|
||||||
$this->bearer
|
$this->bearer
|
||||||
->expects('bearer')->andReturn($token);
|
->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('is_wp_error')->andReturn(false);
|
||||||
expect('wp_remote_retrieve_response_code')->andReturn(500);
|
expect('wp_remote_retrieve_response_code')->andReturn(500);
|
||||||
|
when('wc_print_r')->returnArg();
|
||||||
$this->logger->shouldReceive('log');
|
$this->logger->shouldReceive('log');
|
||||||
|
$this->logger->shouldReceive('debug');
|
||||||
|
|
||||||
$this->expectException(PayPalApiException::class);
|
$this->expectException(PayPalApiException::class);
|
||||||
$this->sut->generate_for_customer(1);
|
$this->sut->generate_for_customer(1);
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||||
|
|
||||||
use Hamcrest\Matchers;
|
use Hamcrest\Matchers;
|
||||||
|
use Requests_Utility_CaseInsensitiveDictionary;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||||
use Woocommerce\PayPalCommerce\ApiClient\Entity\Capture;
|
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\Repository\PayPalRequestIdRepository;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
|
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use function Brain\Monkey\Functions\expect;
|
use function Brain\Monkey\Functions\expect;
|
||||||
|
use function Brain\Monkey\Functions\when;
|
||||||
|
|
||||||
class OrderEndpointTest extends TestCase
|
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');
|
expect('wp_json_encode')->andReturnUsing('json_encode');
|
||||||
$orderId = 'id';
|
$orderId = 'id';
|
||||||
|
@ -51,10 +58,14 @@ class OrderEndpointTest extends TestCase
|
||||||
$intent = 'CAPTURE';
|
$intent = 'CAPTURE';
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldNotReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
->expects('get_for_order_id')->with($orderId)->andReturn('uniqueRequestId');
|
->expects('get_for_order_id')->with($orderId)->andReturn('uniqueRequestId');
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
|
$headers->shouldReceive('getAll');
|
||||||
|
|
||||||
$testee = new OrderEndpoint(
|
$testee = new OrderEndpoint(
|
||||||
$host,
|
$host,
|
||||||
$bearer,
|
$bearer,
|
||||||
|
@ -66,7 +77,10 @@ class OrderEndpointTest extends TestCase
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
);
|
);
|
||||||
|
|
||||||
$rawResponse = ['body' => '{"is_correct":true}'];
|
$rawResponse = [
|
||||||
|
'body' => '{"is_correct":true}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
expect('wp_remote_get')
|
expect('wp_remote_get')
|
||||||
->andReturnUsing(function ($url, $args) use ($rawResponse, $host, $orderId) {
|
->andReturnUsing(function ($url, $args) use ($rawResponse, $host, $orderId) {
|
||||||
if ($url !== $host . 'v2/checkout/orders/' . $orderId) {
|
if ($url !== $host . 'v2/checkout/orders/' . $orderId) {
|
||||||
|
@ -103,10 +117,14 @@ class OrderEndpointTest extends TestCase
|
||||||
$intent = 'CAPTURE';
|
$intent = 'CAPTURE';
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
->expects('get_for_order_id')->with($orderId)->andReturn('uniqueRequestId');
|
->expects('get_for_order_id')->with($orderId)->andReturn('uniqueRequestId');
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
|
$headers->shouldReceive('getAll');
|
||||||
|
|
||||||
$testee = new OrderEndpoint(
|
$testee = new OrderEndpoint(
|
||||||
$host,
|
$host,
|
||||||
$bearer,
|
$bearer,
|
||||||
|
@ -118,7 +136,10 @@ class OrderEndpointTest extends TestCase
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
);
|
);
|
||||||
|
|
||||||
$rawResponse = ['body' => '{"is_correct":true}'];
|
$rawResponse = [
|
||||||
|
'body' => '{"is_correct":true}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
expect('wp_remote_get')->andReturn($rawResponse);
|
expect('wp_remote_get')->andReturn($rawResponse);
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(true);
|
expect('is_wp_error')->with($rawResponse)->andReturn(true);
|
||||||
|
|
||||||
|
@ -140,9 +161,15 @@ class OrderEndpointTest extends TestCase
|
||||||
$orderFactory = Mockery::mock(OrderFactory::class);
|
$orderFactory = Mockery::mock(OrderFactory::class);
|
||||||
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
|
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
|
||||||
$intent = 'CAPTURE';
|
$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 = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
|
@ -176,8 +203,12 @@ class OrderEndpointTest extends TestCase
|
||||||
$orderToCapture = Mockery::mock(Order::class);
|
$orderToCapture = Mockery::mock(Order::class);
|
||||||
$orderToCapture->expects('status')->andReturn($orderToCaptureStatus);
|
$orderToCapture->expects('status')->andReturn($orderToCaptureStatus);
|
||||||
$orderToCapture->expects('id')->andReturn($orderId);
|
$orderToCapture->expects('id')->andReturn($orderId);
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
$rawResponse = ['body' => '{"is_correct":true}'];
|
$headers->shouldReceive('getAll');
|
||||||
|
$rawResponse = [
|
||||||
|
'body' => '{"is_correct":true}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
$expectedOrder = Mockery::mock(Order::class);
|
$expectedOrder = Mockery::mock(Order::class);
|
||||||
$host = 'https://example.com/';
|
$host = 'https://example.com/';
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
|
@ -202,6 +233,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldNotReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
|
@ -307,6 +339,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
|
@ -321,8 +354,12 @@ class OrderEndpointTest extends TestCase
|
||||||
$applicationContextRepository,
|
$applicationContextRepository,
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
);
|
);
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
$rawResponse = ['body' => '{"is_error":true}'];
|
$headers->shouldReceive('getAll');
|
||||||
|
$rawResponse = [
|
||||||
|
'body' => '{"is_error":true}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
expect('wp_remote_get')->andReturn($rawResponse);
|
expect('wp_remote_get')->andReturn($rawResponse);
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(true);
|
expect('is_wp_error')->with($rawResponse)->andReturn(true);
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(RuntimeException::class);
|
||||||
|
@ -351,6 +388,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
|
@ -366,7 +404,12 @@ class OrderEndpointTest extends TestCase
|
||||||
$paypalRequestIdRepository
|
$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('wp_remote_get')->andReturn($rawResponse);
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
||||||
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
|
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
|
||||||
|
@ -396,6 +439,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldNotReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
|
@ -415,8 +459,12 @@ class OrderEndpointTest extends TestCase
|
||||||
)->makePartial();
|
)->makePartial();
|
||||||
$orderToExpect = Mockery::mock(Order::class);
|
$orderToExpect = Mockery::mock(Order::class);
|
||||||
$testee->expects('order')->with($orderId)->andReturn($orderToExpect);
|
$testee->expects('order')->with($orderId)->andReturn($orderToExpect);
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
$rawResponse = ['body' => '{"some_error": "' . ErrorResponse::ORDER_ALREADY_CAPTURED . '"}'];
|
$headers->shouldReceive('getAll');
|
||||||
|
$rawResponse = [
|
||||||
|
'body' => '{"some_error": "' . ErrorResponse::ORDER_ALREADY_CAPTURED . '"}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
expect('wp_remote_get')->andReturn($rawResponse);
|
expect('wp_remote_get')->andReturn($rawResponse);
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
||||||
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
|
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
|
||||||
|
@ -436,8 +484,12 @@ class OrderEndpointTest extends TestCase
|
||||||
->shouldReceive('purchase_units')
|
->shouldReceive('purchase_units')
|
||||||
->andReturn([]);
|
->andReturn([]);
|
||||||
$orderToCompare = Mockery::mock(Order::class);
|
$orderToCompare = Mockery::mock(Order::class);
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
$rawResponse = ['body' => '{"is_correct":true}'];
|
$headers->shouldReceive('getAll');
|
||||||
|
$rawResponse = [
|
||||||
|
'body' => '{"is_correct":true}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
$expectedOrder = Mockery::mock(Order::class);
|
$expectedOrder = Mockery::mock(Order::class);
|
||||||
$host = 'https://example.com/';
|
$host = 'https://example.com/';
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
|
@ -464,6 +516,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldNotReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
|
@ -533,8 +586,12 @@ class OrderEndpointTest extends TestCase
|
||||||
->shouldReceive('purchase_units')
|
->shouldReceive('purchase_units')
|
||||||
->andReturn([]);
|
->andReturn([]);
|
||||||
$orderToCompare = Mockery::mock(Order::class);
|
$orderToCompare = Mockery::mock(Order::class);
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
$rawResponse = ['body' => '{"has_error":true}'];
|
$headers->shouldReceive('getAll');
|
||||||
|
$rawResponse = [
|
||||||
|
'body' => '{"has_error":true}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
$expectedOrder = Mockery::mock(Order::class);
|
$expectedOrder = Mockery::mock(Order::class);
|
||||||
$host = 'https://example.com/';
|
$host = 'https://example.com/';
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
|
@ -561,6 +618,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
$paypalRequestIdRepository
|
$paypalRequestIdRepository
|
||||||
|
@ -624,8 +682,12 @@ class OrderEndpointTest extends TestCase
|
||||||
->shouldReceive('purchase_units')
|
->shouldReceive('purchase_units')
|
||||||
->andReturn([]);
|
->andReturn([]);
|
||||||
$orderToCompare = Mockery::mock(Order::class);
|
$orderToCompare = Mockery::mock(Order::class);
|
||||||
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
$rawResponse = ['body' => '{"is_correct":true}'];
|
$headers->shouldReceive('getAll');
|
||||||
|
$rawResponse = [
|
||||||
|
'body' => '{"is_correct":true}',
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
$expectedOrder = Mockery::mock(Order::class);
|
$expectedOrder = Mockery::mock(Order::class);
|
||||||
$host = 'https://example.com/';
|
$host = 'https://example.com/';
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
|
@ -652,6 +714,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
|
|
||||||
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
$applicationContextRepository = Mockery::mock(ApplicationContextRepository::class);
|
||||||
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
$paypalRequestIdRepository = Mockery::mock(PayPalRequestIdRepository::class);
|
||||||
|
@ -748,7 +811,12 @@ class OrderEndpointTest extends TestCase
|
||||||
public function testCreateForPurchaseUnitsDefault()
|
public function testCreateForPurchaseUnitsDefault()
|
||||||
{
|
{
|
||||||
expect('wp_json_encode')->andReturnUsing('json_encode');
|
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/';
|
$host = 'https://example.com/';
|
||||||
$bearer = Mockery::mock(Bearer::class);
|
$bearer = Mockery::mock(Bearer::class);
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
|
@ -772,6 +840,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldNotReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContext = Mockery::mock(ApplicationContext::class);
|
$applicationContext = Mockery::mock(ApplicationContext::class);
|
||||||
$applicationContext
|
$applicationContext
|
||||||
->expects('to_array')
|
->expects('to_array')
|
||||||
|
@ -844,7 +913,12 @@ class OrderEndpointTest extends TestCase
|
||||||
public function testCreateForPurchaseUnitsWithPayer()
|
public function testCreateForPurchaseUnitsWithPayer()
|
||||||
{
|
{
|
||||||
expect('wp_json_encode')->andReturnUsing('json_encode');
|
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/';
|
$host = 'https://example.com/';
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
$token
|
$token
|
||||||
|
@ -868,6 +942,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$logger->shouldNotReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContext = Mockery::mock(ApplicationContext::class);
|
$applicationContext = Mockery::mock(ApplicationContext::class);
|
||||||
$applicationContext
|
$applicationContext
|
||||||
->expects('to_array')
|
->expects('to_array')
|
||||||
|
@ -928,7 +1003,12 @@ class OrderEndpointTest extends TestCase
|
||||||
public function testCreateForPurchaseUnitsIsWpError()
|
public function testCreateForPurchaseUnitsIsWpError()
|
||||||
{
|
{
|
||||||
expect('wp_json_encode')->andReturnUsing('json_encode');
|
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/';
|
$host = 'https://example.com/';
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
$token
|
$token
|
||||||
|
@ -943,6 +1023,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContext = Mockery::mock(ApplicationContext::class);
|
$applicationContext = Mockery::mock(ApplicationContext::class);
|
||||||
$applicationContext
|
$applicationContext
|
||||||
->expects('to_array')
|
->expects('to_array')
|
||||||
|
@ -1006,7 +1087,12 @@ class OrderEndpointTest extends TestCase
|
||||||
public function testCreateForPurchaseUnitsIsNot201()
|
public function testCreateForPurchaseUnitsIsNot201()
|
||||||
{
|
{
|
||||||
expect('wp_json_encode')->andReturnUsing('json_encode');
|
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/';
|
$host = 'https://example.com/';
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
$token
|
$token
|
||||||
|
@ -1021,6 +1107,7 @@ class OrderEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
$applicationContext = Mockery::mock(ApplicationContext::class);
|
$applicationContext = Mockery::mock(ApplicationContext::class);
|
||||||
$applicationContext
|
$applicationContext
|
||||||
->expects('to_array')
|
->expects('to_array')
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Requests_Utility_CaseInsensitiveDictionary;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
|
||||||
|
@ -48,7 +49,12 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
{
|
{
|
||||||
$id = 1;
|
$id = 1;
|
||||||
$token = Mockery::mock(Token::class);
|
$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 = Mockery::mock(PaymentToken::class);
|
||||||
$paymentToken->shouldReceive('id')
|
$paymentToken->shouldReceive('id')
|
||||||
->andReturn('foo');
|
->andReturn('foo');
|
||||||
|
@ -65,6 +71,8 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
$this->factory->shouldReceive('from_paypal_response')
|
$this->factory->shouldReceive('from_paypal_response')
|
||||||
->andReturn($paymentToken);
|
->andReturn($paymentToken);
|
||||||
|
|
||||||
|
$this->logger->shouldReceive('debug');
|
||||||
|
|
||||||
$result = $this->sut->for_user($id);
|
$result = $this->sut->for_user($id);
|
||||||
$this->assertInstanceOf(PaymentToken::class, $result[0]);
|
$this->assertInstanceOf(PaymentToken::class, $result[0]);
|
||||||
|
|
||||||
|
@ -74,7 +82,9 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
{
|
{
|
||||||
$id = 1;
|
$id = 1;
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
$rawResponse = [];
|
$headers = Mockery::mock(Requests_Utility_CaseInsensitiveDictionary::class);
|
||||||
|
$headers->shouldReceive('getAll');
|
||||||
|
$rawResponse = ['headers' => $headers,];
|
||||||
$this->bearer->shouldReceive('bearer')
|
$this->bearer->shouldReceive('bearer')
|
||||||
->andReturn($token);
|
->andReturn($token);
|
||||||
$token->shouldReceive('token')
|
$token->shouldReceive('token')
|
||||||
|
@ -84,6 +94,7 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
expect('wp_remote_get')->andReturn($rawResponse);
|
expect('wp_remote_get')->andReturn($rawResponse);
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(true);
|
expect('is_wp_error')->with($rawResponse)->andReturn(true);
|
||||||
$this->logger->shouldReceive('log');
|
$this->logger->shouldReceive('log');
|
||||||
|
$this->logger->shouldReceive('debug');
|
||||||
|
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(RuntimeException::class);
|
||||||
$this->sut->for_user($id);
|
$this->sut->for_user($id);
|
||||||
|
@ -93,7 +104,12 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
{
|
{
|
||||||
$id = 1;
|
$id = 1;
|
||||||
$token = Mockery::mock(Token::class);
|
$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')
|
$this->bearer->shouldReceive('bearer')
|
||||||
->andReturn($token);
|
->andReturn($token);
|
||||||
$token->shouldReceive('token')
|
$token->shouldReceive('token')
|
||||||
|
@ -105,35 +121,15 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
||||||
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
|
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
|
||||||
$this->logger->shouldReceive('log');
|
$this->logger->shouldReceive('log');
|
||||||
|
$this->logger->shouldReceive('debug');
|
||||||
|
|
||||||
$this->expectException(PayPalApiException::class);
|
$this->expectException(PayPalApiException::class);
|
||||||
$this->sut->for_user($id);
|
$this->sut->for_user($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testForUserFailBecauseEmptyTokens()
|
|
||||||
{
|
|
||||||
$id = 1;
|
|
||||||
$token = Mockery::mock(Token::class);
|
|
||||||
$rawResponse = ['body' => '{"payment_tokens":[]}'];
|
|
||||||
$this->bearer->shouldReceive('bearer')
|
|
||||||
->andReturn($token);
|
|
||||||
$token->shouldReceive('token')
|
|
||||||
->andReturn('bearer');
|
|
||||||
$this->ensureRequestForUser($rawResponse, $id);
|
|
||||||
|
|
||||||
|
|
||||||
expect('wp_remote_get')->andReturn($rawResponse);
|
|
||||||
expect('is_wp_error')->with($rawResponse)->andReturn(false);
|
|
||||||
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200);
|
|
||||||
$this->logger->shouldReceive('log');
|
|
||||||
|
|
||||||
$this->expectException(RuntimeException::class);
|
|
||||||
$this->sut->for_user($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteToken()
|
public function testDeleteToken()
|
||||||
{
|
{
|
||||||
$paymentToken = $paymentToken = Mockery::mock(PaymentToken::class);
|
$paymentToken = Mockery::mock(PaymentToken::class);
|
||||||
$paymentToken->shouldReceive('id')
|
$paymentToken->shouldReceive('id')
|
||||||
->andReturn('foo');
|
->andReturn('foo');
|
||||||
$token = Mockery::mock(Token::class);
|
$token = Mockery::mock(Token::class);
|
||||||
|
@ -142,9 +138,14 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
$token->shouldReceive('token')
|
$token->shouldReceive('token')
|
||||||
->andReturn('bearer');
|
->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('is_wp_error')->andReturn(false);
|
||||||
expect('wp_remote_retrieve_response_code')->andReturn(204);
|
expect('wp_remote_retrieve_response_code')->andReturn(204);
|
||||||
|
$this->logger->shouldReceive('debug');
|
||||||
|
|
||||||
$this->sut->delete_token($paymentToken);
|
$this->sut->delete_token($paymentToken);
|
||||||
}
|
}
|
||||||
|
@ -160,9 +161,14 @@ class PaymentTokenEndpointTest extends TestCase
|
||||||
$token->shouldReceive('token')
|
$token->shouldReceive('token')
|
||||||
->andReturn('bearer');
|
->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);
|
expect('is_wp_error')->andReturn(true);
|
||||||
$this->logger->shouldReceive('log');
|
$this->logger->shouldReceive('log');
|
||||||
|
$this->logger->shouldReceive('debug');
|
||||||
|
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(RuntimeException::class);
|
||||||
$this->sut->delete_token($paymentToken);
|
$this->sut->delete_token($paymentToken);
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||||
|
|
||||||
|
use Requests_Utility_CaseInsensitiveDictionary;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ErrorResponseCollection;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\ErrorResponseCollection;
|
||||||
|
@ -40,8 +41,14 @@ class PaymentsEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$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(
|
$testee = new PaymentsEndpoint(
|
||||||
$host,
|
$host,
|
||||||
|
@ -88,8 +95,14 @@ class PaymentsEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$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(
|
$testee = new PaymentsEndpoint(
|
||||||
$host,
|
$host,
|
||||||
|
@ -119,10 +132,16 @@ class PaymentsEndpointTest extends TestCase
|
||||||
|
|
||||||
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
|
$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 = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldReceive('log');
|
$logger->shouldReceive('log');
|
||||||
|
$logger->shouldReceive('debug');
|
||||||
|
|
||||||
$testee = new PaymentsEndpoint(
|
$testee = new PaymentsEndpoint(
|
||||||
$host,
|
$host,
|
||||||
|
@ -161,8 +180,14 @@ class PaymentsEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->shouldNotReceive('log');
|
$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(
|
$testee = new PaymentsEndpoint(
|
||||||
$host,
|
$host,
|
||||||
|
@ -212,8 +237,14 @@ class PaymentsEndpointTest extends TestCase
|
||||||
|
|
||||||
$logger = Mockery::mock(LoggerInterface::class);
|
$logger = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->expects('log');
|
$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(
|
$testee = new PaymentsEndpoint(
|
||||||
$host,
|
$host,
|
||||||
|
@ -243,10 +274,16 @@ class PaymentsEndpointTest extends TestCase
|
||||||
|
|
||||||
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
|
$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 = Mockery::mock(LoggerInterface::class);
|
||||||
$logger->expects('log');
|
$logger->expects('log');
|
||||||
|
$logger->expects('debug');
|
||||||
|
|
||||||
$testee = new PaymentsEndpoint(
|
$testee = new PaymentsEndpoint(
|
||||||
$host,
|
$host,
|
||||||
|
|
|
@ -8,6 +8,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||||
use WooCommerce\PayPalCommerce\TestCase;
|
use WooCommerce\PayPalCommerce\TestCase;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
|
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||||
use function Brain\Monkey\Functions\expect;
|
use function Brain\Monkey\Functions\expect;
|
||||||
|
|
||||||
class ChangeCartEndpointTest extends TestCase
|
class ChangeCartEndpointTest extends TestCase
|
||||||
|
@ -68,7 +69,8 @@ class ChangeCartEndpointTest extends TestCase
|
||||||
$shipping,
|
$shipping,
|
||||||
$requestData,
|
$requestData,
|
||||||
$cartRepository,
|
$cartRepository,
|
||||||
$dataStore
|
$dataStore,
|
||||||
|
new NullLogger()
|
||||||
);
|
);
|
||||||
|
|
||||||
expect('wp_send_json_success')
|
expect('wp_send_json_success')
|
||||||
|
@ -171,4 +173,4 @@ class ChangeCartEndpointTest extends TestCase
|
||||||
|
|
||||||
return $testData;
|
return $testData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||||
use WooCommerce\PayPalCommerce\TestCase;
|
use WooCommerce\PayPalCommerce\TestCase;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||||
|
|
||||||
|
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||||
use function Brain\Monkey\Functions\expect;
|
use function Brain\Monkey\Functions\expect;
|
||||||
|
|
||||||
class CreateOrderEndpointTest extends TestCase
|
class CreateOrderEndpointTest extends TestCase
|
||||||
|
@ -32,7 +33,7 @@ class CreateOrderEndpointTest extends TestCase
|
||||||
{
|
{
|
||||||
list($payer_factory, $testee) = $this->mockTestee();
|
list($payer_factory, $testee) = $this->mockTestee();
|
||||||
|
|
||||||
$method = $this->getProtectedMethodAccessibleReflection(CreateOrderEndpoint::class, 'payer');
|
$method = $this->makePrivateMethod(CreateOrderEndpoint::class, 'payer');
|
||||||
$dataString = wp_json_encode($expectedResult['payer']);
|
$dataString = wp_json_encode($expectedResult['payer']);
|
||||||
$dataObj = json_decode(wp_json_encode($expectedResult['payer']));
|
$dataObj = json_decode(wp_json_encode($expectedResult['payer']));
|
||||||
|
|
||||||
|
@ -160,7 +161,8 @@ class CreateOrderEndpointTest extends TestCase
|
||||||
$payer_factory,
|
$payer_factory,
|
||||||
$session_handler,
|
$session_handler,
|
||||||
$settings,
|
$settings,
|
||||||
$early_order_handler
|
$early_order_handler,
|
||||||
|
new NullLogger()
|
||||||
);
|
);
|
||||||
return array($payer_factory, $testee);
|
return array($payer_factory, $testee);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +175,7 @@ class CreateOrderEndpointTest extends TestCase
|
||||||
* @return \ReflectionMethod
|
* @return \ReflectionMethod
|
||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
*/
|
*/
|
||||||
protected function getProtectedMethodAccessibleReflection($class, $method)
|
protected function makePrivateMethod($class, $method)
|
||||||
{
|
{
|
||||||
$reflector = new ReflectionClass($class);
|
$reflector = new ReflectionClass($class);
|
||||||
$method = $reflector->getMethod($method);
|
$method = $reflector->getMethod($method);
|
||||||
|
|
|
@ -8,6 +8,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
use WooCommerce\PayPalCommerce\TestCase;
|
use WooCommerce\PayPalCommerce\TestCase;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
|
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||||
use function Brain\Monkey\Functions\when;
|
use function Brain\Monkey\Functions\when;
|
||||||
use function Brain\Monkey\Functions\expect;
|
use function Brain\Monkey\Functions\expect;
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ class DataClientIdEndpointTest extends TestCase
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->requestData = Mockery::mock(RequestData::class);
|
$this->requestData = Mockery::mock(RequestData::class);
|
||||||
$this->identityToken = Mockery::mock(IdentityToken::class);
|
$this->identityToken = Mockery::mock(IdentityToken::class);
|
||||||
$this->sut = new DataClientIdEndpoint($this->requestData, $this->identityToken);
|
$this->sut = new DataClientIdEndpoint($this->requestData, $this->identityToken, new NullLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHandleRequestSuccess()
|
public function testHandleRequestSuccess()
|
||||||
|
|
|
@ -4,12 +4,14 @@ declare(strict_types=1);
|
||||||
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||||
|
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\CardAuthenticationResult;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSourceCard;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSourceCard;
|
||||||
use WooCommerce\PayPalCommerce\TestCase;
|
use WooCommerce\PayPalCommerce\TestCase;
|
||||||
use Mockery\Mock;
|
use Mockery\Mock;
|
||||||
|
use function Brain\Monkey\Functions\when;
|
||||||
|
|
||||||
class ThreeDSecureTest extends TestCase
|
class ThreeDSecureTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -25,13 +27,18 @@ class ThreeDSecureTest extends TestCase
|
||||||
$result->shouldReceive('liability_shift')->andReturn($liabilityShift);
|
$result->shouldReceive('liability_shift')->andReturn($liabilityShift);
|
||||||
$result->shouldReceive('authentication_result')->andReturn($authenticationResult);
|
$result->shouldReceive('authentication_result')->andReturn($authenticationResult);
|
||||||
$result->shouldReceive('enrollment_status')->andReturn($enrollment);
|
$result->shouldReceive('enrollment_status')->andReturn($enrollment);
|
||||||
|
$result->shouldReceive('to_array')->andReturn(['foo' => 'bar',]);
|
||||||
$card = \Mockery::mock(PaymentSourceCard::class);
|
$card = \Mockery::mock(PaymentSourceCard::class);
|
||||||
$card->shouldReceive('authentication_result')->andReturn($result);
|
$card->shouldReceive('authentication_result')->andReturn($result);
|
||||||
$source = \Mockery::mock(PaymentSource::class);
|
$source = \Mockery::mock(PaymentSource::class);
|
||||||
$source->shouldReceive('card')->andReturn($card);
|
$source->shouldReceive('card')->andReturn($card);
|
||||||
$order = \Mockery::mock(Order::class);
|
$order = \Mockery::mock(Order::class);
|
||||||
$order->shouldReceive('payment_source')->andReturn($source);
|
$order->shouldReceive('payment_source')->andReturn($source);
|
||||||
$testee = new ThreeDSecure();
|
$logger = \Mockery::mock(LoggerInterface::class);
|
||||||
|
$logger->shouldReceive('info');
|
||||||
|
when('wc_print_r')->justReturn();
|
||||||
|
|
||||||
|
$testee = new ThreeDSecure($logger);
|
||||||
$result = $testee->proceed_with_order($order);
|
$result = $testee->proceed_with_order($order);
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
}
|
}
|
||||||
|
@ -120,4 +127,4 @@ class ThreeDSecureTest extends TestCase
|
||||||
];
|
];
|
||||||
return $matrix;
|
return $matrix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
70
tests/PHPUnit/ModularTestCase.php
Normal file
70
tests/PHPUnit/ModularTestCase.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,10 +11,10 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository;
|
|
||||||
use WooCommerce\PayPalCommerce\TestCase;
|
use WooCommerce\PayPalCommerce\TestCase;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
||||||
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
|
|
||||||
class RenewalHandlerTest extends TestCase
|
class RenewalHandlerTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
|
||||||
use WooCommerce\PayPalCommerce\TestCase;
|
use WooCommerce\PayPalCommerce\TestCase;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
||||||
|
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||||
use function Brain\Monkey\Functions\expect;
|
use function Brain\Monkey\Functions\expect;
|
||||||
use function Brain\Monkey\Functions\when;
|
use function Brain\Monkey\Functions\when;
|
||||||
|
|
||||||
|
@ -90,4 +91,72 @@ class PaymentTokenRepositoryTest extends TestCase
|
||||||
|
|
||||||
$this->sut->delete_token($id, $paymentToken);
|
$this->sut->delete_token($id, $paymentToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAllForUserId()
|
||||||
|
{
|
||||||
|
$id = 1;
|
||||||
|
$tokens = [];
|
||||||
|
|
||||||
|
$this->endpoint->shouldReceive('for_user')
|
||||||
|
->with($id)
|
||||||
|
->andReturn($tokens);
|
||||||
|
expect('update_user_meta')->with($id, $this->sut::USER_META, $tokens);
|
||||||
|
|
||||||
|
$result = $this->sut->all_for_user_id($id);
|
||||||
|
$this->assertSame($tokens, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_AllForUserIdReturnsEmptyArrayIfGettingTokenFails()
|
||||||
|
{
|
||||||
|
$id = 1;
|
||||||
|
$tokens = [];
|
||||||
|
|
||||||
|
$this->endpoint
|
||||||
|
->expects('for_user')
|
||||||
|
->with($id)
|
||||||
|
->andThrow(RuntimeException::class);
|
||||||
|
|
||||||
|
$result = $this->sut->all_for_user_id($id);
|
||||||
|
$this->assertSame($tokens, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTokensContainCardReturnsTrue()
|
||||||
|
{
|
||||||
|
$source = new \stdClass();
|
||||||
|
$card = new \stdClass();
|
||||||
|
$source->card = $card;
|
||||||
|
$token = Mockery::mock(PaymentToken::class);
|
||||||
|
$tokens = [$token];
|
||||||
|
|
||||||
|
$token->shouldReceive('source')->andReturn($source);
|
||||||
|
|
||||||
|
$this->assertTrue($this->sut->tokens_contains_card($tokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTokensContainCardReturnsFalse()
|
||||||
|
{
|
||||||
|
$tokens = [];
|
||||||
|
$this->assertFalse($this->sut->tokens_contains_card($tokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTokensContainPayPalReturnsTrue()
|
||||||
|
{
|
||||||
|
$source = new \stdClass();
|
||||||
|
$paypal = new \stdClass();
|
||||||
|
$source->paypal = $paypal;
|
||||||
|
$token = Mockery::mock(PaymentToken::class);
|
||||||
|
$tokens = [$token];
|
||||||
|
|
||||||
|
$token->shouldReceive('source')->andReturn($source);
|
||||||
|
|
||||||
|
$this->assertTrue($this->sut->tokens_contains_paypal($tokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTokensContainPayPalReturnsFalse()
|
||||||
|
{
|
||||||
|
$tokens = [];
|
||||||
|
$this->assertFalse($this->sut->tokens_contains_paypal($tokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,26 +3,36 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace WooCommerce\PayPalCommerce;
|
namespace WooCommerce\PayPalCommerce;
|
||||||
|
|
||||||
|
use function Brain\Monkey\Functions\when;
|
||||||
use function Brain\Monkey\setUp;
|
use function Brain\Monkey\setUp;
|
||||||
use function Brain\Monkey\tearDown;
|
use function Brain\Monkey\tearDown;
|
||||||
use function Brain\Monkey\Functions\expect;
|
|
||||||
use Mockery;
|
use Mockery;
|
||||||
|
|
||||||
class TestCase extends \PHPUnit\Framework\TestCase
|
class TestCase extends \PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
public function setUp(): void
|
public function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
expect('__')->andReturnUsing(function (string $text) {
|
|
||||||
return $text;
|
|
||||||
});
|
|
||||||
setUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown(): void
|
when('__')->returnArg();
|
||||||
{
|
when('_x')->returnArg();
|
||||||
tearDown();
|
when('esc_url')->returnArg();
|
||||||
Mockery::close();
|
when('esc_attr')->returnArg();
|
||||||
parent::tearDown();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,8 @@ class WcGatewayTest extends TestCase
|
||||||
$refundProcessor,
|
$refundProcessor,
|
||||||
$state,
|
$state,
|
||||||
$transactionUrlProvider,
|
$transactionUrlProvider,
|
||||||
$subscriptionHelper
|
$subscriptionHelper,
|
||||||
|
PayPalGateway::ID
|
||||||
);
|
);
|
||||||
|
|
||||||
expect('wc_get_order')
|
expect('wc_get_order')
|
||||||
|
@ -116,7 +117,8 @@ class WcGatewayTest extends TestCase
|
||||||
$refundProcessor,
|
$refundProcessor,
|
||||||
$state,
|
$state,
|
||||||
$transactionUrlProvider,
|
$transactionUrlProvider,
|
||||||
$subscriptionHelper
|
$subscriptionHelper,
|
||||||
|
PayPalGateway::ID
|
||||||
);
|
);
|
||||||
|
|
||||||
expect('wc_get_order')
|
expect('wc_get_order')
|
||||||
|
@ -181,7 +183,8 @@ class WcGatewayTest extends TestCase
|
||||||
$refundProcessor,
|
$refundProcessor,
|
||||||
$state,
|
$state,
|
||||||
$transactionUrlProvider,
|
$transactionUrlProvider,
|
||||||
$subscriptionHelper
|
$subscriptionHelper,
|
||||||
|
PayPalGateway::ID
|
||||||
);
|
);
|
||||||
|
|
||||||
expect('wc_get_order')
|
expect('wc_get_order')
|
||||||
|
@ -254,7 +257,8 @@ class WcGatewayTest extends TestCase
|
||||||
$refundProcessor,
|
$refundProcessor,
|
||||||
$state,
|
$state,
|
||||||
$transactionUrlProvider,
|
$transactionUrlProvider,
|
||||||
$subscriptionHelper
|
$subscriptionHelper,
|
||||||
|
PayPalGateway::ID
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
|
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
|
||||||
|
@ -311,7 +315,8 @@ class WcGatewayTest extends TestCase
|
||||||
$refundProcessor,
|
$refundProcessor,
|
||||||
$state,
|
$state,
|
||||||
$transactionUrlProvider,
|
$transactionUrlProvider,
|
||||||
$subscriptionHelper
|
$subscriptionHelper,
|
||||||
|
PayPalGateway::ID
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
|
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
|
||||||
|
@ -362,12 +367,13 @@ class WcGatewayTest extends TestCase
|
||||||
$refundProcessor,
|
$refundProcessor,
|
||||||
$state,
|
$state,
|
||||||
$transactionUrlProvider,
|
$transactionUrlProvider,
|
||||||
$subscriptionHelper
|
$subscriptionHelper,
|
||||||
|
PayPalGateway::ID
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertFalse($testee->capture_authorized_payment($wcOrder));
|
$this->assertFalse($testee->capture_authorized_payment($wcOrder));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider dataForTestNeedsSetup
|
* @dataProvider dataForTestNeedsSetup
|
||||||
*/
|
*/
|
||||||
|
@ -390,7 +396,7 @@ class WcGatewayTest extends TestCase
|
||||||
->andReturn($currentState);
|
->andReturn($currentState);
|
||||||
$transactionUrlProvider = Mockery::mock(TransactionUrlProvider::class);
|
$transactionUrlProvider = Mockery::mock(TransactionUrlProvider::class);
|
||||||
$subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
$subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||||
|
|
||||||
$testee = new PayPalGateway(
|
$testee = new PayPalGateway(
|
||||||
$settingsRenderer,
|
$settingsRenderer,
|
||||||
$orderProcessor,
|
$orderProcessor,
|
||||||
|
@ -401,9 +407,10 @@ class WcGatewayTest extends TestCase
|
||||||
$refundProcessor,
|
$refundProcessor,
|
||||||
$onboardingState,
|
$onboardingState,
|
||||||
$transactionUrlProvider,
|
$transactionUrlProvider,
|
||||||
$subscriptionHelper
|
$subscriptionHelper,
|
||||||
|
PayPalGateway::ID
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertSame($needSetup, $testee->needs_setup());
|
$this->assertSame($needSetup, $testee->needs_setup());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +431,7 @@ class WcGatewayTest extends TestCase
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dataForTestNeedsSetup(): array
|
public function dataForTestNeedsSetup(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -4,63 +4,77 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||||
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||||
|
use WooCommerce\PayPalCommerce\ModularTestCase;
|
||||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||||
use WooCommerce\PayPalCommerce\TestCase;
|
|
||||||
use Mockery;
|
use Mockery;
|
||||||
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
|
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
|
||||||
use function Brain\Monkey\Functions\when;
|
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()
|
public function setUp(): void
|
||||||
{
|
{
|
||||||
$settings = Mockery::mock(Settings::class);
|
parent::setUp();
|
||||||
$setting_fields = [];
|
|
||||||
$webhook_registrar = Mockery::mock(WebhookRegistrar::class);
|
|
||||||
$cache = Mockery::mock(Cache::class);
|
|
||||||
$state = Mockery::mock(State::class);
|
|
||||||
$bearer = Mockery::mock(Bearer::class);
|
|
||||||
|
|
||||||
$testee = new SettingsListener(
|
$this->appContainer = $this->bootstrapModule();
|
||||||
$settings,
|
}
|
||||||
$setting_fields,
|
|
||||||
$webhook_registrar,
|
|
||||||
$cache,
|
|
||||||
$state,
|
|
||||||
$bearer
|
|
||||||
);
|
|
||||||
|
|
||||||
$_REQUEST['section'] = 'ppcp-gateway';
|
public function testListen()
|
||||||
$_POST['ppcp-nonce'] = 'foo';
|
{
|
||||||
$_POST['ppcp'] = [
|
$settings = Mockery::mock(Settings::class);
|
||||||
'client_id' => 'client_id',
|
$settings->shouldReceive('set');
|
||||||
];
|
|
||||||
$_GET['ppcp-tab'] = 'just-a-tab';
|
|
||||||
|
|
||||||
when('sanitize_text_field')->justReturn('ppcp-gateway');
|
$setting_fields = $this->appContainer->get('wcgateway.settings.fields');
|
||||||
when('wp_unslash')->justReturn('ppcp-gateway');
|
|
||||||
when('current_user_can')->justReturn(true);
|
|
||||||
when('wp_verify_nonce')->justReturn(true);
|
|
||||||
|
|
||||||
$settings->shouldReceive('has')
|
$webhook_registrar = Mockery::mock(WebhookRegistrar::class);
|
||||||
->with('client_id')
|
$webhook_registrar->shouldReceive('unregister')->andReturnTrue();
|
||||||
->andReturn('client_id');
|
$webhook_registrar->shouldReceive('register')->andReturnTrue();
|
||||||
$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();
|
$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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
89
tests/PHPUnit/Webhooks/Status/WebhookSimulationTest.php
Normal file
89
tests/PHPUnit/Webhooks/Status/WebhookSimulationTest.php
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Webhooks\Status;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Mockery;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Webhook;
|
||||||
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\WebhookEvent;
|
||||||
|
use WooCommerce\PayPalCommerce\TestCase;
|
||||||
|
use function Brain\Monkey\Functions\when;
|
||||||
|
|
||||||
|
class WebhookSimulationTest extends TestCase
|
||||||
|
{
|
||||||
|
private $webhook_endpoint;
|
||||||
|
|
||||||
|
private $webhook;
|
||||||
|
|
||||||
|
private $event_type = 'CHECKOUT.ORDER.APPROVED';
|
||||||
|
private $event_version = '2.0';
|
||||||
|
|
||||||
|
private $sut;
|
||||||
|
|
||||||
|
private $storage;
|
||||||
|
|
||||||
|
private $event_id = '123';
|
||||||
|
private $event;
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->webhook_endpoint = Mockery::mock(WebhookEndpoint::class);
|
||||||
|
$this->webhook = new Webhook('https://example.com', []);
|
||||||
|
|
||||||
|
$this->sut = new WebhookSimulation($this->webhook_endpoint, $this->webhook, $this->event_type, $this->event_version);
|
||||||
|
|
||||||
|
when('update_option')->alias(function ($key, $value) {
|
||||||
|
$this->storage[$key] = $value;
|
||||||
|
});
|
||||||
|
when('get_option')->alias(function ($key, $default = false) {
|
||||||
|
return $this->storage[$key] ?? $default;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->event = $this->createEvent($this->event_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSimulation()
|
||||||
|
{
|
||||||
|
$this->webhook_endpoint
|
||||||
|
->expects('simulate')
|
||||||
|
->with($this->webhook, $this->event_type, $this->event_version)
|
||||||
|
->andReturn($this->event);
|
||||||
|
|
||||||
|
$this->sut->start();
|
||||||
|
|
||||||
|
self::assertTrue($this->sut->is_simulation_event($this->createEvent($this->event_id)));
|
||||||
|
self::assertFalse($this->sut->is_simulation_event($this->createEvent('456')));
|
||||||
|
|
||||||
|
self::assertFalse($this->sut->receive($this->createEvent('456')));
|
||||||
|
|
||||||
|
self::assertEquals(WebhookSimulation::STATE_WAITING, $this->sut->get_state());
|
||||||
|
|
||||||
|
self::assertTrue($this->sut->receive($this->createEvent($this->event_id)));
|
||||||
|
self::assertEquals(WebhookSimulation::STATE_RECEIVED, $this->sut->get_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsSimulationNeverThrows()
|
||||||
|
{
|
||||||
|
self::assertFalse($this->sut->is_simulation_event($this->createEvent($this->event_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSimulationWhenNoWebhook()
|
||||||
|
{
|
||||||
|
$this->sut = new WebhookSimulation($this->webhook_endpoint, null, $this->event_type, $this->event_version);
|
||||||
|
|
||||||
|
self::assertFalse($this->sut->is_simulation_event($this->createEvent($this->event_id)));
|
||||||
|
|
||||||
|
$this->expectException(Exception::class);
|
||||||
|
|
||||||
|
$this->sut->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createEvent(string $id): WebhookEvent
|
||||||
|
{
|
||||||
|
return new WebhookEvent($id, null, '', '', $this->event_type, '', '', (object) []);
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue