Skip to content

Commit

Permalink
feature #121 Paypal URLs and codes based on configuration (Zales0123)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.0-dev branch.

Discussion
----------

Better solution *right now*, but we should still aim to something like #118

Commits
-------

f065977 Use always PAYPAL_ATTRIBUTION_ID from payment method configuration
9ec03ba Use configuration to detemine which URLs to use
8aee023 Inform about sandbox mode in README
  • Loading branch information
SirDomin authored Sep 28, 2020
2 parents 52d0a98 + 8aee023 commit 3a0ea37
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 108 deletions.
46 changes: 14 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,31 +79,7 @@ Sylius Core Team’s plugin for [PayPal Commerce Platform](https://www.paypal.co
cp -R vendor/sylius/paypal-plugin/src/Resources/views/bundles/* templates/bundles/
```
4. Add env variables
### Sandbox
```
#.env
PAYPAL_API_BASE_URL='https://api.sandbox.paypal.com/'
# just for now, it will be eventually hardcoded (as we always want to use Sylius PayPal facilitator)
PAYPAL_FACILITATOR_URL='https://paypal.sylius.com'
PAYPAL_TRACKING_ID='sylius-ppcp4p-bn-code'
```
### Live
```
#.env
PAYPAL_API_BASE_URL='https://api.paypal.com/'
# just for now, it will be eventually hardcoded (as we always want to use Sylius PayPal facilitator)
PAYPAL_FACILITATOR_URL='https://prod.paypal.sylius.com'
PAYPAL_TRACKING_ID='sylius-ppcp4p-bn-code'
```
5. Copy and apply migrations
4. Copy and apply migrations
```
cp -R vendor/sylius/paypal-plugin/migrations/ src/Migrations/
Expand All @@ -115,6 +91,18 @@ Sylius Core Team’s plugin for [PayPal Commerce Platform](https://www.paypal.co
To make PayPal integration working, your local Sylius URL should be accessible for the PayPal servers. Therefore you can
add the proper directive to your `/etc/hosts` (something like `127.0.0.1 sylius.local`) or use a service as [ngrok](https://ngrok.com/).
#### Sandbox vs Live
By default, plugin operates in the sandbox mode. I means all the transactions would be used with the sandbox URLs and code.
To change it, you need to configure the plugin properly:
```yaml
sylius_pay_pal:
sandbox: false
```
You can, for example, configure it only for the production environment (e.g. in `config/packages/prod/sylius_pay_pal_plugin.yaml`).
## PayPal reports
To be able to download reports about your payouts, you need to have reports feature enabled on your PayPal account. Also,
Expand All @@ -133,13 +121,7 @@ it's required to configure SFTP account and set its data in `.env` file.
![accounts](docs/reports-accounts.png)
5. Configure following env variables
```
PAYPAL_REPORTS_SFTP_HOST='reports.paypal.com'
PAYPAL_REPORTS_SFTP_USERNAME='USERNAME'
PAYPAL_REPORTS_SFTP_PASSWORD='PASSWORD'
```
5. Configure username and password in payment method's configuration
## Processing payments
Expand Down
87 changes: 57 additions & 30 deletions spec/Api/WebhookApiSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,71 @@

namespace spec\Sylius\PayPalPlugin\Api;

use GuzzleHttp\ClientInterface;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\PayPalPlugin\Client\PayPalClientInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

final class WebhookApiSpec extends ObjectBehavior
{
function let(PayPalClientInterface $client): void
function let(ClientInterface $client): void
{
$this->beConstructedWith($client);
$this->beConstructedWith($client, 'http://base-url.com/');
}

function it_registers_webhook(PayPalClientInterface $client): void
{
$client->post(
'v1/notifications/webhooks',
'TOKEN',
Argument::that(function ($data): bool {
return
$data['url'] === 'https://webhook.com' &&
$data['event_types'][0]['name'] === 'PAYMENT.CAPTURE.REFUNDED';
})
)->shouldBeCalled();

$this->register('TOKEN', 'https://webhook.com');
function it_registers_webhook(
ClientInterface $client,
ResponseInterface $response,
StreamInterface $body
): void {
$client->request(
'POST',
'http://base-url.com/v1/notifications/webhooks',
[
'headers' => [
'Authorization' => 'Bearer TOKEN',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'url' => 'https://webhook.com',
'event_types' => [
['name' => 'PAYMENT.CAPTURE.REFUNDED'],
],
],
]
)->willReturn($response);
$response->getBody()->willReturn($body);
$body->getContents()->willReturn('{ "status": "CREATED" }');

$this->register('TOKEN', 'https://webhook.com')->shouldReturn(['status' => 'CREATED']);
}

function it_registers_webhook_without_https(PayPalClientInterface $client): void
{
$client->post(
'v1/notifications/webhooks',
'TOKEN',
Argument::that(function ($data): bool {
return
$data['url'] === 'https://webhook.com' &&
$data['event_types'][0]['name'] === 'PAYMENT.CAPTURE.REFUNDED';
})
)->shouldBeCalled();

$this->register('TOKEN', 'http://webhook.com');
function it_registers_webhook_without_https(
ClientInterface $client,
ResponseInterface $response,
StreamInterface $body
): void {
$client->request(
'POST',
'http://base-url.com/v1/notifications/webhooks',
[
'headers' => [
'Authorization' => 'Bearer TOKEN',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'url' => 'https://webhook.com',
'event_types' => [
['name' => 'PAYMENT.CAPTURE.REFUNDED'],
],
],
]
)->willReturn($response);
$response->getBody()->willReturn($body);
$body->getContents()->willReturn('{ "status": "CREATED" }');

$this->register('TOKEN', 'http://webhook.com')->shouldReturn(['status' => 'CREATED']);
}
}
83 changes: 73 additions & 10 deletions spec/Client/PayPalClientSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,35 @@
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Log\LoggerInterface;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\PayPalPlugin\Client\PayPalClientInterface;
use Sylius\PayPalPlugin\Exception\PayPalApiTimeoutException;
use Sylius\PayPalPlugin\Exception\PayPalAuthorizationException;
use Sylius\PayPalPlugin\Provider\PayPalConfigurationProviderInterface;
use Sylius\PayPalPlugin\Provider\UuidProviderInterface;

final class PayPalClientSpec extends ObjectBehavior
{
function let(ClientInterface $client, LoggerInterface $logger, UuidProviderInterface $uuidProvider): void
{
$this->beConstructedWith($client, $logger, $uuidProvider, 'https://test-api.paypal.com/', 'TRACKING-ID', 5);
function let(
ClientInterface $client,
LoggerInterface $logger,
UuidProviderInterface $uuidProvider,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelContextInterface $channelContext,
ChannelInterface $channel
): void {
$channelContext->getChannel()->willReturn($channel);

$this->beConstructedWith(
$client,
$logger,
$uuidProvider,
$payPalConfigurationProvider,
$channelContext,
'https://test-api.paypal.com/',
5
);
}

function it_implements_pay_pal_client_interface(): void
Expand Down Expand Up @@ -79,9 +98,13 @@ function it_throws_an_exception_if_client_could_not_be_authorized(

function it_calls_get_request_on_paypal_api(
ClientInterface $client,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel,
ResponseInterface $response,
StreamInterface $body
): void {
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'GET',
'https://test-api.paypal.com/v2/get-request/',
Expand All @@ -105,10 +128,25 @@ function it_logs_all_requests_if_logging_level_is_increased(
ClientInterface $client,
LoggerInterface $logger,
UuidProviderInterface $uuidProvider,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelContextInterface $channelContext,
ChannelInterface $channel,
ResponseInterface $response,
StreamInterface $body
): void {
$this->beConstructedWith($client, $logger, $uuidProvider, 'https://test-api.paypal.com/', 'TRACKING-ID', 5, true);
$this->beConstructedWith(
$client,
$logger,
$uuidProvider,
$payPalConfigurationProvider,
$channelContext,
'https://test-api.paypal.com/',
5,
true
);

$channelContext->getChannel()->willReturn($channel);
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'GET',
Expand Down Expand Up @@ -137,10 +175,14 @@ function it_logs_all_requests_if_logging_level_is_increased(
function it_logs_debug_id_from_failed_get_request(
ClientInterface $client,
LoggerInterface $logger,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel,
RequestException $exception,
ResponseInterface $response,
StreamInterface $body
): void {
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'GET',
'https://test-api.paypal.com/v2/get-request/',
Expand Down Expand Up @@ -171,9 +213,12 @@ function it_calls_post_request_on_paypal_api(
ClientInterface $client,
ResponseInterface $response,
StreamInterface $body,
UuidProviderInterface $uuidProvider
UuidProviderInterface $uuidProvider,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel
): void {
$uuidProvider->provide()->willReturn('REQUEST-ID');
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'POST',
Expand Down Expand Up @@ -203,9 +248,12 @@ function it_calls_post_request_on_paypal_api_with_extra_headers(
ClientInterface $client,
ResponseInterface $response,
StreamInterface $body,
UuidProviderInterface $uuidProvider
UuidProviderInterface $uuidProvider,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel
): void {
$uuidProvider->provide()->willReturn('REQUEST-ID');
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'POST',
Expand Down Expand Up @@ -238,9 +286,12 @@ function it_logs_debug_id_from_failed_post_request(
RequestException $exception,
ResponseInterface $response,
StreamInterface $body,
UuidProviderInterface $uuidProvider
UuidProviderInterface $uuidProvider,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel
): void {
$uuidProvider->provide()->willReturn('REQUEST-ID');
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'POST',
Expand Down Expand Up @@ -276,8 +327,12 @@ function it_logs_debug_id_from_failed_post_request(
function it_calls_patch_request_on_paypal_api(
ClientInterface $client,
ResponseInterface $response,
StreamInterface $body
StreamInterface $body,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel
): void {
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'PATCH',
'https://test-api.paypal.com/v2/patch-request/123123',
Expand Down Expand Up @@ -306,8 +361,12 @@ function it_logs_debug_id_from_failed_patch_request(
LoggerInterface $logger,
RequestException $exception,
ResponseInterface $response,
StreamInterface $body
StreamInterface $body,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel
): void {
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'PATCH',
'https://test-api.paypal.com/v2/patch-request/123123',
Expand Down Expand Up @@ -339,8 +398,12 @@ function it_logs_debug_id_from_failed_patch_request(
}

function it_throws_exception_if_the_timeout_has_been_reached_the_specified_amount_of_time(
ClientInterface $client
ClientInterface $client,
PayPalConfigurationProviderInterface $payPalConfigurationProvider,
ChannelInterface $channel
): void {
$payPalConfigurationProvider->getPartnerAttributionId($channel)->willReturn('TRACKING-ID');

$client->request(
'GET',
'https://test-api.paypal.com/v2/get-request/',
Expand Down
29 changes: 20 additions & 9 deletions src/Api/WebhookApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,38 @@

namespace Sylius\PayPalPlugin\Api;

use Sylius\PayPalPlugin\Client\PayPalClientInterface;
use GuzzleHttp\ClientInterface;

final class WebhookApi implements WebhookApiInterface
{
/** @var PayPalClientInterface */
/** @var ClientInterface */
private $client;

public function __construct(PayPalClientInterface $client)
/** @var string */
private $baseUrl;

public function __construct(ClientInterface $client, string $baseUrl)
{
$this->client = $client;
$this->baseUrl = $baseUrl;
}

public function register(string $token, string $webhookUrl): array
{
$data = [
'url' => preg_replace('/^http:/i', 'https:', $webhookUrl),
'event_types' => [
['name' => 'PAYMENT.CAPTURE.REFUNDED'],
$response = $this->client->request('POST', $this->baseUrl . 'v1/notifications/webhooks', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'url' => preg_replace('/^http:/i', 'https:', $webhookUrl),
'event_types' => [
['name' => 'PAYMENT.CAPTURE.REFUNDED'],
],
],
];
]);

return $this->client->post('v1/notifications/webhooks', $token, $data);
return (array) json_decode($response->getBody()->getContents(), true);
}
}
Loading

0 comments on commit 3a0ea37

Please sign in to comment.