enable refunds through gateway

This commit is contained in:
David Remer 2020-09-28 11:47:24 +03:00
parent a609b6f90b
commit d6abaafadb
14 changed files with 775 additions and 37 deletions

View file

@ -23,6 +23,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\AddressFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\AmountFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\ApplicationContextFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\CaptureFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\ItemFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
@ -214,6 +215,11 @@ return array(
'api.factory.webhook' => static function ( $container ): WebhookFactory {
return new WebhookFactory();
},
'api.factory.capture' => static function ( $container ): CaptureFactory {
$amount_factory = $container->get( 'api.factory.amount' );
return new CaptureFactory( $amount_factory );
},
'api.factory.purchase-unit' => static function ( $container ): PurchaseUnitFactory {
$amount_factory = $container->get( 'api.factory.amount' );
@ -277,7 +283,8 @@ return array(
},
'api.factory.payments' => static function ( $container ): PaymentsFactory {
$authorizations_factory = $container->get( 'api.factory.authorization' );
return new PaymentsFactory( $authorizations_factory );
$capture_factory = $container->get( 'api.factory.capture' );
return new PaymentsFactory( $authorizations_factory, $capture_factory );
},
'api.factory.authorization' => static function ( $container ): AuthorizationFactory {
return new AuthorizationFactory();

View file

@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Refund;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
@ -188,4 +189,63 @@ class PaymentsEndpoint {
$authorization = $this->authorizations_factory->from_paypal_response( $json );
return $authorization;
}
/**
* Refunds a payment.
*
* @param Refund $refund The refund to be processed.
*
* @return bool
* @throws RuntimeException If the request fails.
*/
public function refund( Refund $refund ) : bool {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/payments/captures/' . $refund->for_capture()->id() . '/refund';
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
),
'body' => wp_json_encode( $refund->to_array() ),
);
$response = $this->request( $url, $args );
$json = json_decode( $response['body'] );
if ( is_wp_error( $response ) ) {
$error = new RuntimeException(
__( 'Could not refund payment.', 'paypal-payments-for-woocommerce' )
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
$status_code = (int) wp_remote_retrieve_response_code( $response );
if ( 201 !== $status_code ) {
$error = new PayPalApiException(
$json,
$status_code
);
$this->logger->log(
'warning',
$error->getMessage(),
array(
'args' => $args,
'response' => $response,
)
);
throw $error;
}
return true;
}
}

View file

@ -0,0 +1,197 @@
<?php
/**
* The capture entity.
*
* @link https://developer.paypal.com/docs/api/orders/v2/#definition-capture
*
* @package Woocommerce\PayPalCommerce\ApiClient\Entity
*/
declare( strict_types=1 );
namespace Woocommerce\PayPalCommerce\ApiClient\Entity;
/**
* Class Capture
*/
class Capture {
/**
* The ID.
*
* @var string
*/
private $id;
/**
* The status.
*
* @var string
*/
private $status;
/**
* The status details.
*
* @var string
*/
private $status_details;
/**
* The amount.
*
* @var Amount
*/
private $amount;
/**
* Whether this is the final capture or not.
*
* @var bool
*/
private $final_capture;
/**
* The seller protection.
*
* @var string
*/
private $seller_protection;
/**
* The invoice id.
*
* @var string
*/
private $invoice_id;
/**
* The custom id.
*
* @var string
*/
private $custom_id;
/**
* 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.
*/
public function __construct(
string $id,
string $status,
string $status_details,
Amount $amount,
bool $final_capture,
string $seller_protection,
string $invoice_id,
string $custom_id
) {
$this->id = $id;
$this->status = $status;
$this->status_details = $status_details;
$this->amount = $amount;
$this->final_capture = $final_capture;
$this->seller_protection = $seller_protection;
$this->invoice_id = $invoice_id;
$this->custom_id = $custom_id;
}
/**
* Returns the ID.
*
* @return string
*/
public function id() : string {
return $this->id;
}
/**
* Returns the status.
*
* @return string
*/
public function status() : string {
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.
*
* @return Amount
*/
public function amount() : Amount {
return $this->amount;
}
/**
* Returns whether this is the final capture or not.
*
* @return bool
*/
public function final_capture() : bool {
return $this->final_capture;
}
/**
* Returns the seller protection object.
*
* @return \stdClass
*/
public function seller_protection() : \stdClass {
return (object) array( 'status' => $this->seller_protection );
}
/**
* Returns the invoice id.
*
* @return string
*/
public function invoice_id() : string {
return $this->invoice_id;
}
/**
* Returns the custom id.
*
* @return string
*/
public function custom_id() : string {
return $this->custom_id;
}
/**
* Returns the entity as array.
*
* @return array
*/
public function to_array() : array {
return array(
'id' => $this->id(),
'status' => $this->status(),
'status_details' => (array) $this->status_details(),
'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(),
);
}
}

View file

@ -21,13 +21,34 @@ class Payments {
*/
private $authorizations;
/**
* The Captures.
*
* @var Capture[]
*/
private $captures;
/**
* Payments constructor.
*
* @param Authorization ...$authorizations The Authorizations.
* @param array $authorizations The Authorizations.
* @param array $captures The Captures.
*/
public function __construct( Authorization ...$authorizations ) {
public function __construct( array $authorizations, array $captures ) {
foreach ( $authorizations as $key => $authorization ) {
if ( is_a( $authorization, Authorization::class ) ) {
continue;
}
unset( $authorizations[ $key ] );
}
foreach ( $captures as $key => $capture ) {
if ( is_a( $capture, Capture::class ) ) {
continue;
}
unset( $captures[ $key ] );
}
$this->authorizations = $authorizations;
$this->captures = $captures;
}
/**
@ -43,6 +64,12 @@ class Payments {
},
$this->authorizations()
),
'captures' => array_map(
static function ( Capture $capture ): array {
return $capture->to_array();
},
$this->captures()
),
);
}
@ -54,4 +81,13 @@ class Payments {
public function authorizations(): array {
return $this->authorizations;
}
/**
* Returns the Captures.
*
* @return Capture[]
**/
public function captures(): array {
return $this->captures;
}
}

View file

@ -0,0 +1,118 @@
<?php
/**
* The refund object.
*
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
*/
declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
/**
* Class Refund
*/
class Refund {
/**
* The Capture.
*
* @var Capture
*/
private $capture;
/**
* The invoice id.
*
* @var string
*/
private $invoice_id;
/**
* The note to the payer.
*
* @var string
*/
private $note_to_payer;
/**
* The Amount.
*
* @var Amount|null
*/
private $amount;
/**
* Refund constructor.
*
* @param Capture $capture The capture where the refund is supposed to be applied at.
* @param string $invoice_id The invoice id.
* @param string $note_to_payer The note to the payer.
* @param Amount|null $amount The Amount.
*/
public function __construct(
Capture $capture,
string $invoice_id,
string $note_to_payer = '',
Amount $amount = null
) {
$this->capture = $capture;
$this->invoice_id = $invoice_id;
$this->note_to_payer = $note_to_payer;
$this->amount = $amount;
}
/**
* Returns the capture for the refund.
*
* @return Capture
*/
public function for_capture() : Capture {
return $this->capture;
}
/**
* Return the invoice id.
*
* @return string
*/
public function invoice_id() : string {
return $this->invoice_id;
}
/**
* Returns the note to the payer.
*
* @return string
*/
public function note_to_payer() : string {
return $this->note_to_payer;
}
/**
* Returns the Amount.
*
* @return Amount|null
*/
public function amount() {
return $this->amount;
}
/**
* Returns the object as array.
*
* @return array
*/
public function to_array() : array {
$data = array(
'invoice_id' => $this->invoice_id(),
);
if ( $this->note_to_payer() ) {
$data['note_to_payer'] = $this->note_to_payer();
}
if ( $this->amount() ) {
$data['amount'] = $this->amount()->to_array();
}
return $data;
}
}

View file

@ -0,0 +1,56 @@
<?php
/**
* The capture factory.
*
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
*/
declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use Woocommerce\PayPalCommerce\ApiClient\Entity\Capture;
/**
* Class CaptureFactory
*/
class CaptureFactory {
/**
* The Amount factory.
*
* @var AmountFactory
*/
private $amount_factory;
/**
* CaptureFactory constructor.
*
* @param AmountFactory $amount_factory The amount factory.
*/
public function __construct( AmountFactory $amount_factory ) {
$this->amount_factory = $amount_factory;
}
/**
* Returns the capture object based off the PayPal response.
*
* @param \stdClass $data The PayPal response.
*
* @return Capture
*/
public function from_paypal_response( \stdClass $data ) : Capture {
return new Capture(
(string) $data->id,
(string) $data->status,
(string) $data->status_details->reason,
$this->amount_factory->from_paypal_response( $data->amount ),
(bool) $data->final_capture,
(string) $data->seller_protection->status,
(string) $data->invoice_id,
(string) $data->custom_id
);
}
}

View file

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use Woocommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
/**
@ -24,16 +25,26 @@ class PaymentsFactory {
*/
private $authorization_factory;
/**
* The Capture factory.
*
* @var CaptureFactory
*/
private $capture_factory;
/**
* PaymentsFactory constructor.
*
* @param AuthorizationFactory $authorization_factory The AuthorizationFactory.
* @param AuthorizationFactory $authorization_factory The Authorization factory.
* @param CaptureFactory $capture_factory The Capture factory.
*/
public function __construct(
AuthorizationFactory $authorization_factory
AuthorizationFactory $authorization_factory,
CaptureFactory $capture_factory
) {
$this->authorization_factory = $authorization_factory;
$this->capture_factory = $capture_factory;
}
/**
@ -50,7 +61,13 @@ class PaymentsFactory {
},
isset( $data->authorizations ) ? $data->authorizations : array()
);
$payments = new Payments( ...$authorizations );
$captures = array_map(
function ( \stdClass $authorization ): Capture {
return $this->capture_factory->from_paypal_response( $authorization );
},
isset( $data->captures ) ? $data->captures : array()
);
$payments = new Payments( $authorizations, $captures );
return $payments;
}
}

View file

@ -25,6 +25,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener;
@ -36,9 +37,11 @@ return array(
$order_processor = $container->get( 'wcgateway.order-processor' );
$settings_renderer = $container->get( 'wcgateway.settings.render' );
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
$notice = $container->get( 'wcgateway.notice.authorize-order-action' );
$settings = $container->get( 'wcgateway.settings' );
$notice = $container->get( 'wcgateway.notice.authorize-order-action' );
$settings = $container->get( 'wcgateway.settings' );
$session_handler = $container->get( 'session.handler' );
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
$state = $container->get( 'onboarding.state' );
return new PayPalGateway(
$settings_renderer,
@ -46,7 +49,9 @@ return array(
$authorized_payments,
$notice,
$settings,
$session_handler
$session_handler,
$refund_processor,
$state
);
},
'wcgateway.credit-card-gateway' => static function ( $container ): CreditCardGateway {
@ -57,6 +62,8 @@ return array(
$settings = $container->get( 'wcgateway.settings' );
$module_url = $container->get( 'wcgateway.url' );
$session_handler = $container->get( 'session.handler' );
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
$state = $container->get( 'onboarding.state' );
return new CreditCardGateway(
$settings_renderer,
$order_processor,
@ -64,7 +71,9 @@ return array(
$notice,
$settings,
$module_url,
$session_handler
$session_handler,
$refund_processor,
$state
);
},
'wcgateway.disabler' => static function ( $container ): DisableGateways {
@ -132,6 +141,11 @@ return array(
$settings
);
},
'wcgateway.processor.refunds' => static function ( $container ): RefundProcessor {
$order_endpoint = $container->get( 'api.endpoint.order' );
$payments_endpoint = $container->get( 'api.endpoint.payments' );
return new RefundProcessor( $order_endpoint, $payments_endpoint );
},
'wcgateway.processor.authorized-payments' => static function ( $container ): AuthorizedPaymentsProcessor {
$order_endpoint = $container->get( 'api.endpoint.order' );
$payments_endpoint = $container->get( 'api.endpoint.payments' );

View file

@ -9,10 +9,12 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
use Psr\Container\ContainerInterface;
@ -32,6 +34,13 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
*/
private $module_url;
/**
* The refund processor.
*
* @var RefundProcessor
*/
private $refund_processor;
/**
* CreditCardGateway constructor.
*
@ -42,6 +51,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
* @param ContainerInterface $config The settings.
* @param string $module_url The URL to the module.
* @param SessionHandler $session_handler The Session Handler.
* @param RefundProcessor $refund_processor The refund processor.
* @param State $state The state.
*/
public function __construct(
SettingsRenderer $settings_renderer,
@ -50,7 +61,9 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
AuthorizeOrderActionNotice $notice,
ContainerInterface $config,
string $module_url,
SessionHandler $session_handler
SessionHandler $session_handler,
RefundProcessor $refund_processor,
State $state
) {
$this->id = self::ID;
@ -60,6 +73,11 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
$this->settings_renderer = $settings_renderer;
$this->config = $config;
$this->session_handler = $session_handler;
$this->refund_processor = $refund_processor;
if ( $state->current_state() === State::STATE_ONBOARDED ) {
$this->supports = array( 'refunds' );
}
if (
defined( 'PPCP_FLAG_SUBSCRIPTION' )
&& PPCP_FLAG_SUBSCRIPTION
@ -67,6 +85,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
&& $this->config->get( 'vault_enabled' )
) {
$this->supports = array(
'refunds',
'products',
'subscriptions',
'subscription_cancellation',
@ -209,4 +228,24 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
public function is_available() : bool {
return $this->config->has( 'dcc_enabled' ) && $this->config->get( 'dcc_enabled' );
}
/**
* Process refund.
*
* If the gateway declares 'refunds' support, this will allow it to refund.
* a passed in amount.
*
* @param int $order_id Order ID.
* @param float $amount Refund amount.
* @param string $reason Refund reason.
* @return boolean True or false based on success, or a WP_Error object.
*/
public function process_refund( $order_id, $amount = null, $reason = '' ) {
$order = wc_get_order( $order_id );
if ( ! is_a( $order, \WC_Order::class ) ) {
return false;
}
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
}
}

View file

@ -10,10 +10,12 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
use Psr\Container\ContainerInterface;
@ -72,6 +74,13 @@ class PayPalGateway extends \WC_Payment_Gateway {
*/
protected $session_handler;
/**
* The Refund Processor.
*
* @var RefundProcessor
*/
private $refund_processor;
/**
* PayPalGateway constructor.
*
@ -81,6 +90,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
* @param AuthorizeOrderActionNotice $notice The Order Action Notice object.
* @param ContainerInterface $config The settings.
* @param SessionHandler $session_handler The Session Handler.
* @param RefundProcessor $refund_processor The Refund Processor.
* @param State $state The state.
*/
public function __construct(
SettingsRenderer $settings_renderer,
@ -88,7 +99,9 @@ class PayPalGateway extends \WC_Payment_Gateway {
AuthorizedPaymentsProcessor $authorized_payments_processor,
AuthorizeOrderActionNotice $notice,
ContainerInterface $config,
SessionHandler $session_handler
SessionHandler $session_handler,
RefundProcessor $refund_processor,
State $state
) {
$this->id = self::ID;
@ -98,6 +111,11 @@ class PayPalGateway extends \WC_Payment_Gateway {
$this->settings_renderer = $settings_renderer;
$this->config = $config;
$this->session_handler = $session_handler;
$this->refund_processor = $refund_processor;
if ( $state->current_state() === State::STATE_ONBOARDED ) {
$this->supports = array( 'refunds' );
}
if (
defined( 'PPCP_FLAG_SUBSCRIPTION' )
&& PPCP_FLAG_SUBSCRIPTION
@ -105,6 +123,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
&& $this->config->get( 'vault_enabled' )
) {
$this->supports = array(
'refunds',
'products',
'subscriptions',
'subscription_cancellation',
@ -300,4 +319,23 @@ class PayPalGateway extends \WC_Payment_Gateway {
&& self::ID === sanitize_text_field( wp_unslash( $_GET['section'] ) );
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
/**
* Process refund.
*
* If the gateway declares 'refunds' support, this will allow it to refund.
* a passed in amount.
*
* @param int $order_id Order ID.
* @param float $amount Refund amount.
* @param string $reason Refund reason.
* @return boolean True or false based on success, or a WP_Error object.
*/
public function process_refund( $order_id, $amount = null, $reason = '' ) {
$order = wc_get_order( $order_id );
if ( ! is_a( $order, \WC_Order::class ) ) {
return false;
}
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
}
}

View file

@ -0,0 +1,85 @@
<?php
/**
* Processes refunds started in the WooCommerce environment.
*
* @package WooCommerce\PayPalCommerce\WcGateway\Processor
*/
declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Refund;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
/**
* Class RefundProcessor
*/
class RefundProcessor {
/**
* The order endpoint.
*
* @var OrderEndpoint
*/
private $order_endpoint;
/**
* The payments endpoint.
*
* @var PaymentsEndpoint
*/
private $payments_endpoint;
/**
* RefundProcessor constructor.
*
* @param OrderEndpoint $order_endpoint The order endpoint.
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
*/
public function __construct( OrderEndpoint $order_endpoint, PaymentsEndpoint $payments_endpoint ) {
$this->order_endpoint = $order_endpoint;
$this->payments_endpoint = $payments_endpoint;
}
/**
* Processes a refund.
*
* @param \WC_Order $wc_order The WooCommerce order.
* @param float|null $amount The refund amount.
* @param string $reason The reason for the refund.
*
* @return bool
*/
public function process( \WC_Order $wc_order, float $amount = null, string $reason = '' ) : bool {
$order_id = $wc_order->get_meta( PayPalGateway::ORDER_ID_META_KEY );
if ( ! $order_id ) {
return false;
}
try {
$order = $this->order_endpoint->order( $order_id );
if ( ! $order ) {
return false;
}
$capture = $order->purchase_units()[0]->payments()->captures()[0];
$refund = new Refund(
$capture,
$capture->invoice_id(),
$reason,
new Amount(
new Money( $amount, get_woocommerce_currency() )
)
);
return $this->payments_endpoint->refund( $refund );
} catch ( RuntimeException $error ) {
return false;
}
}
}

View file

@ -8,15 +8,24 @@ use WooCommerce\PayPalCommerce\ApiClient\TestCase;
class PaymentsTest extends TestCase
{
public function testAuthorizations()
{
$authorization = \Mockery::mock(Authorization::class);
$authorizations = [$authorization];
public function testAuthorizations()
{
$authorization = \Mockery::mock(Authorization::class);
$authorizations = [$authorization];
$testee = new Payments(...$authorizations);
$testee = new Payments($authorizations, []);
$this->assertEquals($authorizations, $testee->authorizations());
}
$this->assertEquals($authorizations, $testee->authorizations());
}
public function testCaptures()
{
$capture = \Mockery::mock(Capture::class);
$captures = [$capture];
$testee = new Payments([], $captures);
$this->assertEquals($captures, $testee->captures());
}
public function testToArray()
{
@ -27,9 +36,17 @@ class PaymentsTest extends TestCase
'status' => 'CREATED',
]
);
$capture = \Mockery::mock(Capture::class);
$capture->shouldReceive('to_array')->andReturn(
[
'id' => 'capture',
'status' => 'CREATED',
]
);
$captures = [$capture];
$authorizations = [$authorization];
$testee = new Payments(...$authorizations);
$testee = new Payments($authorizations, $captures);
$this->assertEquals(
[
@ -39,6 +56,12 @@ class PaymentsTest extends TestCase
'status' => 'CREATED',
],
],
'captures' => [
[
'id' => 'capture',
'status' => 'CREATED',
],
],
],
$testee->to_array()
);

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use Woocommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
@ -13,27 +14,36 @@ class PaymentsFactoryTest extends TestCase
{
public function testFromPayPalResponse()
{
$authorization = Mockery::mock(Authorization::class);
$authorization->shouldReceive('to_array')->andReturn(['id' => 'foo', 'status' => 'CREATED']);
$authorization = Mockery::mock(Authorization::class);
$authorization->shouldReceive('to_array')->andReturn(['id' => 'foo', 'status' => 'CREATED']);
$capture = Mockery::mock(Capture::class);
$capture->shouldReceive('to_array')->andReturn(['id' => 'capture', 'status' => 'CREATED']);
$authorizationsFactory = Mockery::mock(AuthorizationFactory::class);
$authorizationsFactory->shouldReceive('from_paypal_response')->andReturn($authorization);
$authorizationsFactory->shouldReceive('from_paypal_response')->andReturn($authorization);
$captureFactory = Mockery::mock(CaptureFactory::class);
$captureFactory->shouldReceive('from_paypal_response')->andReturn($capture);
$response = (object)[
'authorizations' => [
(object)['id' => 'foo', 'status' => 'CREATED'],
],
'authorizations' => [
(object)['id' => 'foo', 'status' => 'CREATED'],
],
'captures' => [
(object)['id' => 'capture', 'status' => 'CREATED'],
],
];
$testee = new PaymentsFactory($authorizationsFactory);
$testee = new PaymentsFactory($authorizationsFactory, $captureFactory);
$result = $testee->from_paypal_response($response);
$this->assertInstanceOf(Payments::class, $result);
$expectedToArray = [
'authorizations' => [
['id' => 'foo', 'status' => 'CREATED'],
],
'authorizations' => [
['id' => 'foo', 'status' => 'CREATED'],
],
'captures' => [
['id' => 'capture', 'status' => 'CREATED'],
],
];
$this->assertEquals($expectedToArray, $result->to_array());
}

View file

@ -5,11 +5,13 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\TestCase;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsFields;
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
@ -42,13 +44,19 @@ class WcGatewayTest extends TestCase
->shouldReceive('destroy_session_data');
$settings
->shouldReceive('has')->andReturnFalse();
$refundProcessor = Mockery::mock(RefundProcessor::class);
$state = Mockery::mock(State::class);
$state
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
$testee = new PayPalGateway(
$settingsRenderer,
$orderProcessor,
$authorizedPaymentsProcessor,
$authorizedOrderActionNotice,
$settings,
$sessionHandler
$sessionHandler,
$refundProcessor,
$state
);
expect('wc_get_order')
@ -76,13 +84,19 @@ class WcGatewayTest extends TestCase
$settings
->shouldReceive('has')->andReturnFalse();
$sessionHandler = Mockery::mock(SessionHandler::class);
$refundProcessor = Mockery::mock(RefundProcessor::class);
$state = Mockery::mock(State::class);
$state
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
$testee = new PayPalGateway(
$settingsRenderer,
$orderProcessor,
$authorizedPaymentsProcessor,
$authorizedOrderActionNotice,
$settings,
$sessionHandler
$sessionHandler,
$refundProcessor,
$state
);
expect('wc_get_order')
@ -116,13 +130,19 @@ class WcGatewayTest extends TestCase
$settings
->shouldReceive('has')->andReturnFalse();
$sessionHandler = Mockery::mock(SessionHandler::class);
$refundProcessor = Mockery::mock(RefundProcessor::class);
$state = Mockery::mock(State::class);
$state
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
$testee = new PayPalGateway(
$settingsRenderer,
$orderProcessor,
$authorizedPaymentsProcessor,
$authorizedOrderActionNotice,
$settings,
$sessionHandler
$sessionHandler,
$refundProcessor,
$state
);
expect('wc_get_order')
@ -171,13 +191,19 @@ class WcGatewayTest extends TestCase
$settings
->shouldReceive('has')->andReturnFalse();
$sessionHandler = Mockery::mock(SessionHandler::class);
$refundProcessor = Mockery::mock(RefundProcessor::class);
$state = Mockery::mock(State::class);
$state
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
$testee = new PayPalGateway(
$settingsRenderer,
$orderProcessor,
$authorizedPaymentsProcessor,
$authorizedOrderActionNotice,
$settings,
$sessionHandler
$sessionHandler,
$refundProcessor,
$state
);
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
@ -218,13 +244,19 @@ class WcGatewayTest extends TestCase
$settings
->shouldReceive('has')->andReturnFalse();
$sessionHandler = Mockery::mock(SessionHandler::class);
$refundProcessor = Mockery::mock(RefundProcessor::class);
$state = Mockery::mock(State::class);
$state
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
$testee = new PayPalGateway(
$settingsRenderer,
$orderProcessor,
$authorizedPaymentsProcessor,
$authorizedOrderActionNotice,
$settings,
$sessionHandler
$sessionHandler,
$refundProcessor,
$state
);
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
@ -258,13 +290,19 @@ class WcGatewayTest extends TestCase
$settings
->shouldReceive('has')->andReturnFalse();
$sessionHandler = Mockery::mock(SessionHandler::class);
$refundProcessor = Mockery::mock(RefundProcessor::class);
$state = Mockery::mock(State::class);
$state
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
$testee = new PayPalGateway(
$settingsRenderer,
$orderProcessor,
$authorizedPaymentsProcessor,
$authorizedOrderActionNotice,
$settings,
$sessionHandler
$sessionHandler,
$refundProcessor,
$state
);
$this->assertFalse($testee->capture_authorized_payment($wcOrder));