mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-04 08:47:23 +08:00
coding standards for webhook module
This commit is contained in:
parent
653a765235
commit
7fcda592f7
19 changed files with 813 additions and 409 deletions
|
@ -55,7 +55,7 @@ class EarlyOrderHandler {
|
|||
$orderId = false;
|
||||
foreach ( $order->purchaseUnits() as $purchaseUnit ) {
|
||||
if ( $purchaseUnit->customId() === sanitize_text_field( wp_unslash( $_REQUEST['ppcp-resume-order'] ) ) ) {
|
||||
$orderId = (int) $this->sanitizeCustomId( $purchaseUnit->customId() );
|
||||
$orderId = (int) $this->sanitize_custom_id( $purchaseUnit->customId() );
|
||||
}
|
||||
}
|
||||
if ( $orderId === $resumeOrderId ) {
|
||||
|
|
|
@ -31,7 +31,7 @@ class ReturnUrlEndpoint {
|
|||
exit;
|
||||
}
|
||||
|
||||
$wcOrderId = $this->sanitizeCustomId( $order->purchaseUnits()[0]->customId() );
|
||||
$wcOrderId = $this->sanitize_custom_id( $order->purchaseUnits()[0]->customId() );
|
||||
if ( ! $wcOrderId ) {
|
||||
exit;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* The webhook module extensions.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks;
|
||||
|
||||
return [
|
||||
|
||||
];
|
||||
return array();
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* The webhook module.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -7,5 +12,5 @@ namespace Inpsyde\PayPalCommerce\Webhooks;
|
|||
use Dhii\Modular\Module\ModuleInterface;
|
||||
|
||||
return static function (): ModuleInterface {
|
||||
return new WebhookModule();
|
||||
return new WebhookModule();
|
||||
};
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* The webhook module services.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -11,43 +16,43 @@ use Inpsyde\PayPalCommerce\Webhooks\Handler\PaymentCaptureRefunded;
|
|||
use Inpsyde\PayPalCommerce\Webhooks\Handler\PaymentCaptureReversed;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
return [
|
||||
return array(
|
||||
|
||||
'webhook.registrar' => function(ContainerInterface $container) : WebhookRegistrar {
|
||||
$factory = $container->get('api.factory.webhook');
|
||||
$endpoint = $container->get('api.endpoint.webhook');
|
||||
$restEndpoint = $container->get('webhook.endpoint.controller');
|
||||
return new WebhookRegistrar(
|
||||
$factory,
|
||||
$endpoint,
|
||||
$restEndpoint
|
||||
);
|
||||
},
|
||||
'webhook.endpoint.controller' => function(ContainerInterface $container) : IncomingWebhookEndpoint {
|
||||
$webhookEndpoint = $container->get('api.endpoint.webhook');
|
||||
$webhookFactory = $container->get('api.factory.webhook');
|
||||
$handler = $container->get('webhook.endpoint.handler');
|
||||
$logger = $container->get('woocommerce.logger.woocommerce');
|
||||
$verifyRequest = ! defined('PAYPAL_WEBHOOK_REQUEST_VERIFICATION') || PAYPAL_WEBHOOK_REQUEST_VERIFICATION;
|
||||
'webhook.registrar' => function( ContainerInterface $container ) : WebhookRegistrar {
|
||||
$factory = $container->get( 'api.factory.webhook' );
|
||||
$endpoint = $container->get( 'api.endpoint.webhook' );
|
||||
$rest_endpoint = $container->get( 'webhook.endpoint.controller' );
|
||||
return new WebhookRegistrar(
|
||||
$factory,
|
||||
$endpoint,
|
||||
$rest_endpoint
|
||||
);
|
||||
},
|
||||
'webhook.endpoint.controller' => function( ContainerInterface $container ) : IncomingWebhookEndpoint {
|
||||
$webhook_endpoint = $container->get( 'api.endpoint.webhook' );
|
||||
$webhook_factory = $container->get( 'api.factory.webhook' );
|
||||
$handler = $container->get( 'webhook.endpoint.handler' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$verify_request = ! defined( 'PAYPAL_WEBHOOK_REQUEST_VERIFICATION' ) || PAYPAL_WEBHOOK_REQUEST_VERIFICATION;
|
||||
|
||||
return new IncomingWebhookEndpoint(
|
||||
$webhookEndpoint,
|
||||
$webhookFactory,
|
||||
$logger,
|
||||
$verifyRequest,
|
||||
... $handler
|
||||
);
|
||||
},
|
||||
'webhook.endpoint.handler' => function(ContainerInterface $container) : array {
|
||||
$logger = $container->get('woocommerce.logger.woocommerce');
|
||||
$prefix = $container->get('api.prefix');
|
||||
$orderEndpoint = $container->get('api.endpoint.order');
|
||||
return [
|
||||
new CheckoutOrderApproved($logger, $prefix, $orderEndpoint),
|
||||
new CheckoutOrderCompleted($logger, $prefix),
|
||||
new PaymentCaptureRefunded($logger, $prefix),
|
||||
new PaymentCaptureReversed($logger, $prefix),
|
||||
new PaymentCaptureCompleted($logger, $prefix),
|
||||
];
|
||||
}
|
||||
];
|
||||
return new IncomingWebhookEndpoint(
|
||||
$webhook_endpoint,
|
||||
$webhook_factory,
|
||||
$logger,
|
||||
$verify_request,
|
||||
... $handler
|
||||
);
|
||||
},
|
||||
'webhook.endpoint.handler' => function( ContainerInterface $container ) : array {
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$prefix = $container->get( 'api.prefix' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
return array(
|
||||
new CheckoutOrderApproved( $logger, $prefix, $order_endpoint ),
|
||||
new CheckoutOrderCompleted( $logger, $prefix ),
|
||||
new PaymentCaptureRefunded( $logger, $prefix ),
|
||||
new PaymentCaptureReversed( $logger, $prefix ),
|
||||
new PaymentCaptureCompleted( $logger, $prefix ),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
||||
|
||||
trait PrefixTrait {
|
||||
|
||||
|
||||
private $prefix = '';
|
||||
|
||||
private function sanitizeCustomId( string $customId ): int {
|
||||
|
||||
$orderId = str_replace( $this->prefix, '', $customId );
|
||||
return (int) $orderId;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
||||
|
||||
interface RequestHandler {
|
||||
|
||||
|
||||
public function eventTypes(): array;
|
||||
|
||||
public function responsibleForRequest( \WP_REST_Request $request): bool;
|
||||
|
||||
public function handleRequest( \WP_REST_Request $request): \WP_REST_Response;
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles the Webhook CHECKOUT.ORDER.APPROVED
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -8,47 +13,86 @@ use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
|||
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class CheckoutOrderApproved
|
||||
*/
|
||||
class CheckoutOrderApproved implements RequestHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
private $orderEndpoint;
|
||||
|
||||
public function __construct( LoggerInterface $logger, string $prefix, OrderEndpoint $orderEndpoint ) {
|
||||
$this->logger = $logger;
|
||||
$this->prefix = $prefix;
|
||||
$this->orderEndpoint = $orderEndpoint;
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $order_endpoint;
|
||||
|
||||
/**
|
||||
* CheckoutOrderApproved constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $prefix The prefix.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
*/
|
||||
public function __construct( LoggerInterface $logger, string $prefix, OrderEndpoint $order_endpoint ) {
|
||||
$this->logger = $logger;
|
||||
$this->prefix = $prefix;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
}
|
||||
|
||||
public function eventTypes(): array {
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array(
|
||||
'CHECKOUT.ORDER.APPROVED',
|
||||
);
|
||||
}
|
||||
|
||||
public function responsibleForRequest( \WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->eventTypes(), true );
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
//phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
public function handleRequest( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
$response = array( 'success' => false );
|
||||
$customIds = array_filter(
|
||||
/**
|
||||
* 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 = array_filter(
|
||||
array_map(
|
||||
static function ( array $purchaseUnit ): string {
|
||||
return isset( $purchaseUnit['custom_id'] ) ?
|
||||
(string) $purchaseUnit['custom_id'] : '';
|
||||
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 $orderId ): bool {
|
||||
return ! empty( $orderId );
|
||||
static function ( string $order_id ): bool {
|
||||
return ! empty( $order_id );
|
||||
}
|
||||
);
|
||||
|
||||
if ( empty( $customIds ) ) {
|
||||
if ( empty( $custom_ids ) ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
|
@ -70,7 +114,7 @@ class CheckoutOrderApproved implements RequestHandler {
|
|||
|
||||
try {
|
||||
$order = isset( $request['resource']['id'] ) ?
|
||||
$this->orderEndpoint->order( $request['resource']['id'] ) : null;
|
||||
$this->order_endpoint->order( $request['resource']['id'] ) : null;
|
||||
if ( ! $order ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
|
@ -92,7 +136,7 @@ class CheckoutOrderApproved implements RequestHandler {
|
|||
}
|
||||
|
||||
if ( $order->intent() === 'CAPTURE' ) {
|
||||
$this->orderEndpoint->capture( $order );
|
||||
$this->order_endpoint->capture( $order );
|
||||
}
|
||||
} catch ( RuntimeException $error ) {
|
||||
$message = sprintf(
|
||||
|
@ -114,19 +158,19 @@ class CheckoutOrderApproved implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
$wcOrderIds = array_map(
|
||||
$wc_order_ids = array_map(
|
||||
array(
|
||||
$this,
|
||||
'sanitizeCustomId',
|
||||
'sanitize_custom_id',
|
||||
),
|
||||
$customIds
|
||||
$custom_ids
|
||||
);
|
||||
$args = array(
|
||||
'post__in' => $wcOrderIds,
|
||||
$args = array(
|
||||
'post__in' => $wc_order_ids,
|
||||
'limit' => -1,
|
||||
);
|
||||
$wcOrders = wc_get_orders( $args );
|
||||
if ( ! $wcOrders ) {
|
||||
$wc_orders = wc_get_orders( $args );
|
||||
if ( ! $wc_orders ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal order Id.
|
||||
__( 'Order for PayPal order %s not found.', 'woocommerce-paypal-commerce-gateway' ),
|
||||
|
@ -143,20 +187,22 @@ class CheckoutOrderApproved implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
$newStatus = $order->intent() === 'CAPTURE' ? 'processing' : 'on-hold';
|
||||
$statusMessage = $order->intent() === 'CAPTURE' ?
|
||||
$new_status = $order->intent() === 'CAPTURE' ? 'processing' : 'on-hold';
|
||||
$status_message = $order->intent() === 'CAPTURE' ?
|
||||
__( 'Payment received.', 'woocommerce-paypal-commerce-gateway' )
|
||||
: __( 'Payment can be captured.', 'woocommerce-paypal-commerce-gateway' );
|
||||
foreach ( $wcOrders as $wcOrder ) {
|
||||
if ( ! in_array( $wcOrder->get_status(), array( 'pending', 'on-hold' ), true ) ) {
|
||||
foreach ( $wc_orders as $wc_order ) {
|
||||
if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
|
||||
continue;
|
||||
}
|
||||
/**
|
||||
* @var \WC_Order $wcOrder
|
||||
* The Woocommerce order.
|
||||
*
|
||||
* @var \WC_Order $wc_order
|
||||
*/
|
||||
$wcOrder->update_status(
|
||||
$newStatus,
|
||||
$statusMessage
|
||||
$wc_order->update_status(
|
||||
$new_status,
|
||||
$status_message
|
||||
);
|
||||
$this->logger->log(
|
||||
'info',
|
||||
|
@ -166,16 +212,15 @@ class CheckoutOrderApproved implements RequestHandler {
|
|||
'Order %s has been updated through PayPal',
|
||||
'woocommerce-paypal-commerce-gateway'
|
||||
),
|
||||
(string) $wcOrder->get_id()
|
||||
(string) $wc_order->get_id()
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
'order' => $wcOrder,
|
||||
'order' => $wc_order,
|
||||
)
|
||||
);
|
||||
}
|
||||
$response['success'] = true;
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
//phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles the Webhook CHECKOUT.ORDER.COMPLETED
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -6,44 +11,77 @@ namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class CheckoutOrderCompleted
|
||||
*/
|
||||
class CheckoutOrderCompleted implements RequestHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* CheckoutOrderCompleted constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $prefix The prefix.
|
||||
*/
|
||||
public function __construct( LoggerInterface $logger, string $prefix ) {
|
||||
$this->logger = $logger;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
public function eventTypes(): array {
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array(
|
||||
'CHECKOUT.ORDER.COMPLETED',
|
||||
);
|
||||
}
|
||||
|
||||
public function responsibleForRequest( \WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->eventTypes(), true );
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
public function handleRequest( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
$response = array( 'success' => false );
|
||||
$customIds = array_filter(
|
||||
/**
|
||||
* 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 = array_filter(
|
||||
array_map(
|
||||
static function ( array $purchaseUnit ): string {
|
||||
return isset( $purchaseUnit['custom_id'] ) ?
|
||||
(string) $purchaseUnit['custom_id'] : '';
|
||||
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 $orderId ): bool {
|
||||
return ! empty( $orderId );
|
||||
static function ( string $order_id ): bool {
|
||||
return ! empty( $order_id );
|
||||
}
|
||||
);
|
||||
|
||||
if ( empty( $customIds ) ) {
|
||||
if ( empty( $custom_ids ) ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
|
@ -63,19 +101,19 @@ class CheckoutOrderCompleted implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
$orderIds = array_map(
|
||||
$order_ids = array_map(
|
||||
array(
|
||||
$this,
|
||||
'sanitizeCustomId',
|
||||
'sanitize_custom_id',
|
||||
),
|
||||
$customIds
|
||||
$custom_ids
|
||||
);
|
||||
$args = array(
|
||||
'post__in' => $orderIds,
|
||||
$args = array(
|
||||
'post__in' => $order_ids,
|
||||
'limit' => -1,
|
||||
);
|
||||
$wcOrders = wc_get_orders( $args );
|
||||
if ( ! $wcOrders ) {
|
||||
$wc_orders = wc_get_orders( $args );
|
||||
if ( ! $wc_orders ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal order Id.
|
||||
__( 'Order for PayPal order %s not found.', 'woocommerce-paypal-commerce-gateway' ),
|
||||
|
@ -92,14 +130,16 @@ class CheckoutOrderCompleted implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
foreach ( $wcOrders as $wcOrder ) {
|
||||
if ( ! in_array( $wcOrder->get_status(), array( 'pending', 'on-hold' ), true ) ) {
|
||||
foreach ( $wc_orders as $wc_order ) {
|
||||
if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) {
|
||||
continue;
|
||||
}
|
||||
/**
|
||||
* @var \WC_Order $wcOrder
|
||||
* The Woocommerce order.
|
||||
*
|
||||
* @var \WC_Order $wc_order
|
||||
*/
|
||||
$wcOrder->update_status(
|
||||
$wc_order->update_status(
|
||||
'processing',
|
||||
__( 'Payment received.', 'woocommerce-paypal-commerce-gateway' )
|
||||
);
|
||||
|
@ -111,16 +151,16 @@ class CheckoutOrderCompleted implements RequestHandler {
|
|||
'Order %s has been updated through PayPal',
|
||||
'woocommerce-paypal-commerce-gateway'
|
||||
),
|
||||
(string) $wcOrder->get_id()
|
||||
(string) $wc_order->get_id()
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
'order' => $wcOrder,
|
||||
'order' => $wc_order,
|
||||
)
|
||||
);
|
||||
}
|
||||
$response['success'] = true;
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles the Webhook PAYMENT.CAPTURE.COMPLETED
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -7,30 +12,63 @@ namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
|||
use Inpsyde\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class PaymentCaptureCompleted
|
||||
*/
|
||||
class PaymentCaptureCompleted implements RequestHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* PaymentCaptureCompleted constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $prefix The prefix.
|
||||
*/
|
||||
public function __construct( LoggerInterface $logger, string $prefix ) {
|
||||
$this->logger = $logger;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
public function eventTypes(): array {
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array( 'PAYMENT.CAPTURE.COMPLETED' );
|
||||
}
|
||||
|
||||
public function responsibleForRequest( \WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->eventTypes(), true );
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
public function handleRequest( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
/**
|
||||
* 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 );
|
||||
$orderId = isset( $request['resource']['custom_id'] ) ?
|
||||
$this->sanitizeCustomId( $request['resource']['custom_id'] ) : 0;
|
||||
if ( ! $orderId ) {
|
||||
$order_id = isset( $request['resource']['custom_id'] ) ?
|
||||
$this->sanitize_custom_id( $request['resource']['custom_id'] ) : 0;
|
||||
if ( ! $order_id ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
|
@ -49,9 +87,9 @@ class PaymentCaptureCompleted implements RequestHandler {
|
|||
$response['message'] = $message;
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
$wcOrder = wc_get_order( $orderId );
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
|
||||
if ( ! is_a( $wcOrder, \WC_Order::class ) ) {
|
||||
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
|
@ -71,17 +109,17 @@ class PaymentCaptureCompleted implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
if ( $wcOrder->get_status() !== 'on-hold' ) {
|
||||
if ( $wc_order->get_status() !== 'on-hold' ) {
|
||||
$response['success'] = true;
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
$wcOrder->add_order_note(
|
||||
$wc_order->add_order_note(
|
||||
__( 'Payment successfully captured.', 'woocommerce-paypal-commerce-gateway' )
|
||||
);
|
||||
|
||||
$wcOrder->set_status( 'processing' );
|
||||
$wcOrder->update_meta_data( PayPalGateway::CAPTURED_META_KEY, 'true' );
|
||||
$wcOrder->save();
|
||||
$wc_order->set_status( 'processing' );
|
||||
$wc_order->update_meta_data( PayPalGateway::CAPTURED_META_KEY, 'true' );
|
||||
$wc_order->save();
|
||||
$this->logger->log(
|
||||
'info',
|
||||
sprintf(
|
||||
|
@ -90,15 +128,14 @@ class PaymentCaptureCompleted implements RequestHandler {
|
|||
'Order %s has been updated through PayPal',
|
||||
'woocommerce-paypal-commerce-gateway'
|
||||
),
|
||||
(string) $wcOrder->get_id()
|
||||
(string) $wc_order->get_id()
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
'order' => $wcOrder,
|
||||
'order' => $wc_order,
|
||||
)
|
||||
);
|
||||
$response['success'] = true;
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* Handels the Webhook PAYMENT.CAPTURE.REFUNDED
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -6,30 +11,63 @@ namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class PaymentCaptureRefunded
|
||||
*/
|
||||
class PaymentCaptureRefunded implements RequestHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* PaymentCaptureRefunded constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $prefix The prefix.
|
||||
*/
|
||||
public function __construct( LoggerInterface $logger, string $prefix ) {
|
||||
$this->logger = $logger;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
public function eventTypes(): array {
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array( 'PAYMENT.CAPTURE.REFUNDED' );
|
||||
}
|
||||
|
||||
public function responsibleForRequest( \WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->eventTypes(), true );
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
public function handleRequest( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
/**
|
||||
* 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 );
|
||||
$orderId = isset( $request['resource']['custom_id'] ) ?
|
||||
$this->sanitizeCustomId( $request['resource']['custom_id'] ) : 0;
|
||||
if ( ! $orderId ) {
|
||||
$order_id = isset( $request['resource']['custom_id'] ) ?
|
||||
$this->sanitize_custom_id( $request['resource']['custom_id'] ) : 0;
|
||||
if ( ! $order_id ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
|
@ -49,8 +87,8 @@ class PaymentCaptureRefunded implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
$wcOrder = wc_get_order( $orderId );
|
||||
if ( ! is_a( $wcOrder, \WC_Order::class ) ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal refund Id.
|
||||
__( 'Order for PayPal refund %s not found.', 'woocommerce-paypal-commerce-gateway' ),
|
||||
|
@ -68,11 +106,13 @@ class PaymentCaptureRefunded implements RequestHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* @var \WC_Order $wcOrder
|
||||
* The Woocommerce order.
|
||||
*
|
||||
* @var \WC_Order $wc_order
|
||||
*/
|
||||
$refund = wc_create_refund(
|
||||
array(
|
||||
'order_id' => $wcOrder->get_id(),
|
||||
'order_id' => $wc_order->get_id(),
|
||||
'amount' => $request['resource']['amount']['value'],
|
||||
)
|
||||
);
|
||||
|
@ -82,7 +122,7 @@ class PaymentCaptureRefunded implements RequestHandler {
|
|||
sprintf(
|
||||
// translators: %s is the order id.
|
||||
__( 'Order %s could not be refunded', 'woocommerce-paypal-commerce-gateway' ),
|
||||
(string) $wcOrder->get_id()
|
||||
(string) $wc_order->get_id()
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
|
@ -102,16 +142,15 @@ class PaymentCaptureRefunded implements RequestHandler {
|
|||
'Order %1$s has been refunded with %2$s through PayPal',
|
||||
'woocommerce-paypal-commerce-gateway'
|
||||
),
|
||||
(string) $wcOrder->get_id(),
|
||||
(string) $wc_order->get_id(),
|
||||
(string) $refund->get_amount()
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
'order' => $wcOrder,
|
||||
'order' => $wc_order,
|
||||
)
|
||||
);
|
||||
$response['success'] = true;
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
}
|
|
@ -1,4 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles the following Webhooks:
|
||||
* - PAYMENT.CAPTURE.REVERSED
|
||||
* - PAYMENT.ORDER.CANCELLED
|
||||
* - PAYMENT.CAPTURE.DENIED
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -6,17 +14,37 @@ namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class PaymentCaptureReversed
|
||||
*/
|
||||
class PaymentCaptureReversed implements RequestHandler {
|
||||
|
||||
use PrefixTrait;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* PaymentCaptureReversed constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $prefix The prefix.
|
||||
*/
|
||||
public function __construct( LoggerInterface $logger, string $prefix ) {
|
||||
$this->logger = $logger;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
public function eventTypes(): array {
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array(
|
||||
'PAYMENT.CAPTURE.REVERSED',
|
||||
'PAYMENT.ORDER.CANCELLED',
|
||||
|
@ -24,16 +52,29 @@ class PaymentCaptureReversed implements RequestHandler {
|
|||
);
|
||||
}
|
||||
|
||||
public function responsibleForRequest( \WP_REST_Request $request ): bool {
|
||||
return in_array( $request['event_type'], $this->eventTypes(), true );
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
// phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
public function handleRequest( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
/**
|
||||
* 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 );
|
||||
$orderId = isset( $request['resource']['custom_id'] ) ?
|
||||
$this->sanitizeCustomId( $request['resource']['custom_id'] ) : 0;
|
||||
if ( ! $orderId ) {
|
||||
$order_id = isset( $request['resource']['custom_id'] ) ?
|
||||
$this->sanitize_custom_id( $request['resource']['custom_id'] ) : 0;
|
||||
if ( ! $order_id ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal webhook Id.
|
||||
__(
|
||||
|
@ -53,8 +94,8 @@ class PaymentCaptureReversed implements RequestHandler {
|
|||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
$wcOrder = wc_get_order( $orderId );
|
||||
if ( ! is_a( $wcOrder, \WC_Order::class ) ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
||||
$message = sprintf(
|
||||
// translators: %s is the PayPal refund Id.
|
||||
__( 'Order for PayPal refund %s not found.', 'woocommerce-paypal-commerce-gateway' ),
|
||||
|
@ -72,9 +113,11 @@ class PaymentCaptureReversed implements RequestHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* @var \WC_Order $wcOrder
|
||||
* The Woocommerce order.
|
||||
*
|
||||
* @var \WC_Order $wc_order
|
||||
*/
|
||||
$response['success'] = (bool) $wcOrder->update_status( 'cancelled' );
|
||||
$response['success'] = (bool) $wc_order->update_status( 'cancelled' );
|
||||
|
||||
$message = $response['success'] ? sprintf(
|
||||
// translators: %1$s is the order id.
|
||||
|
@ -82,21 +125,20 @@ class PaymentCaptureReversed implements RequestHandler {
|
|||
'Order %1$s has been cancelled through PayPal',
|
||||
'woocommerce-paypal-commerce-gateway'
|
||||
),
|
||||
(string) $wcOrder->get_id()
|
||||
(string) $wc_order->get_id()
|
||||
) : sprintf(
|
||||
// translators: %1$s is the order id.
|
||||
__( 'Failed to cancel order %1$s through PayPal', 'woocommerce-paypal-commerce-gateway' ),
|
||||
(string) $wcOrder->get_id()
|
||||
(string) $wc_order->get_id()
|
||||
);
|
||||
$this->logger->log(
|
||||
$response['success'] ? 'info' : 'warning',
|
||||
$message,
|
||||
array(
|
||||
'request' => $request,
|
||||
'order' => $wcOrder,
|
||||
'order' => $wc_order,
|
||||
)
|
||||
);
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
// phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* Trait which helps to remove the prefix of IDs.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
||||
|
||||
/**
|
||||
* Trait PrefixTrait
|
||||
*/
|
||||
trait PrefixTrait {
|
||||
|
||||
|
||||
/**
|
||||
* The prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $prefix = '';
|
||||
|
||||
/**
|
||||
* Removes the prefix from a given Id.
|
||||
*
|
||||
* @param string $custom_id The custom id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function sanitize_custom_id( string $custom_id ): int {
|
||||
|
||||
$id = str_replace( $this->prefix, '', $custom_id );
|
||||
return (int) $id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* The interface for the request handlers.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks\Handler;
|
||||
|
||||
/**
|
||||
* Interface RequestHandler
|
||||
*/
|
||||
interface RequestHandler {
|
||||
|
||||
/**
|
||||
* The event types a handler handles.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function event_types(): array;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||
use Inpsyde\PayPalCommerce\Webhooks\Handler\RequestHandler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class IncomingWebhookEndpoint {
|
||||
|
||||
|
||||
public const NAMESPACE = 'paypal/v1';
|
||||
public const ROUTE = 'incoming';
|
||||
private $webhookEndpoint;
|
||||
private $webhookFactory;
|
||||
private $handlers;
|
||||
private $logger;
|
||||
private $verifyRequest;
|
||||
public function __construct(
|
||||
WebhookEndpoint $webhookEndpoint,
|
||||
WebhookFactory $webhookFactory,
|
||||
LoggerInterface $logger,
|
||||
bool $verifyRequest,
|
||||
RequestHandler ...$handlers
|
||||
) {
|
||||
|
||||
$this->webhookEndpoint = $webhookEndpoint;
|
||||
$this->webhookFactory = $webhookFactory;
|
||||
$this->handlers = $handlers;
|
||||
$this->logger = $logger;
|
||||
$this->verifyRequest = $verifyRequest;
|
||||
}
|
||||
|
||||
public function register(): bool {
|
||||
return (bool) register_rest_route(
|
||||
self::NAMESPACE,
|
||||
self::ROUTE,
|
||||
array(
|
||||
'methods' => array(
|
||||
'POST',
|
||||
),
|
||||
'callback' => array(
|
||||
$this,
|
||||
'handleRequest',
|
||||
),
|
||||
'permission_callback' => array(
|
||||
$this,
|
||||
'verifyRequest',
|
||||
),
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function verifyRequest(): bool {
|
||||
if ( ! $this->verifyRequest ) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
$data = (array) get_option( WebhookRegistrar::KEY, array() );
|
||||
$webhook = $this->webhookFactory->fromArray( $data );
|
||||
$result = $this->webhookEndpoint->verifyCurrentRequestForWebhook( $webhook );
|
||||
if ( ! $result ) {
|
||||
$this->logger->log(
|
||||
'error',
|
||||
__( 'Illegit Webhook request detected.', 'woocommerce-paypal-commerce-gateway' ),
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$this->logger->log(
|
||||
'error',
|
||||
sprintf(
|
||||
// translators: %s is the error message.
|
||||
__(
|
||||
'Illegit Webhook request detected: %s',
|
||||
'woocommerce-paypal-commerce-gateway'
|
||||
),
|
||||
$exception->getMessage()
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function handleRequest( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
|
||||
foreach ( $this->handlers as $handler ) {
|
||||
if ( $handler->responsibleForRequest( $request ) ) {
|
||||
$response = $handler->handleRequest( $request );
|
||||
$this->logger->log(
|
||||
'info',
|
||||
sprintf(
|
||||
// translators: %s is the event type
|
||||
__( 'Webhook has been handled by %s', 'woocommerce-paypal-commerce-gateway' ),
|
||||
( $handler->eventTypes() ) ? current( $handler->eventTypes() ) : ''
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
'response' => $response,
|
||||
)
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
// translators: %s is the request type.
|
||||
__( 'Could not find handler for request type %s', 'woocommerce-paypal-commerce-gateway' ),
|
||||
$request['event_type']
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$message,
|
||||
array(
|
||||
'request' => $request,
|
||||
)
|
||||
);
|
||||
$response = array(
|
||||
'success' => false,
|
||||
'message' => $message,
|
||||
);
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
public function url(): string {
|
||||
return rest_url( self::NAMESPACE . '/' . self::ROUTE );
|
||||
}
|
||||
|
||||
public function handledEventTypes(): array {
|
||||
$eventTypes = array();
|
||||
foreach ( $this->handlers as $handler ) {
|
||||
$eventTypes = array_merge( $eventTypes, $handler->eventTypes() );
|
||||
}
|
||||
return array_unique( $eventTypes );
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||
|
||||
class WebhookRegistrar {
|
||||
|
||||
|
||||
public const EVENT_HOOK = 'ppcp-register-event';
|
||||
public const KEY = 'ppcp-webhook';
|
||||
|
||||
private $webhookFactory;
|
||||
private $endpoint;
|
||||
private $restEndpoint;
|
||||
public function __construct(
|
||||
WebhookFactory $webhookFactory,
|
||||
WebhookEndpoint $endpoint,
|
||||
IncomingWebhookEndpoint $restEndpoint
|
||||
) {
|
||||
|
||||
$this->webhookFactory = $webhookFactory;
|
||||
$this->endpoint = $endpoint;
|
||||
$this->restEndpoint = $restEndpoint;
|
||||
}
|
||||
|
||||
public function register(): bool {
|
||||
$webhook = $this->webhookFactory->forUrlAndEvents(
|
||||
$this->restEndpoint->url(),
|
||||
$this->restEndpoint->handledEventTypes()
|
||||
);
|
||||
|
||||
try {
|
||||
$created = $this->endpoint->create( $webhook );
|
||||
if ( empty( $created->id() ) ) {
|
||||
return false;
|
||||
}
|
||||
update_option(
|
||||
self::KEY,
|
||||
$created->toArray()
|
||||
);
|
||||
return true;
|
||||
} catch ( RuntimeException $error ) {
|
||||
wp_schedule_single_event(
|
||||
time() - 1,
|
||||
self::EVENT_HOOK
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function unregister(): bool {
|
||||
$data = (array) get_option( self::KEY, array() );
|
||||
if ( ! $data ) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$webhook = $this->webhookFactory->fromArray( $data );
|
||||
$success = $this->endpoint->delete( $webhook );
|
||||
} catch ( RuntimeException $error ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $success ) {
|
||||
delete_option( self::KEY );
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
/**
|
||||
* Controls the endpoint for the incoming webhooks.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||
use Inpsyde\PayPalCommerce\Webhooks\Handler\RequestHandler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class IncomingWebhookEndpoint
|
||||
*/
|
||||
class IncomingWebhookEndpoint {
|
||||
|
||||
public const NAMESPACE = 'paypal/v1';
|
||||
public const ROUTE = 'incoming';
|
||||
|
||||
/**
|
||||
* The Webhook endpoint.
|
||||
*
|
||||
* @var WebhookEndpoint
|
||||
*/
|
||||
private $webhook_endpoint;
|
||||
|
||||
/**
|
||||
* The Webhook Factory.
|
||||
*
|
||||
* @var WebhookFactory
|
||||
*/
|
||||
private $webhook_factory;
|
||||
|
||||
/**
|
||||
* The Request handlers.
|
||||
*
|
||||
* @var RequestHandler[]
|
||||
*/
|
||||
private $handlers;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Whether requests need to be verified.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $verify_request;
|
||||
|
||||
/**
|
||||
* IncomingWebhookEndpoint constructor.
|
||||
*
|
||||
* @param WebhookEndpoint $webhook_endpoint The webhook endpoint.
|
||||
* @param WebhookFactory $webhook_factory The webhook factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param bool $verify_request Whether requests need to be verified or not.
|
||||
* @param RequestHandler ...$handlers The handlers, which process a request in the end.
|
||||
*/
|
||||
public function __construct(
|
||||
WebhookEndpoint $webhook_endpoint,
|
||||
WebhookFactory $webhook_factory,
|
||||
LoggerInterface $logger,
|
||||
bool $verify_request,
|
||||
RequestHandler ...$handlers
|
||||
) {
|
||||
|
||||
$this->webhook_endpoint = $webhook_endpoint;
|
||||
$this->webhook_factory = $webhook_factory;
|
||||
$this->handlers = $handlers;
|
||||
$this->logger = $logger;
|
||||
$this->verify_request = $verify_request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the endpoint.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function register(): bool {
|
||||
return (bool) register_rest_route(
|
||||
self::NAMESPACE,
|
||||
self::ROUTE,
|
||||
array(
|
||||
'methods' => array(
|
||||
'POST',
|
||||
),
|
||||
'callback' => array(
|
||||
$this,
|
||||
'handle_request',
|
||||
),
|
||||
'permission_callback' => array(
|
||||
$this,
|
||||
'verify_request',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the current request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verify_request(): bool {
|
||||
if ( ! $this->verify_request ) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
$data = (array) get_option( WebhookRegistrar::KEY, array() );
|
||||
$webhook = $this->webhook_factory->fromArray( $data );
|
||||
$result = $this->webhook_endpoint->verifyCurrentRequestForWebhook( $webhook );
|
||||
if ( ! $result ) {
|
||||
$this->logger->log(
|
||||
'error',
|
||||
__( 'Illegit Webhook request detected.', 'woocommerce-paypal-commerce-gateway' )
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$this->logger->log(
|
||||
'error',
|
||||
sprintf(
|
||||
// translators: %s is the error message.
|
||||
__(
|
||||
'Illegit Webhook request detected: %s',
|
||||
'woocommerce-paypal-commerce-gateway'
|
||||
),
|
||||
$exception->getMessage()
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @param \WP_REST_Request $request The request.
|
||||
*
|
||||
* @return \WP_REST_Response
|
||||
*/
|
||||
public function handle_request( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
|
||||
foreach ( $this->handlers as $handler ) {
|
||||
if ( $handler->responsible_for_request( $request ) ) {
|
||||
$response = $handler->handle_request( $request );
|
||||
$this->logger->log(
|
||||
'info',
|
||||
sprintf(
|
||||
// translators: %s is the event type.
|
||||
__( 'Webhook has been handled by %s', 'woocommerce-paypal-commerce-gateway' ),
|
||||
( $handler->event_types() ) ? current( $handler->event_types() ) : ''
|
||||
),
|
||||
array(
|
||||
'request' => $request,
|
||||
'response' => $response,
|
||||
)
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
// translators: %s is the request type.
|
||||
__( 'Could not find handler for request type %s', 'woocommerce-paypal-commerce-gateway' ),
|
||||
$request['event_type']
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$message,
|
||||
array(
|
||||
'request' => $request,
|
||||
)
|
||||
);
|
||||
$response = array(
|
||||
'success' => false,
|
||||
'message' => $message,
|
||||
);
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to the endpoint.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url(): string {
|
||||
return rest_url( self::NAMESPACE . '/' . self::ROUTE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event types, which are handled by the endpoint.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function handled_event_types(): array {
|
||||
$event_types = array();
|
||||
foreach ( $this->handlers as $handler ) {
|
||||
$event_types = array_merge( $event_types, $handler->event_types() );
|
||||
}
|
||||
return array_unique( $event_types );
|
||||
}
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* The webhook module.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -6,15 +11,19 @@ namespace Inpsyde\PayPalCommerce\Webhooks;
|
|||
|
||||
use Dhii\Container\ServiceProvider;
|
||||
use Dhii\Modular\Module\ModuleInterface;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Entity\Webhook;
|
||||
use Inpsyde\PayPalCommerce\Onboarding\Assets\OnboardingAssets;
|
||||
use Inpsyde\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint;
|
||||
use Inpsyde\PayPalCommerce\Onboarding\Render\OnboardingRenderer;
|
||||
use Interop\Container\ServiceProviderInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Class WebhookModule
|
||||
*/
|
||||
class WebhookModule implements ModuleInterface {
|
||||
|
||||
/**
|
||||
* Setup the Webhook module.
|
||||
*
|
||||
* @return ServiceProviderInterface
|
||||
*/
|
||||
public function setup(): ServiceProviderInterface {
|
||||
return new ServiceProvider(
|
||||
require __DIR__ . '/../services.php',
|
||||
|
@ -22,12 +31,19 @@ class WebhookModule implements ModuleInterface {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the Webhook module.
|
||||
*
|
||||
* @param ContainerInterface $container The Container.
|
||||
*/
|
||||
public function run( ContainerInterface $container ) {
|
||||
add_action(
|
||||
'rest_api_init',
|
||||
static function () use ( $container ) {
|
||||
$endpoint = $container->get( 'webhook.endpoint.controller' );
|
||||
/**
|
||||
* The Incoming Webhook Endpoint.
|
||||
*
|
||||
* @var IncomingWebhookEndpoint $endpoint
|
||||
*/
|
||||
$endpoint->register();
|
||||
|
@ -38,6 +54,11 @@ class WebhookModule implements ModuleInterface {
|
|||
WebhookRegistrar::EVENT_HOOK,
|
||||
static function () use ( $container ) {
|
||||
$registrar = $container->get( 'webhook.registrar' );
|
||||
/**
|
||||
* The Webhook Registrar.
|
||||
*
|
||||
* @var WebhookRegistrar $endpoint
|
||||
*/
|
||||
$registrar->register();
|
||||
}
|
||||
);
|
||||
|
@ -46,6 +67,11 @@ class WebhookModule implements ModuleInterface {
|
|||
'woocommerce-paypal-commerce-gateway.deactivate',
|
||||
static function () use ( $container ) {
|
||||
$registrar = $container->get( 'webhook.registrar' );
|
||||
/**
|
||||
* The Webhook Registrar.
|
||||
*
|
||||
* @var WebhookRegistrar $endpoint
|
||||
*/
|
||||
$registrar->unregister();
|
||||
}
|
||||
);
|
116
modules.local/ppcp-webhooks/src/class-webhookregistrar.php
Normal file
116
modules.local/ppcp-webhooks/src/class-webhookregistrar.php
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
/**
|
||||
* The WebhookRegistrar registers and unregisters webhooks with PayPal.
|
||||
*
|
||||
* @package Inpsyde\PayPalCommerce\Webhooks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Inpsyde\PayPalCommerce\Webhooks;
|
||||
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\WebhookEndpoint;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use Inpsyde\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||
|
||||
/**
|
||||
* Class WebhookRegistrar
|
||||
*/
|
||||
class WebhookRegistrar {
|
||||
|
||||
|
||||
public const EVENT_HOOK = 'ppcp-register-event';
|
||||
public const KEY = 'ppcp-webhook';
|
||||
|
||||
/**
|
||||
* The Webhook factory.
|
||||
*
|
||||
* @var WebhookFactory
|
||||
*/
|
||||
private $webhook_factory;
|
||||
|
||||
/**
|
||||
* The Webhook endpoint.
|
||||
*
|
||||
* @var WebhookEndpoint
|
||||
*/
|
||||
private $endpoint;
|
||||
|
||||
/**
|
||||
* The WordPress Rest API endpoint.
|
||||
*
|
||||
* @var IncomingWebhookEndpoint
|
||||
*/
|
||||
private $rest_endpoint;
|
||||
|
||||
/**
|
||||
* WebhookRegistrar constructor.
|
||||
*
|
||||
* @param WebhookFactory $webhook_factory The Webhook factory.
|
||||
* @param WebhookEndpoint $endpoint The Webhook endpoint.
|
||||
* @param IncomingWebhookEndpoint $rest_endpoint The WordPress Rest API endpoint.
|
||||
*/
|
||||
public function __construct(
|
||||
WebhookFactory $webhook_factory,
|
||||
WebhookEndpoint $endpoint,
|
||||
IncomingWebhookEndpoint $rest_endpoint
|
||||
) {
|
||||
|
||||
$this->webhook_factory = $webhook_factory;
|
||||
$this->endpoint = $endpoint;
|
||||
$this->rest_endpoint = $rest_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Webhooks with PayPal.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function register(): bool {
|
||||
$webhook = $this->webhook_factory->forUrlAndEvents(
|
||||
$this->rest_endpoint->url(),
|
||||
$this->rest_endpoint->handled_event_types()
|
||||
);
|
||||
|
||||
try {
|
||||
$created = $this->endpoint->create( $webhook );
|
||||
if ( empty( $created->id() ) ) {
|
||||
return false;
|
||||
}
|
||||
update_option(
|
||||
self::KEY,
|
||||
$created->toArray()
|
||||
);
|
||||
return true;
|
||||
} catch ( RuntimeException $error ) {
|
||||
wp_schedule_single_event(
|
||||
time() - 1,
|
||||
self::EVENT_HOOK
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister webhooks with PayPal.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function unregister(): bool {
|
||||
$data = (array) get_option( self::KEY, array() );
|
||||
if ( ! $data ) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$webhook = $this->webhook_factory->fromArray( $data );
|
||||
$success = $this->endpoint->delete( $webhook );
|
||||
} catch ( RuntimeException $error ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $success ) {
|
||||
delete_option( self::KEY );
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue