Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle denied authorization #313

Merged
merged 13 commits into from
Oct 7, 2021
4 changes: 3 additions & 1 deletion modules/ppcp-api-client/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,14 @@
},
'api.endpoint.payments' => static function ( $container ): PaymentsEndpoint {
$authorizations_factory = $container->get( 'api.factory.authorization' );
$logger = $container->get( 'woocommerce.logger.woocommerce' );
$capture_factory = $container->get( 'api.factory.capture' );
$logger = $container->get( 'woocommerce.logger.woocommerce' );

return new PaymentsEndpoint(
$container->get( 'api.host' ),
$container->get( 'api.bearer' ),
$authorizations_factory,
$capture_factory,
$logger
);
},
Expand Down
12 changes: 10 additions & 2 deletions modules/ppcp-api-client/src/Endpoint/class-orderendpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
Expand Down Expand Up @@ -338,8 +340,8 @@ public function capture( Order $order ): Order {

$order = $this->order_factory->from_paypal_response( $json );

$purchase_units_payments_captures_status = $order->purchase_units()[0]->payments()->captures()[0]->status() ?? '';
if ( $purchase_units_payments_captures_status && 'DECLINED' === $purchase_units_payments_captures_status ) {
$capture_status = $order->purchase_units()[0]->payments()->captures()[0]->status() ?? null;
if ( $capture_status && $capture_status->is( CaptureStatus::DECLINED ) ) {
throw new RuntimeException( __( 'Payment provider declined the payment, please use a different payment method.', 'woocommerce-paypal-payments' ) );
}

Expand Down Expand Up @@ -412,6 +414,12 @@ public function authorize( Order $order ): Order {
throw $error;
}
$order = $this->order_factory->from_paypal_response( $json );

$authorization_status = $order->purchase_units()[0]->payments()->authorizations()[0]->status() ?? null;
if ( $authorization_status && $authorization_status->is( AuthorizationStatus::DENIED ) ) {
throw new RuntimeException( __( 'Payment provider declined the payment, please use a different payment method.', 'woocommerce-paypal-payments' ) );
}

return $order;
}

Expand Down
18 changes: 15 additions & 3 deletions modules/ppcp-api-client/src/Endpoint/class-paymentsendpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@

use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use Woocommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Refund;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\ApiClient\Factory\CaptureFactory;

/**
* Class PaymentsEndpoint
Expand Down Expand Up @@ -45,6 +47,13 @@ class PaymentsEndpoint {
*/
private $authorizations_factory;

/**
* The capture factory.
*
* @var CaptureFactory
*/
private $capture_factory;

/**
* The logger.
*
Expand All @@ -58,18 +67,21 @@ class PaymentsEndpoint {
* @param string $host The host.
* @param Bearer $bearer The bearer.
* @param AuthorizationFactory $authorization_factory The authorization factory.
* @param CaptureFactory $capture_factory The capture factory.
* @param LoggerInterface $logger The logger.
*/
public function __construct(
string $host,
Bearer $bearer,
AuthorizationFactory $authorization_factory,
CaptureFactory $capture_factory,
LoggerInterface $logger
) {

$this->host = $host;
$this->bearer = $bearer;
$this->authorizations_factory = $authorization_factory;
$this->capture_factory = $capture_factory;
$this->logger = $logger;
}

Expand Down Expand Up @@ -136,11 +148,11 @@ public function authorization( string $authorization_id ): Authorization {
*
* @param string $authorization_id The id.
*
* @return Authorization
* @return Capture
* @throws RuntimeException If the request fails.
* @throws PayPalApiException If the request fails.
*/
public function capture( string $authorization_id ): Authorization {
public function capture( string $authorization_id ): Capture {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id . '/capture';
$args = array(
Expand All @@ -167,7 +179,7 @@ public function capture( string $authorization_id ): Authorization {
);
}

return $this->authorizations_factory->from_paypal_response( $json );
return $this->capture_factory->from_paypal_response( $json );
}

/**
Expand Down
24 changes: 21 additions & 3 deletions modules/ppcp-api-client/src/Entity/class-authorizationstatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,21 @@ class AuthorizationStatus {
*/
private $status;

/**
* The details.
*
* @var AuthorizationStatusDetails|null
*/
private $details;

/**
* AuthorizationStatus constructor.
*
* @param string $status The status.
* @param string $status The status.
* @param AuthorizationStatusDetails|null $details The details.
* @throws RuntimeException When the status is not valid.
*/
public function __construct( string $status ) {
public function __construct( string $status, ?AuthorizationStatusDetails $details = null ) {
if ( ! in_array( $status, self::VALID_STATUS, true ) ) {
throw new RuntimeException(
sprintf(
Expand All @@ -60,7 +68,8 @@ public function __construct( string $status ) {
)
);
}
$this->status = $status;
$this->status = $status;
$this->details = $details;
}

/**
Expand Down Expand Up @@ -91,4 +100,13 @@ public function is( string $status ): bool {
public function name(): string {
return $this->status;
}

/**
* Returns the details.
*
* @return AuthorizationStatusDetails|null
*/
public function details(): ?AuthorizationStatusDetails {
return $this->details;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
/**
* The AuthorizationStatusDetails object.
*
* @see https://developer.paypal.com/docs/api/payments/v2/#definition-authorization_status_details
*
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
*/

declare(strict_types=1);

namespace WooCommerce\PayPalCommerce\ApiClient\Entity;

/**
* Class AuthorizationStatusDetails
*/
class AuthorizationStatusDetails {

const PENDING_REVIEW = 'PENDING_REVIEW';

/**
* The reason.
*
* @var string
*/
private $reason;

/**
* AuthorizationStatusDetails constructor.
*
* @param string $reason The reason explaining authorization status.
*/
public function __construct( string $reason ) {
$this->reason = $reason;
}

/**
* Compares the current reason with a given one.
*
* @param string $reason The reason to compare with.
*
* @return bool
*/
public function is( string $reason ): bool {
return $this->reason === $reason;
}

/**
* Returns the reason explaining authorization status.
*
* @return string
*/
public function reason(): string {
return $this->reason;
}
}
50 changes: 17 additions & 33 deletions modules/ppcp-api-client/src/Entity/class-capture.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,10 @@ class Capture {
/**
* The status.
*
* @var string
* @var CaptureStatus
*/
private $status;

/**
* The status details.
*
* @var string
*/
private $status_details;

/**
* The amount.
*
Expand Down Expand Up @@ -75,19 +68,17 @@ class Capture {
/**
* Capture constructor.
*
* @param string $id The ID.
* @param string $status The status.
* @param string $status_details The status details.
* @param Amount $amount The amount.
* @param bool $final_capture The final capture.
* @param string $seller_protection The seller protection.
* @param string $invoice_id The invoice id.
* @param string $custom_id The custom id.
* @param string $id The ID.
* @param CaptureStatus $status The status.
* @param Amount $amount The amount.
* @param bool $final_capture The final capture.
* @param string $seller_protection The seller protection.
* @param string $invoice_id The invoice id.
* @param string $custom_id The custom id.
*/
public function __construct(
string $id,
string $status,
string $status_details,
CaptureStatus $status,
Amount $amount,
bool $final_capture,
string $seller_protection,
Expand All @@ -97,7 +88,6 @@ public function __construct(

$this->id = $id;
$this->status = $status;
$this->status_details = $status_details;
$this->amount = $amount;
$this->final_capture = $final_capture;
$this->seller_protection = $seller_protection;
Expand All @@ -117,21 +107,12 @@ public function id() : string {
/**
* Returns the status.
*
* @return string
* @return CaptureStatus
*/
public function status() : string {
public function status() : CaptureStatus {
return $this->status;
}

/**
* Returns the status details object.
*
* @return \stdClass
*/
public function status_details() : \stdClass {
return (object) array( 'reason' => $this->status_details );
}

/**
* Returns the amount.
*
Expand Down Expand Up @@ -183,15 +164,18 @@ public function custom_id() : string {
* @return array
*/
public function to_array() : array {
return array(
$data = array(
'id' => $this->id(),
'status' => $this->status(),
'status_details' => (array) $this->status_details(),
'status' => $this->status()->name(),
'amount' => $this->amount()->to_array(),
'final_capture' => $this->final_capture(),
'seller_protection' => (array) $this->seller_protection(),
'invoice_id' => $this->invoice_id(),
'custom_id' => $this->custom_id(),
);
if ( $this->status()->details() ) {
$data['status_details'] = array( 'reason' => $this->status()->details()->reason() );
}
return $data;
}
}
Loading