From 15b28f7c85054af76d68f2791ba5e85f31f69d96 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 12 Sep 2022 10:35:27 +0200 Subject: [PATCH 1/5] Add files from PCP-166 PR --- modules/ppcp-webhooks/services.php | 2 + .../src/Handler/CheckoutOrderCompleted.php | 90 +++----------- .../CheckoutPaymentApprovalReversed.php | 103 ++++++++++++++++ .../src/Handler/RequestHandlerTrait.php | 110 ++++++++++++++++++ 4 files changed, 233 insertions(+), 72 deletions(-) create mode 100644 modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php create mode 100644 modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php diff --git a/modules/ppcp-webhooks/services.php b/modules/ppcp-webhooks/services.php index 5e7ca8674..4883a06d2 100644 --- a/modules/ppcp-webhooks/services.php +++ b/modules/ppcp-webhooks/services.php @@ -19,6 +19,7 @@ use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulateEndpoint; use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint; use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderApproved; use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutOrderCompleted; +use WooCommerce\PayPalCommerce\Webhooks\Handler\CheckoutPaymentApprovalReversed; use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureCompleted; use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCaptureDenied; use WooCommerce\PayPalCommerce\Webhooks\Handler\PaymentCapturePending; @@ -75,6 +76,7 @@ return array( return array( new CheckoutOrderApproved( $logger, $prefix, $order_endpoint ), new CheckoutOrderCompleted( $logger, $prefix ), + new CheckoutPaymentApprovalReversed($logger), new PaymentCaptureRefunded( $logger, $prefix ), new PaymentCaptureReversed( $logger, $prefix ), new PaymentCaptureCompleted( $logger, $prefix, $order_endpoint ), diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php b/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php index 3159c9cb1..85bbd376d 100644 --- a/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php +++ b/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php @@ -11,13 +11,15 @@ namespace WooCommerce\PayPalCommerce\Webhooks\Handler; use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; +use WP_REST_Request; +use WP_REST_Response; /** * Class CheckoutOrderCompleted */ class CheckoutOrderCompleted implements RequestHandler { - use PrefixTrait; + use PrefixTrait, RequestHandlerTrait; /** * The logger. @@ -51,97 +53,45 @@ class CheckoutOrderCompleted implements RequestHandler { /** * Whether a handler is responsible for a given request or not. * - * @param \WP_REST_Request $request The request. + * @param WP_REST_Request $request The request. * * @return bool */ - public function responsible_for_request( \WP_REST_Request $request ): bool { + public function responsible_for_request( WP_REST_Request $request ): bool { return in_array( $request['event_type'], $this->event_types(), true ); } /** * Responsible for handling the request. * - * @param \WP_REST_Request $request The request. + * @param WP_REST_Request $request The request. * - * @return \WP_REST_Response + * @return WP_REST_Response */ - public function handle_request( \WP_REST_Request $request ): \WP_REST_Response { - $response = array( 'success' => false ); - $custom_ids = array_filter( - array_map( - static function ( array $purchase_unit ): string { - return isset( $purchase_unit['custom_id'] ) ? - (string) $purchase_unit['custom_id'] : ''; - }, - isset( $request['resource']['purchase_units'] ) ? - (array) $request['resource']['purchase_units'] : array() - ), - static function ( string $order_id ): bool { - return ! empty( $order_id ); - } - ); + public function handle_request( WP_REST_Request $request ): WP_REST_Response { + $response = array( 'success' => false ); + $custom_ids = $this->get_custom_ids_from_request( $request ); if ( empty( $custom_ids ) ) { - $message = sprintf( - // translators: %s is the PayPal webhook Id. - __( - 'No order for webhook event %s was found.', - 'woocommerce-paypal-payments' - ), - isset( $request['id'] ) ? $request['id'] : '' - ); - $this->logger->log( - 'warning', - $message, - array( - 'request' => $request, - ) - ); - $response['message'] = $message; - return rest_ensure_response( $response ); + return $this->no_custom_ids_from_request( $request, $response ); } - $order_ids = array_map( - array( - $this, - 'sanitize_custom_id', - ), - $custom_ids - ); - $args = array( - 'post__in' => $order_ids, - 'limit' => -1, - ); - $wc_orders = wc_get_orders( $args ); + $wc_orders = $this->get_wc_orders_from_custom_ids( $custom_ids ); if ( ! $wc_orders ) { - $message = sprintf( - // translators: %s is the PayPal order Id. - __( 'Order for PayPal order %s not found.', 'woocommerce-paypal-payments' ), - isset( $request['resource']['id'] ) ? $request['resource']['id'] : '' - ); - $this->logger->log( - 'warning', - $message, - array( - 'request' => $request, - ) - ); - $response['message'] = $message; - return rest_ensure_response( $response ); + return $this->no_wc_orders_from_custom_ids( $request, $response ); } foreach ( $wc_orders as $wc_order ) { if ( PayUponInvoiceGateway::ID === $wc_order->get_payment_method() ) { continue; } - if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) { continue; } + $wc_order->payment_complete(); - $this->logger->log( - 'info', + + $this->logger->info( sprintf( // translators: %s is the order ID. __( @@ -149,15 +99,11 @@ class CheckoutOrderCompleted implements RequestHandler { 'woocommerce-paypal-payments' ), (string) $wc_order->get_id() - ), - array( - 'request' => $request, - 'order' => $wc_order, ) ); } + $response['success'] = true; - return rest_ensure_response( $response ); + return new WP_REST_Response( $response ); } - // phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong } diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php b/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php new file mode 100644 index 000000000..58ad66474 --- /dev/null +++ b/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php @@ -0,0 +1,103 @@ +logger = $logger; + } + + /** + * The event types a handler handles. + * + * @return string[] + */ + public function event_types(): array { + return array( + 'CHECKOUT.PAYMENT-APPROVAL.REVERSED', + ); + } + + /** + * Whether a handler is responsible for a given request or not. + * + * @param WP_REST_Request $request The request. + * + * @return bool + */ + public function responsible_for_request( WP_REST_Request $request ): bool { + return in_array( $request['event_type'], $this->event_types(), true ); + } + + /** + * Responsible for handling the request. + * + * @param WP_REST_Request $request The request. + * + * @return WP_REST_Response + */ + public function handle_request( WP_REST_Request $request ): WP_REST_Response { + $response = array( 'success' => false ); + + $custom_ids = $this->get_custom_ids_from_request( $request ); + if ( empty( $custom_ids ) ) { + return $this->no_custom_ids_from_request( $request, $response ); + } + + $wc_orders = $this->get_wc_orders_from_custom_ids( $custom_ids ); + if ( ! $wc_orders ) { + return $this->no_wc_orders_from_custom_ids( $request, $response ); + } + + if ( is_array( $wc_orders ) ) { + foreach ( $wc_orders as $wc_order ) { + if ( in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) { + $error_message = sprintf( + // translators: %1$s is the order id. + __( + 'Failed to capture order %1$s through PayPal.', + 'woocommerce-paypal-payments' + ), + (string) $wc_order->get_id() + ); + + $this->logger->warning( 'CHECKOUT.PAYMENT-APPROVAL.REVERSED received. ' . $error_message ); + + $wc_order->update_status( 'failed', $error_message ); + } + } + } + + $response['success'] = true; + return new WP_REST_Response( $response ); + } +} diff --git a/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php b/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php new file mode 100644 index 000000000..714a23e06 --- /dev/null +++ b/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php @@ -0,0 +1,110 @@ + $order_ids, + 'limit' => -1, + ); + + return wc_get_orders( $args ); + } + + /** + * Return and log response for no custom ids found in request. + * + * @param WP_REST_Request $request The request. + * @param array $response The response. + * @return WP_REST_Response + */ + protected function no_custom_ids_from_request( WP_REST_Request $request, array $response ): WP_REST_Response { + $message = sprintf( + // translators: %s is the PayPal webhook Id. + __( 'No order for webhook event %s was found.', 'woocommerce-paypal-payments' ), + isset( $request['id'] ) ? $request['id'] : '' + ); + + return $this->log_and_return_response( $message, $response ); + } + + /** + * Return and log response for no WC orders found in response. + * + * @param WP_REST_Request $request The request. + * @param array $response The response. + * @return WP_REST_Response + */ + protected function no_wc_orders_from_custom_ids( WP_REST_Request $request, array $response ): WP_REST_Response { + $message = sprintf( + // translators: %s is the PayPal order Id. + __( 'WC order for PayPal order %s not found.', 'woocommerce-paypal-payments' ), + isset( $request['resource']['id'] ) ? $request['resource']['id'] : '' + ); + + return $this->log_and_return_response( $message, $response ); + } + + /** + * Return and log response with the given message. + * + * @param string $message The message. + * @param array $response The response. + * @return WP_REST_Response + */ + private function log_and_return_response( string $message, array $response ): WP_REST_Response { + $this->logger->warning( $message ); + $response['message'] = $message; + + return new WP_REST_Response( $response ); + } +} From 2654fac15fc59325bf43760b9e56ab4b69ca0bbb Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 12 Sep 2022 11:41:29 +0200 Subject: [PATCH 2/5] Fix psalm --- .ddev/config.yaml | 4 ++-- .../src/Handler/CheckoutPaymentApprovalReversed.php | 2 +- modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 3d732fd50..8ac94d6a5 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -3,8 +3,8 @@ type: php docroot: .ddev/wordpress php_version: "7.1" webserver_type: apache-fpm -router_http_port: "80" -router_https_port: "443" +router_http_port: "8080" +router_https_port: "8443" xdebug_enabled: false additional_hostnames: ['wc-pp'] additional_fqdns: [] diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php b/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php index 58ad66474..772023e4e 100644 --- a/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php +++ b/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php @@ -18,7 +18,7 @@ use WP_REST_Response; */ class CheckoutPaymentApprovalReversed implements RequestHandler { - use RequestHandlerTrait; + use RequestHandlerTrait, PrefixTrait; /** * The logger. diff --git a/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php b/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php index 714a23e06..e9e7637e9 100644 --- a/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php +++ b/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php @@ -29,7 +29,7 @@ trait RequestHandlerTrait { return isset( $purchase_unit['custom_id'] ) ? (string) $purchase_unit['custom_id'] : ''; }, - isset( $request['resource'] ) && isset( $request['resource']['purchase_units'] ) ? + $request['resource'] !== null && isset( $request['resource']['purchase_units'] ) ? (array) $request['resource']['purchase_units'] : array() ), static function ( string $order_id ): bool { @@ -71,7 +71,7 @@ trait RequestHandlerTrait { $message = sprintf( // translators: %s is the PayPal webhook Id. __( 'No order for webhook event %s was found.', 'woocommerce-paypal-payments' ), - isset( $request['id'] ) ? $request['id'] : '' + $request['id'] !== null && isset( $request['id'] ) ? $request['id'] : '' ); return $this->log_and_return_response( $message, $response ); @@ -88,7 +88,7 @@ trait RequestHandlerTrait { $message = sprintf( // translators: %s is the PayPal order Id. __( 'WC order for PayPal order %s not found.', 'woocommerce-paypal-payments' ), - isset( $request['resource']['id'] ) ? $request['resource']['id'] : '' + $request['resource'] !== null && isset( $request['resource']['id'] ) ? $request['resource']['id'] : '' ); return $this->log_and_return_response( $message, $response ); From 0d9f06ca3f38e926b507d3d47223d2d643404da2 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 12 Sep 2022 12:01:13 +0200 Subject: [PATCH 3/5] Fix phpcs --- modules/ppcp-webhooks/services.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-webhooks/services.php b/modules/ppcp-webhooks/services.php index 4883a06d2..ef2b9f3cc 100644 --- a/modules/ppcp-webhooks/services.php +++ b/modules/ppcp-webhooks/services.php @@ -76,7 +76,7 @@ return array( return array( new CheckoutOrderApproved( $logger, $prefix, $order_endpoint ), new CheckoutOrderCompleted( $logger, $prefix ), - new CheckoutPaymentApprovalReversed($logger), + new CheckoutPaymentApprovalReversed( $logger ), new PaymentCaptureRefunded( $logger, $prefix ), new PaymentCaptureReversed( $logger, $prefix ), new PaymentCaptureCompleted( $logger, $prefix, $order_endpoint ), From 1396520c5727dd2b9a418dcdaf13c4e7c081c13a Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 12 Sep 2022 12:03:55 +0200 Subject: [PATCH 4/5] Revert ddev config to default --- .ddev/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 8ac94d6a5..3d732fd50 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -3,8 +3,8 @@ type: php docroot: .ddev/wordpress php_version: "7.1" webserver_type: apache-fpm -router_http_port: "8080" -router_https_port: "8443" +router_http_port: "80" +router_https_port: "443" xdebug_enabled: false additional_hostnames: ['wc-pp'] additional_fqdns: [] From 82418a071acff62c2602bc68ce743da072526d22 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 14 Sep 2022 10:39:15 +0200 Subject: [PATCH 5/5] Return array when getting wc orders --- .../CheckoutPaymentApprovalReversed.php | 26 +++++++++---------- .../src/Handler/RequestHandlerTrait.php | 7 ++--- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php b/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php index 772023e4e..7377ec3bd 100644 --- a/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php +++ b/modules/ppcp-webhooks/src/Handler/CheckoutPaymentApprovalReversed.php @@ -78,22 +78,20 @@ class CheckoutPaymentApprovalReversed implements RequestHandler { return $this->no_wc_orders_from_custom_ids( $request, $response ); } - if ( is_array( $wc_orders ) ) { - foreach ( $wc_orders as $wc_order ) { - if ( in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) { - $error_message = sprintf( - // translators: %1$s is the order id. - __( - 'Failed to capture order %1$s through PayPal.', - 'woocommerce-paypal-payments' - ), - (string) $wc_order->get_id() - ); + foreach ( $wc_orders as $wc_order ) { + if ( in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) { + $error_message = sprintf( + // translators: %1$s is the order id. + __( + 'Failed to capture order %1$s through PayPal.', + 'woocommerce-paypal-payments' + ), + (string) $wc_order->get_id() + ); - $this->logger->warning( 'CHECKOUT.PAYMENT-APPROVAL.REVERSED received. ' . $error_message ); + $this->logger->warning( 'CHECKOUT.PAYMENT-APPROVAL.REVERSED received. ' . $error_message ); - $wc_order->update_status( 'failed', $error_message ); - } + $wc_order->update_status( 'failed', $error_message ); } } diff --git a/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php b/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php index e9e7637e9..be155c0ee 100644 --- a/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php +++ b/modules/ppcp-webhooks/src/Handler/RequestHandlerTrait.php @@ -42,9 +42,9 @@ trait RequestHandlerTrait { * Get WC orders from the given custom ids. * * @param array $custom_ids The custom ids. - * @return stdClass|WC_Order[] + * @return WC_Order[] */ - protected function get_wc_orders_from_custom_ids( array $custom_ids ) { + protected function get_wc_orders_from_custom_ids( array $custom_ids ): array { $order_ids = array_map( array( $this, @@ -57,7 +57,8 @@ trait RequestHandlerTrait { 'limit' => -1, ); - return wc_get_orders( $args ); + $orders = wc_get_orders( $args ); + return is_array( $orders ) ? $orders : array(); } /**