Component\AdyenCreditCard
<?php | |
namespace Component\AdyenCreditCard; | |
use Component\AdyenCreditCard\DataService\ResponseLogDataService; | |
use GuzzleHttp\Client; | |
use GuzzleHttp\Exception\RequestException; | |
class PaymentHandler | |
{ | |
/** | |
* @var array | |
*/ | |
protected $params = []; | |
/** | |
* @var Client | |
*/ | |
protected $client; | |
/** | |
* @var ResponseLogDataService | |
*/ | |
protected $responseLogDataService; | |
/** | |
* @param array $params | |
*/ | |
public function __construct(array $params) | |
{ | |
foreach (['authoriseUrl', 'username', 'password', 'merchantAccount'] as $name) { | |
if (!isset($params[$name])) { | |
throw new \Exception(sprintf('Missing param: "%s"', $name)); | |
} | |
} | |
$this->params = $params; | |
} | |
/** | |
* @param Client $client | |
*/ | |
public function setClient(Client $client) | |
{ | |
$this->client = $client; | |
} | |
/** | |
* @return Client | |
*/ | |
public function getClient() | |
{ | |
if (!$this->client) { | |
$this->client = new Client; | |
} | |
return $this->client; | |
} | |
/** | |
* @param ResponseLogDataService | |
*/ | |
public function setResponseLogDataService(ResponseLogDataService $responseLogDataService) | |
{ | |
$this->responseLogDataService = $responseLogDataService; | |
} | |
/** | |
* @param array $data | |
* @return PaymentResponse | |
*/ | |
public function handle(array $data) | |
{ | |
$authoriseUrl = $this->params['authoriseUrl']; | |
$authData = [$this->params['username'], $this->params['password']]; | |
$merchantAccount = $this->params['merchantAccount']; | |
$paymentData = [ | |
'merchantAccount' => $merchantAccount, | |
'amount' => [ | |
'currency' => 'EUR', | |
// adyen amount format: x/100 = x EUR, eg. 1500 = 15 EUR | |
'value' => $data['amount'] * 100, | |
], | |
'reference' => $data['reference'], | |
'shopperIP' => $data['userIp'], | |
'shopperEmail' => $data['userEmail'], | |
'additionalData' => [ | |
'card.encrypted.json' => $data['encryptedData'] | |
], | |
]; | |
try { | |
$response = $this->getClient()->post($authoriseUrl, ['auth' => $authData, 'json' => $paymentData]); | |
} catch (RequestException $e) { | |
$response = $e->getResponse(); | |
} | |
$responseBody = $response->getBody(); | |
$responseData = json_decode($responseBody, true); | |
$statusCode = $response->getStatusCode(); | |
$resultCode = (isset($responseData['resultCode']) ? $responseData['resultCode'] : null); | |
if ($this->responseLogDataService) { | |
$this->responseLogDataService->logResponse( | |
$data['reference'], | |
(isset($responseData['pspReference']) ? $responseData['pspReference'] : null), | |
$statusCode, | |
$responseBody | |
); | |
} | |
if ($statusCode != PaymentStatusEnum::OK) { | |
$errorCode = (isset($responseData['errorCode']) ? $responseData['errorCode'] : null); | |
return new PaymentResult(false, $errorCode); | |
} | |
if ($resultCode != PaymentStateEnum::AUTHORISED) { | |
return new PaymentResult(false, $resultCode); | |
} | |
return new PaymentResult(true); | |
} | |
} |
<?php | |
namespace Component\AdyenCreditCard; | |
use Component\AdyenCreditCard\PaymentHandler; | |
use Hamcrest; | |
use Mockery; | |
class PaymentHandlerTest extends \PHPUnit_Framework_TestCase | |
{ | |
public function testDataCorrectlyFormattedForAdyen() | |
{ | |
$params = $this->getParams(); | |
$data = $this->getData(); | |
$expectedPaymentData = [ | |
'merchantAccount' => $params['merchantAccount'], | |
'amount' => [ | |
'currency' => 'EUR', | |
'value' => 6600, | |
], | |
'reference' => $data['reference'], | |
'shopperIP' => $data['userIp'], | |
'shopperEmail' => $data['userEmail'], | |
'additionalData' => [ | |
'card.encrypted.json' => $data['encryptedData'] | |
], | |
]; | |
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface'); | |
$responseMock | |
->shouldReceive('getBody') | |
->andReturn('{}') | |
->shouldReceive('getStatusCode') | |
->andReturn(null); | |
$clientMock = Mockery::mock('GuzzleHttp\Client'); | |
$clientMock | |
->shouldReceive('post') | |
->withArgs([$params['authoriseUrl'], ['auth' => [$params['username'], $params['password']], 'json' => $expectedPaymentData]]) | |
->andReturn($responseMock) | |
; | |
$paymentHandler = new PaymentHandler($params); | |
$paymentHandler->setClient($clientMock); | |
$paymentHandler->handle($data); | |
} | |
public function testInvalidTransaction() | |
{ | |
$params = $this->getParams(); | |
$data = $this->getData(); | |
$responseBody = '{"status":422,"errorCode":"101","message":"Invalid card number","errorType":"validation","pspReference":"8814393041104109"}'; | |
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface'); | |
$responseMock | |
->shouldReceive('getBody') | |
->andReturn($responseBody) | |
->shouldReceive('getStatusCode') | |
->andReturn(422); | |
$clientMock = Mockery::mock('GuzzleHttp\Client'); | |
$clientMock | |
->shouldReceive('post') | |
->andReturn($responseMock) | |
; | |
$paymentHandler = new PaymentHandler($params); | |
$paymentHandler->setClient($clientMock); | |
$paymentResult = $paymentHandler->handle($data); | |
assertThat($paymentResult->isSuccess(), equalTo(false)); | |
assertThat($paymentResult->getCode(), equalTo(101)); | |
} | |
public function testRefusedTransaction() | |
{ | |
$params = $this->getParams(); | |
$data = $this->getData(); | |
$responseBody = '{"pspReference":"7914393044485464","refusalReason":"Refused","resultCode":"Refused"}'; | |
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface'); | |
$responseMock | |
->shouldReceive('getBody') | |
->andReturn($responseBody) | |
->shouldReceive('getStatusCode') | |
->andReturn(200); | |
$clientMock = Mockery::mock('GuzzleHttp\Client'); | |
$clientMock | |
->shouldReceive('post') | |
->andReturn($responseMock) | |
; | |
$paymentHandler = new PaymentHandler($params); | |
$paymentHandler->setClient($clientMock); | |
$paymentResult = $paymentHandler->handle($data); | |
assertThat($paymentResult->isSuccess(), equalTo(false)); | |
assertThat($paymentResult->getCode(), equalTo('Refused')); | |
} | |
public function testSuccessfulTransaction() | |
{ | |
$params = $this->getParams(); | |
$data = $this->getData(); | |
$responseBody = '{"pspReference":"7914388654786011","resultCode":"Authorised","authCode":"32682"}'; | |
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface'); | |
$responseMock | |
->shouldReceive('getBody') | |
->andReturn($responseBody) | |
->shouldReceive('getStatusCode') | |
->andReturn(200); | |
$clientMock = Mockery::mock('GuzzleHttp\Client'); | |
$clientMock | |
->shouldReceive('post') | |
->andReturn($responseMock) | |
; | |
$paymentHandler = new PaymentHandler($params); | |
$paymentHandler->setClient($clientMock); | |
$paymentResult = $paymentHandler->handle($data); | |
assertThat($paymentResult->isSuccess(), equalTo(true)); | |
} | |
protected function getParams() | |
{ | |
return [ | |
'authoriseUrl' => 'http://url', | |
'username' => 'user', | |
'password' => 'secretpass', | |
'merchantAccount' => 'BestMerchantEver' | |
]; | |
} | |
protected function getData() | |
{ | |
return [ | |
'encryptedData' => 'adyenjs_0_1_13$abcxyz0123456789', | |
'amount' => 66, | |
'reference' => uniqid(), | |
'userIp' => '127.0.0.1', | |
'userEmail' => 'protipster@localhost' | |
]; | |
} | |
} |
<?php | |
namespace Component\AdyenCreditCard; | |
class PaymentResult | |
{ | |
/** | |
* @param bool | |
*/ | |
protected $success; | |
/** | |
* @param int | |
*/ | |
protected $code; | |
/** | |
* @param string $message | |
* @param int $errorCode | |
*/ | |
public function __construct($success, $code = null) | |
{ | |
$this->success = (bool)$success; | |
$this->code = $code; | |
} | |
/** | |
* @return bool | |
*/ | |
public function isSuccess() | |
{ | |
return $this->success; | |
} | |
/** | |
* @return bool | |
*/ | |
public function isError() | |
{ | |
return (!$this->success); | |
} | |
/** | |
* @return int | |
*/ | |
public function getCode() | |
{ | |
return $this->code; | |
} | |
} |
<?php | |
namespace Component\AdyenCreditCard; | |
/** | |
* State of nomrally processed request | |
*/ | |
class PaymentStateEnum | |
{ | |
/** | |
* Authorised (approved by the financial institution) | |
*/ | |
const AUTHORISED = 'Authorised'; | |
/** | |
* Refused (payment declined by the financial institution) | |
*/ | |
const REFUSED = 'Refused'; | |
/** | |
* Error (communication error with the financial institution) | |
*/ | |
const ERROR = 'Error'; | |
} |
<?php | |
namespace Component\AdyenCreditCard; | |
/** | |
* Adyen payment status (it's HTTP code) | |
*/ | |
class PaymentStatusEnum | |
{ | |
/** | |
* Request processed normally | |
*/ | |
const OK = 200; | |
/** | |
* Problem reading or understanding request | |
*/ | |
const BAD_REQUEST = 400; | |
/** | |
* Authentication required | |
*/ | |
const UNAUTHORIZED = 401; | |
/** | |
* Insufficient permission to process request | |
*/ | |
const FORBIDDEN = 403; | |
/** | |
* Request validation error | |
*/ | |
const VALIDATION_ERROR = 422; | |
/** | |
* Server could not process request | |
*/ | |
const SERVER_ERROR = 500; | |
} |
<?php | |
namespace Component\AdyenCreditCard; | |
use Doctrine\ORM\EntityManager; | |
class ResponseLogDataService | |
{ | |
/** | |
* @var EntityManager | |
*/ | |
protected $entityManager; | |
/** | |
* @param EntityManager $entityManager | |
*/ | |
public function __construct(EntityManager $entityManager) | |
{ | |
$this->setEntityManager($entityManager); | |
} | |
/** | |
* @param EntityManager $entityManager | |
*/ | |
protected function setEntityManager(EntityManager $entityManager) | |
{ | |
$this->entityManager = $entityManager; | |
} | |
/** | |
* @return EntityManager | |
*/ | |
protected function getEntityManager() | |
{ | |
return $this->entityManager; | |
} | |
/** | |
* Log response returned by Adyen API | |
* | |
* @param string $externalId | |
* @param int $pspReference | |
* @param int $statusCode | |
* @param string $responseBody | |
*/ | |
public function logResponse($externalId, $pspReference, $statusCode, $responseBody) | |
{ | |
$conn = $this->getEntityManager()->getConnection(); | |
$qb = $conn->createQueryBuilder(); | |
$qb | |
->insert('transaction_adyen_log') | |
->values([ | |
'external_id' => ':externalId', | |
'psp_reference' => ':pspReference', | |
'status_code' => ':statusCode', | |
'response_body' => ':responseBody', | |
'date' => 'NOW()' | |
]) | |
->setParameter('externalId', $externalId) | |
->setParameter('pspReference', $pspReference) | |
->setParameter('statusCode', $statusCode) | |
->setParameter('responseBody', $responseBody) | |
->execute(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment