first commit

This commit is contained in:
2025-03-12 17:06:23 +01:00
commit 2241f7131f
13185 changed files with 1692479 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
## 1.1.0
- Fixed signature calculation with special chars
## 1.0.6
- Marked `getErrorType` for `Error` as deprecated
- Fixed hash calculation for slashed data
## 1.0.5
- Fixed missing headers for payment status
## 1.0.4
- Added support for `signature` from headers
## 1.0.3
- Fixed dependencies
- Fixed examples for README file
- Added Travis CI support
## 1.0.2
- Changed Http Client
## 1.0.1
- Added implicit Idempotency Key for payment authorize
- Added Payment Status enums
- Removed User-agent version
## 1.0.0
- Initial release

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 mBank S.A.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,70 @@
# Paynow PHP SDK
[![Latest Version](https://img.shields.io/github/release/pay-now/paynow-php-sdk.svg?style=flat-square)](https://github.com/pay-now/paynow-php-sdk/releases)
[![Build Status](https://travis-ci.org/pay-now/paynow-php-sdk.svg?branch=master)](https://travis-ci.org/pay-now/paynow-php-sdk)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
<!--[![Total Downloads](https://img.shields.io/packagist/dt/pay-now/paynow-php-sdk.svg?style=flat-square)](https://packagist.org/packages/pay-now/paynow-php-sdk)-->
Paynow PHP Library provides access to Paynow API from Applications written in PHP language.
## Installation
### Composer
Install the library using [Composer](https://getcomposer.org)
```bash
$ composer require pay-now/paynow-php-sdk
```
and include composer autoloader
```php
require_once('vendor/autoload.php');
```
## Usage
Making a payment
```php
$client = new \Paynow\Client('TestApiKey', 'TestSignatureKey', Environment::SANDBOX);
$orderReference = "success_1234567";
$idempotencyKey = uniqid($orderReference . '_');
$paymentData = [
"amount" => "100",
"currency" => "PLN",
"externalId" => $orderReference,
"description" => "Payment description",
"buyer" => [
"email" => "customer@domain.com"
]
];
try {
$payment = new \Paynow\Service\Payment($client);
$result = $payment->authorize($paymentData, $idempotencyKey);
} catch (PaynowException $exception) {
// catch errors
}
```
Handling notification with current payment status
```php
$payload = trim(file_get_contents('php://input'));
$headers = getallheaders();
$notificationData = json_decode($payload, true);
try {
new \Paynow\Notification('TestSignatureKey', $payload, $headers);
// process notification with $notificationData
} catch (\Exception $exception) {
header('HTTP/1.1 400 Bad Request', true, 400);
}
header('HTTP/1.1 202 Accepted', true, 202);
```
## Documentation
See the [Paynow API documentation](https://docs.paynow.pl)
## Support
If you have any questions or issues, please contact our support at support@paynow.pl.
## License
MIT license. For more information see the [LICENSE file](LICENSE)

View File

@@ -0,0 +1,49 @@
{
"name": "pay-now/paynow-php-sdk",
"description": "PHP client library for accessing Paynow API",
"version": "1.1.0",
"keywords": [
"paynow",
"mbank",
"payment processing",
"api"
],
"type": "library",
"homepage": "https://www.paynow.pl",
"license": "MIT",
"authors": [
{
"name": "mBank S.A.",
"email": "kontakt@paynow.pl"
}
],
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": "^5.6 || ~7.0",
"ext-curl": "*",
"ext-json": "*",
"guzzlehttp/psr7": "^1.6",
"php-http/curl-client": "^1.7",
"php-http/message": "^1.7"
},
"require-dev": {
"php-http/mock-client": "^1.3",
"phpunit/phpunit": "^5.7",
"squizlabs/php_codesniffer": "^3.4",
"friendsofphp/php-cs-fixer": "^2.15",
"phpcompatibility/php-compatibility": "^9.3",
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0"
},
"autoload": {
"psr-4": {
"Paynow\\": "src/Paynow/",
"Paynow\\Tests\\": "tests"
}
},
"scripts": {
"test": "vendor/bin/phpunit",
"cs-check": "php-cs-fixer fix --no-interaction --dry-run --diff",
"cs-fix": "php-cs-fixer fix -v --diff"
}
}

View File

@@ -0,0 +1,17 @@
<phpunit bootstrap="tests/bootstrap.php"
colors="false">
<testsuites>
<testsuite name="Paynow PHP Test Suite">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./src</directory>
<exclude>
<directory>vendor</directory>
<directory suffix=".php">tests</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,52 @@
<?php
namespace Paynow;
use Paynow\HttpClient\HttpClientInterface;
class Client
{
private $configuration;
private $httpClient;
/**
* @param $apiKey
* @param $apiSignatureKey
* @param $environment
* @param $applicationName
*/
public function __construct($apiKey, $apiSignatureKey, $environment, $applicationName = null)
{
$this->configuration = new Configuration();
$this->configuration->setApiKey($apiKey);
$this->configuration->setSignatureKey($apiSignatureKey);
$this->configuration->setEnvironment($environment);
$this->configuration->setApplicationName($applicationName);
$this->httpClient = new HttpClient\HttpClient($this->configuration);
}
/**
* @return Configuration
*/
public function getConfiguration()
{
return $this->configuration;
}
/**
* @param HttpClientInterface $httpClient
*/
public function setHttpClient(HttpClientInterface $httpClient)
{
$this->httpClient = $httpClient;
}
/**
* @return HttpClient\HttpClient
*/
public function getHttpClient()
{
return $this->httpClient;
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace Paynow;
class Configuration implements ConfigurationInterface
{
const API_VERSION = 'v1';
const API_PRODUCTION_URL = 'https://api.paynow.pl/';
const API_SANDBOX_URL = 'https://api.sandbox.paynow.pl/';
const USER_AGENT = 'paynow-php-sdk';
/**
* @var array
*/
protected $data = [];
/**
* Set a key value pair
*
* @param string $key Key to set
* @param mixed $value Value to set
*/
private function set($key, $value)
{
$this->data[$key] = $value;
}
/**
* Get a specific key value
*
* @param string $key key to retrieve
* @return mixed|null Value of the key or NULL
*/
private function get($key)
{
return isset($this->data[$key]) ? $this->data[$key] : null;
}
/**
* Get an API key
*
* @return mixed|null
*/
public function getApiKey()
{
return $this->get('api_key');
}
/**
* Get Signature key
*
* @return mixed|null
*/
public function getSignatureKey()
{
return $this->get('signature_key');
}
/**
* Get environment name
*
* @return mixed|null
*/
public function getEnvironment()
{
return $this->get('environment');
}
/**
* Get API url
*
* @return mixed|null
*/
public function getUrl()
{
return $this->get('url');
}
/**
* Set an API Key
*
* @param $apiKey
*/
public function setApiKey($apiKey)
{
$this->set('api_key', $apiKey);
}
/**
* Set Signature Key
*
* @param $signatureKey
*/
public function setSignatureKey($signatureKey)
{
$this->set('signature_key', $signatureKey);
}
/**
* Set environment
*
* @param $environment
*/
public function setEnvironment($environment)
{
if (Environment::PRODUCTION === $environment) {
$this->set('environment', Environment::PRODUCTION);
$this->set('url', self::API_PRODUCTION_URL);
} else {
$this->set('environment', Environment::SANDBOX);
$this->set('url', self::API_SANDBOX_URL);
}
}
/**
* Set an application name
*
* @param $applicationName
*/
public function setApplicationName($applicationName)
{
$this->set('application_name', $applicationName);
}
/**
* @return mixed|null
*/
public function getApplicationName()
{
return $this->get('application_name');
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Paynow;
interface ConfigurationInterface
{
public function getApiKey();
public function getSignatureKey();
public function getEnvironment();
public function getUrl();
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Paynow;
class Environment
{
const PRODUCTION = 'production';
const SANDBOX = 'sandbox';
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Paynow\Exception;
class ConfigurationException extends PaynowException
{
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Paynow\Exception;
class Error
{
/**
* @var string
*/
private $errorType;
/**
* @var string
*/
private $message;
public function __construct($errorType, $message)
{
$this->errorType = $errorType;
$this->message = $message;
}
/**
* @deprecated
* @return string
*/
public function getErrorType()
{
return $this->errorType;
}
/**
* @return string
*/
public function getMessage()
{
return $this->message;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Paynow\Exception;
use Exception;
class PaynowException extends Exception
{
private $errors;
public function __construct($message = '', $code = 0, $body = null)
{
parent::__construct($message, $code, null);
if ($body) {
$json = json_decode($body);
if ($json->errors) {
foreach ($json->errors as $error) {
$this->errors[] = new Error($error->errorType, $error->message);
}
$this->errors = $json->errors;
}
}
}
/**
* @return mixed
*/
public function getErrors()
{
return $this->errors;
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Paynow\Exception;
class SignatureVerificationException extends PaynowException
{
}

View File

@@ -0,0 +1,78 @@
<?php
namespace Paynow\HttpClient;
use Psr\Http\Message\ResponseInterface;
class ApiResponse
{
/**
* Body content
*
* @var string
*/
public $body;
/**
* Http status
*
* @var int
*/
public $status;
/**
* Headers list
*
* @var array
*/
protected $headers;
/**
* @param ResponseInterface $response
* @throws HttpClientException
*/
public function __construct(ResponseInterface $response)
{
$this->body = $response->getBody();
$this->status = $response->getStatusCode();
$this->headers = $response->getHeaders();
if ($response->getStatusCode() >= 400) {
throw new HttpClientException(
'Error occurred during processing request',
$response->getStatusCode(),
$response->getBody()->getContents()
);
}
}
/**
* Parse JSON
*
* @return mixed
*/
public function decode()
{
return json_decode($this->body);
}
/**
* Get status
*
* @return int
*/
public function getStatus()
{
return $this->status;
}
/**
* Get headers
*
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
}

View File

@@ -0,0 +1,161 @@
<?php
namespace Paynow\HttpClient;
use Http\Client\Curl\Client;
use Http\Client\Exception\RequestException;
use Http\Message\MessageFactory\GuzzleMessageFactory;
use Http\Message\StreamFactory\GuzzleStreamFactory;
use Paynow\Configuration;
use Paynow\Util\SignatureCalculator;
use Psr\Http\Message\RequestInterface;
class HttpClient implements HttpClientInterface
{
/**
* @var Client
*/
protected $client;
protected $messageFactory;
/**
* @var Configuration
*/
protected $config;
/**
* @param Configuration $config
*/
public function __construct(Configuration $config)
{
$this->config = $config;
$options = [
CURLOPT_CONNECTTIMEOUT => 10,
];
$this->messageFactory = new GuzzleMessageFactory();
$this->client = new Client($this->messageFactory, new GuzzleStreamFactory(), $options);
}
/**
* @return string
*/
private function getUserAgent()
{
if ($this->config->getApplicationName()) {
return $this->config->getApplicationName().' ('.Configuration::USER_AGENT.')';
}
return Configuration::USER_AGENT;
}
/**
* @param RequestInterface $request
* @throws HttpClientException
* @return ApiResponse
*/
private function send(RequestInterface $request)
{
try {
return new ApiResponse($this->client->sendRequest($request));
} catch (RequestException $exception) {
throw new HttpClientException($exception->getMessage());
}
}
/**
* @param $url
* @param array $data
* @param null $idempotencyKey
* @throws HttpClientException
* @return ApiResponse
*/
public function post($url, array $data, $idempotencyKey = null)
{
$headers = $this->prepareHeaders($data);
if ($idempotencyKey) {
$headers['Idempotency-Key'] = $idempotencyKey;
}
$request = $this->messageFactory->createRequest(
'POST',
$this->config->getUrl().$url,
$headers,
$this->prepareData($data)
);
try {
return $this->send($request);
} catch (RequestException $exception) {
throw new HttpClientException($exception->getMessage());
}
}
/**
* @param $url
* @param array $data
* @throws HttpClientException
* @return ApiResponse
*/
public function patch($url, array $data)
{
$headers = $this->prepareHeaders($data);
$request = $this->messageFactory->createRequest(
'PATCH',
$this->config->getUrl().$url,
$headers,
$this->prepareData($data)
);
return $this->send($request);
}
/**
* @param $url
* @throws HttpClientException
* @return ApiResponse
*/
public function get($url)
{
$request = $this->messageFactory->createRequest(
'GET',
$this->config->getUrl().$url,
$this->prepareHeaders()
);
return $this->send($request);
}
/**
* @param array $data
* @return string
*/
private function prepareData(array $data)
{
return json_encode($data);
}
/**
* @param null|array|string $data
* @return array
*/
private function prepareHeaders($data = null)
{
$headers = [
'Api-Key' => $this->config->getApiKey(),
'User-Agent' => $this->getUserAgent(),
'Accept' => 'application/json'
];
if ($data) {
$headers['Content-Type'] = 'application/json';
if (is_array($data)) {
$data = $this->prepareData($data);
}
$headers['Signature'] = (string)new SignatureCalculator($this->config->getSignatureKey(), $data);
}
return $headers;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Paynow\HttpClient;
use Exception;
class HttpClientException extends Exception
{
/**
* @var string
*/
private $body;
/**
* @var array
*/
private $errors;
/**
* @var int
*/
private $status;
/**
* HttpClientException constructor.
*
* @param $message
* @param $status
* @param $body
*/
public function __construct($message, $status = null, $body = null)
{
parent::__construct($message);
$this->status = $status;
$this->body = $body;
}
/**
* @return string
*/
public function getBody()
{
return $this->body;
}
/**
* @return int
*/
public function getStatus()
{
return $this->status;
}
/**
* @return array
*/
public function getErrors()
{
return $this->errors;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Paynow\HttpClient;
interface HttpClientInterface
{
public function post($url, array $data);
public function patch($url, array $data);
public function get($url);
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Paynow\Model\Payment;
class Status
{
const STATUS_NEW = 'NEW';
const STATUS_PENDING = 'PENDING';
const STATUS_REJECTED = 'REJECTED';
const STATUS_CONFIRMED = 'CONFIRMED';
const STATUS_ERROR = 'ERROR';
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Paynow;
use InvalidArgumentException;
use Paynow\Exception\SignatureVerificationException;
use Paynow\Util\SignatureCalculator;
use UnexpectedValueException;
class Notification
{
/**
* @param $signatureKey
* @param $payload
* @param $headers
* @throws SignatureVerificationException
*/
public function __construct($signatureKey, $payload, $headers)
{
if (! $payload) {
throw new InvalidArgumentException('No payload has been provided');
}
if (! $headers) {
throw new InvalidArgumentException('No headers have been provided');
}
$this->verify($signatureKey, $this->parsePayload($payload), $headers);
}
/**
* Parse payload
*
* @param $payload
* @return mixed
*/
private function parsePayload($payload)
{
$data = json_decode(trim($payload), true);
$error = json_last_error();
if (! $data && JSON_ERROR_NONE !== $error) {
throw new UnexpectedValueException("Invalid payload: $error");
}
return $data;
}
/**
* Verify payload Signature
*
* @param $signatureKey
* @param $data
* @param array $headers
* @throws SignatureVerificationException
* @return bool
*/
private function verify($signatureKey, $data, array $headers)
{
$calculatedSignature = (string) new SignatureCalculator($signatureKey, $data);
if ($calculatedSignature !== $this->getPayloadSignature($headers)) {
throw new SignatureVerificationException('Signature mismatched for payload');
}
return true;
}
/**
* Retrieve Signature from payload
*
* @param array $headers
* @throws SignatureVerificationException
* @return mixed
*/
private function getPayloadSignature(array $headers)
{
if (isset($headers['Signature']) && $headers['Signature']) {
$signature = $headers['Signature'];
}
if (isset($headers['signature']) && $headers['signature']) {
$signature = $headers['signature'];
}
if (empty($signature)) {
throw new SignatureVerificationException('No signature was found for payload');
}
return $signature;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Paynow\Service;
use Paynow\Configuration;
use Paynow\Exception\PaynowException;
use Paynow\HttpClient\ApiResponse;
use Paynow\HttpClient\HttpClientException;
class Payment extends Service
{
/**
* Authorize payment
*
* @param array $data
* @param string $idempotencyKey
* @throws PaynowException
* @return ApiResponse
*/
public function authorize(array $data, $idempotencyKey = null)
{
try {
return $this->getClient()
->getHttpClient()
->post(
Configuration::API_VERSION.'/payments',
$data,
$idempotencyKey ? $idempotencyKey : $data['externalId']
)
->decode();
} catch (HttpClientException $exception) {
throw new PaynowException(
$exception->getMessage(),
$exception->getStatus(),
$exception->getBody()
);
}
}
/**
* @param string $paymentId
* @throws PaynowException
* @return ApiResponse
*/
public function status($paymentId)
{
try {
return $this->getClient()
->getHttpClient()
->get(Configuration::API_VERSION."/payments/$paymentId/status")
->decode();
} catch (HttpClientException $exception) {
throw new PaynowException(
$exception->getMessage(),
$exception->getStatus(),
$exception->getBody()
);
}
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Paynow\Service;
use Paynow\Client;
use Paynow\Environment;
use Paynow\Exception\ConfigurationException;
class Service
{
/**
* @var Client
*/
private $client;
/**
* @param Client $client
* @throws ConfigurationException
*/
public function __construct(Client $client)
{
if (! $client->getConfiguration()->getEnvironment()) {
$message = 'Provide correct environment, use '.Environment::PRODUCTION.' or '.Environment::SANDBOX;
throw new ConfigurationException($message);
}
if (! $client->getConfiguration()->getApiKey()) {
throw new ConfigurationException('You did not provide Api Key');
}
if (! $client->getConfiguration()->getSignatureKey()) {
throw new ConfigurationException('You did not provide Signature Key');
}
$this->client = $client;
}
/**
* @return Client
*/
public function getClient()
{
return $this->client;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Paynow\Service;
use Paynow\Configuration;
use Paynow\Exception\PaynowException;
use Paynow\HttpClient\ApiResponse;
use Paynow\HttpClient\HttpClientException;
class ShopConfiguration extends Service
{
/**
* @param string $continueUrl
* @param string $notificationUrl
* @throws PaynowException
* @return ApiResponse
*/
public function changeUrls($continueUrl, $notificationUrl)
{
$data = [
'continueUrl' => $continueUrl,
'notificationUrl' => $notificationUrl,
];
try {
return $this->getClient()
->getHttpClient()
->patch(Configuration::API_VERSION.'/configuration/shop/urls', $data);
} catch (HttpClientException $exception) {
throw new PaynowException(
$exception->getMessage(),
$exception->getStatus(),
$exception->getBody()
);
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Paynow\Util;
use InvalidArgumentException;
class SignatureCalculator
{
/**
* @var string
*/
protected $hash;
/**
* @param string $signatureKey
* @param array|string $data
* @throws InvalidArgumentException
*/
public function __construct($signatureKey, $data)
{
if (empty($signatureKey)) {
throw new InvalidArgumentException('You did not provide a Signature key');
}
if (empty($data)) {
throw new InvalidArgumentException('You did not provide any data');
}
if (is_array($data)) {
$data = json_encode($data, JSON_UNESCAPED_SLASHES);
}
$this->hash = base64_encode(hash_hmac('sha256', $data, $signatureKey, true));
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->getHash();
}
/**
* @return string
*/
public function getHash()
{
return $this->hash;
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Paynow\Tests;
use Paynow\Exception\SignatureVerificationException;
use Paynow\Notification;
class NotificationTest extends TestCase
{
/**
* @dataProvider requestsToTest
*/
public function testVerifyPayloadSuccessfully($payload, $headers)
{
// given
// when
new Notification('s3ecret-k3y', $payload, $headers);
// then
$this->assertTrue(true);
}
public function requestsToTest()
{
$payload = $this->loadData('notification.json', true);
return [
[
$payload,
['Signature' => 'UZgTT6iSv174R/OyQ2DWRCE9UCmvdXDS8rbQQcjk+AA=']
],
[
$payload,
['signature' => 'UZgTT6iSv174R/OyQ2DWRCE9UCmvdXDS8rbQQcjk+AA=']
]
];
}
public function testShouldThrowExceptionOnIncorrectSignature()
{
// given
$this->expectException(SignatureVerificationException::class);
$payload = $this->loadData('notification.json', true);
$headers = ['Signature' => 'Aq/VmN15rtjVbuy9F7Yw+Ym76H+VZjVSuHGpg4dwitY='];
// when
new Notification('s3ecret-k3y', $payload, $headers);
// then
}
public function testShouldThrowExceptionOnMissingPayload()
{
// given
$this->expectException(\InvalidArgumentException::class);
$payload = null;
$headers = [];
// when
new Notification('s3ecret-k3y', null, null);
// then
}
public function testShouldThrowExceptionOnMissingPayloadHeaders()
{
// given
$this->expectException(\InvalidArgumentException::class);
$payload = $this->loadData('notification.json', true);
$headers = null;
// when
new Notification('s3ecret-k3y', $payload, null);
// then
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace Paynow\Tests\Service;
use Paynow\Exception\PaynowException;
use Paynow\Service\Payment;
use Paynow\Tests\TestCase;
class PaymentTest extends TestCase
{
public function testShouldAuthorizePaymentSuccessfully()
{
// given
$this->testHttpClient->mockResponse('payment_success.json', 200);
$this->client->setHttpClient($this->testHttpClient);
$paymentService = new Payment($this->client);
$paymentData = $this->loadData('payment_request.json');
// when
$response = $paymentService->authorize($paymentData, 'idempotencyKey123');
// then
$this->assertNotEmpty($response->redirectUrl);
$this->assertNotEmpty($response->paymentId);
$this->assertNotEmpty($response->status);
}
public function testShouldNotAuthorizePaymentSuccessfully()
{
// given
$this->testHttpClient->mockResponse('payment_failed.json', 400);
$this->client->setHttpClient($this->testHttpClient);
$paymentData = $this->loadData('payment_request.json');
$paymentService = new Payment($this->client);
// when
try {
$response = $paymentService->authorize($paymentData, 'idempotencyKey123');
} catch (PaynowException $exception) {
// then
$this->assertEquals(400, $exception->getCode());
$this->assertEquals('VALIDATION_ERROR', $exception->getErrors()[0]->errorType);
$this->assertEquals(
'currency: invalid field value (EUR)',
$exception->getErrors()[0]->message
);
}
}
public function testShouldRetrievePaymentStatusSuccessfully()
{
// given
$this->testHttpClient->mockResponse('payment_status.json', 200);
$this->client->setHttpClient($this->testHttpClient);
$paymentService = new Payment($this->client);
$paymentId = 'PBYV-3AZ-UPW-DPC';
// when
$response = $paymentService->status($paymentId);
// then
$this->assertEquals($response->paymentId, $paymentId);
$this->assertEquals($response->status, 'NEW');
}
public function testShouldNotRetrievePaymentStatusSuccesfully()
{
// given
$this->testHttpClient->mockResponse('payment_status_not_found.json', 404);
$this->client->setHttpClient($this->testHttpClient);
$paymentService = new Payment($this->client);
$paymentId = 'PBYV-3AZ-UPW-DPC';
// when
try {
$response = $paymentService->status($paymentId);
} catch (PaynowException $exception) {
// then
$this->assertEquals(404, $exception->getCode());
$this->assertEquals('NOT_FOUND', $exception->getErrors()[0]->errorType);
$this->assertEquals(
'Could not find status for payment {paymentId=PBYV-3AZ-UPW-DPCf}',
$exception->getErrors()[0]->message
);
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Paynow\Tests\Service;
use Paynow\Exception\PaynowException;
use Paynow\Service\ShopConfiguration;
use Paynow\Tests\TestCase;
class ShopConfigurationTest extends TestCase
{
private $continueUrl = 'http://shopdomain.com/return';
private $notificationUrl = 'http://shopdomain.com/notifications';
public function testShouldUpdateShopConfigurationSuccessfully()
{
// given
$this->testHttpClient->mockResponse(null, 204);
$this->client->setHttpClient($this->testHttpClient);
$shopConfigurationService = new ShopConfiguration($this->client);
// when
$response = $shopConfigurationService->changeUrls($this->continueUrl, $this->notificationUrl);
// then
$this->assertEquals(204, $response->status);
}
public function testShouldNotUpdateShopConfigurationSuccessfully()
{
// given
$this->testHttpClient->mockResponse('shop_configuration_urls_failed.json', 400);
$this->client->setHttpClient($this->testHttpClient);
$shopConfigurationService = new ShopConfiguration($this->client);
// when
try {
$response = $shopConfigurationService->changeUrls($this->continueUrl, $this->notificationUrl);
} catch (PaynowException $exception) {
// then
$this->assertEquals(400, $exception->getCode());
$this->assertEquals('VALIDATION_ERROR', $exception->getErrors()[0]->errorType);
$this->assertEquals(
'continue_url: invalid field value',
$exception->getErrors()[0]->message
);
}
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Paynow\Tests;
use Paynow\Client;
use Paynow\Environment;
use PHPUnit\Framework\TestCase as BaseTestCase;
class TestCase extends BaseTestCase
{
protected $testHttpClient;
protected $client;
public function __construct($name = null, array $data = [], $dataName = '')
{
$this->client = new Client(
'TestApiKey',
'TestSignatureKey',
Environment::SANDBOX,
'PHPUnitTests'
);
$this->testHttpClient = new TestHttpClient($this->client->getConfiguration());
parent::__construct($name, $data, $dataName);
}
public function loadData($fileName, $asString = false)
{
$filePath = dirname(__FILE__).'/resources/'.$fileName;
if (! $asString) {
return json_decode(file_get_contents($filePath), true);
} else {
return file_get_contents($filePath);
}
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Paynow\Tests;
use GuzzleHttp\Psr7\Response;
use Http\Mock\Client;
use Paynow\HttpClient\HttpClient;
class TestHttpClient extends HttpClient
{
public function mockResponse($responseFile, $httpStatus)
{
$this->client = new Client();
$content = null;
if (null != $responseFile) {
$filePath = dirname(__FILE__).'/resources/'.$responseFile;
$content = file_get_contents($filePath, true);
}
$response = new Response($httpStatus, ['Content-Type' => 'application/json'], $content);
$this->client->addResponse($response);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Paynow\Tests\Util;
use Paynow\Tests\TestCase;
use Paynow\Util\SignatureCalculator;
class SignatureCalculatorTest extends TestCase
{
public function testNotValidSuccessfully()
{
// given + when
$signatureCalculator = new SignatureCalculator('InvalidSecretKey', ['key' => 'value']);
// then
$this->assertNotEquals('hash', $signatureCalculator->getHash());
}
public function testShouldValidSuccessfully()
{
// given + when
$signatureCalculator = new SignatureCalculator(
'a621a1fb-b4d8-48ba-a6a3-2a28ed61f605',
[
'key1' => 'value1',
'key2' => 'val/ue2',
]
);
// then
$this->assertEquals('bqD6spGJwPABe58i+mbqsYoF/JLUDR58yqxRqrb0AR0=', $signatureCalculator->getHash());
}
public function testExceptionForEmptyData()
{
// given
$this->expectException(\InvalidArgumentException::class);
// when
$signatureCalculator = new SignatureCalculator('a621a1fb-b4d8-48ba-a6a3-2a28ed61f605', []);
// then
}
}

View File

@@ -0,0 +1,5 @@
<?php
require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/TestCase.php';
require_once __DIR__.'/TestHttpClient.php';

View File

@@ -0,0 +1,5 @@
{
"paymentId": "NOLV-8F9-08K-WGD",
"status": "CONFIRMED",
"modifiedAt": "2018-12-12T13:24:52"
}

View File

@@ -0,0 +1,9 @@
{
"statusCode": 400,
"errors": [
{
"errorType": "VALIDATION_ERROR",
"message": "currency: invalid field value (EUR)"
}
]
}

View File

@@ -0,0 +1,9 @@
{
"amount": 100,
"currency": "PLN",
"externalId": "success_1234567",
"description": "Test payment",
"buyer": {
"email": "customer@domain.com"
}
}

View File

@@ -0,0 +1,4 @@
{
"paymentId": "PBYV-3AZ-UPW-DPC",
"status": "NEW"
}

View File

@@ -0,0 +1,9 @@
{
"statusCode": 404,
"errors": [
{
"errorType": "NOT_FOUND",
"message": "Could not find status for payment {paymentId=PBYV-3AZ-UPW-DPCf}"
}
]
}

View File

@@ -0,0 +1,5 @@
{
"redirectUrl": "https://paywall.sandbox.paynow.pl/NO0U-5G2-XC1-ESX?token=eyJraWQiOiJhMDAyNjJjYS02NTU3LTRjOTktOGU0NC1kMTFlMTAxYjhhNTIiLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJOTzBVLTVHMi1YQzEtRVNYIiwiYXVkIjoicGF5d2FsbC5zYW5kYm94LnBheW5vdy5wbCIsImlzcyI6InNhbmRib3gucGF5bm93LnBsIiwiZXhwIjoxNTY2ODk5MTYwLCJpYXQiOjE1NjY4MTI3NjB9.25TM-BXTDJV3NLEufgYVNZ7W_0JmJjS2Qu-0-d1HIQM",
"paymentId": "NO0U-5G2-XC1-ESX",
"status": "NEW"
}

View File

@@ -0,0 +1,9 @@
{
"statusCode": 400,
"errors": [
{
"errorType": "VALIDATION_ERROR",
"message": "continue_url: invalid field value"
}
]
}