Skip to content

Commit

Permalink
Merge pull request #4 from villafinder/redirect-url
Browse files Browse the repository at this point in the history
Pass redirect URL to 2c2p user defined parameters
  • Loading branch information
winzou authored Sep 23, 2019
2 parents bb21c12 + 7f1c6cb commit 22c73d6
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 14 deletions.
8 changes: 7 additions & 1 deletion Action/CaptureOnsiteAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@ class CaptureOnsiteAction extends CaptureAction
{
use CheckRequestOnsiteTrait;

const USER_DEFINED_TOKEN = 1;
const USER_DEFINED_URL = 2;

protected function doExecute(Capture $request, GetHttpRequest $httpRequest, \ArrayAccess $model)
{
if ('POST' === $httpRequest->method) {
// We POST redirect to 2c2p
throw new HttpPostRedirect(
$this->api->getOnsiteUrl(),
$this->api->prepareOnsitePayment($model->toUnsafeArray(), $httpRequest->request)
$this->api->prepareOnsitePayment($model->toUnsafeArray(), $httpRequest->request, [
self::USER_DEFINED_TOKEN => $request->getToken()->getHash(),
self::USER_DEFINED_URL => $request->getToken()->getTargetUrl(),
])
);
}

Expand Down
87 changes: 87 additions & 0 deletions Action/CaptureOnsiteNullAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

namespace Villafinder\Payum2c2p\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Exception\LogicException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Reply\HttpPostRedirect;
use Payum\Core\Reply\HttpResponse;
use Payum\Core\Request\Capture;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\GetHttpRequest;
use Payum\Core\Security\GenericTokenFactoryAwareInterface;
use Payum\Core\Security\GenericTokenFactoryAwareTrait;
use Villafinder\Payum2c2p\Api;

/**
* @property Api $api
*/
class CaptureOnsiteNullAction implements ActionInterface, ApiAwareInterface, GatewayAwareInterface, GenericTokenFactoryAwareInterface
{
use ApiAwareTrait;
use GatewayAwareTrait;
use GenericTokenFactoryAwareTrait;
use CheckRequestOnsiteTrait;

public function __construct()
{
$this->apiClass = Api::class;
}

/**
* @param Capture $request
*/
public function execute($request)
{
RequestNotSupportedException::assertSupports($this, $request);

$httpRequest = new GetHttpRequest();
$this->gateway->execute($httpRequest);

if (!$this->isBackFrom2c2p($httpRequest)) {
return;
}

if (!$this->api->trustUserRequest()) {
return;
}

try {
$response = $this->readFromRequest($httpRequest);
} catch (LogicException $e) {
throw new HttpResponse($e->getMessage(), 400);
}

$redirectIndex = sprintf('userDefined%d', CaptureOnsiteAction::USER_DEFINED_URL);

if (!isset($response[$redirectIndex])) {
throw new HttpResponse('Redirect URL is missing from 2C2P response.', 400);
}

$redirectUrl = $response[$redirectIndex];

if (!filter_var($redirectUrl, FILTER_VALIDATE_URL)) {
throw new HttpResponse('Redirect URL is invalid.', 400);
}

throw new HttpPostRedirect(
$redirectUrl,
$httpRequest->request
);
}

/**
* {@inheritDoc}
*/
public function supports($request)
{
return
$request instanceof Capture &&
null === $request->getModel()
;
}
}
27 changes: 15 additions & 12 deletions Action/CheckRequestOnsiteTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ protected function updateModelFromRequest(ArrayObject $model, GetHttpRequest $ht
return;
}

$response = $this->readFromRequest($httpRequest);

// We check payment_status because in case of error, 2C2P can sometimes omit the amount in its response
if (StatusOnsiteAction::STATUS_FAILED !== $response['status'] && $model['amount'] != $response['amt']) {
throw new LogicException('Onsite request is invalid. Code 4');
}

$model->replace($response);
}

protected function readFromRequest(GetHttpRequest $httpRequest)
{
if ('POST' !== $httpRequest->method) {
throw new LogicException('Onsite request is invalid. Code 1');
}
Expand All @@ -27,20 +39,11 @@ protected function updateModelFromRequest(ArrayObject $model, GetHttpRequest $ht
throw new LogicException('Onsite request is invalid. Code 2');
}


try {
$response = $this->api->readOnsiteResponse($httpRequest->request['paymentResponse']);
} catch( \Exception $e) {
throw new \LogicException('Onsite request is invalid. Code 3', $e->getCode(), $e);
return $this->api->readOnsiteResponse($httpRequest->request['paymentResponse']);
} catch (\Exception $e) {
throw new LogicException('Onsite request is invalid. Code 3', $e->getCode(), $e);
}


// We check payment_status because in case of error, 2C2P can sometimes omit the amount in its response
if (StatusOnsiteAction::STATUS_FAILED !== $response['status'] && $model['amount'] != $response['amt']) {
throw new LogicException('Onsite request is invalid. Code 4');
}

$model->replace($response);
}

protected function isBackFrom2c2p(GetHttpRequest $httpRequest)
Expand Down
76 changes: 76 additions & 0 deletions Action/NotifyOnsiteNullAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace Villafinder\Payum2c2p\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Exception\LogicException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Reply\HttpResponse;
use Payum\Core\Request\GetHttpRequest;
use Payum\Core\Request\GetToken;
use Payum\Core\Request\Notify;
use Payum\Core\Security\TokenInterface;
use Villafinder\Payum2c2p\Api;

/**
* @property Api $api
*/
class NotifyOnsiteNullAction implements ActionInterface, ApiAwareInterface, GatewayAwareInterface
{
use ApiAwareTrait;
use GatewayAwareTrait;
use CheckRequestOnsiteTrait;

public function __construct()
{
$this->apiClass = Api::class;
}

/**
* @param Notify $request
*/
public function execute($request)
{
RequestNotSupportedException::assertSupports($this, $request);

$httpRequest = new GetHttpRequest();
$this->gateway->execute($httpRequest);

try {
$response = $this->readFromRequest($httpRequest);
} catch (LogicException $e) {
throw new HttpResponse($e->getMessage(), 400);
}

$tokenIndex = sprintf('userDefined%d', CaptureOnsiteAction::USER_DEFINED_TOKEN);

if (!isset($response[$tokenIndex])) {
throw new HttpResponse('Token is missing from 2C2P response.', 400);
}

$this->gateway->execute($getToken = new GetToken($response[$tokenIndex]));

if (!$getToken->getToken() instanceof TokenInterface) {
throw new HttpResponse('Token does not exist.', 400);
}

$this->gateway->execute(new Notify($getToken->getToken()));

throw new HttpResponse('OK', 200);
}

/**
* {@inheritDoc}
*/
public function supports($request)
{
return
$request instanceof Notify &&
null === $request->getModel()
;
}
}
10 changes: 9 additions & 1 deletion Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public function prepareOffsitePayment(array $params)
/**
* @return array
*/
public function prepareOnsitePayment(array $model, array $creditCard)
public function prepareOnsitePayment(array $model, array $creditCard, array $userDefined = [])
{
$params = [
'merchantID' => $this->getMerchantIdForCurrency($model['currency']),
Expand All @@ -178,6 +178,14 @@ public function prepareOnsitePayment(array $model, array $creditCard)
'encCardData' => $creditCard['encryptedCardInfo'],
];

$userDefined = array_filter($userDefined, function ($value, $key) {
return in_array($key, range(1, 5));
}, ARRAY_FILTER_USE_BOTH);

array_walk($userDefined, function ($value, $key) use (&$params) {
$params[sprintf('userDefined%d', $key)] = $value;
});

$paymentPayload = base64_encode($this->makeXml($params, 'PaymentRequest'));

$finalPayload = [
Expand Down
4 changes: 4 additions & 0 deletions Payum2c2pOnsiteGatewayFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

namespace Villafinder\Payum2c2p;

use Villafinder\Payum2c2p\Action\CaptureOnsiteNullAction;
use Villafinder\Payum2c2p\Action\CaptureOnsiteUnsafeAction;
use Villafinder\Payum2c2p\Action\ConvertPaymentAction;
use Villafinder\Payum2c2p\Action\CaptureOnsiteAction;
use Villafinder\Payum2c2p\Action\NotifyAction;
use Villafinder\Payum2c2p\Action\NotifyOnsiteAction;
use Villafinder\Payum2c2p\Action\NotifyOnsiteNullAction;
use Villafinder\Payum2c2p\Action\StatusAction;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayFactory;
Expand All @@ -23,7 +25,9 @@ protected function populateConfig(ArrayObject $config)
'payum.factory_name' => '2c2p_onsite',
'payum.factory_title' => '2C2P On-Site',
'payum.action.capture' => new CaptureOnsiteAction(),
'payum.action.capture_null' => new CaptureOnsiteNullAction(),
'payum.action.notify' => new NotifyOnsiteAction(),
'payum.action.notify_null' => new NotifyOnsiteNullAction(),
'payum.action.status' => new StatusOnsiteAction(),
'payum.action.convert_payment' => new ConvertPaymentAction(),
]);
Expand Down

0 comments on commit 22c73d6

Please sign in to comment.