From 07bda403e371f3dbe943c5cd8bec3834c13cb9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 11:23:55 +0300 Subject: [PATCH 01/61] Add setting field for intent --- .../src/Settings/SettingsFields.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/modules.local/ppcp-wc-gateway/src/Settings/SettingsFields.php b/modules.local/ppcp-wc-gateway/src/Settings/SettingsFields.php index 8b93467c1..014416ecf 100644 --- a/modules.local/ppcp-wc-gateway/src/Settings/SettingsFields.php +++ b/modules.local/ppcp-wc-gateway/src/Settings/SettingsFields.php @@ -47,6 +47,21 @@ class SettingsFields 'woocommerce-paypal-gateway' ), ], + 'intent' => [ + 'title' => __('Intent', 'woocommerce-paypal-gateway'), + 'type' => 'select', + 'class' => 'wc-enhanced-select', + 'default' => 'capture', + 'desc_tip' => true, + 'description' => __( + 'The intent to either capture payment immediately or authorize a payment for an order after order creation.', + 'woocommerce-paypal-gateway' + ), + 'options' => [ + 'capture' => __('Capture', 'woocommerce-paypal-gateway'), + 'authorize' => __('Authorize', 'woocommerce-paypal-gateway'), + ], + ], ]; } From 717b7d1689da8c2d34ce52dfa6c94cf8d892b9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 11:24:33 +0300 Subject: [PATCH 02/61] Add intent type to the smart button URL param --- modules.local/ppcp-button/src/Assets/SmartButton.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules.local/ppcp-button/src/Assets/SmartButton.php b/modules.local/ppcp-button/src/Assets/SmartButton.php index aaaaef3cc..3f7299667 100644 --- a/modules.local/ppcp-button/src/Assets/SmartButton.php +++ b/modules.local/ppcp-button/src/Assets/SmartButton.php @@ -81,6 +81,7 @@ class SmartButton implements SmartButtonInterface //ToDo: Probably only needed, when DCC 'vault' => 'true', 'commit' => is_checkout() ? 'true' : 'false', + 'intent' => $this->settings->get('intent') ]; $smartButtonUrl = add_query_arg($params, 'https://www.paypal.com/sdk/js'); From f4fd1d8b7d95feb9f7d8188f608473e2af7cbb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 11:25:01 +0300 Subject: [PATCH 03/61] Capture the order only if the intent is capture --- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 06258809b..3e3bc4165 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -84,7 +84,9 @@ class WcGateway extends \WC_Payment_Gateway } $order = $this->patchOrder($wcOrder, $order); - $order = $this->endpoint->capture($order); + if($order->intent() === 'CAPTURE') { + $order = $this->endpoint->capture($order); + } $wcOrder->update_status('on-hold', __('Awaiting payment.', 'woocommerce-paypal-gateway')); if ($order->status()->is(OrderStatus::COMPLETED)) { From 35afcb5d2c8ccb70189a5b9e33f3de7e69bf48e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 11:52:24 +0300 Subject: [PATCH 04/61] For now pass the intent type as dependency --- modules.local/ppcp-api-client/services.php | 8 +++++++- .../ppcp-api-client/src/Endpoint/OrderEndpoint.php | 8 ++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/modules.local/ppcp-api-client/services.php b/modules.local/ppcp-api-client/services.php index b1ed4f219..d5e2cb41e 100644 --- a/modules.local/ppcp-api-client/services.php +++ b/modules.local/ppcp-api-client/services.php @@ -46,11 +46,17 @@ return [ 'api.endpoint.order' => function (ContainerInterface $container) : OrderEndpoint { $orderFactory = $container->get('api.factory.order'); $patchCollectionFactory = $container->get('api.factory.patch-collection-factory'); + + // TODO: get the settings using the class + // Using it now throws a maximum nested error because they share the same dependency + $intent = strtoupper(get_option('woocommerce_ppcp-gateway_settings')['intent']); + return new OrderEndpoint( $container->get('api.host'), $container->get('api.bearer'), $orderFactory, - $patchCollectionFactory + $patchCollectionFactory, + $intent ); }, 'api.cart-repository' => function (ContainerInterface $container) : CartRepository { diff --git a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php index 70b57fcf1..9c8c6c94d 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -18,24 +18,28 @@ class OrderEndpoint private $bearer; private $orderFactory; private $patchCollectionFactory; + private $intent; + public function __construct( string $host, Bearer $bearer, OrderFactory $orderFactory, - PatchCollectionFactory $patchCollectionFactory + PatchCollectionFactory $patchCollectionFactory, + string $intent ) { $this->host = $host; $this->bearer = $bearer; $this->orderFactory = $orderFactory; $this->patchCollectionFactory = $patchCollectionFactory; + $this->intent = $intent; } public function createForPurchaseUnits(PurchaseUnit ...$items) : Order { $bearer = $this->bearer->bearer(); $data = [ - 'intent' => 'CAPTURE', + 'intent' => $this->intent, // TODO: read this from the global settings 'purchase_units' => array_map( function (PurchaseUnit $item) : array { return $item->toArray(); From 846d351f4a8f99636d06e7de72674f7fddfa572f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 12:38:36 +0300 Subject: [PATCH 05/61] Store the PayPal order id so we can use it later --- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 3e3bc4165..ee3abfb6f 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -73,6 +73,8 @@ class WcGateway extends \WC_Payment_Gateway //ToDo: We need to fetch the order from paypal again to get it with the new status. $order = $this->sessionHandler->order(); + update_post_meta($orderId, '_paypal_order_id', $order->id()); + $errorMessage = null; if (! $order || ! $order->status()->is(OrderStatus::APPROVED)) { $errorMessage = 'not approve yet'; @@ -84,7 +86,7 @@ class WcGateway extends \WC_Payment_Gateway } $order = $this->patchOrder($wcOrder, $order); - if($order->intent() === 'CAPTURE') { + if ($order->intent() === 'CAPTURE') { $order = $this->endpoint->capture($order); } From 35cceed23179f0620b27a67600cdb7e0c22f71c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 12:39:34 +0300 Subject: [PATCH 06/61] WIP authorize order from admin panel --- .../src/Endpoint/OrderEndpoint.php | 21 ++++++++++++++ .../ppcp-wc-gateway/src/WcGatewayModule.php | 29 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php index 9c8c6c94d..8f32c823c 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -105,6 +105,27 @@ class OrderEndpoint return $order; } + public function authorize(string $orderId) { + $bearer = $this->bearer->bearer(); + $url = trailingslashit($this->host) . 'v2/checkout/orders/' . $orderId . '/authorize'; + $args = [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $bearer, + 'Content-Type' => 'application/json', + 'Prefer' => 'return=representation', + ], + ]; + $response = wp_remote_post($url, $args); + + if (is_wp_error($response)) { + throw new RuntimeException(__('Could not authorize order.', 'woocommerce-paypal-commerce-gateway')); + } + if (wp_remote_retrieve_response_code($response) !== 201) { + throw new RuntimeException(__('Could not capture order.', 'woocommerce-paypal-commerce-gateway')); + } + return $orderId; + } + public function order(string $id) : Order { $bearer = $this->bearer->bearer(); diff --git a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php index bfb8b7bd3..ba858c905 100644 --- a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php +++ b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php @@ -4,8 +4,8 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Container\ServiceProvider; -use Dhii\Modular\Module\Exception\ModuleExceptionInterface; use Dhii\Modular\Module\ModuleInterface; +use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Interop\Container\ServiceProviderInterface; use Psr\Container\ContainerInterface; @@ -42,5 +42,32 @@ class WcGatewayModule implements ModuleInterface return $disabler->handler((array) $methods); } ); + + add_filter( + 'woocommerce_order_actions', + function ($orderActions) : array { + $orderActions['ppcp_authorize_order'] = __( + 'Authorize PayPal Order', + 'woocommerce-paypal-gateway' + ); + return $orderActions; + } + ); + + add_action( + 'woocommerce_order_action_ppcp_authorize_order', + function (\WC_Order $wcOrder) use ($container) { + $payPalOrderId = get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); + + /** + * @var OrderEndpoint $orderEndpoint + */ + $orderEndpoint = $container->get('api.endpoint.order'); + + $orderEndpoint->authorize($payPalOrderId); + + $wcOrder->update_status('processing'); + } + ); } } From cd1da8c460de3089a7106cffa0cd43fb78bf5475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 14:25:20 +0300 Subject: [PATCH 07/61] Move the logic to Gateway --- .../src/Endpoint/OrderEndpoint.php | 6 +- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 68 ++++++++++++++++++- .../ppcp-wc-gateway/src/WcGatewayModule.php | 13 ++-- 3 files changed, 72 insertions(+), 15 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php index 8f32c823c..d0d646155 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -105,7 +105,7 @@ class OrderEndpoint return $order; } - public function authorize(string $orderId) { + public function authorize(string $orderId) : bool { $bearer = $this->bearer->bearer(); $url = trailingslashit($this->host) . 'v2/checkout/orders/' . $orderId . '/authorize'; $args = [ @@ -121,9 +121,9 @@ class OrderEndpoint throw new RuntimeException(__('Could not authorize order.', 'woocommerce-paypal-commerce-gateway')); } if (wp_remote_retrieve_response_code($response) !== 201) { - throw new RuntimeException(__('Could not capture order.', 'woocommerce-paypal-commerce-gateway')); + throw new RuntimeException(__('Could not authorize order.', 'woocommerce-paypal-commerce-gateway')); } - return $orderId; + return true; } public function order(string $id) : Order diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index ee3abfb6f..3871fd797 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -1,4 +1,5 @@ form_fields = $this->settingsFields->fields(); } - public function process_payment($orderId) : ?array + public function process_payment($orderId): ?array { global $woocommerce; $wcOrder = new \WC_Order($orderId); @@ -76,7 +78,7 @@ class WcGateway extends \WC_Payment_Gateway update_post_meta($orderId, '_paypal_order_id', $order->id()); $errorMessage = null; - if (! $order || ! $order->status()->is(OrderStatus::APPROVED)) { + if (!$order || !$order->status()->is(OrderStatus::APPROVED)) { $errorMessage = 'not approve yet'; } $errorMessage = null; @@ -103,7 +105,67 @@ class WcGateway extends \WC_Payment_Gateway ]; } - private function patchOrder(\WC_Order $wcOrder, Order $order) : Order + public function authorizeOrder(\WC_Order $wcOrder) + { + $payPalOrderId = get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); + + try { + $order = $this->endpoint->order($payPalOrderId); + } catch (RuntimeException $e) { + // TODO: add a notice instead + $wcOrder->add_order_note( + __( + 'Unable to capture charge:', + 'woocommerce-paypal-gateway' + ) . ' ' . $e->getMessage() + ); + } + + if ($order->status()->is(OrderStatus::COMPLETED)) { + // TODO: add a notice instead + $wcOrder->add_order_note( + __( + 'Order already completed', + 'woocommerce-paypal-gateway' + ) + ); + return; + } + + if (!$order->status()->is(OrderStatus::APPROVED)) { + // TODO: add a notice instead + $wcOrder->add_order_note( + __( + 'Order not approved', + 'woocommerce-paypal-gateway' + ) + ); + return; + } + + try { + $this->endpoint->authorize($payPalOrderId); + } catch (RuntimeException $e) { + // TODO: display admin error message + $wcOrder->add_order_note( + __( + 'Unable to capture charge:', + 'woocommerce-paypal-gateway' + ) . ' ' . $e->getMessage() + ); + return; + } + $wcOrder->add_order_note( + __( + 'Payment authorized.', + 'woocommerce-paypal-gateway' + ) + ); + + $wcOrder->update_status('processing'); + } + + private function patchOrder(\WC_Order $wcOrder, Order $order): Order { $updatedOrder = $this->orderFactory->fromWcOrder($wcOrder, $order); $order = $this->endpoint->patchOrderWith($order, $updatedOrder); diff --git a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php index ba858c905..2585d99e0 100644 --- a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php +++ b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php @@ -5,8 +5,8 @@ namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Container\ServiceProvider; use Dhii\Modular\Module\ModuleInterface; -use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; +use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; use Interop\Container\ServiceProviderInterface; use Psr\Container\ContainerInterface; @@ -57,16 +57,11 @@ class WcGatewayModule implements ModuleInterface add_action( 'woocommerce_order_action_ppcp_authorize_order', function (\WC_Order $wcOrder) use ($container) { - $payPalOrderId = get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); - /** - * @var OrderEndpoint $orderEndpoint + * @var WcGateway $gateway */ - $orderEndpoint = $container->get('api.endpoint.order'); - - $orderEndpoint->authorize($payPalOrderId); - - $wcOrder->update_status('processing'); + $gateway = $container->get('wcgateway.gateway'); + $gateway->authorizeOrder($wcOrder); } ); } From 48176a18a74d0bb49d6ab7a84436f657854ea24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 15:26:30 +0300 Subject: [PATCH 08/61] Read the intent from the WC settings --- modules.local/ppcp-api-client/services.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules.local/ppcp-api-client/services.php b/modules.local/ppcp-api-client/services.php index d37e2521f..9ea227942 100644 --- a/modules.local/ppcp-api-client/services.php +++ b/modules.local/ppcp-api-client/services.php @@ -19,6 +19,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\ShippingFactory; use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository; +use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings; return [ @@ -49,9 +50,11 @@ return [ $patchCollectionFactory = $container->get('api.factory.patch-collection-factory'); $errorResponseFactory = $container->get('api.factory.response-error'); - // TODO: get the settings using the class - // Using it now throws a maximum nested error because they share the same dependency - $intent = strtoupper(get_option('woocommerce_ppcp-gateway_settings')['intent']); + /** + * @var Settings $settings + */ + $settings = $container->get('wcgateway.settings'); + $intent = strtoupper($settings->get('intent')); return new OrderEndpoint( $container->get('api.host'), From b655750485a7d03d930aace94466a59020cc0ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Mon, 13 Apr 2020 22:30:57 +0300 Subject: [PATCH 09/61] Change order string payment --- modules.local/ppcp-wc-gateway/services.php | 7 ++- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 47 +++++------------- .../src/Notice/AuthorizeOrderActionNotice.php | 48 +++++++++++++++++++ .../ppcp-wc-gateway/src/WcGatewayModule.php | 27 ++++++++--- 4 files changed, 86 insertions(+), 43 deletions(-) create mode 100644 modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php diff --git a/modules.local/ppcp-wc-gateway/services.php b/modules.local/ppcp-wc-gateway/services.php index 7bfd23152..bc3bb6c5b 100644 --- a/modules.local/ppcp-wc-gateway/services.php +++ b/modules.local/ppcp-wc-gateway/services.php @@ -7,6 +7,7 @@ use Dhii\Data\Container\ContainerInterface; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGatewayBase; +use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice; use Inpsyde\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice; use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings; use Inpsyde\PayPalCommerce\WcGateway\Settings\SettingsFields; @@ -36,7 +37,11 @@ return [ $settings = $container->get('wcgateway.settings'); return new ConnectAdminNotice($settings); }, - 'wcgateway.settings.fields' => function (ContainerInterface $container) : SettingsFields { + 'wcgateway.notice.authorize-order-action' => + function (ContainerInterface $container): AuthorizeOrderActionNotice { + return new AuthorizeOrderActionNotice(); + }, + 'wcgateway.settings.fields' => function (ContainerInterface $container): SettingsFields { return new SettingsFields(); }, ]; diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 6b49dbdee..0991a3fb2 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -11,6 +11,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory; use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository; use Inpsyde\PayPalCommerce\Session\SessionHandler; +use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice; use Inpsyde\PayPalCommerce\WcGateway\Settings\SettingsFields; //phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps @@ -31,6 +32,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface OrderFactory $orderFactory, SettingsFields $settingsFields ) { + $this->sessionHandler = $sessionHandler; $this->cartRepository = $cartRepository; $this->endpoint = $endpoint; @@ -108,53 +110,28 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface try { $order = $this->endpoint->order($payPalOrderId); - } catch (RuntimeException $e) { - // TODO: add a notice instead - $wcOrder->add_order_note( - __( - 'Unable to capture charge:', - 'woocommerce-paypal-gateway' - ) . ' ' . $e->getMessage() - ); - } - - if ($order->status()->is(OrderStatus::COMPLETED)) { - // TODO: add a notice instead - $wcOrder->add_order_note( - __( - 'Order already completed', - 'woocommerce-paypal-gateway' - ) - ); + } catch (RuntimeException $exception) { + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::NO_INFO); return; } - if (!$order->status()->is(OrderStatus::APPROVED)) { - // TODO: add a notice instead - $wcOrder->add_order_note( - __( - 'Order not approved', - 'woocommerce-paypal-gateway' - ) - ); + if ($order->status()->is(OrderStatus::COMPLETED)) { + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_AUTHORIZED); return; } try { $this->endpoint->authorize($payPalOrderId); - } catch (RuntimeException $e) { - // TODO: display admin error message - $wcOrder->add_order_note( - __( - 'Unable to capture charge:', - 'woocommerce-paypal-gateway' - ) . ' ' . $e->getMessage() - ); + } catch (RuntimeException $exception) { + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); return; } + + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::SUCCESS); + $wcOrder->add_order_note( __( - 'Payment authorized.', + 'Payment successfully authorized.', 'woocommerce-paypal-gateway' ) ); diff --git a/modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php b/modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php new file mode 100644 index 000000000..adababaf8 --- /dev/null +++ b/modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php @@ -0,0 +1,48 @@ +get('wcgateway.gateway'); - return (array) $methods; + return (array)$methods; } ); @@ -40,7 +41,7 @@ class WcGatewayModule implements ModuleInterface /** * @var DisableGateways $disabler */ - return $disabler->handler((array) $methods); + return $disabler->handler((array)$methods); } ); @@ -57,9 +58,9 @@ class WcGatewayModule implements ModuleInterface add_filter( 'woocommerce_order_actions', - function ($orderActions) : array { + function ($orderActions): array { $orderActions['ppcp_authorize_order'] = __( - 'Authorize PayPal Order', + 'Authorize PayPal Payment', 'woocommerce-paypal-gateway' ); return $orderActions; @@ -76,5 +77,17 @@ class WcGatewayModule implements ModuleInterface $gateway->authorizeOrder($wcOrder); } ); + + add_filter( + 'post_updated_messages', + function ($messages) use ($container) { + /** + * @var AuthorizeOrderActionNotice $authorizeOrderAction + */ + $authorizeOrderAction = $container->get('wcgateway.notice.authorize-order-action'); + return $authorizeOrderAction->registerMessages($messages); + }, + 20 + ); } } From 49071e2d9c638744e850c8305876b46c5c722db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 11:18:46 +0300 Subject: [PATCH 10/61] Remove todo --- modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php index cd9924c1d..bf0ed3242 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -44,7 +44,7 @@ class OrderEndpoint { $bearer = $this->bearer->bearer(); $data = [ - 'intent' => $this->intent, // TODO: read this from the global settings + 'intent' => $this->intent, 'purchase_units' => array_map( function (PurchaseUnit $item) : array { return $item->toArray(); From 584a1f4a3a545266e4b05f67309c0c0a5f23b1fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 15:38:39 +0300 Subject: [PATCH 11/61] Create Authorization entity --- modules.local/ppcp-api-client/services.php | 18 +++++- .../src/Entity/Authorization.php | 29 ++++++++++ .../src/Entity/AuthorizationStatus.php | 55 +++++++++++++++++++ .../src/Factory/AuthorizationsFactory.php | 38 +++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 modules.local/ppcp-api-client/src/Entity/Authorization.php create mode 100644 modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php create mode 100644 modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php diff --git a/modules.local/ppcp-api-client/services.php b/modules.local/ppcp-api-client/services.php index 4dcab54de..4cff301cc 100644 --- a/modules.local/ppcp-api-client/services.php +++ b/modules.local/ppcp-api-client/services.php @@ -8,8 +8,10 @@ use Inpsyde\CacheModule\Provider\CacheProviderInterface; use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer; use Inpsyde\PayPalCommerce\ApiClient\Config\Config; use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; +use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint; use Inpsyde\PayPalCommerce\ApiClient\Factory\AddressFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\AmountFactory; +use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationsFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\ItemFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory; @@ -19,8 +21,8 @@ use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\ShippingFactory; use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository; -use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings; use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository; +use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings; return [ @@ -46,6 +48,17 @@ return [ $container->get('api.secret') ); }, + 'api.endpoint.payments' => function (ContainerInterface $container) : PaymentsEndpoint { + $authorizationFactory = $container->get('api.factory.authorization'); + $errorResponseFactory = $container->get('api.factory.response-error'); + + return new PaymentsEndpoint( + $container->get('api.host'), + $container->get('api.bearer'), + $authorizationFactory, + $errorResponseFactory + ); + }, 'api.endpoint.order' => function (ContainerInterface $container) : OrderEndpoint { $orderFactory = $container->get('api.factory.order'); $patchCollectionFactory = $container->get('api.factory.patch-collection-factory'); @@ -138,4 +151,7 @@ return [ $payerFactory = $container->get('api.factory.payer'); return new OrderFactory($purchaseUnitFactory, $payerFactory); }, + 'api.factory.authorization' => function (ContainerInterface $container) : AuthorizationsFactory { + return new AuthorizationsFactory(); + }, ]; diff --git a/modules.local/ppcp-api-client/src/Entity/Authorization.php b/modules.local/ppcp-api-client/src/Entity/Authorization.php new file mode 100644 index 000000000..4bea3c109 --- /dev/null +++ b/modules.local/ppcp-api-client/src/Entity/Authorization.php @@ -0,0 +1,29 @@ +id = $id; + $this->authorizationStatus = $authorizationStatus; + } + + public function id() : string + { + return $this->id; + } + + public function status() : AuthorizationStatus + { + return $this->authorizationStatus; + } +} \ No newline at end of file diff --git a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php new file mode 100644 index 000000000..1bb2c6c76 --- /dev/null +++ b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php @@ -0,0 +1,55 @@ +status = $status; + } + + public static function asInternal(): AuthorizationStatus + { + return new self(self::INTERNAL); + } + + public function is(string $status): bool + { + return $this->status === $status; + } + + public function name(): string + { + return $this->status; + } +} \ No newline at end of file diff --git a/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php b/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php new file mode 100644 index 000000000..736bb31e1 --- /dev/null +++ b/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php @@ -0,0 +1,38 @@ +id)) { + throw new RuntimeException( + __( + 'Does not contain an id.', + 'woocommerce-paypal-commerce-gateway' + ) + ); + } + + if (!isset($orderData->status)) { + throw new RuntimeException( + __( + 'Des not contain status.', + 'woocommerce-paypal-commerce-gateway' + ) + ); + } + + return new Authorization( + $data->id, + new AuthorizationStatus($data->status) + ); + } +} \ No newline at end of file From c6c931dc5c4c33077e6b15892d4660fe1bd8a7d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 15:39:55 +0300 Subject: [PATCH 12/61] Authorize the order/payment during the checkout process --- .../ppcp-api-client/src/Endpoint/OrderEndpoint.php | 8 +++++--- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 5 +++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php index 0a007c363..5b55f4062 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -122,9 +122,9 @@ class OrderEndpoint return $order; } - public function authorize(string $orderId) : bool { + public function authorize(Order $order) : Order { $bearer = $this->bearer->bearer(); - $url = trailingslashit($this->host) . 'v2/checkout/orders/' . $orderId . '/authorize'; + $url = trailingslashit($this->host) . 'v2/checkout/orders/' . $order->id() . '/authorize'; $args = [ 'headers' => [ 'Authorization' => 'Bearer ' . $bearer, @@ -140,7 +140,9 @@ class OrderEndpoint if (wp_remote_retrieve_response_code($response) !== 201) { throw new RuntimeException(__('Could not authorize order.', 'woocommerce-paypal-commerce-gateway')); } - return true; + $json = json_decode($response['body']); + $order = $this->orderFactory->fromPayPalResponse($json); + return $order; } public function order(string $id) : Order diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 0991a3fb2..121fa688f 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -73,6 +73,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface $wcOrder = new \WC_Order($orderId); //ToDo: We need to fetch the order from paypal again to get it with the new status. + $order = $this->sessionHandler->order(); update_post_meta($orderId, '_paypal_order_id', $order->id()); @@ -91,6 +92,10 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface $order = $this->endpoint->capture($order); } + if ($order->intent() === 'AUTHORIZE') { + $order = $this->endpoint->authorize($order); + } + $wcOrder->update_status('on-hold', __('Awaiting payment.', 'woocommerce-paypal-gateway')); if ($order->status()->is(OrderStatus::COMPLETED)) { $wcOrder->update_status('processing', __('Payment received.', 'woocommerce-paypal-gateway')); From d94cb24393294661f966d1cac77e97d9b00957e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 16:02:10 +0300 Subject: [PATCH 13/61] Don't throw an error if the order was already authorized --- .../src/Endpoint/OrderEndpoint.php | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php index 5b55f4062..08655526a 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -122,7 +122,8 @@ class OrderEndpoint return $order; } - public function authorize(Order $order) : Order { + public function authorize(Order $order): Order + { $bearer = $this->bearer->bearer(); $url = trailingslashit($this->host) . 'v2/checkout/orders/' . $order->id() . '/authorize'; $args = [ @@ -135,12 +136,34 @@ class OrderEndpoint $response = wp_remote_post($url, $args); if (is_wp_error($response)) { - throw new RuntimeException(__('Could not authorize order.', 'woocommerce-paypal-commerce-gateway')); - } - if (wp_remote_retrieve_response_code($response) !== 201) { - throw new RuntimeException(__('Could not authorize order.', 'woocommerce-paypal-commerce-gateway')); + $this->handleResponseWpError($url, $args); + throw new RuntimeException( + __( + 'Could not authorize order.', + 'woocommerce-paypal-commerce-gateway' + ) + ); } $json = json_decode($response['body']); + if (wp_remote_retrieve_response_code($response) !== 201) { + $errors = $this->errorResponseFactory->fromPayPalResponse( + $json, + (int)wp_remote_retrieve_response_code($response), + $url, + $args + ); + + if ($errors->hasErrorCode(ErrorResponse::ORDER_ALREADY_AUTHORIZED)) { + return $this->order($order->id()); + } + add_action('woocommerce-paypal-commerce-gateway.error', $errors); + throw new RuntimeException( + __( + 'Could not authorize order.', + 'woocommerce-paypal-commerce-gateway' + ) + ); + } $order = $this->orderFactory->fromPayPalResponse($json); return $order; } From 04cf4363a63b354fbffbfde442ef67775e004d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 16:03:04 +0300 Subject: [PATCH 14/61] Code Beautifier and Fixer --- modules.local/ppcp-api-client/src/Entity/Authorization.php | 3 ++- .../ppcp-api-client/src/Entity/AuthorizationStatus.php | 2 +- .../ppcp-api-client/src/Factory/AuthorizationsFactory.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Entity/Authorization.php b/modules.local/ppcp-api-client/src/Entity/Authorization.php index 4bea3c109..add288ea5 100644 --- a/modules.local/ppcp-api-client/src/Entity/Authorization.php +++ b/modules.local/ppcp-api-client/src/Entity/Authorization.php @@ -13,6 +13,7 @@ class Authorization string $id, AuthorizationStatus $authorizationStatus ) { + $this->id = $id; $this->authorizationStatus = $authorizationStatus; } @@ -26,4 +27,4 @@ class Authorization { return $this->authorizationStatus; } -} \ No newline at end of file +} diff --git a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php index 1bb2c6c76..039d6242e 100644 --- a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php +++ b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php @@ -52,4 +52,4 @@ class AuthorizationStatus { return $this->status; } -} \ No newline at end of file +} diff --git a/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php b/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php index 736bb31e1..4cee615ef 100644 --- a/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php @@ -35,4 +35,4 @@ class AuthorizationsFactory new AuthorizationStatus($data->status) ); } -} \ No newline at end of file +} From 210b7d6845ee3abd2ab73681ca9dd022bd529452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 16:08:24 +0300 Subject: [PATCH 15/61] Create and pass the payments endpoint to the gateway --- .../src/Endpoint/PaymentsEndpoint.php | 103 ++++++++++++++++++ modules.local/ppcp-wc-gateway/services.php | 5 +- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 23 ++-- 3 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php diff --git a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php new file mode 100644 index 000000000..63aaddfa7 --- /dev/null +++ b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php @@ -0,0 +1,103 @@ +host = $host; + $this->bearer = $bearer; + $this->authorizationsFactory = $authorizationsFactory; + $this->errorResponseFactory = $errorResponseFactory; + } + + public function authorization($authorizationId) + { + $bearer = $this->bearer->bearer(); + $url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId; + $args = [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $bearer, + 'Content-Type' => 'application/json', + 'Prefer' => 'return=representation', + ], + ]; + + $response = wp_remote_get($url, $args); + + if (is_wp_error($response)) { + throw new RuntimeException( + __( + 'Could not get authorized payment info.', + 'woocommerce-paypal-commerce-gateway' + ) + ); + } + + if (wp_remote_retrieve_response_code($response) !== 200) { + throw new RuntimeException( + __( + 'Could not get authorized payment info.', + 'woocommerce-paypal-commerce-gateway' + ) + ); + } + + $json = json_decode($response['body']); + $authorization = $this->authorizationsFactory->fromPayPalRequest($json); + return $authorization; + } + + public function captureAuthorization($authorizationId) + { + $bearer = $this->bearer->bearer(); + $url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId . '/capture'; + $args = [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $bearer, + 'Content-Type' => 'application/json', + 'Prefer' => 'return=representation', + ], + ]; + + $response = wp_remote_post($url, $args); + + if (is_wp_error($response)) { + throw new RuntimeException( + __( + 'Could not capture authorized payment.', + 'woocommerce-paypal-commerce-gateway' + ) + ); + } + + if (wp_remote_retrieve_response_code($response) !== 201) { + throw new RuntimeException( + __( + 'Could not capture authorized payment.', + 'woocommerce-paypal-commerce-gateway' + ) + ); + } + + $json = json_decode($response['body']); + return $json; + } +} diff --git a/modules.local/ppcp-wc-gateway/services.php b/modules.local/ppcp-wc-gateway/services.php index aa858ac04..c9dc551f0 100644 --- a/modules.local/ppcp-wc-gateway/services.php +++ b/modules.local/ppcp-wc-gateway/services.php @@ -19,10 +19,11 @@ return [ 'wcgateway.gateway' => function (ContainerInterface $container) : WcGateway { $sessionHandler = $container->get('session.handler'); $cartRepository = $container->get('api.repository.cart'); - $endpoint = $container->get('api.endpoint.order'); + $orderEndpoint = $container->get('api.endpoint.order'); + $paymentsEndpoint = $container->get('api.endpoint.payments'); $orderFactory = $container->get('api.factory.order'); $settingsFields = $container->get('wcgateway.settings.fields'); - return new WcGateway($sessionHandler, $cartRepository, $endpoint, $orderFactory, $settingsFields); + return new WcGateway($sessionHandler, $cartRepository, $orderEndpoint, $paymentsEndpoint, $orderFactory, $settingsFields); }, 'wcgateway.disabler' => function (ContainerInterface $container) : DisableGateways { $sessionHandler = $container->get('session.handler'); diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 121fa688f..12e9e4e82 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\WcGateway\Gateway; use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; +use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint; use Inpsyde\PayPalCommerce\ApiClient\Entity\Order; use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus; use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; @@ -20,22 +21,28 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface { private $isSandbox = true; private $sessionHandler; - private $endpoint; + private $orderEndpoint; private $cartRepository; private $orderFactory; private $settingsFields; + /** + * @var PaymentsEndpoint + */ + private $paymentsEndpoint; public function __construct( SessionHandler $sessionHandler, CartRepository $cartRepository, - OrderEndpoint $endpoint, + OrderEndpoint $orderEndpoint, + PaymentsEndpoint $paymentsEndpoint, OrderFactory $orderFactory, SettingsFields $settingsFields ) { $this->sessionHandler = $sessionHandler; $this->cartRepository = $cartRepository; - $this->endpoint = $endpoint; + $this->orderEndpoint = $orderEndpoint; + $this->paymentsEndpoint = $paymentsEndpoint; $this->orderFactory = $orderFactory; $this->settingsFields = $settingsFields; @@ -89,11 +96,11 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface $order = $this->patchOrder($wcOrder, $order); if ($order->intent() === 'CAPTURE') { - $order = $this->endpoint->capture($order); + $order = $this->orderEndpoint->capture($order); } if ($order->intent() === 'AUTHORIZE') { - $order = $this->endpoint->authorize($order); + $order = $this->orderEndpoint->authorize($order); } $wcOrder->update_status('on-hold', __('Awaiting payment.', 'woocommerce-paypal-gateway')); @@ -114,7 +121,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface $payPalOrderId = get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); try { - $order = $this->endpoint->order($payPalOrderId); + $order = $this->orderEndpoint->order($payPalOrderId); } catch (RuntimeException $exception) { AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::NO_INFO); return; @@ -126,7 +133,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface } try { - $this->endpoint->authorize($payPalOrderId); + $this->orderEndpoint->authorize($payPalOrderId); } catch (RuntimeException $exception) { AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); return; @@ -147,7 +154,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface private function patchOrder(\WC_Order $wcOrder, Order $order): Order { $updatedOrder = $this->orderFactory->fromWcOrder($wcOrder, $order); - $order = $this->endpoint->patchOrderWith($order, $updatedOrder); + $order = $this->orderEndpoint->patchOrderWith($order, $updatedOrder); return $order; } } From 676216415b45c74f8f138a0c4d27f9c70e6d6490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 16:11:10 +0300 Subject: [PATCH 16/61] Only set the status to processing of the intent was capture --- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 12e9e4e82..8127d9cab 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -104,7 +104,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface } $wcOrder->update_status('on-hold', __('Awaiting payment.', 'woocommerce-paypal-gateway')); - if ($order->status()->is(OrderStatus::COMPLETED)) { + if ($order->status()->is(OrderStatus::COMPLETED) && $order->intent() === 'CAPTURE') { $wcOrder->update_status('processing', __('Payment received.', 'woocommerce-paypal-gateway')); } $woocommerce->cart->empty_cart(); From d1af783f34a68236fa10bd3975f4975f61f0d63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 19:15:32 +0300 Subject: [PATCH 17/61] Add missing captured status --- .../ppcp-api-client/src/Entity/AuthorizationStatus.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php index 039d6242e..b966e8e98 100644 --- a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php +++ b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php @@ -8,6 +8,7 @@ class AuthorizationStatus { const INTERNAL = 'INTERNAL'; const CREATED = 'CREATED'; + const CAPTURED = 'CAPTURED'; const DENIED = 'DENIED'; const EXPIRED = 'EXPIRED'; const PARTIALLY_CAPTURED = 'PARTIALLY_CAPTURED'; @@ -16,6 +17,7 @@ class AuthorizationStatus const VALID_STATUS = [ self::INTERNAL, self::CREATED, + self::CAPTURED, self::DENIED, self::EXPIRED, self::PARTIALLY_CAPTURED, From 6c1dec1c3a246c1422e141769b8884a616619270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 19:16:04 +0300 Subject: [PATCH 18/61] Rename AuthorizationFactory file and fix variable --- .../{AuthorizationsFactory.php => AuthorizationFactory.php} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename modules.local/ppcp-api-client/src/Factory/{AuthorizationsFactory.php => AuthorizationFactory.php} (88%) diff --git a/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php b/modules.local/ppcp-api-client/src/Factory/AuthorizationFactory.php similarity index 88% rename from modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php rename to modules.local/ppcp-api-client/src/Factory/AuthorizationFactory.php index 4cee615ef..eaf721654 100644 --- a/modules.local/ppcp-api-client/src/Factory/AuthorizationsFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/AuthorizationFactory.php @@ -8,7 +8,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization; use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus; use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; -class AuthorizationsFactory +class AuthorizationFactory { public function fromPayPalRequest(\stdClass $data): Authorization { @@ -21,10 +21,10 @@ class AuthorizationsFactory ); } - if (!isset($orderData->status)) { + if (!isset($data->status)) { throw new RuntimeException( __( - 'Des not contain status.', + 'Does not contain status.', 'woocommerce-paypal-commerce-gateway' ) ); From 7d0e3d2e38caca451301ac1c7366081ae75500f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 19:18:12 +0300 Subject: [PATCH 19/61] Add Payments to the PurchaseUnit --- modules.local/ppcp-api-client/services.php | 21 ++++++++---- .../ppcp-api-client/src/Entity/Payments.php | 26 +++++++++++++++ .../src/Entity/PurchaseUnit.php | 11 ++++++- .../src/Factory/PaymentsFactory.php | 32 +++++++++++++++++++ .../src/Factory/PurchaseUnitFactory.php | 17 ++++++++-- 5 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 modules.local/ppcp-api-client/src/Entity/Payments.php create mode 100644 modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php diff --git a/modules.local/ppcp-api-client/services.php b/modules.local/ppcp-api-client/services.php index 4cff301cc..9a0e7f536 100644 --- a/modules.local/ppcp-api-client/services.php +++ b/modules.local/ppcp-api-client/services.php @@ -1,4 +1,5 @@ get('api.secret') ); }, - 'api.endpoint.payments' => function (ContainerInterface $container) : PaymentsEndpoint { + 'api.endpoint.payments' => function (ContainerInterface $container): PaymentsEndpoint { $authorizationFactory = $container->get('api.factory.authorization'); $errorResponseFactory = $container->get('api.factory.response-error'); @@ -59,7 +61,7 @@ return [ $errorResponseFactory ); }, - 'api.endpoint.order' => function (ContainerInterface $container) : OrderEndpoint { + 'api.endpoint.order' => function (ContainerInterface $container): OrderEndpoint { $orderFactory = $container->get('api.factory.order'); $patchCollectionFactory = $container->get('api.factory.patch-collection-factory'); $errorResponseFactory = $container->get('api.factory.response-error'); @@ -110,12 +112,15 @@ return [ $payeeFactory = $container->get('api.factory.payee'); $itemFactory = $container->get('api.factory.item'); $shippingFactory = $container->get('api.factory.shipping'); + $paymentsFactory = $container->get('api.factory.payments'); + return new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFactory ); }, 'api.factory.patch-collection-factory' => function (ContainerInterface $container) @@ -151,7 +156,11 @@ return [ $payerFactory = $container->get('api.factory.payer'); return new OrderFactory($purchaseUnitFactory, $payerFactory); }, - 'api.factory.authorization' => function (ContainerInterface $container) : AuthorizationsFactory { - return new AuthorizationsFactory(); + 'api.factory.payments' => function (ContainerInterface $container): PaymentsFactory { + $authorizationFactory = $container->get('api.factory.authorization'); + return new PaymentsFactory($authorizationFactory); + }, + 'api.factory.authorization' => function (ContainerInterface $container): AuthorizationFactory { + return new AuthorizationFactory(); }, ]; diff --git a/modules.local/ppcp-api-client/src/Entity/Payments.php b/modules.local/ppcp-api-client/src/Entity/Payments.php new file mode 100644 index 000000000..7a81141da --- /dev/null +++ b/modules.local/ppcp-api-client/src/Entity/Payments.php @@ -0,0 +1,26 @@ +authorizations = $authorizations; + } + + public function toArray() + { + return [ + + ]; + } + + public function authorizations() : array + { + return $this->authorizations; + } +} diff --git a/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php b/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php index c1023ce6b..dbbab80ff 100644 --- a/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php +++ b/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php @@ -1,4 +1,5 @@ amount = $amount; @@ -43,6 +47,7 @@ class PurchaseUnit $this->customId = $customId; $this->invoiceId = $invoiceId; $this->softDescriptor = $softDescriptor; + $this->payments = $payments; } public function amount() : Amount @@ -114,6 +119,10 @@ class PurchaseUnit $purchaseUnit['payee'] = $this->payee()->toArray(); } + if ($this->payments()) { + $purchaseUnit['payments'] = $this->payments()->toArray(); + } + if ($this->shipping()) { $purchaseUnit['shipping'] = $this->shipping()->toArray(); } diff --git a/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php b/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php new file mode 100644 index 000000000..3263621bd --- /dev/null +++ b/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php @@ -0,0 +1,32 @@ +authorizationsFactory = $authorizationsFactory; + } + + public function fromPayPalResponse(\stdClass $data) + { + $authorizations = array_map( + function (\stdClass $authorization): Authorization { + return $this->authorizationsFactory->fromPayPalRequest($authorization); + }, + $data->authorizations + ); + $payments = new Payments($authorizations); + return $payments; + } +} diff --git a/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php b/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php index 2fea9b2ff..6f63bc59e 100644 --- a/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php @@ -1,4 +1,5 @@ amountFactory = $amountFactory; @@ -29,6 +33,7 @@ class PurchaseUnitFactory $this->payeeFactory = $payeeFactory; $this->itemFactory = $itemFactory; $this->shippingFactory = $shippingFactory; + $this->$paymentsFactory = $paymentsFactory; } public function fromWcOrder(\WC_Order $order) : PurchaseUnit @@ -129,7 +134,11 @@ class PurchaseUnitFactory $shipping = isset($data->shipping) ? $this->shippingFactory->fromPayPalResponse($data->shipping) : null; - return new PurchaseUnit( + $payments = isset($data->payments) ? + $this->paymentsFactory->fromPayPalResponse($data->payments) : + null; + + $purchaseUnit = new PurchaseUnit( $amount, $items, $shipping, @@ -138,7 +147,9 @@ class PurchaseUnitFactory $payee, $customId, $invoiceId, - $softDescriptor + $softDescriptor, + $payments ); + return $purchaseUnit; } } From c7f437b2b635a95f1356902cf899cc6440cdffe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Tue, 14 Apr 2020 19:19:29 +0300 Subject: [PATCH 20/61] WIP payment capture --- .../src/Endpoint/PaymentsEndpoint.php | 15 +++++----- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 28 +++++++++++-------- .../ppcp-wc-gateway/src/WcGatewayModule.php | 2 +- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php index 63aaddfa7..4bcdc72bd 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php @@ -5,26 +5,26 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint; use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer; -use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationsFactory; +use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory; class PaymentsEndpoint { private $host; private $bearer; - private $authorizationsFactory; + private $authorizationFactory; private $errorResponseFactory; public function __construct( string $host, Bearer $bearer, - AuthorizationsFactory $authorizationsFactory, + AuthorizationFactory $authorizationsFactory, ErrorResponseCollectionFactory $errorResponseFactory ) { $this->host = $host; $this->bearer = $bearer; - $this->authorizationsFactory = $authorizationsFactory; + $this->authorizationFactory = $authorizationsFactory; $this->errorResponseFactory = $errorResponseFactory; } @@ -61,11 +61,11 @@ class PaymentsEndpoint } $json = json_decode($response['body']); - $authorization = $this->authorizationsFactory->fromPayPalRequest($json); + $authorization = $this->authorizationFactory->fromPayPalRequest($json); return $authorization; } - public function captureAuthorization($authorizationId) + public function capture($authorizationId) { $bearer = $this->bearer->bearer(); $url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId . '/capture'; @@ -98,6 +98,7 @@ class PaymentsEndpoint } $json = json_decode($response['body']); - return $json; + $authorization = $this->authorizationFactory->fromPayPalRequest($json); + return $authorization; } } diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 8127d9cab..277d4ce95 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -6,6 +6,8 @@ namespace Inpsyde\PayPalCommerce\WcGateway\Gateway; use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint; +use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization; +use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus; use Inpsyde\PayPalCommerce\ApiClient\Entity\Order; use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus; use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; @@ -116,7 +118,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface ]; } - public function authorizeOrder(\WC_Order $wcOrder) + public function captureAuthorizedPayment(\WC_Order $wcOrder) { $payPalOrderId = get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); @@ -127,16 +129,20 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface return; } - if ($order->status()->is(OrderStatus::COMPLETED)) { - AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_AUTHORIZED); - return; - } - - try { - $this->orderEndpoint->authorize($payPalOrderId); - } catch (RuntimeException $exception) { - AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); - return; + foreach ($order->purchaseUnits() as $purchaseUnit) { + foreach ($purchaseUnit->payments()->authorizations() as $authorization) { + /** + * @var Authorization $authorization; + */ + if ($authorization->status()->name() === AuthorizationStatus::CREATED) { + try { + $result = $this->paymentsEndpoint->capture($authorization->id()); + } catch (RuntimeException $exception) { + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); + return; + } + } + } } AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::SUCCESS); diff --git a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php index 4c862f461..e61014a11 100644 --- a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php +++ b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php @@ -74,7 +74,7 @@ class WcGatewayModule implements ModuleInterface * @var WcGateway $gateway */ $gateway = $container->get('wcgateway.gateway'); - $gateway->authorizeOrder($wcOrder); + $gateway->captureAuthorizedPayment($wcOrder); } ); From df9a74d551ad6f046d6082c57552d4f5e3da4bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 10:57:46 +0300 Subject: [PATCH 21/61] Add type hint and docblock for the type --- .../ppcp-api-client/src/Endpoint/PaymentsEndpoint.php | 6 +++--- modules.local/ppcp-api-client/src/Entity/Payments.php | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php index 4bcdc72bd..d61b953d5 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint; use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer; +use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization; use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory; @@ -21,14 +22,13 @@ class PaymentsEndpoint AuthorizationFactory $authorizationsFactory, ErrorResponseCollectionFactory $errorResponseFactory ) { - $this->host = $host; $this->bearer = $bearer; $this->authorizationFactory = $authorizationsFactory; $this->errorResponseFactory = $errorResponseFactory; } - public function authorization($authorizationId) + public function authorization(string $authorizationId): Authorization { $bearer = $this->bearer->bearer(); $url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId; @@ -65,7 +65,7 @@ class PaymentsEndpoint return $authorization; } - public function capture($authorizationId) + public function capture(string $authorizationId): Authorization { $bearer = $this->bearer->bearer(); $url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId . '/capture'; diff --git a/modules.local/ppcp-api-client/src/Entity/Payments.php b/modules.local/ppcp-api-client/src/Entity/Payments.php index 7a81141da..82cbcb05e 100644 --- a/modules.local/ppcp-api-client/src/Entity/Payments.php +++ b/modules.local/ppcp-api-client/src/Entity/Payments.php @@ -1,4 +1,5 @@ authorizations = $authorizations; } @@ -19,7 +20,10 @@ class Payments ]; } - public function authorizations() : array + /** + * @return Authorization[] + **/ + public function authorizations(): array { return $this->authorizations; } From d989617f6989143901151b3f65f47bfe5dcac19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:14:26 +0300 Subject: [PATCH 22/61] Pass the errors to the ErrorResponse handler --- .../src/Endpoint/PaymentsEndpoint.php | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php index d61b953d5..a5e9d0a05 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php @@ -41,8 +41,10 @@ class PaymentsEndpoint ]; $response = wp_remote_get($url, $args); + $json = json_decode($response['body']); if (is_wp_error($response)) { + $this->handleResponseWpError($url, $args); throw new RuntimeException( __( 'Could not get authorized payment info.', @@ -52,6 +54,13 @@ class PaymentsEndpoint } if (wp_remote_retrieve_response_code($response) !== 200) { + $errors = $this->errorResponseFactory->fromPayPalResponse( + $json, + (int)wp_remote_retrieve_response_code($response), + $url, + $args + ); + add_action('woocommerce-paypal-commerce-gateway.error', $errors); throw new RuntimeException( __( 'Could not get authorized payment info.', @@ -60,7 +69,6 @@ class PaymentsEndpoint ); } - $json = json_decode($response['body']); $authorization = $this->authorizationFactory->fromPayPalRequest($json); return $authorization; } @@ -78,8 +86,10 @@ class PaymentsEndpoint ]; $response = wp_remote_post($url, $args); + $json = json_decode($response['body']); if (is_wp_error($response)) { + $this->handleResponseWpError($url, $args); throw new RuntimeException( __( 'Could not capture authorized payment.', @@ -89,6 +99,13 @@ class PaymentsEndpoint } if (wp_remote_retrieve_response_code($response) !== 201) { + $errors = $this->errorResponseFactory->fromPayPalResponse( + $json, + (int)wp_remote_retrieve_response_code($response), + $url, + $args + ); + add_action('woocommerce-paypal-commerce-gateway.error', $errors); throw new RuntimeException( __( 'Could not capture authorized payment.', @@ -97,8 +114,16 @@ class PaymentsEndpoint ); } - $json = json_decode($response['body']); $authorization = $this->authorizationFactory->fromPayPalRequest($json); return $authorization; } + + private function handleResponseWpError(string $url, array $args) + { + $errors = $this->errorResponseFactory->unknownError( + $url, + $args + ); + add_action('woocommerce-paypal-commerce-gateway.error', $errors); + } } From edf4972c3afdc3372d1a35795f4881bb4f57d2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:27:00 +0300 Subject: [PATCH 23/61] Fix variable assignment --- .../ppcp-api-client/src/Factory/PurchaseUnitFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php b/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php index cb346881c..7d33c15d1 100644 --- a/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/PurchaseUnitFactory.php @@ -33,7 +33,7 @@ class PurchaseUnitFactory $this->payeeFactory = $payeeFactory; $this->itemFactory = $itemFactory; $this->shippingFactory = $shippingFactory; - $this->$paymentsFactory = $paymentsFactory; + $this->paymentsFactory = $paymentsFactory; } public function fromWcOrder(\WC_Order $order) : PurchaseUnit From 117e3f54bebf8f97c26a9168d680265c1a026c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:27:26 +0300 Subject: [PATCH 24/61] Add returned data to toArray method --- .../ppcp-api-client/src/Entity/Authorization.php | 8 ++++++++ modules.local/ppcp-api-client/src/Entity/Payments.php | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Entity/Authorization.php b/modules.local/ppcp-api-client/src/Entity/Authorization.php index add288ea5..13500188d 100644 --- a/modules.local/ppcp-api-client/src/Entity/Authorization.php +++ b/modules.local/ppcp-api-client/src/Entity/Authorization.php @@ -27,4 +27,12 @@ class Authorization { return $this->authorizationStatus; } + + public function toArray(): array + { + return [ + 'id' => $this->id, + 'status' => $this->authorizationStatus->name(), + ]; + } } diff --git a/modules.local/ppcp-api-client/src/Entity/Payments.php b/modules.local/ppcp-api-client/src/Entity/Payments.php index 82cbcb05e..4d9083c03 100644 --- a/modules.local/ppcp-api-client/src/Entity/Payments.php +++ b/modules.local/ppcp-api-client/src/Entity/Payments.php @@ -13,10 +13,15 @@ class Payments $this->authorizations = $authorizations; } - public function toArray() + public function toArray(): array { return [ - + 'authorizations' => array_map( + function (Authorization $authorization) { + return $authorization->toArray(); + }, + $this->authorizations() + ) ]; } From c6b59484991d2867dba0dd57334891ac95667bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:27:38 +0300 Subject: [PATCH 25/61] Add missing return type --- modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php b/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php index 3263621bd..114336663 100644 --- a/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php @@ -18,7 +18,7 @@ class PaymentsFactory $this->authorizationsFactory = $authorizationsFactory; } - public function fromPayPalResponse(\stdClass $data) + public function fromPayPalResponse(\stdClass $data): Payments { $authorizations = array_map( function (\stdClass $authorization): Authorization { From 5ce264a508912d71c738af7a2f125ca3eecc49a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:57:22 +0300 Subject: [PATCH 26/61] Add payments method to the PurchaseUnit.php --- modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php b/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php index dbbab80ff..169558b75 100644 --- a/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php +++ b/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php @@ -90,6 +90,10 @@ class PurchaseUnit return $this->payee; } + public function payments() : ?Payments { + return $this->payments; + } + /** * @return Item[] */ From 9d01e6c02f5e6faec2b0a83673a32d17a5d16645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:57:54 +0300 Subject: [PATCH 27/61] Deal with missing phone type --- modules.local/ppcp-api-client/src/Factory/PayerFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/src/Factory/PayerFactory.php b/modules.local/ppcp-api-client/src/Factory/PayerFactory.php index f061fed3b..f1245f002 100644 --- a/modules.local/ppcp-api-client/src/Factory/PayerFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/PayerFactory.php @@ -26,7 +26,7 @@ class PayerFactory $data->name->surname ); $phone = (isset($data->phone)) ? new PhoneWithType( - $data->phone->type, + (isset($data->phone->type)) ? $data->phone->type : 'undefined', new Phone( $data->phone->phone_number->national_number ) From d1bd60b5a7f85cdb4e39cd2a0aa67569a87c4432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:58:14 +0300 Subject: [PATCH 28/61] Fix expected type --- modules.local/ppcp-api-client/src/Entity/Payments.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/src/Entity/Payments.php b/modules.local/ppcp-api-client/src/Entity/Payments.php index 4d9083c03..445049024 100644 --- a/modules.local/ppcp-api-client/src/Entity/Payments.php +++ b/modules.local/ppcp-api-client/src/Entity/Payments.php @@ -8,7 +8,10 @@ class Payments { private $authorizations; - public function __construct(Authorization ...$authorizations) + /** + * @var Authorization[] $authorizations + */ + public function __construct(array $authorizations) { $this->authorizations = $authorizations; } From f482bbfc26926ea363b089c3abdf1fe7bd653ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 11:58:36 +0300 Subject: [PATCH 29/61] Add DocBlocks for autocomplete --- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 277d4ce95..5ea6f1903 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -10,6 +10,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization; use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus; use Inpsyde\PayPalCommerce\ApiClient\Entity\Order; use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus; +use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory; use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository; @@ -130,6 +131,9 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface } foreach ($order->purchaseUnits() as $purchaseUnit) { + /** + * @var PurchaseUnit $purchaseUnit + */ foreach ($purchaseUnit->payments()->authorizations() as $authorization) { /** * @var Authorization $authorization; From 3cebbd8237075e12a7a8b30460884807535e5569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 12:26:03 +0300 Subject: [PATCH 30/61] Only capture those that have the created status --- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 5ea6f1903..fc26ebd56 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -10,7 +10,6 @@ use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization; use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus; use Inpsyde\PayPalCommerce\ApiClient\Entity\Order; use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus; -use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory; use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository; @@ -41,7 +40,6 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface OrderFactory $orderFactory, SettingsFields $settingsFields ) { - $this->sessionHandler = $sessionHandler; $this->cartRepository = $cartRepository; $this->orderEndpoint = $orderEndpoint; @@ -130,22 +128,37 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface return; } + $allAuthorizations = []; foreach ($order->purchaseUnits() as $purchaseUnit) { - /** - * @var PurchaseUnit $purchaseUnit - */ foreach ($purchaseUnit->payments()->authorizations() as $authorization) { + $allAuthorizations[] = $authorization; + } + } + $authorizationsWithCreatedStatus = array_filter( + $allAuthorizations, + function (Authorization $authorization) { + return $authorization->status()->is(AuthorizationStatus::CREATED); + }); + $authorizationsWithCapturedStatus = array_filter( + $allAuthorizations, + function (Authorization $authorization) { + return $authorization->status()->is(AuthorizationStatus::CAPTURED); + }); + + if (count($authorizationsWithCapturedStatus) === count($allAuthorizations)) { + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_AUTHORIZED); + return; + } + + foreach ($authorizationsWithCreatedStatus as $authorization) { + try { /** * @var Authorization $authorization; */ - if ($authorization->status()->name() === AuthorizationStatus::CREATED) { - try { - $result = $this->paymentsEndpoint->capture($authorization->id()); - } catch (RuntimeException $exception) { - AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); - return; - } - } + $result = $this->paymentsEndpoint->capture($authorization->id()); + } catch (RuntimeException $exception) { + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); + return; } } From 715c9d29a499142d0975076fdb536d2b44e7e830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 12:44:28 +0300 Subject: [PATCH 31/61] Update the status to processing if it was not when all are captured --- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index fc26ebd56..86b73df82 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -146,6 +146,16 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface }); if (count($authorizationsWithCapturedStatus) === count($allAuthorizations)) { + if ($wcOrder->get_status() === 'on-hold') { + $wcOrder->add_order_note( + __( + 'Payment successfully authorized.', + 'woocommerce-paypal-gateway' + ) + ); + + $wcOrder->update_status('processing'); + } AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_AUTHORIZED); return; } From ff4f3d2bba9ee2a7c1d3b89198cd0eca2f748d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 13:32:28 +0300 Subject: [PATCH 32/61] Add todo for dealing with phone without types --- modules.local/ppcp-api-client/src/Factory/PayerFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules.local/ppcp-api-client/src/Factory/PayerFactory.php b/modules.local/ppcp-api-client/src/Factory/PayerFactory.php index f1245f002..173092fd2 100644 --- a/modules.local/ppcp-api-client/src/Factory/PayerFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/PayerFactory.php @@ -25,6 +25,7 @@ class PayerFactory $data->name->given_name, $data->name->surname ); + // TODO deal with phones without type instead of passing a invalid type $phone = (isset($data->phone)) ? new PhoneWithType( (isset($data->phone->type)) ? $data->phone->type : 'undefined', new Phone( From 5fda97307b050debc05b4d0b04912c097ab1223b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 13:46:44 +0300 Subject: [PATCH 33/61] Enforce array elements type for Payments constructor --- modules.local/ppcp-api-client/src/Entity/Payments.php | 5 +---- .../ppcp-api-client/src/Factory/PaymentsFactory.php | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Entity/Payments.php b/modules.local/ppcp-api-client/src/Entity/Payments.php index 445049024..4d9083c03 100644 --- a/modules.local/ppcp-api-client/src/Entity/Payments.php +++ b/modules.local/ppcp-api-client/src/Entity/Payments.php @@ -8,10 +8,7 @@ class Payments { private $authorizations; - /** - * @var Authorization[] $authorizations - */ - public function __construct(array $authorizations) + public function __construct(Authorization ...$authorizations) { $this->authorizations = $authorizations; } diff --git a/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php b/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php index 114336663..b99971812 100644 --- a/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/PaymentsFactory.php @@ -26,7 +26,7 @@ class PaymentsFactory }, $data->authorizations ); - $payments = new Payments($authorizations); + $payments = new Payments(...$authorizations); return $payments; } } From 55c3bcefc59ee2144e9acc9f9d3f42f6b70e10f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 13:51:06 +0300 Subject: [PATCH 34/61] After Code Beautifier and Fixer --- .../ppcp-api-client/src/Endpoint/PaymentsEndpoint.php | 2 ++ .../src/Entity/ErrorResponseCollection.php | 2 +- modules.local/ppcp-api-client/src/Entity/Payments.php | 2 +- .../ppcp-api-client/src/Entity/PurchaseUnit.php | 10 +++++----- .../ppcp-api-client/src/Factory/ItemFactory.php | 11 ++++++----- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 9 ++++++--- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php index a5e9d0a05..6cde2c11a 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php @@ -6,6 +6,7 @@ namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint; use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer; use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization; +use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory; @@ -22,6 +23,7 @@ class PaymentsEndpoint AuthorizationFactory $authorizationsFactory, ErrorResponseCollectionFactory $errorResponseFactory ) { + $this->host = $host; $this->bearer = $bearer; $this->authorizationFactory = $authorizationsFactory; diff --git a/modules.local/ppcp-api-client/src/Entity/ErrorResponseCollection.php b/modules.local/ppcp-api-client/src/Entity/ErrorResponseCollection.php index 9440bd9a3..778164ebc 100644 --- a/modules.local/ppcp-api-client/src/Entity/ErrorResponseCollection.php +++ b/modules.local/ppcp-api-client/src/Entity/ErrorResponseCollection.php @@ -24,7 +24,7 @@ class ErrorResponseCollection public function codes() : array { return array_values(array_map( - function(ErrorResponse $error) : string { + function (ErrorResponse $error) : string { return $error->code(); }, $this->errors() diff --git a/modules.local/ppcp-api-client/src/Entity/Payments.php b/modules.local/ppcp-api-client/src/Entity/Payments.php index 4d9083c03..a0448c498 100644 --- a/modules.local/ppcp-api-client/src/Entity/Payments.php +++ b/modules.local/ppcp-api-client/src/Entity/Payments.php @@ -21,7 +21,7 @@ class Payments return $authorization->toArray(); }, $this->authorizations() - ) + ), ]; } diff --git a/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php b/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php index 169558b75..380e32168 100644 --- a/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php +++ b/modules.local/ppcp-api-client/src/Entity/PurchaseUnit.php @@ -36,7 +36,7 @@ class PurchaseUnit $this->referenceId = $referenceId; $this->description = $description; //phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType - $this->items = array_values( array_filter( + $this->items = array_values(array_filter( $items, function ($item) : bool { return is_a($item, Item::class); @@ -90,7 +90,8 @@ class PurchaseUnit return $this->payee; } - public function payments() : ?Payments { + public function payments() : ?Payments + { return $this->payments; } @@ -110,9 +111,8 @@ class PurchaseUnit 'description' => $this->description(), 'items' => array_map(function (Item $item) : array { return $item->toArray(); - }, - $this->items() - ), + }, + $this->items()), ]; if ($this->ditchItemsWhenMismatch($this->amount(), ...$this->items())) { unset($purchaseUnit['items']); diff --git a/modules.local/ppcp-api-client/src/Factory/ItemFactory.php b/modules.local/ppcp-api-client/src/Factory/ItemFactory.php index 69939de80..6f9bacd77 100644 --- a/modules.local/ppcp-api-client/src/Factory/ItemFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/ItemFactory.php @@ -14,7 +14,8 @@ class ItemFactory { } - public function fromWcCart(\WC_Cart $cart) : array { + public function fromWcCart(\WC_Cart $cart) : array + { $currency = get_woocommerce_currency(); $items = array_map( function (array $item) use ($currency): Item { @@ -48,8 +49,8 @@ class ItemFactory * @param \WC_Order $order * @return Item[] */ - public function fromWcOrder(\WC_Order $order) : array { - + public function fromWcOrder(\WC_Order $order) : array + { return array_map( function (\WC_Order_Item_Product $item) use ($order): Item { return $this->fromWcOrderLineItem($item, $order); @@ -58,8 +59,8 @@ class ItemFactory ); } - private function fromWcOrderLineItem(\WC_Order_Item_Product $item, \WC_Order $order) : Item { - + private function fromWcOrderLineItem(\WC_Order_Item_Product $item, \WC_Order $order) : Item + { $currency = $order->get_currency(); $product = $item->get_product(); /** diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 86b73df82..c43a1e4a1 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -40,6 +40,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface OrderFactory $orderFactory, SettingsFields $settingsFields ) { + $this->sessionHandler = $sessionHandler; $this->cartRepository = $cartRepository; $this->orderEndpoint = $orderEndpoint; @@ -138,12 +139,14 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface $allAuthorizations, function (Authorization $authorization) { return $authorization->status()->is(AuthorizationStatus::CREATED); - }); + } + ); $authorizationsWithCapturedStatus = array_filter( $allAuthorizations, function (Authorization $authorization) { return $authorization->status()->is(AuthorizationStatus::CAPTURED); - }); + } + ); if (count($authorizationsWithCapturedStatus) === count($allAuthorizations)) { if ($wcOrder->get_status() === 'on-hold') { @@ -163,7 +166,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface foreach ($authorizationsWithCreatedStatus as $authorization) { try { /** - * @var Authorization $authorization; + * @var Authorization $authorization */ $result = $this->paymentsEndpoint->capture($authorization->id()); } catch (RuntimeException $exception) { From 3c69b11fea8cfdcecd4a22b4d2d9472004820160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 14:03:39 +0300 Subject: [PATCH 35/61] Rename add_action to do_action --- .../ppcp-api-client/src/Endpoint/PaymentsEndpoint.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php index 6cde2c11a..cd563ad89 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php @@ -62,7 +62,7 @@ class PaymentsEndpoint $url, $args ); - add_action('woocommerce-paypal-commerce-gateway.error', $errors); + do_action('woocommerce-paypal-commerce-gateway.error', $errors); throw new RuntimeException( __( 'Could not get authorized payment info.', @@ -107,7 +107,7 @@ class PaymentsEndpoint $url, $args ); - add_action('woocommerce-paypal-commerce-gateway.error', $errors); + do_action('woocommerce-paypal-commerce-gateway.error', $errors); throw new RuntimeException( __( 'Could not capture authorized payment.', @@ -126,6 +126,6 @@ class PaymentsEndpoint $url, $args ); - add_action('woocommerce-paypal-commerce-gateway.error', $errors); + do_action('woocommerce-paypal-commerce-gateway.error', $errors); } } From 380f0180187a7d60efce9d90d970bc20aacceaf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 14:54:50 +0300 Subject: [PATCH 36/61] Pass intent to the mocked OrderEndpoint --- .../PHPUnit/Endpoint/OrderEndpointTest.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php index 5136975ab..69cbe00e3 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php @@ -15,6 +15,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory; use Inpsyde\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory; use Inpsyde\PayPalCommerce\ApiClient\TestCase; use Mockery; + use function Brain\Monkey\Functions\expect; class OrderEndpointTest extends TestCase @@ -33,12 +34,14 @@ class OrderEndpointTest extends TestCase return ($object->is_correct) ? $order : null; }); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $testee = new OrderEndpoint( $host, $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -75,6 +78,7 @@ class OrderEndpointTest extends TestCase $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory ->expects('unknownError') ->withSomeOfArgs($host . 'v2/checkout/orders/' . $orderId) @@ -84,6 +88,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -106,6 +111,7 @@ class OrderEndpointTest extends TestCase ->expects('bearer')->andReturn('bearer'); $orderFactory = Mockery::mock(OrderFactory::class); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $rawResponse = ['body' => '{"some_error":true}']; $error = Mockery::mock(ErrorResponseCollection::class); @@ -138,6 +144,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -179,6 +186,7 @@ class OrderEndpointTest extends TestCase } ); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $testee = new OrderEndpoint( @@ -186,6 +194,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -225,6 +234,7 @@ class OrderEndpointTest extends TestCase $bearer = Mockery::mock(Bearer::class); $orderFactory = Mockery::mock(OrderFactory::class); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $testee = new OrderEndpoint( @@ -232,6 +242,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -254,6 +265,7 @@ class OrderEndpointTest extends TestCase $bearer->expects('bearer')->andReturn('bearer'); $orderFactory = Mockery::mock(OrderFactory::class); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); $errorResponseCollectionFactory @@ -265,6 +277,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -292,6 +305,7 @@ class OrderEndpointTest extends TestCase $bearer->expects('bearer')->andReturn('bearer'); $orderFactory = Mockery::mock(OrderFactory::class); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); $error->expects('hasErrorCode')->with('ORDER_ALREADY_CAPTURED')->andReturn(false); @@ -324,6 +338,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -352,6 +367,7 @@ class OrderEndpointTest extends TestCase $bearer->expects('bearer')->andReturn('bearer'); $orderFactory = Mockery::mock(OrderFactory::class); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); $error->expects('hasErrorCode')->with('ORDER_ALREADY_CAPTURED')->andReturn(true); @@ -386,6 +402,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory, ] )->makePartial(); @@ -429,6 +446,7 @@ class OrderEndpointTest extends TestCase ->expects('fromOrders') ->with($orderToUpdate, $orderToCompare) ->andReturn($patchCollection); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $testee = Mockery::mock( @@ -438,6 +456,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ] )->makePartial(); @@ -507,6 +526,7 @@ class OrderEndpointTest extends TestCase ->expects('fromOrders') ->with($orderToUpdate, $orderToCompare) ->andReturn($patchCollection); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); $errorResponseCollectionFactory @@ -535,6 +555,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -601,6 +622,7 @@ class OrderEndpointTest extends TestCase ->expects('fromOrders') ->with($orderToUpdate, $orderToCompare) ->andReturn($patchCollection); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); $errorResponseCollectionFactory @@ -615,6 +637,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ] )->makePartial(); @@ -670,6 +693,7 @@ class OrderEndpointTest extends TestCase ->expects('fromOrders') ->with($orderToUpdate, $orderToCompare) ->andReturn($patchCollection); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $testee = new OrderEndpoint( @@ -677,6 +701,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -703,6 +728,7 @@ class OrderEndpointTest extends TestCase return $expectedOrder; }); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $testee = new OrderEndpoint( @@ -710,6 +736,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -759,6 +786,7 @@ class OrderEndpointTest extends TestCase ->andReturn('bearer'); $orderFactory = Mockery::mock(OrderFactory::class); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); @@ -772,6 +800,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -821,6 +850,7 @@ class OrderEndpointTest extends TestCase ->andReturn('bearer'); $orderFactory = Mockery::mock(OrderFactory::class); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $error = Mockery::mock(ErrorResponseCollection::class); @@ -850,6 +880,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); From f1b8ee128a3ddbe94eb4db6995ccc5270fb073cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 15:08:07 +0300 Subject: [PATCH 37/61] Pass missing mocked PaymentsFactory --- .../Factory/PurchaseUnitFactoryTest.php | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php index 5540b587a..3c3e3cddb 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php @@ -11,9 +11,10 @@ use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use Inpsyde\PayPalCommerce\ApiClient\Entity\Shipping; use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository; use Inpsyde\PayPalCommerce\ApiClient\TestCase; -use function Brain\Monkey\Functions\expect; use Mockery; +use function Brain\Monkey\Functions\expect; + class PurchaseUnitFactoryTest extends TestCase { @@ -54,12 +55,14 @@ class PurchaseUnitFactoryTest extends TestCase ->shouldReceive('fromWcOrder') ->with($wcOrder) ->andReturn($shipping); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $unit = $testee->fromWcOrder($wcOrder); @@ -113,12 +116,14 @@ class PurchaseUnitFactoryTest extends TestCase ->expects('fromWcOrder') ->with($wcOrder) ->andReturn($shipping); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $unit = $testee->fromWcOrder($wcOrder); @@ -158,12 +163,14 @@ class PurchaseUnitFactoryTest extends TestCase ->expects('fromWcOrder') ->with($wcOrder) ->andReturn($shipping); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $unit = $testee->fromWcOrder($wcOrder); @@ -212,12 +219,14 @@ class PurchaseUnitFactoryTest extends TestCase ->expects('fromWcCustomer') ->with($wcCustomer) ->andReturn($shipping); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $unit = $testee->fromWcCart($wcCart); @@ -256,13 +265,14 @@ class PurchaseUnitFactoryTest extends TestCase ->with($wcCart) ->andReturn([]); $shippingFactory = Mockery::mock(ShippingFactory::class); - + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $unit = $testee->fromWcCart($wcCart); @@ -308,13 +318,14 @@ class PurchaseUnitFactoryTest extends TestCase $shippingFactory ->expects('fromWcCustomer') ->andReturn($shipping); - + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $unit = $testee->fromWcCart($wcCart); @@ -357,13 +368,14 @@ class PurchaseUnitFactoryTest extends TestCase $shippingFactory ->expects('fromWcCustomer') ->andReturn($shipping); - + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $unit = $testee->fromWcCart($wcCart); @@ -389,12 +401,14 @@ class PurchaseUnitFactoryTest extends TestCase $shippingFactory = Mockery::mock(ShippingFactory::class); $shipping = Mockery::mock(Shipping::class); $shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $response = (object) [ @@ -440,12 +454,14 @@ class PurchaseUnitFactoryTest extends TestCase $shippingFactory = Mockery::mock(ShippingFactory::class); $shipping = Mockery::mock(Shipping::class); $shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $response = (object) [ @@ -480,12 +496,14 @@ class PurchaseUnitFactoryTest extends TestCase $item = Mockery::mock(Item::class); $itemFactory->expects('fromPayPalResponse')->with($rawItem)->andReturn($item); $shippingFactory = Mockery::mock(ShippingFactory::class); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $response = (object) [ @@ -509,12 +527,14 @@ class PurchaseUnitFactoryTest extends TestCase $payeeRepository = Mockery::mock(PayeeRepository::class); $itemFactory = Mockery::mock(ItemFactory::class); $shippingFactory = Mockery::mock(ShippingFactory::class); + $paymentsFacory = Mockery::mock(PaymentsFactory::class); $testee = new PurchaseUnitFactory( $amountFactory, $payeeRepository, $payeeFactory, $itemFactory, - $shippingFactory + $shippingFactory, + $paymentsFacory ); $response = (object) [ From 60e979a4a20ce592e89762c33acf276bda32193d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 16:17:33 +0300 Subject: [PATCH 38/61] Add test to check the payments are added when the PayPal response contains it --- .../Factory/PurchaseUnitFactoryTest.php | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php index 3c3e3cddb..869cc6276 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php @@ -552,4 +552,55 @@ class PurchaseUnitFactoryTest extends TestCase $testee->fromPayPalResponse($response); } + public function testFromPayPalResponsePaymentsGetAppended() + { + $rawItem = (object)['items' => 1]; + $rawAmount = (object)['amount' => 1]; + $rawPayee = (object)['payee' => 1]; + $rawShipping = (object)['shipping' => 1]; + $rawPayments = (object)['payments' => 1]; + + $amountFactory = Mockery::mock(AmountFactory::class); + $amount = Mockery::mock(Amount::class); + $amountFactory->expects('fromPayPalResponse')->with($rawAmount)->andReturn($amount); + $payeeFactory = Mockery::mock(PayeeFactory::class); + $payee = Mockery::mock(Payee::class); + $payeeFactory->expects('fromPayPalResponse')->with($rawPayee)->andReturn($payee); + $payeeRepository = Mockery::mock(PayeeRepository::class); + $itemFactory = Mockery::mock(ItemFactory::class); + $item = Mockery::mock(Item::class); + $itemFactory->expects('fromPayPalResponse')->with($rawItem)->andReturn($item); + $shippingFactory = Mockery::mock(ShippingFactory::class); + $shipping = Mockery::mock(Shipping::class); + $shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping); + + $paymentsFactory = Mockery::mock(PaymentsFactory::class); + $payments = Mockery::mock(Payments::class); + $paymentsFactory->expects('fromPayPalResponse')->with($rawPayments)->andReturn($payments); + + $testee = new PurchaseUnitFactory( + $amountFactory, + $payeeRepository, + $payeeFactory, + $itemFactory, + $shippingFactory, + $paymentsFactory + ); + + $response = (object)[ + 'reference_id' => 'default', + 'description' => 'description', + 'customId' => 'customId', + 'invoiceId' => 'invoiceId', + 'softDescriptor' => 'softDescriptor', + 'amount' => $rawAmount, + 'items' => [$rawItem], + 'payee' => $rawPayee, + 'shipping' => $rawShipping, + 'payments' => $rawPayments, + ]; + + $unit = $testee->fromPayPalResponse($response); + $this->assertEquals($payments, $unit->payments()); + } } \ No newline at end of file From 0494b5e71ee38ea5c7193fb2c37ccbcb430f1a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 16:42:27 +0300 Subject: [PATCH 39/61] Test for Authorization --- .../PHPUnit/Entity/AuthorizationTest.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php new file mode 100644 index 000000000..7a84eef31 --- /dev/null +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php @@ -0,0 +1,33 @@ +assertEquals('foo', $testee->id()); + $this->assertEquals($authorizationStatus, $testee->status()); + } + + public function testToArray() + { + $authorizationStatus = \Mockery::mock(AuthorizationStatus::class); + $authorizationStatus->expects('name')->andReturn('CAPTURED'); + + $testee = new Authorization('foo', $authorizationStatus); + + $expected = [ + 'id' => 'foo', + 'status' => 'CAPTURED', + ]; + $this->assertEquals($expected, $testee->toArray()); + } +} From f3ef9fe8a6fc25ea9a1969e27c06b3c0691e8089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 16:45:31 +0300 Subject: [PATCH 40/61] CamelCaseThatMethod --- .../ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php index 7a84eef31..bbada5e45 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationTest.php @@ -8,7 +8,7 @@ use Inpsyde\PayPalCommerce\ApiClient\TestCase; class AuthorizationTest extends TestCase { - public function testIdandStatus() + public function testIdAndStatus() { $authorizationStatus = \Mockery::mock(AuthorizationStatus::class); $testee = new Authorization('foo', $authorizationStatus); From 48970fa4b7d92d0ed45f786b76044013ddf104cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 16:53:21 +0300 Subject: [PATCH 41/61] Add testFromPayPalResponsePaymentsIsNull test --- .../Factory/PurchaseUnitFactoryTest.php | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php index 869cc6276..99b35f71a 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php @@ -603,4 +603,53 @@ class PurchaseUnitFactoryTest extends TestCase $unit = $testee->fromPayPalResponse($response); $this->assertEquals($payments, $unit->payments()); } + + public function testFromPayPalResponsePaymentsIsNull() + { + $rawItem = (object)['items' => 1]; + $rawAmount = (object)['amount' => 1]; + $rawPayee = (object)['payee' => 1]; + $rawShipping = (object)['shipping' => 1]; + $rawPayments = (object)['payments' => 1]; + + $amountFactory = Mockery::mock(AmountFactory::class); + $amount = Mockery::mock(Amount::class); + $amountFactory->expects('fromPayPalResponse')->with($rawAmount)->andReturn($amount); + $payeeFactory = Mockery::mock(PayeeFactory::class); + $payee = Mockery::mock(Payee::class); + $payeeFactory->expects('fromPayPalResponse')->with($rawPayee)->andReturn($payee); + $payeeRepository = Mockery::mock(PayeeRepository::class); + $itemFactory = Mockery::mock(ItemFactory::class); + $item = Mockery::mock(Item::class); + $itemFactory->expects('fromPayPalResponse')->with($rawItem)->andReturn($item); + $shippingFactory = Mockery::mock(ShippingFactory::class); + $shipping = Mockery::mock(Shipping::class); + $shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping); + + $paymentsFactory = Mockery::mock(PaymentsFactory::class); + + $testee = new PurchaseUnitFactory( + $amountFactory, + $payeeRepository, + $payeeFactory, + $itemFactory, + $shippingFactory, + $paymentsFactory + ); + + $response = (object)[ + 'reference_id' => 'default', + 'description' => 'description', + 'customId' => 'customId', + 'invoiceId' => 'invoiceId', + 'softDescriptor' => 'softDescriptor', + 'amount' => $rawAmount, + 'items' => [$rawItem], + 'payee' => $rawPayee, + 'shipping' => $rawShipping, + ]; + + $unit = $testee->fromPayPalResponse($response); + $this->assertNull($unit->payments()); + } } \ No newline at end of file From ed8ec50601a198058612f2558b340e3c71307f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 15 Apr 2020 17:26:19 +0300 Subject: [PATCH 42/61] Add test for AuthorizationStatus --- .../src/Entity/AuthorizationStatus.php | 2 + .../Entity/AuthorizationStatusTest.php | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationStatusTest.php diff --git a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php index b966e8e98..073bb85d5 100644 --- a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php +++ b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\ApiClient\Entity; +use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; + class AuthorizationStatus { const INTERNAL = 'INTERNAL'; diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationStatusTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationStatusTest.php new file mode 100644 index 000000000..b8870e97e --- /dev/null +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/AuthorizationStatusTest.php @@ -0,0 +1,51 @@ +assertEquals($authorizationStatus->name(), $status); + } + + public function testInvalidStatusProvided() + { + $this->expectException(RuntimeException::class); + + new AuthorizationStatus('invalid'); + } + + public function testStatusComparision() + { + $authorizationStatus = new AuthorizationStatus('CREATED'); + + $this->assertTrue($authorizationStatus->is('CREATED')); + $this->assertFalse($authorizationStatus->is('NOT_CREATED')); + } + + public function statusDataProvider(): array + { + return [ + ['INTERNAL'], + ['CREATED'], + ['CAPTURED'], + ['DENIED'], + ['EXPIRED'], + ['PARTIALLY_CAPTURED'], + ['VOIDED'], + ['PENDING'], + ]; + } +} From 5427f4ae83c71fcc6c5327ededade916e3680678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 08:39:32 +0300 Subject: [PATCH 43/61] Fix class import --- .../tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php index 99b35f71a..4392dbb61 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PurchaseUnitFactoryTest.php @@ -7,6 +7,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Entity\Address; use Inpsyde\PayPalCommerce\ApiClient\Entity\Amount; use Inpsyde\PayPalCommerce\ApiClient\Entity\Item; use Inpsyde\PayPalCommerce\ApiClient\Entity\Payee; +use Inpsyde\PayPalCommerce\ApiClient\Entity\Payments; use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use Inpsyde\PayPalCommerce\ApiClient\Entity\Shipping; use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository; From c72e4aa50538ffd05f5b569c354ee5262a795e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 08:39:41 +0300 Subject: [PATCH 44/61] Test for AuthorizationFactory --- .../Factory/AuthorizationFactoryTest.php | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 modules.local/ppcp-api-client/tests/PHPUnit/Factory/AuthorizationFactoryTest.php diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/AuthorizationFactoryTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/AuthorizationFactoryTest.php new file mode 100644 index 000000000..4544f35ce --- /dev/null +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/AuthorizationFactoryTest.php @@ -0,0 +1,53 @@ + 'foo', + 'status' => 'CAPTURED', + ]; + + $testee = new AuthorizationFactory(); + $result = $testee->fromPayPalRequest($response); + + $this->assertInstanceOf(Authorization::class, $result); + + $this->assertEquals('foo', $result->id()); + $this->assertInstanceOf(AuthorizationStatus::class, $result->status()); + + $this->assertEquals('CAPTURED', $result->status()->name()); + } + + public function testReturnExceptionIdIsMissing() + { + $this->expectException(RuntimeException::class); + $response = (object)[ + 'status' => 'CAPTURED', + ]; + + $testee = new AuthorizationFactory(); + $testee->fromPayPalRequest($response); + } + + public function testReturnExceptionStatusIsMissing() + { + $this->expectException(RuntimeException::class); + $response = (object)[ + 'id' => 'foo', + ]; + + $testee = new AuthorizationFactory(); + $testee->fromPayPalRequest($response); + } +} From e95240530ae9575daa9de4caa1c11d393530e76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 11:27:40 +0300 Subject: [PATCH 45/61] Test for PaymentsEndpoint authorize endpoint --- .../PHPUnit/Endpoint/PaymentsEndpointTest.php | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php new file mode 100644 index 000000000..a3b7d7902 --- /dev/null +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php @@ -0,0 +1,157 @@ +expects('bearer')->andReturn('bearer'); + + $authorization = Mockery::mock(Authorization::class); + $authorizationFactory = Mockery::mock(AuthorizationFactory::class); + $authorizationFactory + ->expects('fromPayPalRequest') + ->andReturn($authorization); + + $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); + + $rawResponse = ['body' => '{"is_correct":true}']; + + $testee = new PaymentsEndpoint( + $host, + $bearer, + $authorizationFactory, + $errorResponseCollectionFactory + ); + + expect('wp_remote_get')->andReturnUsing( + function ($url, $args) use ($rawResponse, $host, $authorizationId) { + if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId) { + return false; + } + if ($args['headers']['Authorization'] !== 'Bearer bearer') { + return false; + } + if ($args['headers']['Content-Type'] !== 'application/json') { + return false; + } + + return $rawResponse; + } + ); + expect('is_wp_error')->with($rawResponse)->andReturn(false); + expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200); + + $result = $testee->authorization($authorizationId); + $this->assertEquals($authorization, $result); + } + + public function testAuthorizationDefaultIsWpError() + { + $host = 'https://example.com/'; + $authorizationId = 'somekindofid'; + + $bearer = Mockery::mock(Bearer::class); + $bearer->expects('bearer')->andReturn('bearer'); + + $authorizationFactory = Mockery::mock(AuthorizationFactory::class); + + $error = Mockery::mock(ErrorResponseCollection::class); + $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); + $errorResponseCollectionFactory + ->expects('unknownError') + ->withSomeOfArgs($host . 'v2/payments/authorizations/' . $authorizationId) + ->andReturn($error); + + $rawResponse = ['body' => '{"is_correct":true}']; + + $testee = new PaymentsEndpoint( + $host, + $bearer, + $authorizationFactory, + $errorResponseCollectionFactory + ); + + expect('wp_remote_get')->andReturn($rawResponse); + expect('is_wp_error')->with($rawResponse)->andReturn(true); + expect('do_action') + ->with('woocommerce-paypal-commerce-gateway.error', $error); + + $this->expectException(RuntimeException::class); + $testee->authorization($authorizationId); + } + + public function testAuthorizationDefaultIsNot200() { + $host = 'https://example.com/'; + $authorizationId = 'somekindofid'; + + $bearer = Mockery::mock(Bearer::class); + $bearer->expects('bearer')->andReturn('bearer'); + + $authorizationFactory = Mockery::mock(AuthorizationFactory::class); + + $rawResponse = ['body' => '{"some_error":true}']; + + $error = Mockery::mock(ErrorResponseCollection::class); + $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); + $errorResponseCollectionFactory + ->expects('fromPayPalResponse') + ->andReturnUsing( + function ($json, $status, $url, $args) use($error, $host, $authorizationId): ?ErrorResponseCollection { + $wrongError = Mockery::mock(ErrorResponseCollection::class); + if (! $json->some_error) { + return $wrongError; + } + if ($status !== 500) { + return $wrongError; + } + if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId) { + return $wrongError; + } + if ($args['headers']['Authorization'] !== 'Bearer bearer') { + return $wrongError; + } + if ($args['headers']['Content-Type'] !== 'application/json') { + return $wrongError; + } + return $error; + } + ); + + + $testee = new PaymentsEndpoint( + $host, + $bearer, + $authorizationFactory, + $errorResponseCollectionFactory + ); + + expect('wp_remote_get')->andReturn($rawResponse); + expect('is_wp_error')->with($rawResponse)->andReturn(false); + expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500); + expect('do_action') + ->with('woocommerce-paypal-commerce-gateway.error', $error); + + $this->expectException(RuntimeException::class); + $testee->authorization($authorizationId); + } +} From 7ca19777379eef3ef46287eb1e697b114f46259a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 11:33:49 +0300 Subject: [PATCH 46/61] Add missing intent to the testCreateForPurchaseUnitsWithPayer test --- .../tests/PHPUnit/Endpoint/OrderEndpointTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php index 2da17ec42..0c5df2972 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/OrderEndpointTest.php @@ -796,6 +796,7 @@ class OrderEndpointTest extends TestCase return $expectedOrder; }); $patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class); + $intent = 'CAPTURE'; $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); $testee = new OrderEndpoint( @@ -803,6 +804,7 @@ class OrderEndpointTest extends TestCase $bearer, $orderFactory, $patchCollectionFactory, + $intent, $errorResponseCollectionFactory ); @@ -974,4 +976,4 @@ class OrderEndpointTest extends TestCase $this->expectException(RuntimeException::class); $testee->createForPurchaseUnits([$purchaseUnit]); } -} \ No newline at end of file +} From 0ef3601f79e801a067495c1ccc2708aa73261895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 11:35:09 +0300 Subject: [PATCH 47/61] After Code Beautifier and Fixer --- .../tests/PHPUnit/Endpoint/PaymentsEndpointTest.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php index a3b7d7902..46b0d08bf 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php @@ -100,7 +100,8 @@ class PaymentsEndpointTest extends TestCase $testee->authorization($authorizationId); } - public function testAuthorizationDefaultIsNot200() { + public function testAuthorizationDefaultIsNot200() + { $host = 'https://example.com/'; $authorizationId = 'somekindofid'; @@ -116,9 +117,9 @@ class PaymentsEndpointTest extends TestCase $errorResponseCollectionFactory ->expects('fromPayPalResponse') ->andReturnUsing( - function ($json, $status, $url, $args) use($error, $host, $authorizationId): ?ErrorResponseCollection { + function ($json, $status, $url, $args) use ($error, $host, $authorizationId): ?ErrorResponseCollection { $wrongError = Mockery::mock(ErrorResponseCollection::class); - if (! $json->some_error) { + if (!$json->some_error) { return $wrongError; } if ($status !== 500) { @@ -133,11 +134,11 @@ class PaymentsEndpointTest extends TestCase if ($args['headers']['Content-Type'] !== 'application/json') { return $wrongError; } + return $error; } ); - $testee = new PaymentsEndpoint( $host, $bearer, From ad2b25b6006e52661582666eb488f66821c592d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 12:36:18 +0300 Subject: [PATCH 48/61] Add test for payments capture endpoint --- .../PHPUnit/Endpoint/PaymentsEndpointTest.php | 142 +++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php index 46b0d08bf..b82c3b1c2 100644 --- a/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Endpoint/PaymentsEndpointTest.php @@ -65,7 +65,7 @@ class PaymentsEndpointTest extends TestCase $this->assertEquals($authorization, $result); } - public function testAuthorizationDefaultIsWpError() + public function testAuthorizationWpError() { $host = 'https://example.com/'; $authorizationId = 'somekindofid'; @@ -100,7 +100,7 @@ class PaymentsEndpointTest extends TestCase $testee->authorization($authorizationId); } - public function testAuthorizationDefaultIsNot200() + public function testAuthorizationIsNot200() { $host = 'https://example.com/'; $authorizationId = 'somekindofid'; @@ -155,4 +155,142 @@ class PaymentsEndpointTest extends TestCase $this->expectException(RuntimeException::class); $testee->authorization($authorizationId); } + + public function testCaptureDefault() { + $host = 'https://example.com/'; + $authorizationId = 'somekindofid'; + + $bearer = Mockery::mock(Bearer::class); + $bearer + ->expects('bearer')->andReturn('bearer'); + + $authorization = Mockery::mock(Authorization::class); + $authorizationFactory = Mockery::mock(AuthorizationFactory::class); + $authorizationFactory + ->expects('fromPayPalRequest') + ->andReturn($authorization); + + $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); + + $rawResponse = ['body' => '{"is_correct":true}']; + + $testee = new PaymentsEndpoint( + $host, + $bearer, + $authorizationFactory, + $errorResponseCollectionFactory + ); + + expect('wp_remote_post')->andReturnUsing( + function ($url, $args) use ($rawResponse, $host, $authorizationId) { + if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId . '/capture') { + return false; + } + if ($args['headers']['Authorization'] !== 'Bearer bearer') { + return false; + } + if ($args['headers']['Content-Type'] !== 'application/json') { + return false; + } + + return $rawResponse; + } + ); + expect('is_wp_error')->with($rawResponse)->andReturn(false); + expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(201); + + $result = $testee->capture($authorizationId); + $this->assertEquals($authorization, $result); + } + + public function testCaptureIsWpError() { + $host = 'https://example.com/'; + $authorizationId = 'somekindofid'; + + $bearer = Mockery::mock(Bearer::class); + $bearer->expects('bearer')->andReturn('bearer'); + + $authorizationFactory = Mockery::mock(AuthorizationFactory::class); + + $error = Mockery::mock(ErrorResponseCollection::class); + $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); + $errorResponseCollectionFactory + ->expects('unknownError') + ->withSomeOfArgs($host . 'v2/payments/authorizations/' . $authorizationId . '/capture') + ->andReturn($error); + + $rawResponse = ['body' => '{"is_correct":true}']; + + $testee = new PaymentsEndpoint( + $host, + $bearer, + $authorizationFactory, + $errorResponseCollectionFactory + ); + + expect('wp_remote_post')->andReturn($rawResponse); + expect('is_wp_error')->with($rawResponse)->andReturn(true); + expect('do_action') + ->with('woocommerce-paypal-commerce-gateway.error', $error); + + $this->expectException(RuntimeException::class); + $testee->capture($authorizationId); + } + + public function testAuthorizationIsNot201() + { + $host = 'https://example.com/'; + $authorizationId = 'somekindofid'; + + $bearer = Mockery::mock(Bearer::class); + $bearer->expects('bearer')->andReturn('bearer'); + + $authorizationFactory = Mockery::mock(AuthorizationFactory::class); + + $rawResponse = ['body' => '{"some_error":true}']; + + $error = Mockery::mock(ErrorResponseCollection::class); + $errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class); + $errorResponseCollectionFactory + ->expects('fromPayPalResponse') + ->andReturnUsing( + function ($json, $status, $url, $args) use ($error, $host, $authorizationId): ?ErrorResponseCollection { + $wrongError = Mockery::mock(ErrorResponseCollection::class); + if (!$json->some_error) { + return $wrongError; + } + if ($status !== 500) { + return $wrongError; + } + if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId . '/capture') { + return $wrongError; + } + if ($args['headers']['Authorization'] !== 'Bearer bearer') { + return $wrongError; + } + if ($args['headers']['Content-Type'] !== 'application/json') { + return $wrongError; + } + + return $error; + } + ); + + $testee = new PaymentsEndpoint( + $host, + $bearer, + $authorizationFactory, + $errorResponseCollectionFactory + ); + + expect('wp_remote_post')->andReturn($rawResponse); + expect('is_wp_error')->with($rawResponse)->andReturn(false); + expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500); + expect('do_action') + ->with('woocommerce-paypal-commerce-gateway.error', $error); + + $this->expectException(RuntimeException::class); + $testee->capture($authorizationId); + } + } From 8e4af5766e4ee59aac100b60acceaba77303eb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 15:04:53 +0300 Subject: [PATCH 49/61] Create a processor class to handle the authorized payments --- modules.local/ppcp-wc-gateway/services.php | 24 +++- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 89 +++++-------- .../Processor/AuthorizedPaymentsProcessor.php | 119 ++++++++++++++++++ .../src/Processor/Processor.php | 19 +++ 4 files changed, 189 insertions(+), 62 deletions(-) create mode 100644 modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php create mode 100644 modules.local/ppcp-wc-gateway/src/Processor/Processor.php diff --git a/modules.local/ppcp-wc-gateway/services.php b/modules.local/ppcp-wc-gateway/services.php index c9dc551f0..0561891c7 100644 --- a/modules.local/ppcp-wc-gateway/services.php +++ b/modules.local/ppcp-wc-gateway/services.php @@ -1,4 +1,5 @@ function (ContainerInterface $container) : WcGateway { $sessionHandler = $container->get('session.handler'); $cartRepository = $container->get('api.repository.cart'); + // TODO eventuall get rid of the endpoints as the processor is sufficient $orderEndpoint = $container->get('api.endpoint.order'); $paymentsEndpoint = $container->get('api.endpoint.payments'); $orderFactory = $container->get('api.factory.order'); $settingsFields = $container->get('wcgateway.settings.fields'); - return new WcGateway($sessionHandler, $cartRepository, $orderEndpoint, $paymentsEndpoint, $orderFactory, $settingsFields); + $processor = $container->get('wcgateway.processor'); + return new WcGateway( + $sessionHandler, + $cartRepository, + $orderEndpoint, + $paymentsEndpoint, + $orderFactory, + $settingsFields, + $processor + ); }, 'wcgateway.disabler' => function (ContainerInterface $container) : DisableGateways { $sessionHandler = $container->get('session.handler'); @@ -45,4 +58,13 @@ return [ 'wcgateway.settings.fields' => function (ContainerInterface $container): SettingsFields { return new SettingsFields(); }, + 'wcgateway.processor' => function (ContainerInterface $container): Processor { + $authorizedPaymentsProcessor = $container->get('wcgateway.processor.authorized-payments'); + return new Processor($authorizedPaymentsProcessor); + }, + 'wcgateway.processor.authorized-payments' => function (ContainerInterface $container): AuthorizedPaymentsProcessor { + $orderEndpoint = $container->get('api.endpoint.order'); + $paymentsEndpoint = $container->get('api.endpoint.payments'); + return new AuthorizedPaymentsProcessor($orderEndpoint, $paymentsEndpoint); + }, ]; diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index c43a1e4a1..4471a3405 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -6,15 +6,13 @@ namespace Inpsyde\PayPalCommerce\WcGateway\Gateway; use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint; -use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization; -use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus; use Inpsyde\PayPalCommerce\ApiClient\Entity\Order; use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus; -use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException; use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory; use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository; use Inpsyde\PayPalCommerce\Session\SessionHandler; use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice; +use Inpsyde\PayPalCommerce\WcGateway\Processor\Processor; use Inpsyde\PayPalCommerce\WcGateway\Settings\SettingsFields; //phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps @@ -27,10 +25,8 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface private $cartRepository; private $orderFactory; private $settingsFields; - /** - * @var PaymentsEndpoint - */ private $paymentsEndpoint; + private $processor; public function __construct( SessionHandler $sessionHandler, @@ -38,15 +34,16 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface OrderEndpoint $orderEndpoint, PaymentsEndpoint $paymentsEndpoint, OrderFactory $orderFactory, - SettingsFields $settingsFields + SettingsFields $settingsFields, + Processor $processor ) { - $this->sessionHandler = $sessionHandler; $this->cartRepository = $cartRepository; $this->orderEndpoint = $orderEndpoint; $this->paymentsEndpoint = $paymentsEndpoint; $this->orderFactory = $orderFactory; $this->settingsFields = $settingsFields; + $this->processor = $processor; $this->method_title = __('PayPal Payments', 'woocommerce-paypal-gateway'); $this->method_description = __( @@ -118,73 +115,43 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface ]; } - public function captureAuthorizedPayment(\WC_Order $wcOrder) + public function captureAuthorizedPayment(\WC_Order $wcOrder): void { - $payPalOrderId = get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); + $result = $this->processor->authorizedPayments()->process($wcOrder); - try { - $order = $this->orderEndpoint->order($payPalOrderId); - } catch (RuntimeException $exception) { + if ($result === 'INACCESSIBLE') { AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::NO_INFO); - return; } - $allAuthorizations = []; - foreach ($order->purchaseUnits() as $purchaseUnit) { - foreach ($purchaseUnit->payments()->authorizations() as $authorization) { - $allAuthorizations[] = $authorization; - } - } - $authorizationsWithCreatedStatus = array_filter( - $allAuthorizations, - function (Authorization $authorization) { - return $authorization->status()->is(AuthorizationStatus::CREATED); - } - ); - $authorizationsWithCapturedStatus = array_filter( - $allAuthorizations, - function (Authorization $authorization) { - return $authorization->status()->is(AuthorizationStatus::CAPTURED); - } - ); + if ($result === 'ALREADY_CAPTURED' && $wcOrder->get_status() === 'on-hold') { + $wcOrder->add_order_note( + __( + 'Payment successfully authorized.', + 'woocommerce-paypal-gateway' + ) + ); - if (count($authorizationsWithCapturedStatus) === count($allAuthorizations)) { - if ($wcOrder->get_status() === 'on-hold') { - $wcOrder->add_order_note( - __( - 'Payment successfully authorized.', - 'woocommerce-paypal-gateway' - ) - ); + $wcOrder->update_status('processing'); - $wcOrder->update_status('processing'); - } AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_AUTHORIZED); - return; } - foreach ($authorizationsWithCreatedStatus as $authorization) { - try { - /** - * @var Authorization $authorization - */ - $result = $this->paymentsEndpoint->capture($authorization->id()); - } catch (RuntimeException $exception) { - AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); - return; - } + if ($result === 'FAILED') { + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED); } - AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::SUCCESS); + if ($result === 'SUCCESSFUL') { + $wcOrder->add_order_note( + __( + 'Payment successfully authorized.', + 'woocommerce-paypal-gateway' + ) + ); - $wcOrder->add_order_note( - __( - 'Payment successfully authorized.', - 'woocommerce-paypal-gateway' - ) - ); + $wcOrder->update_status('processing'); - $wcOrder->update_status('processing'); + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::SUCCESS); + } } private function patchOrder(\WC_Order $wcOrder, Order $order): Order diff --git a/modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php b/modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php new file mode 100644 index 000000000..570584b1b --- /dev/null +++ b/modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php @@ -0,0 +1,119 @@ +orderEndpoint = $orderEndpoint; + $this->paymentsEndpoint = $paymentsEndpoint; + } + + public function process(\WC_Order $wcOrder): string + { + $orderId = $this->getPayPalOrderId($wcOrder); + + try { + $order = $this->getCurrentOrderInfo($orderId); + } catch (Exception $exception) { + return self::INACCESSIBLE; + } + + $authorizations = $this->getAllAuthorizations($order); + + if (!$this->areAuthorizationToCapture(...$authorizations)) { + return self::ALREADY_CAPTURED; + } + + try { + $this->captureAuthorizations(...$authorizations); + } catch (Exception $exception) { + return self::FAILED; + } + + return self::SUCCESSFUL; + } + + protected function getPayPalOrderId(\WC_Order $wcOrder): string + { + return get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); + } + + protected function getCurrentOrderInfo(string $orderId): Order + { + return $this->orderEndpoint->order($orderId); + } + + protected function getAllAuthorizations(Order $order): array + { + $authorizations = []; + foreach ($order->purchaseUnits() as $purchaseUnit) { + foreach ($purchaseUnit->payments()->authorizations() as $authorization) { + $authorizations[] = $authorization; + } + } + + return $authorizations; + } + + protected function areAuthorizationToCapture(Authorization ...$authorizations): bool + { + $alreadyCapturedAuthorizations = $this->authorizationsWithCapturedStatus(...$authorizations); + + return count($alreadyCapturedAuthorizations) !== count($authorizations); + } + + protected function captureAuthorizations(Authorization ...$authorizations) + { + $uncapturedAuthorizations = $this->authorizationsWithCreatedStatus(...$authorizations); + + foreach ($uncapturedAuthorizations as $authorization) { + $this->paymentsEndpoint->capture($authorization->id()); + } + } + + /** + * @return Authorization[] + */ + protected function authorizationsWithCreatedStatus(Authorization ...$authorizations): array + { + return array_filter( + $authorizations, + function (Authorization $authorization) { + return $authorization->status()->is(AuthorizationStatus::CREATED); + } + ); + } + + /** + * @return Authorization[] + */ + protected function authorizationsWithCapturedStatus(Authorization ...$authorizations): array + { + return array_filter( + $authorizations, + function (Authorization $authorization) { + return $authorization->status()->is(AuthorizationStatus::CAPTURED); + } + ); + } +} diff --git a/modules.local/ppcp-wc-gateway/src/Processor/Processor.php b/modules.local/ppcp-wc-gateway/src/Processor/Processor.php new file mode 100644 index 000000000..9044073fc --- /dev/null +++ b/modules.local/ppcp-wc-gateway/src/Processor/Processor.php @@ -0,0 +1,19 @@ +authorizedPaymentsProcessor = $authorizedPaymentsProcessor; + } + + public function authorizedPayments() { + return $this->authorizedPaymentsProcessor; + } +} From 33777d5ac720c75b84cf92336ab9f6dc0a1ea528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 15:28:07 +0300 Subject: [PATCH 50/61] Update messages shown to user in the admin --- .../ppcp-wc-gateway/src/Gateway/WcGateway.php | 22 ++++++++++--------- .../src/Notice/AuthorizeOrderActionNotice.php | 12 +++++----- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 4471a3405..65d894f73 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -123,17 +123,19 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::NO_INFO); } - if ($result === 'ALREADY_CAPTURED' && $wcOrder->get_status() === 'on-hold') { - $wcOrder->add_order_note( - __( - 'Payment successfully authorized.', - 'woocommerce-paypal-gateway' - ) - ); + if ($result === 'ALREADY_CAPTURED') { + if ($wcOrder->get_status() === 'on-hold') { + $wcOrder->add_order_note( + __( + 'Payment successfully captured.', + 'woocommerce-paypal-gateway' + ) + ); - $wcOrder->update_status('processing'); + $wcOrder->update_status('processing'); + } - AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_AUTHORIZED); + AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_CAPTURED); } if ($result === 'FAILED') { @@ -143,7 +145,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface if ($result === 'SUCCESSFUL') { $wcOrder->add_order_note( __( - 'Payment successfully authorized.', + 'Payment successfully captured.', 'woocommerce-paypal-gateway' ) ); diff --git a/modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php b/modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php index adababaf8..81ceb83de 100644 --- a/modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php +++ b/modules.local/ppcp-wc-gateway/src/Notice/AuthorizeOrderActionNotice.php @@ -6,26 +6,26 @@ namespace Inpsyde\PayPalCommerce\WcGateway\Notice; class AuthorizeOrderActionNotice { const NO_INFO = 81; - const ALREADY_AUTHORIZED = 82; + const ALREADY_CAPTURED = 82; const FAILED = 83; const SUCCESS = 84; public function registerMessages(array $messages): array { $messages['shop_order'][self::NO_INFO] = __( - 'Could not retrieve payment information. Try again.', + 'Could not retrieve information. Try again later.', 'woocommerce-paypal-gateway' ); - $messages['shop_order'][self::ALREADY_AUTHORIZED] = __( - 'Payment was previously authorized.', + $messages['shop_order'][self::ALREADY_CAPTURED] = __( + 'Payment already captured.', 'woocommerce-paypal-gateway' ); $messages['shop_order'][self::FAILED] = __( - 'Authorization failed', + 'Failed to capture. Try again later.', 'woocommerce-paypal-gateway' ); $messages['shop_order'][self::SUCCESS] = __( - 'Authorization successful', + 'Payment successfully captured.', 'woocommerce-paypal-gateway' ); From 09d82e3155f17b7e3aa948e2d4cb155a71a3a196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 16:45:27 +0300 Subject: [PATCH 51/61] Add test for Payments --- .../tests/PHPUnit/Entity/PaymentsTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 modules.local/ppcp-api-client/tests/PHPUnit/Entity/PaymentsTest.php diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Entity/PaymentsTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/PaymentsTest.php new file mode 100644 index 000000000..b5c4319ba --- /dev/null +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Entity/PaymentsTest.php @@ -0,0 +1,46 @@ +assertEquals($authorizations, $testee->authorizations()); + } + + public function testToArray() + { + $authorization = \Mockery::mock(Authorization::class); + $authorization->shouldReceive('toArray')->andReturn( + [ + 'id' => 'foo', + 'status' => 'CREATED', + ] + ); + $authorizations = [$authorization]; + + $testee = new Payments(...$authorizations); + + $this->assertEquals( + [ + 'authorizations' => [ + [ + 'id' => 'foo', + 'status' => 'CREATED', + ], + ], + ], + $testee->toArray() + ); + } +} From d5a6cf54393ee1c1002b7721e1d7e87afca759b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 17:10:58 +0300 Subject: [PATCH 52/61] Add test for PaymentsFactory --- .../PHPUnit/Factory/PaymentsFactoryTest.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 modules.local/ppcp-api-client/tests/PHPUnit/Factory/PaymentsFactoryTest.php diff --git a/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PaymentsFactoryTest.php b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PaymentsFactoryTest.php new file mode 100644 index 000000000..79515e220 --- /dev/null +++ b/modules.local/ppcp-api-client/tests/PHPUnit/Factory/PaymentsFactoryTest.php @@ -0,0 +1,40 @@ +shouldReceive('toArray')->andReturn(['id' => 'foo', 'status' => 'CREATED']); + + $authorizationsFactory = Mockery::mock(AuthorizationFactory::class); + $authorizationsFactory->shouldReceive('fromPayPalRequest')->andReturn($authorization); + + $response = (object)[ + 'authorizations' => [ + (object)['id' => 'foo', 'status' => 'CREATED',], + ], + ]; + + $testee = new PaymentsFactory($authorizationsFactory); + $result = $testee->fromPayPalResponse($response); + + $this->assertInstanceOf(Payments::class, $result); + + $expectedToArray = [ + 'authorizations' => [ + ['id' => 'foo', 'status' => 'CREATED',], + ], + ]; + $this->assertEquals($expectedToArray, $result->toArray()); + } +} From bd6cdf05b598687f91df40755f98c0433adad82a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 16 Apr 2020 17:32:27 +0300 Subject: [PATCH 53/61] Put it in one line To make the code coverage pass --- .../src/Endpoint/PaymentsEndpoint.php | 21 ++++--------------- .../src/Entity/AuthorizationStatus.php | 5 +---- .../src/Factory/AuthorizationFactory.php | 10 ++------- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php index cd563ad89..f734b3915 100644 --- a/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php +++ b/modules.local/ppcp-api-client/src/Endpoint/PaymentsEndpoint.php @@ -23,7 +23,6 @@ class PaymentsEndpoint AuthorizationFactory $authorizationsFactory, ErrorResponseCollectionFactory $errorResponseFactory ) { - $this->host = $host; $this->bearer = $bearer; $this->authorizationFactory = $authorizationsFactory; @@ -48,10 +47,7 @@ class PaymentsEndpoint if (is_wp_error($response)) { $this->handleResponseWpError($url, $args); throw new RuntimeException( - __( - 'Could not get authorized payment info.', - 'woocommerce-paypal-commerce-gateway' - ) + __('Could not get authorized payment info.', 'woocommerce-paypal-commerce-gateway') ); } @@ -64,10 +60,7 @@ class PaymentsEndpoint ); do_action('woocommerce-paypal-commerce-gateway.error', $errors); throw new RuntimeException( - __( - 'Could not get authorized payment info.', - 'woocommerce-paypal-commerce-gateway' - ) + __('Could not get authorized payment info.', 'woocommerce-paypal-commerce-gateway') ); } @@ -93,10 +86,7 @@ class PaymentsEndpoint if (is_wp_error($response)) { $this->handleResponseWpError($url, $args); throw new RuntimeException( - __( - 'Could not capture authorized payment.', - 'woocommerce-paypal-commerce-gateway' - ) + __('Could not capture authorized payment.', 'woocommerce-paypal-commerce-gateway') ); } @@ -109,10 +99,7 @@ class PaymentsEndpoint ); do_action('woocommerce-paypal-commerce-gateway.error', $errors); throw new RuntimeException( - __( - 'Could not capture authorized payment.', - 'woocommerce-paypal-commerce-gateway' - ) + __('Could not capture authorized payment.', 'woocommerce-paypal-commerce-gateway') ); } diff --git a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php index 073bb85d5..5aee9a16e 100644 --- a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php +++ b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php @@ -32,11 +32,8 @@ class AuthorizationStatus { if (!in_array($status, self::VALID_STATUS, true)) { throw new RuntimeException( - sprintf( // translators: %s is the current status. - __("%s is not a valid status", "woocmmerce-paypal-commerce-gateway"), - $status - ) + sprintf(__("%s is not a valid status", 'woocmmerce-paypal-commerce-gateway'), $status) ); } $this->status = $status; diff --git a/modules.local/ppcp-api-client/src/Factory/AuthorizationFactory.php b/modules.local/ppcp-api-client/src/Factory/AuthorizationFactory.php index eaf721654..be004f406 100644 --- a/modules.local/ppcp-api-client/src/Factory/AuthorizationFactory.php +++ b/modules.local/ppcp-api-client/src/Factory/AuthorizationFactory.php @@ -14,19 +14,13 @@ class AuthorizationFactory { if (!isset($data->id)) { throw new RuntimeException( - __( - 'Does not contain an id.', - 'woocommerce-paypal-commerce-gateway' - ) + __('Does not contain an id.', 'woocommerce-paypal-commerce-gateway') ); } if (!isset($data->status)) { throw new RuntimeException( - __( - 'Does not contain status.', - 'woocommerce-paypal-commerce-gateway' - ) + __('Does not contain status.', 'woocommerce-paypal-commerce-gateway') ); } From 857dc9b6669d4c6254008e6103a23160afe5775f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 22 Apr 2020 12:58:42 +0300 Subject: [PATCH 54/61] Use WC meta data wrapper methods instead of the default WP meta functions --- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 2 +- .../src/Processor/AuthorizedPaymentsProcessor.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 65d894f73..042a31e39 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -81,7 +81,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface //ToDo: We need to fetch the order from paypal again to get it with the new status. $order = $this->sessionHandler->order(); - update_post_meta($orderId, '_paypal_order_id', $order->id()); + $wcOrder->update_meta_data('_ppcp_paypal_order_id', $order->id()); $errorMessage = null; if (!$order || !$order->status()->is(OrderStatus::APPROVED)) { diff --git a/modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php b/modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php index 570584b1b..53ddec81f 100644 --- a/modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php +++ b/modules.local/ppcp-wc-gateway/src/Processor/AuthorizedPaymentsProcessor.php @@ -55,7 +55,7 @@ class AuthorizedPaymentsProcessor protected function getPayPalOrderId(\WC_Order $wcOrder): string { - return get_post_meta($wcOrder->get_id(), '_paypal_order_id', true); + return $wcOrder->get_meta('_ppcp_paypal_order_id'); } protected function getCurrentOrderInfo(string $orderId): Order From 82fa0ab75486442cb31d8803c89b630737ff8c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 22 Apr 2020 13:57:20 +0300 Subject: [PATCH 55/61] Store the order intent as meta information --- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 042a31e39..330d9f01c 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -82,6 +82,7 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface $order = $this->sessionHandler->order(); $wcOrder->update_meta_data('_ppcp_paypal_order_id', $order->id()); + $wcOrder->update_meta_data('_ppcp_paypal_intent', $order->intent()); $errorMessage = null; if (!$order || !$order->status()->is(OrderStatus::APPROVED)) { From 708efab5e49957063e6566d69f6ec7951f069c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 22 Apr 2020 16:05:59 +0300 Subject: [PATCH 56/61] Update order action name --- modules.local/ppcp-wc-gateway/src/WcGatewayModule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php index e61014a11..d92306cca 100644 --- a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php +++ b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php @@ -60,7 +60,7 @@ class WcGatewayModule implements ModuleInterface 'woocommerce_order_actions', function ($orderActions): array { $orderActions['ppcp_authorize_order'] = __( - 'Authorize PayPal Payment', + 'Capture authorized PayPal payment', 'woocommerce-paypal-gateway' ); return $orderActions; From 24dd72142bc71c28bad97ca541fb55437fd7c370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 22 Apr 2020 16:07:02 +0300 Subject: [PATCH 57/61] Add option to display the payment status --- modules.local/ppcp-wc-gateway/services.php | 5 ++++ .../src/Admin/AuthorizedPaymentStatus.php | 27 +++++++++++++++++++ .../ppcp-wc-gateway/src/WcGatewayModule.php | 14 +++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php diff --git a/modules.local/ppcp-wc-gateway/services.php b/modules.local/ppcp-wc-gateway/services.php index 0561891c7..675d63558 100644 --- a/modules.local/ppcp-wc-gateway/services.php +++ b/modules.local/ppcp-wc-gateway/services.php @@ -5,6 +5,8 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Data\Container\ContainerInterface; +use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatus; +use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGatewayBase; @@ -67,4 +69,7 @@ return [ $paymentsEndpoint = $container->get('api.endpoint.payments'); return new AuthorizedPaymentsProcessor($orderEndpoint, $paymentsEndpoint); }, + 'wcgateway.admin.authorized-payment-status' => function(ContainerInterface $container): AuthorizedPaymentStatus { + return new AuthorizedPaymentStatus(); + } ]; diff --git a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php b/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php new file mode 100644 index 000000000..0b1775136 --- /dev/null +++ b/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php @@ -0,0 +1,27 @@ +get_meta('_ppcp_paypal_intent'); + + if ($intent !== 'AUTHORIZE') { + return; + } + + //TODO add status check + + printf( + // @phpcs:ignore Inpsyde.CodeQuality.LineLength.TooLong + '
  • %1$s

    %2$s

  • ', + esc_html__('Not captured', 'woocommerce-paypal-gateway'), + esc_html__('To capture the payment select capture action from the list below.', 'woocommerce-paypal-gateway'), + ); + } +} diff --git a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php index d92306cca..b6d584cb0 100644 --- a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php +++ b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php @@ -6,6 +6,8 @@ namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Container\ServiceProvider; use Dhii\Modular\Module\ModuleInterface; +use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatus; +use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice; @@ -15,7 +17,6 @@ use Psr\Container\ContainerInterface; class WcGatewayModule implements ModuleInterface { - public function setup(): ServiceProviderInterface { return new ServiceProvider( @@ -89,5 +90,16 @@ class WcGatewayModule implements ModuleInterface }, 20 ); + + add_action( + 'woocommerce_order_actions_start', + function ($wcOrderId) use ($container) { + /** + * @var AuthorizedPaymentStatus $orderDetail + */ + $orderDetail = $container->get('wcgateway.admin.authorized-payment-status'); + $orderDetail->render(intval($wcOrderId)); + } + ); } } From 72cb5b49441dcc82690617f89e4c688425284052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 22 Apr 2020 17:00:05 +0300 Subject: [PATCH 58/61] Store the captured status of the authorized payment --- .../ppcp-api-client/src/Entity/AuthorizationStatus.php | 2 ++ .../ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php | 5 ++++- modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php index 5aee9a16e..0e9f2dad8 100644 --- a/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php +++ b/modules.local/ppcp-api-client/src/Entity/AuthorizationStatus.php @@ -11,6 +11,7 @@ class AuthorizationStatus const INTERNAL = 'INTERNAL'; const CREATED = 'CREATED'; const CAPTURED = 'CAPTURED'; + const COMPLETED = 'COMPLETED'; const DENIED = 'DENIED'; const EXPIRED = 'EXPIRED'; const PARTIALLY_CAPTURED = 'PARTIALLY_CAPTURED'; @@ -20,6 +21,7 @@ class AuthorizationStatus self::INTERNAL, self::CREATED, self::CAPTURED, + self::COMPLETED, self::DENIED, self::EXPIRED, self::PARTIALLY_CAPTURED, diff --git a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php b/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php index 0b1775136..3c493d685 100644 --- a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php +++ b/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php @@ -10,12 +10,15 @@ class AuthorizedPaymentStatus { $wcOrder = new \WC_Order($wcOrderId); $intent = $wcOrder->get_meta('_ppcp_paypal_intent'); + $captured = $wcOrder->get_meta('_ppcp_paypal_captured'); if ($intent !== 'AUTHORIZE') { return; } - //TODO add status check + if (!empty($captured) && wc_string_to_bool($captured)) { + return; + } printf( // @phpcs:ignore Inpsyde.CodeQuality.LineLength.TooLong diff --git a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php index 330d9f01c..36e6014d5 100644 --- a/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php +++ b/modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php @@ -132,8 +132,10 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface 'woocommerce-paypal-gateway' ) ); - $wcOrder->update_status('processing'); + $wcOrder->update_meta_data('_ppcp_paypal_captured', 'true'); + // TODO investigate why save has to be called + $wcOrder->save(); } AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_CAPTURED); @@ -152,6 +154,9 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface ); $wcOrder->update_status('processing'); + $wcOrder->update_meta_data('_ppcp_paypal_captured', 'true'); + // TODO investigate why save has to be called + $wcOrder->save(); AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::SUCCESS); } From 7e41ca385218c9e491dc2ca0214e4f5e8017ecff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Wed, 22 Apr 2020 19:27:07 +0300 Subject: [PATCH 59/61] Display authorized payment captured state on the orders table --- modules.local/ppcp-wc-gateway/services.php | 5 ++ .../Admin/AuthorizedPaymentStatusColumn.php | 82 +++++++++++++++++++ .../ppcp-wc-gateway/src/WcGatewayModule.php | 31 ++++++- 3 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatusColumn.php diff --git a/modules.local/ppcp-wc-gateway/services.php b/modules.local/ppcp-wc-gateway/services.php index 675d63558..ac98940d3 100644 --- a/modules.local/ppcp-wc-gateway/services.php +++ b/modules.local/ppcp-wc-gateway/services.php @@ -6,6 +6,7 @@ namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Data\Container\ContainerInterface; use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatus; +use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatusColumn; use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; @@ -71,5 +72,9 @@ return [ }, 'wcgateway.admin.authorized-payment-status' => function(ContainerInterface $container): AuthorizedPaymentStatus { return new AuthorizedPaymentStatus(); + }, + 'wcgateway.admin.authorized-payment-status-column' => function(ContainerInterface $container): AuthorizedPaymentStatusColumn { + $settings = $container->get('wcgateway.settings'); + return new AuthorizedPaymentStatusColumn($settings); } ]; diff --git a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatusColumn.php b/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatusColumn.php new file mode 100644 index 000000000..b7e7ca7a8 --- /dev/null +++ b/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatusColumn.php @@ -0,0 +1,82 @@ +settings = $settings; + } + + public function register(array $columns): array + { + if ($this->settings->get('intent') !== self::INTENT) { + return $columns; + } + + $statusColumnPosition = array_search(self::AFTER_COLUMN_KEY, array_keys($columns), true); + $toInsertPosition = false === $statusColumnPosition ? count($columns) : $statusColumnPosition + 1; + + $columns = array_merge( + array_slice($columns, 0, $toInsertPosition), + [ + self::COLUMN_KEY => __('Payment Captured', 'woocommerce-paypal-gateway'), + ], + array_slice($columns, $toInsertPosition) + ); + + return $columns; + } + + public function render(string $column, int $wcOrderId) + { + if ($this->settings->get('intent') !== self::INTENT) { + return; + } + + if (self::COLUMN_KEY !== $column) { + return; + } + + if ($this->isCaptured($wcOrderId)) { + $this->renderCompletedStatus(); + } else { + $this->renderIncompletedStatus(); + } + } + + protected function isCaptured(int $wcOrderId): bool + { + $wcOrder = wc_get_order($wcOrderId); + $captured = $wcOrder->get_meta('_ppcp_paypal_captured'); + + if (!empty($captured) && wc_string_to_bool($captured)) { + return true; + } + + return false; + } + + protected function renderCompletedStatus() + { + echo ''; + } + + protected function renderIncompletedStatus() + { + printf( + '%s', + esc_html__('Not captured', 'woocommerce-paypal-gateway') + ); + } +} diff --git a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php index b6d584cb0..d6a0279e4 100644 --- a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php +++ b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php @@ -7,6 +7,7 @@ namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Container\ServiceProvider; use Dhii\Modular\Module\ModuleInterface; use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatus; +use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatusColumn; use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; @@ -95,11 +96,35 @@ class WcGatewayModule implements ModuleInterface 'woocommerce_order_actions_start', function ($wcOrderId) use ($container) { /** - * @var AuthorizedPaymentStatus $orderDetail + * @var AuthorizedPaymentStatus $class */ - $orderDetail = $container->get('wcgateway.admin.authorized-payment-status'); - $orderDetail->render(intval($wcOrderId)); + $class = $container->get('wcgateway.admin.authorized-payment-status'); + $class->render(intval($wcOrderId)); } ); + + add_filter( + 'manage_edit-shop_order_columns', + function ($columns) use ($container) { + /** + * @var AuthorizedPaymentStatusColumn $paymentStatusColumn + */ + $paymentStatusColumn = $container->get('wcgateway.admin.authorized-payment-status-column'); + return $paymentStatusColumn->register($columns); + } + ); + + add_action( + 'manage_shop_order_posts_custom_column', + function ($column, $wcOrderId) use ($container) { + /** + * @var AuthorizedPaymentStatusColumn $paymentStatusColumn + */ + $paymentStatusColumn = $container->get('wcgateway.admin.authorized-payment-status-column'); + $paymentStatusColumn->render($column, intval($wcOrderId)); + }, + 10, + 2 + ); } } From 25c09fb1988614c810ae6585e0f50b8ceed1200d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 23 Apr 2020 11:19:09 +0300 Subject: [PATCH 60/61] Rename payment status related classes --- modules.local/ppcp-wc-gateway/services.php | 12 ++++++------ ...umn.php => OrderTablePaymentStatusColumn.php} | 2 +- ...ntStatus.php => PaymentStatusOrderDetail.php} | 2 +- .../ppcp-wc-gateway/src/WcGatewayModule.php | 16 ++++++++-------- 4 files changed, 16 insertions(+), 16 deletions(-) rename modules.local/ppcp-wc-gateway/src/Admin/{AuthorizedPaymentStatusColumn.php => OrderTablePaymentStatusColumn.php} (98%) rename modules.local/ppcp-wc-gateway/src/Admin/{AuthorizedPaymentStatus.php => PaymentStatusOrderDetail.php} (96%) diff --git a/modules.local/ppcp-wc-gateway/services.php b/modules.local/ppcp-wc-gateway/services.php index ac98940d3..08ea5e6e0 100644 --- a/modules.local/ppcp-wc-gateway/services.php +++ b/modules.local/ppcp-wc-gateway/services.php @@ -5,9 +5,9 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Data\Container\ContainerInterface; -use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatus; -use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatusColumn; use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail; +use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn; +use Inpsyde\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGatewayBase; @@ -70,11 +70,11 @@ return [ $paymentsEndpoint = $container->get('api.endpoint.payments'); return new AuthorizedPaymentsProcessor($orderEndpoint, $paymentsEndpoint); }, - 'wcgateway.admin.authorized-payment-status' => function(ContainerInterface $container): AuthorizedPaymentStatus { - return new AuthorizedPaymentStatus(); + 'wcgateway.admin.order-payment-status' => function(ContainerInterface $container): PaymentStatusOrderDetail { + return new PaymentStatusOrderDetail(); }, - 'wcgateway.admin.authorized-payment-status-column' => function(ContainerInterface $container): AuthorizedPaymentStatusColumn { + 'wcgateway.admin.orders-payment-status-column' => function(ContainerInterface $container): OrderTablePaymentStatusColumn { $settings = $container->get('wcgateway.settings'); - return new AuthorizedPaymentStatusColumn($settings); + return new OrderTablePaymentStatusColumn($settings); } ]; diff --git a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatusColumn.php b/modules.local/ppcp-wc-gateway/src/Admin/OrderTablePaymentStatusColumn.php similarity index 98% rename from modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatusColumn.php rename to modules.local/ppcp-wc-gateway/src/Admin/OrderTablePaymentStatusColumn.php index b7e7ca7a8..e0f7c3832 100644 --- a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatusColumn.php +++ b/modules.local/ppcp-wc-gateway/src/Admin/OrderTablePaymentStatusColumn.php @@ -6,7 +6,7 @@ namespace Inpsyde\PayPalCommerce\WcGateway\Admin; use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings; -class AuthorizedPaymentStatusColumn +class OrderTablePaymentStatusColumn { const COLUMN_KEY = 'ppcp_payment_status'; const INTENT = 'authorize'; diff --git a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php b/modules.local/ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php similarity index 96% rename from modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php rename to modules.local/ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php index 3c493d685..4ebcd273a 100644 --- a/modules.local/ppcp-wc-gateway/src/Admin/AuthorizedPaymentStatus.php +++ b/modules.local/ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Inpsyde\PayPalCommerce\WcGateway\Admin; -class AuthorizedPaymentStatus +class PaymentStatusOrderDetail { public function render(int $wcOrderId) { diff --git a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php index d6a0279e4..ff5975626 100644 --- a/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php +++ b/modules.local/ppcp-wc-gateway/src/WcGatewayModule.php @@ -6,9 +6,9 @@ namespace Inpsyde\PayPalCommerce\WcGateway; use Dhii\Container\ServiceProvider; use Dhii\Modular\Module\ModuleInterface; -use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatus; -use Inpsyde\PayPalCommerce\WcGateway\Admin\AuthorizedPaymentStatusColumn; use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail; +use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn; +use Inpsyde\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail; use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways; use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway; use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice; @@ -96,9 +96,9 @@ class WcGatewayModule implements ModuleInterface 'woocommerce_order_actions_start', function ($wcOrderId) use ($container) { /** - * @var AuthorizedPaymentStatus $class + * @var PaymentStatusOrderDetail $class */ - $class = $container->get('wcgateway.admin.authorized-payment-status'); + $class = $container->get('wcgateway.admin.order-payment-status'); $class->render(intval($wcOrderId)); } ); @@ -107,9 +107,9 @@ class WcGatewayModule implements ModuleInterface 'manage_edit-shop_order_columns', function ($columns) use ($container) { /** - * @var AuthorizedPaymentStatusColumn $paymentStatusColumn + * @var OrderTablePaymentStatusColumn $paymentStatusColumn */ - $paymentStatusColumn = $container->get('wcgateway.admin.authorized-payment-status-column'); + $paymentStatusColumn = $container->get('wcgateway.admin.orders-payment-status-column'); return $paymentStatusColumn->register($columns); } ); @@ -118,9 +118,9 @@ class WcGatewayModule implements ModuleInterface 'manage_shop_order_posts_custom_column', function ($column, $wcOrderId) use ($container) { /** - * @var AuthorizedPaymentStatusColumn $paymentStatusColumn + * @var OrderTablePaymentStatusColumn $paymentStatusColumn */ - $paymentStatusColumn = $container->get('wcgateway.admin.authorized-payment-status-column'); + $paymentStatusColumn = $container->get('wcgateway.admin.orders-payment-status-column'); $paymentStatusColumn->render($column, intval($wcOrderId)); }, 10, From cb564c3fbb1f285147a3895c812937cd40b280e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20R=C3=B3bert?= Date: Thu, 23 Apr 2020 11:25:46 +0300 Subject: [PATCH 61/61] Compare the intent but don't care about the casing --- .../ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.local/ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php b/modules.local/ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php index 4ebcd273a..f42b48ad0 100644 --- a/modules.local/ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php +++ b/modules.local/ppcp-wc-gateway/src/Admin/PaymentStatusOrderDetail.php @@ -12,7 +12,7 @@ class PaymentStatusOrderDetail $intent = $wcOrder->get_meta('_ppcp_paypal_intent'); $captured = $wcOrder->get_meta('_ppcp_paypal_captured'); - if ($intent !== 'AUTHORIZE') { + if (strcasecmp($intent, 'AUTHORIZE') !== 0) { return; }