diff --git a/spec/Api/CompleteOrderApiSpec.php b/spec/Api/CompleteOrderApiSpec.php index f5fd6610..aa686f88 100644 --- a/spec/Api/CompleteOrderApiSpec.php +++ b/spec/Api/CompleteOrderApiSpec.php @@ -13,19 +13,17 @@ namespace spec\Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; use PhpSpec\ObjectBehavior; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\PayPalPlugin\Api\CompleteOrderApiInterface; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class CompleteOrderApiSpec extends ObjectBehavior { - function let(Client $client): void + function let(PayPalClientInterface $client): void { - $this->beConstructedWith($client, 'https://api.test-paypal.com/', 'PARTNER_ATTRIBUTION_ID'); + $this->beConstructedWith($client); } function it_implements_complete_order_api_interface(): void @@ -34,30 +32,18 @@ function it_implements_complete_order_api_interface(): void } function it_completes_pay_pal_order_with_given_id( - Client $client, + PayPalClientInterface $client, PaymentInterface $payment, - OrderInterface $order, - ResponseInterface $response, - StreamInterface $body + OrderInterface $order ): void { $payment->getOrder()->willReturn($order); $payment->getAmount()->willReturn(10000); $order->getCurrencyCode()->willReturn('PLN'); - $client->request( - 'POST', - 'https://api.test-paypal.com/v2/checkout/orders/123123/capture', - [ - 'headers' => [ - 'Authorization' => 'Bearer TOKEN', - 'Prefer' => 'return=representation', - 'PayPal-Partner-Attribution-Id' => 'PARTNER_ATTRIBUTION_ID', - 'Content-Type' => 'application/json', - ], - ] - )->willReturn($response); - $response->getBody()->willReturn($body); - $body->getContents()->willReturn('{"status": "COMPLETED", "id": 123}'); + $client + ->post('v2/checkout/orders/123123/capture', 'TOKEN') + ->willReturn(['status' => 'COMPLETED', 'id' => 123]) + ; $this->complete('TOKEN', '123123')->shouldReturn(['status' => 'COMPLETED', 'id' => 123]); } diff --git a/spec/Api/CreateOrderApiSpec.php b/spec/Api/CreateOrderApiSpec.php index 3c2b1304..d68bd8cf 100644 --- a/spec/Api/CreateOrderApiSpec.php +++ b/spec/Api/CreateOrderApiSpec.php @@ -13,23 +13,21 @@ namespace spec\Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; use Payum\Core\Model\GatewayConfigInterface; use PhpSpec\ObjectBehavior; use Prophecy\Argument; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; use Sylius\Component\Core\Model\AddressInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\PayPalPlugin\Api\CreateOrderApiInterface; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class CreateOrderApiSpec extends ObjectBehavior { - function let(Client $client): void + function let(PayPalClientInterface $client): void { - $this->beConstructedWith($client, 'https://api.test-paypal.com/', 'PARTNER_ATTRIBUTION_ID'); + $this->beConstructedWith($client); } function it_implements_create_order_api_interface(): void @@ -38,11 +36,9 @@ function it_implements_create_order_api_interface(): void } function it_creates_pay_pal_order_based_on_given_payment( - Client $client, + PayPalClientInterface $client, PaymentInterface $payment, OrderInterface $order, - ResponseInterface $response, - StreamInterface $body, PaymentMethodInterface $paymentMethod, GatewayConfigInterface $gatewayConfig ): void { @@ -58,30 +54,25 @@ function it_creates_pay_pal_order_based_on_given_payment( ['merchant_id' => 'merchant-id', 'sylius_merchant_id' => 'sylius-merchant-id'] ); - $client->request( - 'POST', - 'https://api.test-paypal.com/v2/checkout/orders', + $client->post( + 'v2/checkout/orders', + 'TOKEN', Argument::that(function (array $data): bool { return - $data['headers']['Authorization'] === 'Bearer TOKEN' && - $data['json']['intent'] === 'CAPTURE' && - $data['json']['purchase_units'][0]['amount']['value'] === 100 && - $data['json']['purchase_units'][0]['amount']['currency_code'] === 'PLN' + $data['intent'] === 'CAPTURE' && + $data['purchase_units'][0]['amount']['value'] === 100 && + $data['purchase_units'][0]['amount']['currency_code'] === 'PLN' ; }) - )->willReturn($response); - $response->getBody()->willReturn($body); - $body->getContents()->willReturn('{"status": "CREATED", "id": 123}'); + )->willReturn(['status' => 'CREATED', 'id' => 123]); $this->create('TOKEN', $payment)->shouldReturn(['status' => 'CREATED', 'id' => 123]); } function it_creates_pay_pal_order_with_shipping_address_based_on_given_payment( - Client $client, + PayPalClientInterface $client, PaymentInterface $payment, OrderInterface $order, - ResponseInterface $response, - StreamInterface $body, PaymentMethodInterface $paymentMethod, GatewayConfigInterface $gatewayConfig, AddressInterface $shippingAddress @@ -104,25 +95,22 @@ function it_creates_pay_pal_order_with_shipping_address_based_on_given_payment( ['merchant_id' => 'merchant-id', 'sylius_merchant_id' => 'sylius-merchant-id'] ); - $client->request( - 'POST', - 'https://api.test-paypal.com/v2/checkout/orders', + $client->post( + 'v2/checkout/orders', + 'TOKEN', Argument::that(function (array $data): bool { return - $data['headers']['Authorization'] === 'Bearer TOKEN' && - $data['json']['intent'] === 'CAPTURE' && - $data['json']['purchase_units'][0]['amount']['value'] === 100 && - $data['json']['purchase_units'][0]['amount']['currency_code'] === 'PLN' && - $data['json']['purchase_units'][0]['shipping']['name']['full_name'] === 'Gandalf The Grey' && - $data['json']['purchase_units'][0]['shipping']['address']['address_line_1'] === 'Hobbit St. 123' && - $data['json']['purchase_units'][0]['shipping']['address']['admin_area_2'] === 'Minas Tirith' && - $data['json']['purchase_units'][0]['shipping']['address']['postal_code'] === '000' && - $data['json']['purchase_units'][0]['shipping']['address']['country_code'] === 'US' + $data['intent'] === 'CAPTURE' && + $data['purchase_units'][0]['amount']['value'] === 100 && + $data['purchase_units'][0]['amount']['currency_code'] === 'PLN' && + $data['purchase_units'][0]['shipping']['name']['full_name'] === 'Gandalf The Grey' && + $data['purchase_units'][0]['shipping']['address']['address_line_1'] === 'Hobbit St. 123' && + $data['purchase_units'][0]['shipping']['address']['admin_area_2'] === 'Minas Tirith' && + $data['purchase_units'][0]['shipping']['address']['postal_code'] === '000' && + $data['purchase_units'][0]['shipping']['address']['country_code'] === 'US' ; }) - )->willReturn($response); - $response->getBody()->willReturn($body); - $body->getContents()->willReturn('{"status": "CREATED", "id": 123}'); + )->willReturn(['status' => 'CREATED', 'id' => 123]); $this->create('TOKEN', $payment)->shouldReturn(['status' => 'CREATED', 'id' => 123]); } diff --git a/spec/Api/OrderDetailsApiSpec.php b/spec/Api/OrderDetailsApiSpec.php index be3d2f8f..61cba851 100644 --- a/spec/Api/OrderDetailsApiSpec.php +++ b/spec/Api/OrderDetailsApiSpec.php @@ -13,18 +13,15 @@ namespace spec\Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; use PhpSpec\ObjectBehavior; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; -use Sylius\PayPalPlugin\Api\AuthorizeClientApiInterface; use Sylius\PayPalPlugin\Api\OrderDetailsApiInterface; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class OrderDetailsApiSpec extends ObjectBehavior { - function let(Client $client): void + function let(PayPalClientInterface $client): void { - $this->beConstructedWith($client, 'https://api.test-paypal.com/', 'PARTNER_ATTRIBUTION_ID'); + $this->beConstructedWith($client); } function it_implements_pay_pal_order_details_provider_interface(): void @@ -32,26 +29,12 @@ function it_implements_pay_pal_order_details_provider_interface(): void $this->shouldImplement(OrderDetailsApiInterface::class); } - function it_provides_details_about_pay_pal_order( - Client $client, - AuthorizeClientApiInterface $authorizeClientApi, - ResponseInterface $detailsResponse, - StreamInterface $detailsBody - ): void { - $client->request( - 'GET', - 'https://api.test-paypal.com/v2/checkout/orders/123123', - [ - 'headers' => [ - 'Authorization' => 'Bearer TOKEN', - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'PayPal-Partner-Attribution-Id' => 'PARTNER_ATTRIBUTION_ID', - ], - ] - )->willReturn($detailsResponse); - $detailsResponse->getBody()->willReturn($detailsBody); - $detailsBody->getContents()->willReturn('{"total": 1111}'); + function it_provides_details_about_pay_pal_order(PayPalClientInterface $client): void + { + $client + ->get('v2/checkout/orders/123123', 'TOKEN') + ->willReturn(['total' => 1111]) + ; $this->get('TOKEN', '123123')->shouldReturn(['total' => 1111]); } diff --git a/spec/Api/RefundPaymentApiSpec.php b/spec/Api/RefundPaymentApiSpec.php index 1b2ac4d3..de1aa58a 100644 --- a/spec/Api/RefundPaymentApiSpec.php +++ b/spec/Api/RefundPaymentApiSpec.php @@ -13,20 +13,15 @@ namespace spec\Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; use PhpSpec\ObjectBehavior; -use Prophecy\Argument; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; -use Sylius\Component\Core\Model\OrderInterface; -use Sylius\Component\Core\Model\PaymentInterface; use Sylius\PayPalPlugin\Api\RefundPaymentApiInterface; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class RefundPaymentApiSpec extends ObjectBehavior { - function let(Client $client): void + function let(PayPalClientInterface $client): void { - $this->beConstructedWith($client, 'https://api.test-paypal.com/', 'PARTNER_ATTRIBUTION_ID'); + $this->beConstructedWith($client); } function it_implements_refund_order_api_interface(): void @@ -34,31 +29,12 @@ function it_implements_refund_order_api_interface(): void $this->shouldImplement(RefundPaymentApiInterface::class); } - function it_refunds_pay_pal_payment_with_given_id( - Client $client, - PaymentInterface $payment, - OrderInterface $order, - ResponseInterface $response, - StreamInterface $body - ): void { - $payment->getOrder()->willReturn($order); - $payment->getAmount()->willReturn(10000); - $order->getCurrencyCode()->willReturn('PLN'); - - $client->request( - 'POST', - 'https://api.test-paypal.com/v2/payments/captures/123123/refund', - Argument::that(function (array $options): bool { - return - $options['headers']['Authorization'] === 'Bearer TOKEN' && - $options['headers']['PayPal-Partner-Attribution-Id'] === 'PARTNER_ATTRIBUTION_ID' && - $options['headers']['Content-Type'] === 'application/json' && - is_string($options['headers']['PayPal-Request-Id']) - ; - }) - )->willReturn($response); - $response->getBody()->willReturn($body); - $body->getContents()->willReturn('{"status": "COMPLETED", "id": "123123"}'); + function it_refunds_pay_pal_payment_with_given_id(PayPalClientInterface $client): void + { + $client + ->post('v2/payments/captures/123123/refund', 'TOKEN') + ->willReturn(['status' => 'COMPLETED', 'id' => '123123']) + ; $this->refund('TOKEN', '123123')->shouldReturn(['status' => 'COMPLETED', 'id' => '123123']); } diff --git a/spec/Api/UpdateOrderApiSpec.php b/spec/Api/UpdateOrderApiSpec.php index 066ced67..48e2b977 100644 --- a/spec/Api/UpdateOrderApiSpec.php +++ b/spec/Api/UpdateOrderApiSpec.php @@ -13,18 +13,16 @@ namespace spec\Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; use PhpSpec\ObjectBehavior; use Prophecy\Argument; -use Psr\Http\Message\ResponseInterface; use Sylius\PayPalPlugin\Api\UpdateOrderApiInterface; -use Sylius\PayPalPlugin\Exception\PayPalOrderUpdateException; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class UpdateOrderApiSpec extends ObjectBehavior { - function let(Client $client): void + function let(PayPalClientInterface $client): void { - $this->beConstructedWith($client, 'https://api.test-paypal.com/', 'PARTNER-ATTRIBUTION-ID'); + $this->beConstructedWith($client); } function it_implements_update_order_api_interface(): void @@ -32,52 +30,21 @@ function it_implements_update_order_api_interface(): void $this->shouldImplement(UpdateOrderApiInterface::class); } - function it_updates_pay_pal_order_with_given_new_total( - Client $client, - ResponseInterface $response - ): void { - $client->request( - 'PATCH', - 'https://api.test-paypal.com/v2/checkout/orders/ORDER-ID', + function it_updates_pay_pal_order_with_given_new_total(PayPalClientInterface $client): void + { + $client->patch( + 'v2/checkout/orders/ORDER-ID', + 'TOKEN', Argument::that(function (array $data): bool { return - $data['headers']['Authorization'] === 'Bearer TOKEN' && - $data['headers']['PayPal-Partner-Attribution-Id'] === 'PARTNER-ATTRIBUTION-ID' && - $data['json'][0]['op'] === 'replace' && - $data['json'][0]['path'] === '/purchase_units/@reference_id==\'default\'/amount' && - $data['json'][0]['value']['value'] === '11.22' && - $data['json'][0]['value']['currency_code'] === 'USD' + $data[0]['op'] === 'replace' && + $data[0]['path'] === '/purchase_units/@reference_id==\'default\'/amount' && + $data[0]['value']['value'] === '11.22' && + $data[0]['value']['currency_code'] === 'USD' ; }) - )->willReturn($response); - $response->getStatusCode()->willReturn(204); + )->shouldBeCalled(); $this->update('TOKEN', 'ORDER-ID', '11.22', 'USD'); } - - function it_throws_an_exception_if_update_is_not_successful( - Client $client, - ResponseInterface $response - ): void { - $client->request( - 'PATCH', - 'https://api.test-paypal.com/v2/checkout/orders/ORDER-ID', - Argument::that(function (array $data): bool { - return - $data['headers']['Authorization'] === 'Bearer TOKEN' && - $data['headers']['PayPal-Partner-Attribution-Id'] === 'PARTNER-ATTRIBUTION-ID' && - $data['json'][0]['op'] === 'replace' && - $data['json'][0]['path'] === '/purchase_units/@reference_id==\'default\'/amount' && - $data['json'][0]['value']['value'] === '11.22' && - $data['json'][0]['value']['currency_code'] === 'USD' - ; - }) - )->willReturn($response); - $response->getStatusCode()->willReturn(500); - - $this - ->shouldThrow(PayPalOrderUpdateException::class) - ->during('update', ['TOKEN', 'ORDER-ID', '11.22', 'USD']) - ; - } } diff --git a/spec/Client/PayPalClientSpec.php b/spec/Client/PayPalClientSpec.php new file mode 100644 index 00000000..b4d0ee8b --- /dev/null +++ b/spec/Client/PayPalClientSpec.php @@ -0,0 +1,222 @@ +beConstructedWith($client, $logger, 'https://test-api.paypal.com/', 'TRACKING-ID'); + } + + function it_implements_pay_pal_client_interface(): void + { + $this->shouldImplement(PayPalClientInterface::class); + } + + function it_calls_get_request_on_paypal_api( + ClientInterface $client, + ResponseInterface $response, + StreamInterface $body + ): void { + $client->request( + 'GET', + 'https://test-api.paypal.com/v2/get-request/', + [ + 'headers' => [ + 'Authorization' => 'Bearer TOKEN', + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'PayPal-Partner-Attribution-Id' => 'TRACKING-ID', + ], + ] + )->willReturn($response); + $response->getStatusCode()->willReturn(200); + $response->getBody()->willReturn($body); + $body->getContents()->willReturn('{"status": "OK", "id": "123123"}'); + + $this->get('v2/get-request/', 'TOKEN')->shouldReturn(['status' => 'OK', 'id' => '123123']); + } + + function it_logs_debug_id_from_failed_get_request( + ClientInterface $client, + LoggerInterface $logger, + RequestException $exception, + ResponseInterface $response, + StreamInterface $body + ): void { + $client->request( + 'GET', + 'https://test-api.paypal.com/v2/get-request/', + [ + 'headers' => [ + 'Authorization' => 'Bearer TOKEN', + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'PayPal-Partner-Attribution-Id' => 'TRACKING-ID', + ], + ] + )->willThrow($exception->getWrappedObject()); + + $exception->getResponse()->willReturn($response); + $response->getBody()->willReturn($body); + $response->getStatusCode()->willReturn(400); + $body->getContents()->willReturn('{"status": "FAILED", "debug_id": "123123"}'); + + $logger + ->error('GET request to "https://test-api.paypal.com/v2/get-request/" failed with debug ID 123123') + ->shouldBeCalled() + ; + + $this->get('v2/get-request/', 'TOKEN')->shouldReturn(['status' => 'FAILED', 'debug_id' => '123123']); + } + + function it_calls_post_request_on_paypal_api( + ClientInterface $client, + ResponseInterface $response, + StreamInterface $body + ): void { + $client->request( + 'POST', + 'https://test-api.paypal.com/v2/post-request/', + [ + 'headers' => [ + 'Authorization' => 'Bearer TOKEN', + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'PayPal-Partner-Attribution-Id' => 'TRACKING-ID', + ], + 'json' => ['parameter' => 'value', 'another_parameter' => 'another_value'], + ] + )->willReturn($response); + $response->getStatusCode()->willReturn(200); + $response->getBody()->willReturn($body); + $body->getContents()->willReturn('{"status": "OK", "id": "123123"}'); + + $this + ->post('v2/post-request/', 'TOKEN', ['parameter' => 'value', 'another_parameter' => 'another_value']) + ->shouldReturn(['status' => 'OK', 'id' => '123123']) + ; + } + + function it_logs_debug_id_from_failed_post_request( + ClientInterface $client, + LoggerInterface $logger, + RequestException $exception, + ResponseInterface $response, + StreamInterface $body + ): void { + $client->request( + 'POST', + 'https://test-api.paypal.com/v2/post-request/', + [ + 'headers' => [ + 'Authorization' => 'Bearer TOKEN', + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'PayPal-Partner-Attribution-Id' => 'TRACKING-ID', + ], + 'json' => ['parameter' => 'value', 'another_parameter' => 'another_value'], + ] + )->willThrow($exception->getWrappedObject()); + + $exception->getResponse()->willReturn($response); + $response->getBody()->willReturn($body); + $response->getStatusCode()->willReturn(400); + $body->getContents()->willReturn('{"status": "FAILED", "debug_id": "123123"}'); + + $logger + ->error('POST request to "https://test-api.paypal.com/v2/post-request/" failed with debug ID 123123') + ->shouldBeCalled() + ; + + $this + ->post('v2/post-request/', 'TOKEN', ['parameter' => 'value', 'another_parameter' => 'another_value']) + ->shouldReturn(['status' => 'FAILED', 'debug_id' => '123123']) + ; + } + + function it_calls_patch_request_on_paypal_api( + ClientInterface $client, + ResponseInterface $response, + StreamInterface $body + ): void { + $client->request( + 'PATCH', + 'https://test-api.paypal.com/v2/patch-request/123123', + [ + 'headers' => [ + 'Authorization' => 'Bearer TOKEN', + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'PayPal-Partner-Attribution-Id' => 'TRACKING-ID', + ], + 'json' => ['parameter' => 'value', 'another_parameter' => 'another_value'], + ] + )->willReturn($response); + $response->getStatusCode()->willReturn(200); + $response->getBody()->willReturn($body); + $body->getContents()->willReturn('{"status": "OK", "id": "123123"}'); + + $this + ->patch('v2/patch-request/123123', 'TOKEN', ['parameter' => 'value', 'another_parameter' => 'another_value']) + ->shouldReturn(['status' => 'OK', 'id' => '123123']) + ; + } + + function it_logs_debug_id_from_failed_patch_request( + ClientInterface $client, + LoggerInterface $logger, + RequestException $exception, + ResponseInterface $response, + StreamInterface $body + ): void { + $client->request( + 'PATCH', + 'https://test-api.paypal.com/v2/patch-request/123123', + [ + 'headers' => [ + 'Authorization' => 'Bearer TOKEN', + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'PayPal-Partner-Attribution-Id' => 'TRACKING-ID', + ], + 'json' => ['parameter' => 'value', 'another_parameter' => 'another_value'], + ] + )->willThrow($exception->getWrappedObject()); + + $exception->getResponse()->willReturn($response); + $response->getBody()->willReturn($body); + $response->getStatusCode()->willReturn(400); + $body->getContents()->willReturn('{"status": "FAILED", "debug_id": "123123"}'); + + $logger + ->error('PATCH request to "https://test-api.paypal.com/v2/patch-request/123123" failed with debug ID 123123') + ->shouldBeCalled() + ; + + $this + ->patch('v2/patch-request/123123', 'TOKEN', ['parameter' => 'value', 'another_parameter' => 'another_value']) + ->shouldReturn(['status' => 'FAILED', 'debug_id' => '123123']) + ; + } +} diff --git a/src/Api/CompleteOrderApi.php b/src/Api/CompleteOrderApi.php index a9124134..f563c430 100644 --- a/src/Api/CompleteOrderApi.php +++ b/src/Api/CompleteOrderApi.php @@ -13,41 +13,20 @@ namespace Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class CompleteOrderApi implements CompleteOrderApiInterface { - /** @var Client */ + /** @var PayPalClientInterface */ private $client; - /** @var string */ - private $baseUrl; - - /** @var string */ - private $partnerAttributionId; - - public function __construct(Client $client, string $baseUrl, string $partnerAttributionId) + public function __construct(PayPalClientInterface $client) { $this->client = $client; - $this->baseUrl = $baseUrl; - $this->partnerAttributionId = $partnerAttributionId; } public function complete(string $token, string $orderId): array { - $response = $this->client->request( - 'POST', - sprintf('%sv2/checkout/orders/%s/capture', $this->baseUrl, $orderId), - [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $token, - 'Prefer' => 'return=representation', - 'PayPal-Partner-Attribution-Id' => $this->partnerAttributionId, - 'Content-Type' => 'application/json', - ], - ] - ); - - return (array) json_decode($response->getBody()->getContents(), true); + return $this->client->post(sprintf('v2/checkout/orders/%s/capture', $orderId), $token); } } diff --git a/src/Api/CreateOrderApi.php b/src/Api/CreateOrderApi.php index 316aad3b..72fba126 100644 --- a/src/Api/CreateOrderApi.php +++ b/src/Api/CreateOrderApi.php @@ -13,29 +13,21 @@ namespace Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; use Webmozart\Assert\Assert; final class CreateOrderApi implements CreateOrderApiInterface { - /** @var Client */ + /** @var PayPalClientInterface */ private $client; - /** @var string */ - private $baseUrl; - - /** @var string */ - private $partnerAttributionId; - - public function __construct(Client $client, string $baseUrl, string $partnerAttributionId) + public function __construct(PayPalClientInterface $client) { $this->client = $client; - $this->baseUrl = $baseUrl; - $this->partnerAttributionId = $partnerAttributionId; } public function create(string $token, PaymentInterface $payment): array @@ -93,20 +85,6 @@ public function create(string $token, PaymentInterface $payment): array ]; } - $response = $this->client->request( - 'POST', - $this->baseUrl . 'v2/checkout/orders', - [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $token, - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'PayPal-Partner-Attribution-Id' => $this->partnerAttributionId, - ], - 'json' => $data, - ] - ); - - return (array) json_decode($response->getBody()->getContents(), true); + return $this->client->post('v2/checkout/orders', $token, $data); } } diff --git a/src/Api/OrderDetailsApi.php b/src/Api/OrderDetailsApi.php index 23a1b029..61ca617f 100644 --- a/src/Api/OrderDetailsApi.php +++ b/src/Api/OrderDetailsApi.php @@ -4,40 +4,20 @@ namespace Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class OrderDetailsApi implements OrderDetailsApiInterface { - /** @var Client */ + /** @var PayPalClientInterface */ private $client; - /** @var string */ - private $baseUrl; - - /** @var string */ - private $partnerAttributionId; - - public function __construct(Client $client, string $baseUrl, string $partnerAttributionId) + public function __construct(PayPalClientInterface $client) { $this->client = $client; - $this->baseUrl = $baseUrl; - $this->partnerAttributionId = $partnerAttributionId; } public function get(string $token, string $orderId): array { - $response = $this->client->request( - 'GET', - sprintf('%sv2/checkout/orders/%s', $this->baseUrl, $orderId), [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $token, - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'PayPal-Partner-Attribution-Id' => $this->partnerAttributionId, - ], - ] - ); - - return (array) json_decode($response->getBody()->getContents(), true); + return $this->client->get(sprintf('v2/checkout/orders/%s', $orderId), $token); } } diff --git a/src/Api/RefundPaymentApi.php b/src/Api/RefundPaymentApi.php index 018b8dbb..149c9fe1 100644 --- a/src/Api/RefundPaymentApi.php +++ b/src/Api/RefundPaymentApi.php @@ -13,42 +13,20 @@ namespace Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; -use Ramsey\Uuid\Uuid; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class RefundPaymentApi implements RefundPaymentApiInterface { - /** @var Client */ + /** @var PayPalClientInterface */ private $client; - /** @var string */ - private $baseUrl; - - /** @var string */ - private $partnerAttributionId; - - public function __construct(Client $client, string $baseUrl, string $partnerAttributionId) + public function __construct(PayPalClientInterface $client) { $this->client = $client; - $this->baseUrl = $baseUrl; - $this->partnerAttributionId = $partnerAttributionId; } public function refund(string $token, string $paymentId): array { - $response = $this->client->request( - 'POST', - sprintf('%sv2/payments/captures/%s/refund', $this->baseUrl, $paymentId), - [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $token, - 'PayPal-Partner-Attribution-Id' => $this->partnerAttributionId, - 'Content-Type' => 'application/json', - 'PayPal-Request-Id' => Uuid::uuid4()->toString(), - ], - ] - ); - - return (array) json_decode($response->getBody()->getContents(), true); + return $this->client->post(sprintf('v2/payments/captures/%s/refund', $paymentId), $token); } } diff --git a/src/Api/UpdateOrderApi.php b/src/Api/UpdateOrderApi.php index e38aab2f..970a582f 100644 --- a/src/Api/UpdateOrderApi.php +++ b/src/Api/UpdateOrderApi.php @@ -13,51 +13,30 @@ namespace Sylius\PayPalPlugin\Api; -use GuzzleHttp\Client; -use Sylius\PayPalPlugin\Exception\PayPalOrderUpdateException; +use Sylius\PayPalPlugin\Client\PayPalClientInterface; final class UpdateOrderApi implements UpdateOrderApiInterface { - /** @var Client */ + /** @var PayPalClientInterface */ private $client; - /** @var string */ - private $baseUrl; - - /** @var string */ - private $partnerAttributionId; - - public function __construct(Client $client, string $baseUrl, string $partnerAttributionId) + public function __construct(PayPalClientInterface $client) { $this->client = $client; - $this->baseUrl = $baseUrl; - $this->partnerAttributionId = $partnerAttributionId; } public function update(string $token, string $orderId, string $newTotal, string $newCurrencyCode): void { - $response = $this->client->request( - 'PATCH', - sprintf('%sv2/checkout/orders/%s', $this->baseUrl, $orderId), + $this->client->patch( + sprintf('v2/checkout/orders/%s', $orderId), + $token, [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $token, - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'PayPal-Partner-Attribution-Id' => $this->partnerAttributionId, - ], - 'json' => [ - [ - 'op' => 'replace', - 'path' => '/purchase_units/@reference_id==\'default\'/amount', - 'value' => ['value' => $newTotal, 'currency_code' => $newCurrencyCode], - ], + [ + 'op' => 'replace', + 'path' => '/purchase_units/@reference_id==\'default\'/amount', + 'value' => ['value' => $newTotal, 'currency_code' => $newCurrencyCode], ], ] ); - - if ($response->getStatusCode() !== 204) { - throw new PayPalOrderUpdateException(); - } } } diff --git a/src/Api/UpdateOrderApiInterface.php b/src/Api/UpdateOrderApiInterface.php index 7c9eb0f2..9669dbb6 100644 --- a/src/Api/UpdateOrderApiInterface.php +++ b/src/Api/UpdateOrderApiInterface.php @@ -4,12 +4,7 @@ namespace Sylius\PayPalPlugin\Api; -use Sylius\PayPalPlugin\Exception\PayPalOrderUpdateException; - interface UpdateOrderApiInterface { - /** - * @throws PayPalOrderUpdateException - */ public function update(string $token, string $orderId, string $newTotal, string $newCurrencyCode): void; } diff --git a/src/Client/PayPalClient.php b/src/Client/PayPalClient.php new file mode 100644 index 00000000..2e9da1cb --- /dev/null +++ b/src/Client/PayPalClient.php @@ -0,0 +1,97 @@ +client = $client; + $this->logger = $logger; + $this->baseUrl = $baseUrl; + $this->trackingId = $trackingId; + } + + public function get(string $url, string $token): array + { + return $this->request('GET', $url, $token); + } + + public function post(string $url, string $token, array $data = null): array + { + return $this->request('POST', $url, $token, $data); + } + + public function patch(string $url, string $token, array $data = null): array + { + return $this->request('PATCH', $url, $token, $data); + } + + private function request(string $method, string $url, string $token, array $data = null): array + { + $options = [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $token, + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'PayPal-Partner-Attribution-Id' => $this->trackingId, + ], + ]; + + if ($data !== null) { + $options['json'] = $data; + } + + $fullUrl = $this->baseUrl . $url; + + try { + /** @var ResponseInterface $response */ + $response = $this->client->request($method, $fullUrl, $options); + } catch (RequestException $exception) { + /** @var ResponseInterface $response */ + $response = $exception->getResponse(); + } + + $content = (array) json_decode($response->getBody()->getContents(), true); + + if ( + (!in_array($response->getStatusCode(), [200, 204])) && + isset($content['debug_id']) + ) { + $this + ->logger + ->error(sprintf('%s request to "%s" failed with debug ID %s', $method, $fullUrl, (string) $content['debug_id'])) + ; + } + + return $content; + } +} diff --git a/src/Client/PayPalClientInterface.php b/src/Client/PayPalClientInterface.php new file mode 100644 index 00000000..ebf62304 --- /dev/null +++ b/src/Client/PayPalClientInterface.php @@ -0,0 +1,14 @@ + + + + + %env(resolve:PAYPAL_API_BASE_URL)% + %env(resolve:PAYPAL_TRACKING_ID)% + + - - %env(resolve:PAYPAL_API_BASE_URL)% - %env(resolve:PAYPAL_TRACKING_ID)% + - - %env(resolve:PAYPAL_API_BASE_URL)% - %env(resolve:PAYPAL_TRACKING_ID)%) + - - %env(resolve:PAYPAL_API_BASE_URL)% - %env(resolve:PAYPAL_TRACKING_ID)% + - - %env(resolve:PAYPAL_API_BASE_URL)% - %env(resolve:PAYPAL_TRACKING_ID)% + - - %env(resolve:PAYPAL_API_BASE_URL)% - %env(resolve:PAYPAL_TRACKING_ID)% +