Merge pull request #6 from inpsyde/feature/create-order-intent-authorize

Payment with intent authorize
This commit is contained in:
David Remer 2020-04-23 12:09:08 +03:00 committed by GitHub
commit e13eb0ff82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1642 additions and 54 deletions

View file

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient;
@ -8,18 +9,22 @@ use Inpsyde\CacheModule\Provider\CacheProviderInterface;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Config\Config;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use Inpsyde\PayPalCommerce\ApiClient\Factory\AddressFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\AmountFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ItemFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PayeeFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PayerFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PaymentsFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ShippingFactory;
use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository;
use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings;
return [
@ -45,15 +50,34 @@ return [
$container->get('api.secret')
);
},
'api.endpoint.order' => function (ContainerInterface $container) : OrderEndpoint {
'api.endpoint.payments' => function (ContainerInterface $container): PaymentsEndpoint {
$authorizationFactory = $container->get('api.factory.authorization');
$errorResponseFactory = $container->get('api.factory.response-error');
return new PaymentsEndpoint(
$container->get('api.host'),
$container->get('api.bearer'),
$authorizationFactory,
$errorResponseFactory
);
},
'api.endpoint.order' => function (ContainerInterface $container): OrderEndpoint {
$orderFactory = $container->get('api.factory.order');
$patchCollectionFactory = $container->get('api.factory.patch-collection-factory');
$errorResponseFactory = $container->get('api.factory.response-error');
/**
* @var Settings $settings
*/
$settings = $container->get('wcgateway.settings');
$intent = strtoupper($settings->get('intent'));
return new OrderEndpoint(
$container->get('api.host'),
$container->get('api.bearer'),
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseFactory
);
},
@ -75,12 +99,15 @@ return [
$payeeFactory = $container->get('api.factory.payee');
$itemFactory = $container->get('api.factory.item');
$shippingFactory = $container->get('api.factory.shipping');
$paymentsFactory = $container->get('api.factory.payments');
return new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFactory
);
},
'api.factory.patch-collection-factory' => function (ContainerInterface $container)
@ -116,4 +143,11 @@ return [
$payerFactory = $container->get('api.factory.payer');
return new OrderFactory($purchaseUnitFactory, $payerFactory);
},
'api.factory.payments' => function (ContainerInterface $container): PaymentsFactory {
$authorizationFactory = $container->get('api.factory.authorization');
return new PaymentsFactory($authorizationFactory);
},
'api.factory.authorization' => function (ContainerInterface $container): AuthorizationFactory {
return new AuthorizationFactory();
},
];

View file

@ -21,12 +21,15 @@ class OrderEndpoint
private $bearer;
private $orderFactory;
private $patchCollectionFactory;
private $intent;
private $errorResponseFactory;
public function __construct(
string $host,
Bearer $bearer,
OrderFactory $orderFactory,
PatchCollectionFactory $patchCollectionFactory,
string $intent,
ErrorResponseCollectionFactory $errorResponseFactory
) {
@ -34,6 +37,7 @@ class OrderEndpoint
$this->bearer = $bearer;
$this->orderFactory = $orderFactory;
$this->patchCollectionFactory = $patchCollectionFactory;
$this->intent = $intent;
$this->errorResponseFactory = $errorResponseFactory;
}
@ -47,8 +51,9 @@ class OrderEndpoint
);
$bearer = $this->bearer->bearer();
$data = [
'intent' => 'CAPTURE',
'purchase_units' => array_map(function (PurchaseUnit $item) : array {
'intent' => $this->intent,
'purchase_units' => array_map(
function (PurchaseUnit $item) : array {
return $item->toArray();
},
$items
@ -127,6 +132,52 @@ class OrderEndpoint
return $order;
}
public function authorize(Order $order): Order
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/checkout/orders/' . $order->id() . '/authorize';
$args = [
'headers' => [
'Authorization' => 'Bearer ' . $bearer,
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
],
];
$response = wp_remote_post($url, $args);
if (is_wp_error($response)) {
$this->handleResponseWpError($url, $args);
throw new RuntimeException(
__(
'Could not authorize order.',
'woocommerce-paypal-commerce-gateway'
)
);
}
$json = json_decode($response['body']);
if (wp_remote_retrieve_response_code($response) !== 201) {
$errors = $this->errorResponseFactory->fromPayPalResponse(
$json,
(int)wp_remote_retrieve_response_code($response),
$url,
$args
);
if ($errors->hasErrorCode(ErrorResponse::ORDER_ALREADY_AUTHORIZED)) {
return $this->order($order->id());
}
add_action('woocommerce-paypal-commerce-gateway.error', $errors);
throw new RuntimeException(
__(
'Could not authorize order.',
'woocommerce-paypal-commerce-gateway'
)
);
}
$order = $this->orderFactory->fromPayPalResponse($json);
return $order;
}
public function order(string $id) : Order
{
$bearer = $this->bearer->bearer();

View file

@ -0,0 +1,118 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory;
class PaymentsEndpoint
{
private $host;
private $bearer;
private $authorizationFactory;
private $errorResponseFactory;
public function __construct(
string $host,
Bearer $bearer,
AuthorizationFactory $authorizationsFactory,
ErrorResponseCollectionFactory $errorResponseFactory
) {
$this->host = $host;
$this->bearer = $bearer;
$this->authorizationFactory = $authorizationsFactory;
$this->errorResponseFactory = $errorResponseFactory;
}
public function authorization(string $authorizationId): Authorization
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId;
$args = [
'headers' => [
'Authorization' => 'Bearer ' . $bearer,
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
],
];
$response = wp_remote_get($url, $args);
$json = json_decode($response['body']);
if (is_wp_error($response)) {
$this->handleResponseWpError($url, $args);
throw new RuntimeException(
__('Could not get authorized payment info.', 'woocommerce-paypal-commerce-gateway')
);
}
if (wp_remote_retrieve_response_code($response) !== 200) {
$errors = $this->errorResponseFactory->fromPayPalResponse(
$json,
(int)wp_remote_retrieve_response_code($response),
$url,
$args
);
do_action('woocommerce-paypal-commerce-gateway.error', $errors);
throw new RuntimeException(
__('Could not get authorized payment info.', 'woocommerce-paypal-commerce-gateway')
);
}
$authorization = $this->authorizationFactory->fromPayPalRequest($json);
return $authorization;
}
public function capture(string $authorizationId): Authorization
{
$bearer = $this->bearer->bearer();
$url = trailingslashit($this->host) . 'v2/payments/authorizations/' . $authorizationId . '/capture';
$args = [
'headers' => [
'Authorization' => 'Bearer ' . $bearer,
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
],
];
$response = wp_remote_post($url, $args);
$json = json_decode($response['body']);
if (is_wp_error($response)) {
$this->handleResponseWpError($url, $args);
throw new RuntimeException(
__('Could not capture authorized payment.', 'woocommerce-paypal-commerce-gateway')
);
}
if (wp_remote_retrieve_response_code($response) !== 201) {
$errors = $this->errorResponseFactory->fromPayPalResponse(
$json,
(int)wp_remote_retrieve_response_code($response),
$url,
$args
);
do_action('woocommerce-paypal-commerce-gateway.error', $errors);
throw new RuntimeException(
__('Could not capture authorized payment.', 'woocommerce-paypal-commerce-gateway')
);
}
$authorization = $this->authorizationFactory->fromPayPalRequest($json);
return $authorization;
}
private function handleResponseWpError(string $url, array $args)
{
$errors = $this->errorResponseFactory->unknownError(
$url,
$args
);
do_action('woocommerce-paypal-commerce-gateway.error', $errors);
}
}

View file

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Authorization
{
private $id;
private $authorizationStatus;
public function __construct(
string $id,
AuthorizationStatus $authorizationStatus
) {
$this->id = $id;
$this->authorizationStatus = $authorizationStatus;
}
public function id() : string
{
return $this->id;
}
public function status() : AuthorizationStatus
{
return $this->authorizationStatus;
}
public function toArray(): array
{
return [
'id' => $this->id,
'status' => $this->authorizationStatus->name(),
];
}
}

View file

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class AuthorizationStatus
{
const INTERNAL = 'INTERNAL';
const CREATED = 'CREATED';
const CAPTURED = 'CAPTURED';
const COMPLETED = 'COMPLETED';
const DENIED = 'DENIED';
const EXPIRED = 'EXPIRED';
const PARTIALLY_CAPTURED = 'PARTIALLY_CAPTURED';
const VOIDED = 'VOIDED';
const PENDING = 'PENDING';
const VALID_STATUS = [
self::INTERNAL,
self::CREATED,
self::CAPTURED,
self::COMPLETED,
self::DENIED,
self::EXPIRED,
self::PARTIALLY_CAPTURED,
self::VOIDED,
self::PENDING,
];
private $status;
public function __construct(string $status)
{
if (!in_array($status, self::VALID_STATUS, true)) {
throw new RuntimeException(
// translators: %s is the current status.
sprintf(__("%s is not a valid status", 'woocmmerce-paypal-commerce-gateway'), $status)
);
}
$this->status = $status;
}
public static function asInternal(): AuthorizationStatus
{
return new self(self::INTERNAL);
}
public function is(string $status): bool
{
return $this->status === $status;
}
public function name(): string
{
return $this->status;
}
}

View file

@ -24,7 +24,7 @@ class ErrorResponseCollection
public function codes() : array
{
return array_values(array_map(
function(ErrorResponse $error) : string {
function (ErrorResponse $error) : string {
return $error->code();
},
$this->errors()

View file

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
class Payments
{
private $authorizations;
public function __construct(Authorization ...$authorizations)
{
$this->authorizations = $authorizations;
}
public function toArray(): array
{
return [
'authorizations' => array_map(
function (Authorization $authorization) {
return $authorization->toArray();
},
$this->authorizations()
),
];
}
/**
* @return Authorization[]
**/
public function authorizations(): array
{
return $this->authorizations;
}
}

View file

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
@ -15,6 +16,8 @@ class PurchaseUnit
private $customId;
private $invoiceId;
private $softDescriptor;
private $payments;
public function __construct(
Amount $amount,
array $items = [],
@ -24,7 +27,8 @@ class PurchaseUnit
Payee $payee = null,
string $customId = '',
string $invoiceId = '',
string $softDescriptor = ''
string $softDescriptor = '',
Payments $payments = null
) {
$this->amount = $amount;
@ -32,7 +36,7 @@ class PurchaseUnit
$this->referenceId = $referenceId;
$this->description = $description;
//phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration.NoArgumentType
$this->items = array_values( array_filter(
$this->items = array_values(array_filter(
$items,
function ($item) : bool {
return is_a($item, Item::class);
@ -43,6 +47,7 @@ class PurchaseUnit
$this->customId = $customId;
$this->invoiceId = $invoiceId;
$this->softDescriptor = $softDescriptor;
$this->payments = $payments;
}
public function amount() : Amount
@ -85,6 +90,11 @@ class PurchaseUnit
return $this->payee;
}
public function payments() : ?Payments
{
return $this->payments;
}
/**
* @return Item[]
*/
@ -102,8 +112,7 @@ class PurchaseUnit
'items' => array_map(function (Item $item) : array {
return $item->toArray();
},
$this->items()
),
$this->items()),
];
if ($this->ditchItemsWhenMismatch($this->amount(), ...$this->items())) {
unset($purchaseUnit['items']);
@ -114,6 +123,10 @@ class PurchaseUnit
$purchaseUnit['payee'] = $this->payee()->toArray();
}
if ($this->payments()) {
$purchaseUnit['payments'] = $this->payments()->toArray();
}
if ($this->shipping()) {
$purchaseUnit['shipping'] = $this->shipping()->toArray();
}

View file

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class AuthorizationFactory
{
public function fromPayPalRequest(\stdClass $data): Authorization
{
if (!isset($data->id)) {
throw new RuntimeException(
__('Does not contain an id.', 'woocommerce-paypal-commerce-gateway')
);
}
if (!isset($data->status)) {
throw new RuntimeException(
__('Does not contain status.', 'woocommerce-paypal-commerce-gateway')
);
}
return new Authorization(
$data->id,
new AuthorizationStatus($data->status)
);
}
}

View file

@ -14,7 +14,8 @@ class ItemFactory
{
}
public function fromWcCart(\WC_Cart $cart) : array {
public function fromWcCart(\WC_Cart $cart) : array
{
$currency = get_woocommerce_currency();
$items = array_map(
function (array $item) use ($currency): Item {
@ -48,8 +49,8 @@ class ItemFactory
* @param \WC_Order $order
* @return Item[]
*/
public function fromWcOrder(\WC_Order $order) : array {
public function fromWcOrder(\WC_Order $order) : array
{
return array_map(
function (\WC_Order_Item_Product $item) use ($order): Item {
return $this->fromWcOrderLineItem($item, $order);
@ -58,8 +59,8 @@ class ItemFactory
);
}
private function fromWcOrderLineItem(\WC_Order_Item_Product $item, \WC_Order $order) : Item {
private function fromWcOrderLineItem(\WC_Order_Item_Product $item, \WC_Order $order) : Item
{
$currency = $order->get_currency();
$product = $item->get_product();
/**

View file

@ -25,8 +25,9 @@ class PayerFactory
$data->name->given_name,
$data->name->surname
);
// TODO deal with phones without type instead of passing a invalid type
$phone = (isset($data->phone)) ? new PhoneWithType(
$data->phone->phone_type,
(isset($data->phone->phone_type)) ? $data->phone->phone_type : 'undefined',
new Phone(
$data->phone->phone_number->national_number
)

View file

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payments;
class PaymentsFactory
{
private $authorizationsFactory;
public function __construct(
AuthorizationFactory $authorizationsFactory
) {
$this->authorizationsFactory = $authorizationsFactory;
}
public function fromPayPalResponse(\stdClass $data): Payments
{
$authorizations = array_map(
function (\stdClass $authorization): Authorization {
return $this->authorizationsFactory->fromPayPalRequest($authorization);
},
$data->authorizations
);
$payments = new Payments(...$authorizations);
return $payments;
}
}

View file

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
@ -16,12 +17,15 @@ class PurchaseUnitFactory
private $payeeFactory;
private $itemFactory;
private $shippingFactory;
private $paymentsFactory;
public function __construct(
AmountFactory $amountFactory,
PayeeRepository $payeeRepository,
PayeeFactory $payeeFactory,
ItemFactory $itemFactory,
ShippingFactory $shippingFactory
ShippingFactory $shippingFactory,
PaymentsFactory $paymentsFactory
) {
$this->amountFactory = $amountFactory;
@ -29,6 +33,7 @@ class PurchaseUnitFactory
$this->payeeFactory = $payeeFactory;
$this->itemFactory = $itemFactory;
$this->shippingFactory = $shippingFactory;
$this->paymentsFactory = $paymentsFactory;
}
public function fromWcOrder(\WC_Order $order) : PurchaseUnit
@ -129,7 +134,11 @@ class PurchaseUnitFactory
$shipping = isset($data->shipping) ?
$this->shippingFactory->fromPayPalResponse($data->shipping)
: null;
return new PurchaseUnit(
$payments = isset($data->payments) ?
$this->paymentsFactory->fromPayPalResponse($data->payments) :
null;
$purchaseUnit = new PurchaseUnit(
$amount,
$items,
$shipping,
@ -138,7 +147,9 @@ class PurchaseUnitFactory
$payee,
$customId,
$invoiceId,
$softDescriptor
$softDescriptor,
$payments
);
return $purchaseUnit;
}
}

View file

@ -16,6 +16,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use function Brain\Monkey\Functions\expect;
class OrderEndpointTest extends TestCase
@ -34,12 +35,14 @@ class OrderEndpointTest extends TestCase
return ($object->is_correct) ? $order : null;
});
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$testee = new OrderEndpoint(
$host,
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -76,6 +79,7 @@ class OrderEndpointTest extends TestCase
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory
->expects('unknownError')
->withSomeOfArgs($host . 'v2/checkout/orders/' . $orderId)
@ -85,6 +89,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -107,6 +112,7 @@ class OrderEndpointTest extends TestCase
->expects('bearer')->andReturn('bearer');
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$rawResponse = ['body' => '{"some_error":true}'];
$error = Mockery::mock(ErrorResponseCollection::class);
@ -139,6 +145,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -180,6 +187,7 @@ class OrderEndpointTest extends TestCase
}
);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$testee = new OrderEndpoint(
@ -187,6 +195,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -226,6 +235,7 @@ class OrderEndpointTest extends TestCase
$bearer = Mockery::mock(Bearer::class);
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$testee = new OrderEndpoint(
@ -233,6 +243,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -255,6 +266,7 @@ class OrderEndpointTest extends TestCase
$bearer->expects('bearer')->andReturn('bearer');
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$errorResponseCollectionFactory
@ -266,6 +278,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -293,6 +306,7 @@ class OrderEndpointTest extends TestCase
$bearer->expects('bearer')->andReturn('bearer');
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$error->expects('hasErrorCode')->with('ORDER_ALREADY_CAPTURED')->andReturn(false);
@ -325,6 +339,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -353,6 +368,7 @@ class OrderEndpointTest extends TestCase
$bearer->expects('bearer')->andReturn('bearer');
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$error->expects('hasErrorCode')->with('ORDER_ALREADY_CAPTURED')->andReturn(true);
@ -387,6 +403,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory,
]
)->makePartial();
@ -430,6 +447,7 @@ class OrderEndpointTest extends TestCase
->expects('fromOrders')
->with($orderToUpdate, $orderToCompare)
->andReturn($patchCollection);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$testee = Mockery::mock(
@ -439,6 +457,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
]
)->makePartial();
@ -508,6 +527,7 @@ class OrderEndpointTest extends TestCase
->expects('fromOrders')
->with($orderToUpdate, $orderToCompare)
->andReturn($patchCollection);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$errorResponseCollectionFactory
@ -536,6 +556,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -602,6 +623,7 @@ class OrderEndpointTest extends TestCase
->expects('fromOrders')
->with($orderToUpdate, $orderToCompare)
->andReturn($patchCollection);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$errorResponseCollectionFactory
@ -616,6 +638,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
]
)->makePartial();
@ -671,6 +694,7 @@ class OrderEndpointTest extends TestCase
->expects('fromOrders')
->with($orderToUpdate, $orderToCompare)
->andReturn($patchCollection);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$testee = new OrderEndpoint(
@ -678,6 +702,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -704,6 +729,7 @@ class OrderEndpointTest extends TestCase
return $expectedOrder;
});
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$testee = new OrderEndpoint(
@ -711,6 +737,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -769,6 +796,7 @@ class OrderEndpointTest extends TestCase
return $expectedOrder;
});
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$testee = new OrderEndpoint(
@ -776,6 +804,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -813,6 +842,7 @@ class OrderEndpointTest extends TestCase
->andReturn('bearer');
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
@ -826,6 +856,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);
@ -875,6 +906,7 @@ class OrderEndpointTest extends TestCase
->andReturn('bearer');
$orderFactory = Mockery::mock(OrderFactory::class);
$patchCollectionFactory = Mockery::mock(PatchCollectionFactory::class);
$intent = 'CAPTURE';
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
@ -904,6 +936,7 @@ class OrderEndpointTest extends TestCase
$bearer,
$orderFactory,
$patchCollectionFactory,
$intent,
$errorResponseCollectionFactory
);

View file

@ -0,0 +1,296 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Entity\ErrorResponseCollection;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use Inpsyde\PayPalCommerce\ApiClient\Factory\ErrorResponseCollectionFactory;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use function Brain\Monkey\Functions\expect;
class PaymentsEndpointTest extends TestCase
{
public function testAuthorizationDefault()
{
$host = 'https://example.com/';
$authorizationId = 'somekindofid';
$bearer = Mockery::mock(Bearer::class);
$bearer
->expects('bearer')->andReturn('bearer');
$authorization = Mockery::mock(Authorization::class);
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$authorizationFactory
->expects('fromPayPalRequest')
->andReturn($authorization);
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$rawResponse = ['body' => '{"is_correct":true}'];
$testee = new PaymentsEndpoint(
$host,
$bearer,
$authorizationFactory,
$errorResponseCollectionFactory
);
expect('wp_remote_get')->andReturnUsing(
function ($url, $args) use ($rawResponse, $host, $authorizationId) {
if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId) {
return false;
}
if ($args['headers']['Authorization'] !== 'Bearer bearer') {
return false;
}
if ($args['headers']['Content-Type'] !== 'application/json') {
return false;
}
return $rawResponse;
}
);
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200);
$result = $testee->authorization($authorizationId);
$this->assertEquals($authorization, $result);
}
public function testAuthorizationWpError()
{
$host = 'https://example.com/';
$authorizationId = 'somekindofid';
$bearer = Mockery::mock(Bearer::class);
$bearer->expects('bearer')->andReturn('bearer');
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$errorResponseCollectionFactory
->expects('unknownError')
->withSomeOfArgs($host . 'v2/payments/authorizations/' . $authorizationId)
->andReturn($error);
$rawResponse = ['body' => '{"is_correct":true}'];
$testee = new PaymentsEndpoint(
$host,
$bearer,
$authorizationFactory,
$errorResponseCollectionFactory
);
expect('wp_remote_get')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(true);
expect('do_action')
->with('woocommerce-paypal-commerce-gateway.error', $error);
$this->expectException(RuntimeException::class);
$testee->authorization($authorizationId);
}
public function testAuthorizationIsNot200()
{
$host = 'https://example.com/';
$authorizationId = 'somekindofid';
$bearer = Mockery::mock(Bearer::class);
$bearer->expects('bearer')->andReturn('bearer');
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$rawResponse = ['body' => '{"some_error":true}'];
$error = Mockery::mock(ErrorResponseCollection::class);
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$errorResponseCollectionFactory
->expects('fromPayPalResponse')
->andReturnUsing(
function ($json, $status, $url, $args) use ($error, $host, $authorizationId): ?ErrorResponseCollection {
$wrongError = Mockery::mock(ErrorResponseCollection::class);
if (!$json->some_error) {
return $wrongError;
}
if ($status !== 500) {
return $wrongError;
}
if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId) {
return $wrongError;
}
if ($args['headers']['Authorization'] !== 'Bearer bearer') {
return $wrongError;
}
if ($args['headers']['Content-Type'] !== 'application/json') {
return $wrongError;
}
return $error;
}
);
$testee = new PaymentsEndpoint(
$host,
$bearer,
$authorizationFactory,
$errorResponseCollectionFactory
);
expect('wp_remote_get')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
expect('do_action')
->with('woocommerce-paypal-commerce-gateway.error', $error);
$this->expectException(RuntimeException::class);
$testee->authorization($authorizationId);
}
public function testCaptureDefault() {
$host = 'https://example.com/';
$authorizationId = 'somekindofid';
$bearer = Mockery::mock(Bearer::class);
$bearer
->expects('bearer')->andReturn('bearer');
$authorization = Mockery::mock(Authorization::class);
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$authorizationFactory
->expects('fromPayPalRequest')
->andReturn($authorization);
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$rawResponse = ['body' => '{"is_correct":true}'];
$testee = new PaymentsEndpoint(
$host,
$bearer,
$authorizationFactory,
$errorResponseCollectionFactory
);
expect('wp_remote_post')->andReturnUsing(
function ($url, $args) use ($rawResponse, $host, $authorizationId) {
if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId . '/capture') {
return false;
}
if ($args['headers']['Authorization'] !== 'Bearer bearer') {
return false;
}
if ($args['headers']['Content-Type'] !== 'application/json') {
return false;
}
return $rawResponse;
}
);
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(201);
$result = $testee->capture($authorizationId);
$this->assertEquals($authorization, $result);
}
public function testCaptureIsWpError() {
$host = 'https://example.com/';
$authorizationId = 'somekindofid';
$bearer = Mockery::mock(Bearer::class);
$bearer->expects('bearer')->andReturn('bearer');
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$error = Mockery::mock(ErrorResponseCollection::class);
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$errorResponseCollectionFactory
->expects('unknownError')
->withSomeOfArgs($host . 'v2/payments/authorizations/' . $authorizationId . '/capture')
->andReturn($error);
$rawResponse = ['body' => '{"is_correct":true}'];
$testee = new PaymentsEndpoint(
$host,
$bearer,
$authorizationFactory,
$errorResponseCollectionFactory
);
expect('wp_remote_post')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(true);
expect('do_action')
->with('woocommerce-paypal-commerce-gateway.error', $error);
$this->expectException(RuntimeException::class);
$testee->capture($authorizationId);
}
public function testAuthorizationIsNot201()
{
$host = 'https://example.com/';
$authorizationId = 'somekindofid';
$bearer = Mockery::mock(Bearer::class);
$bearer->expects('bearer')->andReturn('bearer');
$authorizationFactory = Mockery::mock(AuthorizationFactory::class);
$rawResponse = ['body' => '{"some_error":true}'];
$error = Mockery::mock(ErrorResponseCollection::class);
$errorResponseCollectionFactory = Mockery::mock(ErrorResponseCollectionFactory::class);
$errorResponseCollectionFactory
->expects('fromPayPalResponse')
->andReturnUsing(
function ($json, $status, $url, $args) use ($error, $host, $authorizationId): ?ErrorResponseCollection {
$wrongError = Mockery::mock(ErrorResponseCollection::class);
if (!$json->some_error) {
return $wrongError;
}
if ($status !== 500) {
return $wrongError;
}
if ($url !== $host . 'v2/payments/authorizations/' . $authorizationId . '/capture') {
return $wrongError;
}
if ($args['headers']['Authorization'] !== 'Bearer bearer') {
return $wrongError;
}
if ($args['headers']['Content-Type'] !== 'application/json') {
return $wrongError;
}
return $error;
}
);
$testee = new PaymentsEndpoint(
$host,
$bearer,
$authorizationFactory,
$errorResponseCollectionFactory
);
expect('wp_remote_post')->andReturn($rawResponse);
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(500);
expect('do_action')
->with('woocommerce-paypal-commerce-gateway.error', $error);
$this->expectException(RuntimeException::class);
$testee->capture($authorizationId);
}
}

View file

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
class AuthorizationStatusTest extends TestCase
{
/**
* @dataProvider statusDataProvider
* @param $status
*/
public function testValidStatusProvided($status)
{
$authorizationStatus = new AuthorizationStatus($status);
$this->assertEquals($authorizationStatus->name(), $status);
}
public function testInvalidStatusProvided()
{
$this->expectException(RuntimeException::class);
new AuthorizationStatus('invalid');
}
public function testStatusComparision()
{
$authorizationStatus = new AuthorizationStatus('CREATED');
$this->assertTrue($authorizationStatus->is('CREATED'));
$this->assertFalse($authorizationStatus->is('NOT_CREATED'));
}
public function statusDataProvider(): array
{
return [
['INTERNAL'],
['CREATED'],
['CAPTURED'],
['DENIED'],
['EXPIRED'],
['PARTIALLY_CAPTURED'],
['VOIDED'],
['PENDING'],
];
}
}

View file

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
class AuthorizationTest extends TestCase
{
public function testIdAndStatus()
{
$authorizationStatus = \Mockery::mock(AuthorizationStatus::class);
$testee = new Authorization('foo', $authorizationStatus);
$this->assertEquals('foo', $testee->id());
$this->assertEquals($authorizationStatus, $testee->status());
}
public function testToArray()
{
$authorizationStatus = \Mockery::mock(AuthorizationStatus::class);
$authorizationStatus->expects('name')->andReturn('CAPTURED');
$testee = new Authorization('foo', $authorizationStatus);
$expected = [
'id' => 'foo',
'status' => 'CAPTURED',
];
$this->assertEquals($expected, $testee->toArray());
}
}

View file

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
class PaymentsTest extends TestCase
{
public function testAuthorizations()
{
$authorization = \Mockery::mock(Authorization::class);
$authorizations = [$authorization];
$testee = new Payments(...$authorizations);
$this->assertEquals($authorizations, $testee->authorizations());
}
public function testToArray()
{
$authorization = \Mockery::mock(Authorization::class);
$authorization->shouldReceive('toArray')->andReturn(
[
'id' => 'foo',
'status' => 'CREATED',
]
);
$authorizations = [$authorization];
$testee = new Payments(...$authorizations);
$this->assertEquals(
[
'authorizations' => [
[
'id' => 'foo',
'status' => 'CREATED',
],
],
],
$testee->toArray()
);
}
}

View file

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
class AuthorizationFactoryTest extends TestCase
{
public function testFromPayPalRequestDefault()
{
$response = (object)[
'id' => 'foo',
'status' => 'CAPTURED',
];
$testee = new AuthorizationFactory();
$result = $testee->fromPayPalRequest($response);
$this->assertInstanceOf(Authorization::class, $result);
$this->assertEquals('foo', $result->id());
$this->assertInstanceOf(AuthorizationStatus::class, $result->status());
$this->assertEquals('CAPTURED', $result->status()->name());
}
public function testReturnExceptionIdIsMissing()
{
$this->expectException(RuntimeException::class);
$response = (object)[
'status' => 'CAPTURED',
];
$testee = new AuthorizationFactory();
$testee->fromPayPalRequest($response);
}
public function testReturnExceptionStatusIsMissing()
{
$this->expectException(RuntimeException::class);
$response = (object)[
'id' => 'foo',
];
$testee = new AuthorizationFactory();
$testee->fromPayPalRequest($response);
}
}

View file

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payments;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
use Mockery;
class PaymentsFactoryTest extends TestCase
{
public function testFromPayPalResponse()
{
$authorization = Mockery::mock(Authorization::class);
$authorization->shouldReceive('toArray')->andReturn(['id' => 'foo', 'status' => 'CREATED']);
$authorizationsFactory = Mockery::mock(AuthorizationFactory::class);
$authorizationsFactory->shouldReceive('fromPayPalRequest')->andReturn($authorization);
$response = (object)[
'authorizations' => [
(object)['id' => 'foo', 'status' => 'CREATED',],
],
];
$testee = new PaymentsFactory($authorizationsFactory);
$result = $testee->fromPayPalResponse($response);
$this->assertInstanceOf(Payments::class, $result);
$expectedToArray = [
'authorizations' => [
['id' => 'foo', 'status' => 'CREATED',],
],
];
$this->assertEquals($expectedToArray, $result->toArray());
}
}

View file

@ -7,13 +7,15 @@ use Inpsyde\PayPalCommerce\ApiClient\Entity\Address;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Amount;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Item;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payee;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Payments;
use Inpsyde\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Shipping;
use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository;
use Inpsyde\PayPalCommerce\ApiClient\TestCase;
use function Brain\Monkey\Functions\expect;
use Mockery;
use function Brain\Monkey\Functions\expect;
class PurchaseUnitFactoryTest extends TestCase
{
@ -54,12 +56,14 @@ class PurchaseUnitFactoryTest extends TestCase
->shouldReceive('fromWcOrder')
->with($wcOrder)
->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$unit = $testee->fromWcOrder($wcOrder);
@ -113,12 +117,14 @@ class PurchaseUnitFactoryTest extends TestCase
->expects('fromWcOrder')
->with($wcOrder)
->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$unit = $testee->fromWcOrder($wcOrder);
@ -158,12 +164,14 @@ class PurchaseUnitFactoryTest extends TestCase
->expects('fromWcOrder')
->with($wcOrder)
->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$unit = $testee->fromWcOrder($wcOrder);
@ -212,12 +220,14 @@ class PurchaseUnitFactoryTest extends TestCase
->expects('fromWcCustomer')
->with($wcCustomer)
->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$unit = $testee->fromWcCart($wcCart);
@ -256,13 +266,14 @@ class PurchaseUnitFactoryTest extends TestCase
->with($wcCart)
->andReturn([]);
$shippingFactory = Mockery::mock(ShippingFactory::class);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$unit = $testee->fromWcCart($wcCart);
@ -308,13 +319,14 @@ class PurchaseUnitFactoryTest extends TestCase
$shippingFactory
->expects('fromWcCustomer')
->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$unit = $testee->fromWcCart($wcCart);
@ -357,13 +369,14 @@ class PurchaseUnitFactoryTest extends TestCase
$shippingFactory
->expects('fromWcCustomer')
->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$unit = $testee->fromWcCart($wcCart);
@ -389,12 +402,14 @@ class PurchaseUnitFactoryTest extends TestCase
$shippingFactory = Mockery::mock(ShippingFactory::class);
$shipping = Mockery::mock(Shipping::class);
$shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$response = (object) [
@ -440,12 +455,14 @@ class PurchaseUnitFactoryTest extends TestCase
$shippingFactory = Mockery::mock(ShippingFactory::class);
$shipping = Mockery::mock(Shipping::class);
$shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$response = (object) [
@ -480,12 +497,14 @@ class PurchaseUnitFactoryTest extends TestCase
$item = Mockery::mock(Item::class);
$itemFactory->expects('fromPayPalResponse')->with($rawItem)->andReturn($item);
$shippingFactory = Mockery::mock(ShippingFactory::class);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$response = (object) [
@ -509,12 +528,14 @@ class PurchaseUnitFactoryTest extends TestCase
$payeeRepository = Mockery::mock(PayeeRepository::class);
$itemFactory = Mockery::mock(ItemFactory::class);
$shippingFactory = Mockery::mock(ShippingFactory::class);
$paymentsFacory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory
$shippingFactory,
$paymentsFacory
);
$response = (object) [
@ -532,4 +553,104 @@ class PurchaseUnitFactoryTest extends TestCase
$testee->fromPayPalResponse($response);
}
public function testFromPayPalResponsePaymentsGetAppended()
{
$rawItem = (object)['items' => 1];
$rawAmount = (object)['amount' => 1];
$rawPayee = (object)['payee' => 1];
$rawShipping = (object)['shipping' => 1];
$rawPayments = (object)['payments' => 1];
$amountFactory = Mockery::mock(AmountFactory::class);
$amount = Mockery::mock(Amount::class);
$amountFactory->expects('fromPayPalResponse')->with($rawAmount)->andReturn($amount);
$payeeFactory = Mockery::mock(PayeeFactory::class);
$payee = Mockery::mock(Payee::class);
$payeeFactory->expects('fromPayPalResponse')->with($rawPayee)->andReturn($payee);
$payeeRepository = Mockery::mock(PayeeRepository::class);
$itemFactory = Mockery::mock(ItemFactory::class);
$item = Mockery::mock(Item::class);
$itemFactory->expects('fromPayPalResponse')->with($rawItem)->andReturn($item);
$shippingFactory = Mockery::mock(ShippingFactory::class);
$shipping = Mockery::mock(Shipping::class);
$shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping);
$paymentsFactory = Mockery::mock(PaymentsFactory::class);
$payments = Mockery::mock(Payments::class);
$paymentsFactory->expects('fromPayPalResponse')->with($rawPayments)->andReturn($payments);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory,
$paymentsFactory
);
$response = (object)[
'reference_id' => 'default',
'description' => 'description',
'customId' => 'customId',
'invoiceId' => 'invoiceId',
'softDescriptor' => 'softDescriptor',
'amount' => $rawAmount,
'items' => [$rawItem],
'payee' => $rawPayee,
'shipping' => $rawShipping,
'payments' => $rawPayments,
];
$unit = $testee->fromPayPalResponse($response);
$this->assertEquals($payments, $unit->payments());
}
public function testFromPayPalResponsePaymentsIsNull()
{
$rawItem = (object)['items' => 1];
$rawAmount = (object)['amount' => 1];
$rawPayee = (object)['payee' => 1];
$rawShipping = (object)['shipping' => 1];
$rawPayments = (object)['payments' => 1];
$amountFactory = Mockery::mock(AmountFactory::class);
$amount = Mockery::mock(Amount::class);
$amountFactory->expects('fromPayPalResponse')->with($rawAmount)->andReturn($amount);
$payeeFactory = Mockery::mock(PayeeFactory::class);
$payee = Mockery::mock(Payee::class);
$payeeFactory->expects('fromPayPalResponse')->with($rawPayee)->andReturn($payee);
$payeeRepository = Mockery::mock(PayeeRepository::class);
$itemFactory = Mockery::mock(ItemFactory::class);
$item = Mockery::mock(Item::class);
$itemFactory->expects('fromPayPalResponse')->with($rawItem)->andReturn($item);
$shippingFactory = Mockery::mock(ShippingFactory::class);
$shipping = Mockery::mock(Shipping::class);
$shippingFactory->expects('fromPayPalResponse')->with($rawShipping)->andReturn($shipping);
$paymentsFactory = Mockery::mock(PaymentsFactory::class);
$testee = new PurchaseUnitFactory(
$amountFactory,
$payeeRepository,
$payeeFactory,
$itemFactory,
$shippingFactory,
$paymentsFactory
);
$response = (object)[
'reference_id' => 'default',
'description' => 'description',
'customId' => 'customId',
'invoiceId' => 'invoiceId',
'softDescriptor' => 'softDescriptor',
'amount' => $rawAmount,
'items' => [$rawItem],
'payee' => $rawPayee,
'shipping' => $rawShipping,
];
$unit = $testee->fromPayPalResponse($response);
$this->assertNull($unit->payments());
}
}

View file

@ -130,6 +130,7 @@ class SmartButton implements SmartButtonInterface
//ToDo: Probably only needed, when DCC
'vault' => 'false',
'commit' => is_checkout() ? 'true' : 'false',
'intent' => $this->settings->get('intent')
];
$payee = $this->payeeRepository->payee();
if ($payee->merchantId()) {

View file

@ -1,13 +1,20 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway;
use Dhii\Data\Container\ContainerInterface;
use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail;
use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn;
use Inpsyde\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail;
use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways;
use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway;
use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGatewayBase;
use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use Inpsyde\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
use Inpsyde\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use Inpsyde\PayPalCommerce\WcGateway\Processor\Processor;
use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings;
use Inpsyde\PayPalCommerce\WcGateway\Settings\SettingsFields;
@ -18,10 +25,21 @@ return [
'wcgateway.gateway' => function (ContainerInterface $container) : WcGateway {
$sessionHandler = $container->get('session.handler');
$cartRepository = $container->get('api.repository.cart');
$endpoint = $container->get('api.endpoint.order');
// TODO eventuall get rid of the endpoints as the processor is sufficient
$orderEndpoint = $container->get('api.endpoint.order');
$paymentsEndpoint = $container->get('api.endpoint.payments');
$orderFactory = $container->get('api.factory.order');
$settingsFields = $container->get('wcgateway.settings.fields');
return new WcGateway($sessionHandler, $cartRepository, $endpoint, $orderFactory, $settingsFields);
$processor = $container->get('wcgateway.processor');
return new WcGateway(
$sessionHandler,
$cartRepository,
$orderEndpoint,
$paymentsEndpoint,
$orderFactory,
$settingsFields,
$processor
);
},
'wcgateway.disabler' => function (ContainerInterface $container) : DisableGateways {
$sessionHandler = $container->get('session.handler');
@ -36,7 +54,27 @@ return [
$settings = $container->get('wcgateway.settings');
return new ConnectAdminNotice($settings);
},
'wcgateway.settings.fields' => function (ContainerInterface $container) : SettingsFields {
'wcgateway.notice.authorize-order-action' =>
function (ContainerInterface $container): AuthorizeOrderActionNotice {
return new AuthorizeOrderActionNotice();
},
'wcgateway.settings.fields' => function (ContainerInterface $container): SettingsFields {
return new SettingsFields();
},
'wcgateway.processor' => function (ContainerInterface $container): Processor {
$authorizedPaymentsProcessor = $container->get('wcgateway.processor.authorized-payments');
return new Processor($authorizedPaymentsProcessor);
},
'wcgateway.processor.authorized-payments' => function (ContainerInterface $container): AuthorizedPaymentsProcessor {
$orderEndpoint = $container->get('api.endpoint.order');
$paymentsEndpoint = $container->get('api.endpoint.payments');
return new AuthorizedPaymentsProcessor($orderEndpoint, $paymentsEndpoint);
},
'wcgateway.admin.order-payment-status' => function(ContainerInterface $container): PaymentStatusOrderDetail {
return new PaymentStatusOrderDetail();
},
'wcgateway.admin.orders-payment-status-column' => function(ContainerInterface $container): OrderTablePaymentStatusColumn {
$settings = $container->get('wcgateway.settings');
return new OrderTablePaymentStatusColumn($settings);
}
];

View file

@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway\Admin;
use Inpsyde\PayPalCommerce\WcGateway\Settings\Settings;
class OrderTablePaymentStatusColumn
{
const COLUMN_KEY = 'ppcp_payment_status';
const INTENT = 'authorize';
const AFTER_COLUMN_KEY = 'order_status';
protected $settings;
public function __construct(Settings $settings)
{
$this->settings = $settings;
}
public function register(array $columns): array
{
if ($this->settings->get('intent') !== self::INTENT) {
return $columns;
}
$statusColumnPosition = array_search(self::AFTER_COLUMN_KEY, array_keys($columns), true);
$toInsertPosition = false === $statusColumnPosition ? count($columns) : $statusColumnPosition + 1;
$columns = array_merge(
array_slice($columns, 0, $toInsertPosition),
[
self::COLUMN_KEY => __('Payment Captured', 'woocommerce-paypal-gateway'),
],
array_slice($columns, $toInsertPosition)
);
return $columns;
}
public function render(string $column, int $wcOrderId)
{
if ($this->settings->get('intent') !== self::INTENT) {
return;
}
if (self::COLUMN_KEY !== $column) {
return;
}
if ($this->isCaptured($wcOrderId)) {
$this->renderCompletedStatus();
} else {
$this->renderIncompletedStatus();
}
}
protected function isCaptured(int $wcOrderId): bool
{
$wcOrder = wc_get_order($wcOrderId);
$captured = $wcOrder->get_meta('_ppcp_paypal_captured');
if (!empty($captured) && wc_string_to_bool($captured)) {
return true;
}
return false;
}
protected function renderCompletedStatus()
{
echo '<span class="dashicons dashicons-yes"></span>';
}
protected function renderIncompletedStatus()
{
printf(
'<mark class="onbackorder">%s</mark>',
esc_html__('Not captured', 'woocommerce-paypal-gateway')
);
}
}

View file

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway\Admin;
class PaymentStatusOrderDetail
{
public function render(int $wcOrderId)
{
$wcOrder = new \WC_Order($wcOrderId);
$intent = $wcOrder->get_meta('_ppcp_paypal_intent');
$captured = $wcOrder->get_meta('_ppcp_paypal_captured');
if (strcasecmp($intent, 'AUTHORIZE') !== 0) {
return;
}
if (!empty($captured) && wc_string_to_bool($captured)) {
return;
}
printf(
// @phpcs:ignore Inpsyde.CodeQuality.LineLength.TooLong
'<li class="wide"><p><mark class="order-status status-on-hold"><span>%1$s</span></mark></p><p>%2$s</p></li>',
esc_html__('Not captured', 'woocommerce-paypal-gateway'),
esc_html__('To capture the payment select capture action from the list below.', 'woocommerce-paypal-gateway'),
);
}
}

View file

@ -1,14 +1,18 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway\Gateway;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
use Inpsyde\PayPalCommerce\ApiClient\Entity\OrderStatus;
use Inpsyde\PayPalCommerce\ApiClient\Factory\OrderFactory;
use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
use Inpsyde\PayPalCommerce\Session\SessionHandler;
use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use Inpsyde\PayPalCommerce\WcGateway\Processor\Processor;
use Inpsyde\PayPalCommerce\WcGateway\Settings\SettingsFields;
//phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
@ -17,23 +21,29 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface
{
private $isSandbox = true;
private $sessionHandler;
private $endpoint;
private $orderEndpoint;
private $cartRepository;
private $orderFactory;
private $settingsFields;
private $paymentsEndpoint;
private $processor;
public function __construct(
SessionHandler $sessionHandler,
CartRepository $cartRepository,
OrderEndpoint $endpoint,
OrderEndpoint $orderEndpoint,
PaymentsEndpoint $paymentsEndpoint,
OrderFactory $orderFactory,
SettingsFields $settingsFields
SettingsFields $settingsFields,
Processor $processor
) {
$this->sessionHandler = $sessionHandler;
$this->cartRepository = $cartRepository;
$this->endpoint = $endpoint;
$this->orderEndpoint = $orderEndpoint;
$this->paymentsEndpoint = $paymentsEndpoint;
$this->orderFactory = $orderFactory;
$this->settingsFields = $settingsFields;
$this->processor = $processor;
$this->method_title = __('PayPal Payments', 'woocommerce-paypal-gateway');
$this->method_description = __(
@ -63,15 +73,19 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface
$this->form_fields = $this->settingsFields->fields();
}
public function process_payment($orderId) : ?array
public function process_payment($orderId): ?array
{
global $woocommerce;
$wcOrder = new \WC_Order($orderId);
//ToDo: We need to fetch the order from paypal again to get it with the new status.
$order = $this->sessionHandler->order();
$wcOrder->update_meta_data('_ppcp_paypal_order_id', $order->id());
$wcOrder->update_meta_data('_ppcp_paypal_intent', $order->intent());
$errorMessage = null;
if (! $order || ! $order->status()->is(OrderStatus::APPROVED)) {
if (!$order || !$order->status()->is(OrderStatus::APPROVED)) {
$errorMessage = 'not approve yet';
}
$errorMessage = null;
@ -81,10 +95,16 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface
}
$order = $this->patchOrder($wcOrder, $order);
$order = $this->endpoint->capture($order);
if ($order->intent() === 'CAPTURE') {
$order = $this->orderEndpoint->capture($order);
}
if ($order->intent() === 'AUTHORIZE') {
$order = $this->orderEndpoint->authorize($order);
}
$wcOrder->update_status('on-hold', __('Awaiting payment.', 'woocommerce-paypal-gateway'));
if ($order->status()->is(OrderStatus::COMPLETED)) {
if ($order->status()->is(OrderStatus::COMPLETED) && $order->intent() === 'CAPTURE') {
$wcOrder->update_status('processing', __('Payment received.', 'woocommerce-paypal-gateway'));
}
$woocommerce->cart->empty_cart();
@ -96,10 +116,56 @@ class WcGateway extends WcGatewayBase implements WcGatewayInterface
];
}
private function patchOrder(\WC_Order $wcOrder, Order $order) : Order
public function captureAuthorizedPayment(\WC_Order $wcOrder): void
{
$result = $this->processor->authorizedPayments()->process($wcOrder);
if ($result === 'INACCESSIBLE') {
AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::NO_INFO);
}
if ($result === 'ALREADY_CAPTURED') {
if ($wcOrder->get_status() === 'on-hold') {
$wcOrder->add_order_note(
__(
'Payment successfully captured.',
'woocommerce-paypal-gateway'
)
);
$wcOrder->update_status('processing');
$wcOrder->update_meta_data('_ppcp_paypal_captured', 'true');
// TODO investigate why save has to be called
$wcOrder->save();
}
AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::ALREADY_CAPTURED);
}
if ($result === 'FAILED') {
AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::FAILED);
}
if ($result === 'SUCCESSFUL') {
$wcOrder->add_order_note(
__(
'Payment successfully captured.',
'woocommerce-paypal-gateway'
)
);
$wcOrder->update_status('processing');
$wcOrder->update_meta_data('_ppcp_paypal_captured', 'true');
// TODO investigate why save has to be called
$wcOrder->save();
AuthorizeOrderActionNotice::displayMessage(AuthorizeOrderActionNotice::SUCCESS);
}
}
private function patchOrder(\WC_Order $wcOrder, Order $order): Order
{
$updatedOrder = $this->orderFactory->fromWcOrder($wcOrder, $order);
$order = $this->endpoint->patchOrderWith($order, $updatedOrder);
$order = $this->orderEndpoint->patchOrderWith($order, $updatedOrder);
return $order;
}
}

View file

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway\Notice;
class AuthorizeOrderActionNotice
{
const NO_INFO = 81;
const ALREADY_CAPTURED = 82;
const FAILED = 83;
const SUCCESS = 84;
public function registerMessages(array $messages): array
{
$messages['shop_order'][self::NO_INFO] = __(
'Could not retrieve information. Try again later.',
'woocommerce-paypal-gateway'
);
$messages['shop_order'][self::ALREADY_CAPTURED] = __(
'Payment already captured.',
'woocommerce-paypal-gateway'
);
$messages['shop_order'][self::FAILED] = __(
'Failed to capture. Try again later.',
'woocommerce-paypal-gateway'
);
$messages['shop_order'][self::SUCCESS] = __(
'Payment successfully captured.',
'woocommerce-paypal-gateway'
);
return $messages;
}
public static function displayMessage(int $messageCode): void
{
add_filter(
'redirect_post_location',
function ($location) use ($messageCode) {
return add_query_arg(
'message',
$messageCode,
$location
);
}
);
}
}

View file

@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway\Processor;
use Exception;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Authorization;
use Inpsyde\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
class AuthorizedPaymentsProcessor
{
public const SUCCESSFUL = 'SUCCESSFUL';
public const ALREADY_CAPTURED = 'ALREADY_CAPTURED';
public const FAILED = 'FAILED';
public const INACCESSIBLE = 'INACCESSIBLE';
private $orderEndpoint;
private $paymentsEndpoint;
public function __construct(
OrderEndpoint $orderEndpoint,
PaymentsEndpoint $paymentsEndpoint
) {
$this->orderEndpoint = $orderEndpoint;
$this->paymentsEndpoint = $paymentsEndpoint;
}
public function process(\WC_Order $wcOrder): string
{
$orderId = $this->getPayPalOrderId($wcOrder);
try {
$order = $this->getCurrentOrderInfo($orderId);
} catch (Exception $exception) {
return self::INACCESSIBLE;
}
$authorizations = $this->getAllAuthorizations($order);
if (!$this->areAuthorizationToCapture(...$authorizations)) {
return self::ALREADY_CAPTURED;
}
try {
$this->captureAuthorizations(...$authorizations);
} catch (Exception $exception) {
return self::FAILED;
}
return self::SUCCESSFUL;
}
protected function getPayPalOrderId(\WC_Order $wcOrder): string
{
return $wcOrder->get_meta('_ppcp_paypal_order_id');
}
protected function getCurrentOrderInfo(string $orderId): Order
{
return $this->orderEndpoint->order($orderId);
}
protected function getAllAuthorizations(Order $order): array
{
$authorizations = [];
foreach ($order->purchaseUnits() as $purchaseUnit) {
foreach ($purchaseUnit->payments()->authorizations() as $authorization) {
$authorizations[] = $authorization;
}
}
return $authorizations;
}
protected function areAuthorizationToCapture(Authorization ...$authorizations): bool
{
$alreadyCapturedAuthorizations = $this->authorizationsWithCapturedStatus(...$authorizations);
return count($alreadyCapturedAuthorizations) !== count($authorizations);
}
protected function captureAuthorizations(Authorization ...$authorizations)
{
$uncapturedAuthorizations = $this->authorizationsWithCreatedStatus(...$authorizations);
foreach ($uncapturedAuthorizations as $authorization) {
$this->paymentsEndpoint->capture($authorization->id());
}
}
/**
* @return Authorization[]
*/
protected function authorizationsWithCreatedStatus(Authorization ...$authorizations): array
{
return array_filter(
$authorizations,
function (Authorization $authorization) {
return $authorization->status()->is(AuthorizationStatus::CREATED);
}
);
}
/**
* @return Authorization[]
*/
protected function authorizationsWithCapturedStatus(Authorization ...$authorizations): array
{
return array_filter(
$authorizations,
function (Authorization $authorization) {
return $authorization->status()->is(AuthorizationStatus::CAPTURED);
}
);
}
}

View file

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway\Processor;
class Processor
{
protected $authorizedPaymentsProcessor;
public function __construct(AuthorizedPaymentsProcessor $authorizedPaymentsProcessor)
{
$this->authorizedPaymentsProcessor = $authorizedPaymentsProcessor;
}
public function authorizedPayments() {
return $this->authorizedPaymentsProcessor;
}
}

View file

@ -47,6 +47,21 @@ class SettingsFields
'woocommerce-paypal-gateway'
),
],
'intent' => [
'title' => __('Intent', 'woocommerce-paypal-gateway'),
'type' => 'select',
'class' => 'wc-enhanced-select',
'default' => 'capture',
'desc_tip' => true,
'description' => __(
'The intent to either capture payment immediately or authorize a payment for an order after order creation.',
'woocommerce-paypal-gateway'
),
'options' => [
'capture' => __('Capture', 'woocommerce-paypal-gateway'),
'authorize' => __('Authorize', 'woocommerce-paypal-gateway'),
],
],
];
}

View file

@ -1,23 +1,28 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\WcGateway;
use Dhii\Container\ServiceProvider;
use Dhii\Modular\Module\ModuleInterface;
use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderDetail;
use Inpsyde\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn;
use Inpsyde\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail;
use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways;
use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway;
use Inpsyde\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
use Inpsyde\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
class WcGatewayModule implements ModuleInterface
{
public function setup(): ServiceProviderInterface
{
return new ServiceProvider(
require __DIR__.'/../services.php',
require __DIR__.'/../extensions.php'
require __DIR__ . '/../services.php',
require __DIR__ . '/../extensions.php'
);
}
@ -26,9 +31,8 @@ class WcGatewayModule implements ModuleInterface
add_filter(
'woocommerce_payment_gateways',
function ($methods) use ($container) : array {
$methods[] = $container->get('wcgateway.gateway');
return (array) $methods;
return (array)$methods;
}
);
@ -39,7 +43,7 @@ class WcGatewayModule implements ModuleInterface
/**
* @var DisableGateways $disabler
*/
return $disabler->handler((array) $methods);
return $disabler->handler((array)$methods);
}
);
@ -53,5 +57,74 @@ class WcGatewayModule implements ModuleInterface
$notice->display();
}
);
add_filter(
'woocommerce_order_actions',
function ($orderActions): array {
$orderActions['ppcp_authorize_order'] = __(
'Capture authorized PayPal payment',
'woocommerce-paypal-gateway'
);
return $orderActions;
}
);
add_action(
'woocommerce_order_action_ppcp_authorize_order',
function (\WC_Order $wcOrder) use ($container) {
/**
* @var WcGateway $gateway
*/
$gateway = $container->get('wcgateway.gateway');
$gateway->captureAuthorizedPayment($wcOrder);
}
);
add_filter(
'post_updated_messages',
function ($messages) use ($container) {
/**
* @var AuthorizeOrderActionNotice $authorizeOrderAction
*/
$authorizeOrderAction = $container->get('wcgateway.notice.authorize-order-action');
return $authorizeOrderAction->registerMessages($messages);
},
20
);
add_action(
'woocommerce_order_actions_start',
function ($wcOrderId) use ($container) {
/**
* @var PaymentStatusOrderDetail $class
*/
$class = $container->get('wcgateway.admin.order-payment-status');
$class->render(intval($wcOrderId));
}
);
add_filter(
'manage_edit-shop_order_columns',
function ($columns) use ($container) {
/**
* @var OrderTablePaymentStatusColumn $paymentStatusColumn
*/
$paymentStatusColumn = $container->get('wcgateway.admin.orders-payment-status-column');
return $paymentStatusColumn->register($columns);
}
);
add_action(
'manage_shop_order_posts_custom_column',
function ($column, $wcOrderId) use ($container) {
/**
* @var OrderTablePaymentStatusColumn $paymentStatusColumn
*/
$paymentStatusColumn = $container->get('wcgateway.admin.orders-payment-status-column');
$paymentStatusColumn->render($column, intval($wcOrderId));
},
10,
2
);
}
}