mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Add reauthorization functionality.
This commit is contained in:
parent
c6ef12a626
commit
5469cdb3dd
7 changed files with 173 additions and 9 deletions
|
@ -87,6 +87,32 @@ function ppcp_capture_order( WC_Order $wc_order ): void {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes the PayPal order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @throws InvalidArgumentException When the order cannot be captured.
|
||||
* @throws Exception When the operation fails.
|
||||
*/
|
||||
function ppcp_reauthorize_order( WC_Order $wc_order ): void {
|
||||
$intent = strtoupper( (string) $wc_order->get_meta( PayPalGateway::INTENT_META_KEY ) );
|
||||
|
||||
if ( $intent !== 'AUTHORIZE' ) {
|
||||
throw new InvalidArgumentException( 'Only orders with "authorize" intent can be reauthorized.' );
|
||||
}
|
||||
$captured = wc_string_to_bool( $wc_order->get_meta( AuthorizedPaymentsProcessor::CAPTURED_META_KEY ) );
|
||||
if ( $captured ) {
|
||||
throw new InvalidArgumentException( 'The order is already captured.' );
|
||||
}
|
||||
|
||||
$authorized_payment_processor = PPCP::container()->get( 'wcgateway.processor.authorized-payments' );
|
||||
assert( $authorized_payment_processor instanceof AuthorizedPaymentsProcessor );
|
||||
|
||||
if ( $authorized_payment_processor->reauthorize_payment( $wc_order ) !== AuthorizedPaymentsProcessor::SUCCESSFUL ) {
|
||||
throw new RuntimeException( $authorized_payment_processor->reauthorization_failure_reason() ?: 'Reauthorization failed.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refunds the PayPal order.
|
||||
* Note that you can use wc_refund_payment() to trigger the refund in WC and PayPal.
|
||||
|
|
|
@ -193,6 +193,53 @@ class PaymentsEndpoint {
|
|||
return $this->capture_factory->from_paypal_response( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes an order.
|
||||
*
|
||||
* @param string $authorization_id The id.
|
||||
* @param Money|null $amount The amount to capture. If not specified, the whole authorized amount is captured.
|
||||
*
|
||||
* @return string
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function reauthorize( string $authorization_id, ?Money $amount = null ) : string {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id . '/reauthorize';
|
||||
|
||||
$data = array();
|
||||
if ( $amount ) {
|
||||
$data['amount'] = $amount->to_array();
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
'body' => wp_json_encode( $data, JSON_FORCE_OBJECT ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
$json = json_decode( $response['body'] );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
throw new RuntimeException( 'Could not reauthorize authorized payment.' );
|
||||
}
|
||||
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 201 !== $status_code || ! is_object( $json ) ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $json->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refunds a payment.
|
||||
*
|
||||
|
|
|
@ -381,13 +381,15 @@ return array(
|
|||
$notice = $container->get( 'wcgateway.notice.authorize-order-action' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$subscription_helper = $container->get( 'wc-subscriptions.helper' );
|
||||
$amount_factory = $container->get( 'api.factory.amount' );
|
||||
return new AuthorizedPaymentsProcessor(
|
||||
$order_endpoint,
|
||||
$payments_endpoint,
|
||||
$logger,
|
||||
$notice,
|
||||
$settings,
|
||||
$subscription_helper
|
||||
$subscription_helper,
|
||||
$amount_factory
|
||||
);
|
||||
},
|
||||
'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
|
||||
|
|
|
@ -9,9 +9,6 @@ declare( strict_types=1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Admin;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
|
||||
/**
|
||||
* Class RenderAuthorizeAction
|
||||
*/
|
||||
|
|
|
@ -9,9 +9,6 @@ declare( strict_types=1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Admin;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
|
||||
/**
|
||||
* Class RenderReauthorizeAction
|
||||
*/
|
||||
|
@ -47,7 +44,7 @@ class RenderReauthorizeAction {
|
|||
}
|
||||
|
||||
$order_actions['ppcp_reauthorize_order'] = esc_html__(
|
||||
'Reauthorized PayPal payment',
|
||||
'Reauthorize PayPal payment',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
return $order_actions;
|
||||
|
|
|
@ -10,6 +10,8 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\AmountFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
|
@ -91,6 +93,20 @@ class AuthorizedPaymentsProcessor {
|
|||
*/
|
||||
private $subscription_helper;
|
||||
|
||||
/**
|
||||
* The amount factory.
|
||||
*
|
||||
* @var AmountFactory
|
||||
*/
|
||||
private $amount_factory;
|
||||
|
||||
/**
|
||||
* The reauthorization failure reason.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $reauthorization_failure_reason;
|
||||
|
||||
/**
|
||||
* AuthorizedPaymentsProcessor constructor.
|
||||
*
|
||||
|
@ -100,6 +116,7 @@ class AuthorizedPaymentsProcessor {
|
|||
* @param AuthorizeOrderActionNotice $notice The notice.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param AmountFactory $amount_factory The amount factory.
|
||||
*/
|
||||
public function __construct(
|
||||
OrderEndpoint $order_endpoint,
|
||||
|
@ -107,7 +124,8 @@ class AuthorizedPaymentsProcessor {
|
|||
LoggerInterface $logger,
|
||||
AuthorizeOrderActionNotice $notice,
|
||||
ContainerInterface $config,
|
||||
SubscriptionHelper $subscription_helper
|
||||
SubscriptionHelper $subscription_helper,
|
||||
AmountFactory $amount_factory
|
||||
) {
|
||||
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
|
@ -116,6 +134,7 @@ class AuthorizedPaymentsProcessor {
|
|||
$this->notice = $notice;
|
||||
$this->config = $config;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->amount_factory = $amount_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,6 +268,67 @@ class AuthorizedPaymentsProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes an authorized payment for an WooCommerce order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WooCommerce order.
|
||||
*
|
||||
* @return string The status or reauthorization id.
|
||||
*/
|
||||
public function reauthorize_payment( WC_Order $wc_order ): string {
|
||||
$this->reauthorization_failure_reason = '';
|
||||
|
||||
try {
|
||||
$order = $this->paypal_order_from_wc_order( $wc_order );
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Could not get PayPal order from WC order: ' . $exception->getMessage() );
|
||||
if ( $exception->getCode() === 404 ) {
|
||||
return self::NOT_FOUND;
|
||||
}
|
||||
return self::INACCESSIBLE;
|
||||
}
|
||||
|
||||
$amount = $this->amount_factory->from_wc_order( $wc_order );
|
||||
|
||||
$authorizations = $this->all_authorizations( $order );
|
||||
$uncaptured_authorizations = $this->authorizations_to_capture( ...$authorizations );
|
||||
|
||||
if ( ! $uncaptured_authorizations ) {
|
||||
if ( $this->captured_authorizations( ...$authorizations ) ) {
|
||||
$this->logger->info( 'Authorizations already captured.' );
|
||||
return self::ALREADY_CAPTURED;
|
||||
}
|
||||
|
||||
$this->logger->info( 'Bad authorization.' );
|
||||
return self::BAD_AUTHORIZATION;
|
||||
}
|
||||
|
||||
$authorization = end( $uncaptured_authorizations );
|
||||
|
||||
try {
|
||||
$this->payments_endpoint->reauthorize( $authorization->id(), new Money( $amount->value(), $amount->currency_code() ) );
|
||||
} catch ( PayPalApiException $exception ) {
|
||||
$this->reauthorization_failure_reason = $exception->details()[0]->description ?? null;
|
||||
$this->logger->error( 'Reauthorization failed: ' . $exception->name() . ' | ' . $this->reauthorization_failure_reason );
|
||||
return self::FAILED;
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Failed to capture authorization: ' . $exception->getMessage() );
|
||||
return self::FAILED;
|
||||
}
|
||||
|
||||
return self::SUCCESSFUL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The reason for a failed reauthorization.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function reauthorization_failure_reason(): string {
|
||||
return $this->reauthorization_failure_reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Voids authorizations for the given PayPal order.
|
||||
*
|
||||
|
@ -392,4 +472,5 @@ class AuthorizedPaymentsProcessor {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -642,6 +642,20 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_order_action_ppcp_reauthorize_order',
|
||||
static function ( WC_Order $wc_order ) use ( $container ) {
|
||||
|
||||
/**
|
||||
* The authorized payments processor.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor $authorized_payments_processor
|
||||
*/
|
||||
$authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
$authorized_payments_processor->reauthorize_payment( $wc_order );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue