Skip to content

Add SagePay Direct PayPal integration #156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
},
"require": {
"php": "^5.6|^7",
"ext-json": "*",
"ext-simplexml": "*",
"omnipay/common": "~3.0"
},
"require-dev": {
Expand Down
3 changes: 3 additions & 0 deletions src/ConstantsInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ interface ConstantsInterface
const TXTYPE_REFUND = 'REFUND';
const TXTYPE_REPEAT = 'REPEAT';
const TXTYPE_REPEATDEFERRED = 'REPEATDEFERRED';
const TXTYPE_COMPLETE = 'COMPLETE';

/**
*
Expand All @@ -115,6 +116,7 @@ interface ConstantsInterface
const SERVICE_REPEAT = 'repeat';
const SERVICE_TOKEN = 'directtoken';
const SERVICE_DIRECT3D = 'direct3dcallback';
const SERVICE_PAYPAL = 'complete';

/**
* 0 = Do not send either customer or vendor emails
Expand Down Expand Up @@ -149,6 +151,7 @@ interface ConstantsInterface
const SAGEPAY_STATUS_MALFORMED = 'MALFORMED';
const SAGEPAY_STATUS_INVALID = 'INVALID';
const SAGEPAY_STATUS_ERROR = 'ERROR';
const SAGEPAY_STATUS_PAYPALOK = 'PAYPALOK';

/**
* Raw values for AddressResult
Expand Down
8 changes: 7 additions & 1 deletion src/DirectGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Omnipay\SagePay\Message\DirectAuthorizeRequest;
use Omnipay\SagePay\Message\DirectCompleteAuthorizeRequest;
use Omnipay\SagePay\Message\DirectCompletePayPalRequest;
use Omnipay\SagePay\Message\DirectPurchaseRequest;
use Omnipay\SagePay\Message\SharedCaptureRequest;
use Omnipay\SagePay\Message\SharedVoidRequest;
Expand Down Expand Up @@ -44,6 +45,11 @@ public function completeAuthorize(array $parameters = [])
return $this->createRequest(DirectCompleteAuthorizeRequest::class, $parameters);
}

public function completePayPal(array $parameters = [])
{
return $this->createRequest(DirectCompletePayPalRequest::class, $parameters);
}

/**
* Purchase and handling of return from 3D Secure or PayPal redirection.
*/
Expand Down Expand Up @@ -86,7 +92,7 @@ public function abort(array $parameters = [])
}

/**
* Void a completed (captured) transation.
* Void a completed (captured) transaction.
*/
public function refund(array $parameters = [])
{
Expand Down
11 changes: 5 additions & 6 deletions src/Message/AbstractRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function getService()
}

/**
* If it is used, i.e. needed for an enpoint, then it must be defined.
* If it is used, i.e. needed for an endpoint, then it must be defined.
*
* @return string the transaction type.
* @throws InvalidRequestException
Expand Down Expand Up @@ -185,7 +185,7 @@ protected function getDeliveryAddressData(array $data = [])
* then use that to instantiate the response object.
*
* @param array
* @return Response The reponse object initialised with the data returned from the gateway.
* @return Response The response object initialised with the data returned from the gateway.
*/
public function sendData($data)
{
Expand Down Expand Up @@ -332,7 +332,7 @@ public function getCreateCard()
/**
* An optional flag to indicate if you wish to continue to store the
* Token in the SagePay token database for future use.
* Values set in contants SET_TOKEN_*
* Values set in constants SET_TOKEN_*
*
* Note: this is just an override method. It is best to leave this unset,
* and use either setToken or setCardReference. This flag will then be
Expand Down Expand Up @@ -437,11 +437,10 @@ public function getAllowGiftAid()
* Values defined in static::ALLOW_GIFT_AID_* constant.
*
* @param bool|int $allowGiftAid value that casts to boolean
* @return $this
*/
public function setAllowGiftAid($value)
public function setAllowGiftAid($allowGiftAid)
{
$this->setParameter('allowGiftAid', $value);
$this->setParameter('allowGiftAid', $allowGiftAid);
}

/**
Expand Down
27 changes: 22 additions & 5 deletions src/Message/DirectAuthorizeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

namespace Omnipay\SagePay\Message;

use Omnipay\SagePay\PayPal;

/**
* Sage Pay Direct Authorize Request
*/

class DirectAuthorizeRequest extends AbstractRequest
{
/**
* @var array Some mapping from Omnipay card brand codes to Sage Pay card branc codes.
* @var array Some mapping from Omnipay card brand codes to Sage Pay card brand codes.
*/
protected $cardBrandMap = array(
'mastercard' => 'MC',
Expand Down Expand Up @@ -104,7 +106,7 @@ protected function getBaseAuthorizeData()
* SagePay throws an error if passed an IPv6 address.
* Filter out addresses that are not IPv4 format.
*
* @return string|null The IPv4 IP addess string or null if not available in this format.
* @return string|null The IPv4 IP address string or null if not available in this format.
*/
public function getClientIp()
{
Expand Down Expand Up @@ -191,6 +193,14 @@ public function getCardData($data = array())
// Validate the card details (number, date, cardholder name).
$this->getCard()->validate();

$data['CardType'] = $this->getCardBrand();

if ($this->isPayPalPayment()) {
$data['PayPalCallbackURL'] = $this->getCard()->getCallbackUrl();

return $data;
}

if ($this->getCardholderName()) {
$data['CardHolder'] = $this->getCardholderName();
} else {
Expand All @@ -203,7 +213,6 @@ public function getCardData($data = array())
}

$data['ExpiryDate'] = $this->getCard()->getExpiryDate('my');
$data['CardType'] = $this->getCardBrand();

if ($this->getCard()->getStartMonth() and $this->getCard()->getStartYear()) {
$data['StartDate'] = $this->getCard()->getStartDate('my');
Expand Down Expand Up @@ -247,7 +256,7 @@ public function getData()
// A CVV may be supplied whether using a token or credit card details.
// On *first* use of a token for which a CVV was provided, that CVV will
// be used when making a transaction. The CVV will then be deleted by the
// gateway. For each *resuse* of a cardReference, a new CVV must be provided,
// gateway. For each *reuse* of a cardReference, a new CVV must be provided,
// if the security rules require it.

if ($this->getCard()->getCvv() !== null) {
Expand Down Expand Up @@ -285,10 +294,18 @@ public function setSurchargeXml($surchargeXml)
}

/**
* @return string The XML surchange data as set.
* @return string The XML surcharge data as set.
*/
public function getSurchargeXml()
{
return $this->getParameter('surchargeXml');
}

/**
* @return bool
*/
protected function isPayPalPayment()
{
return $this->getCardBrand() === 'PAYPAL' && $this->getCard() instanceof PayPal;
}
}
77 changes: 77 additions & 0 deletions src/Message/DirectCompletePayPalRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace Omnipay\SagePay\Message;

use Omnipay\Common\Exception\InvalidRequestException;

/**
* Sage Pay Direct Complete PayPal Request.
*/
class DirectCompletePayPalRequest extends AbstractRequest
{
/**
* @return string
*/
public function getService()
{
return static::SERVICE_PAYPAL;
}

/**
* @return string
*/
public function getTxType()
{
return static::TXTYPE_COMPLETE;
}

/**
* @return array|mixed
* @throws InvalidRequestException
*/
public function getData()
{
return $this->getBaseAuthorizeData();
}

/**
* The required fields concerning what is being authorised and who
* it is being authorised for.
*
* @return array
* @throws InvalidRequestException
*/
protected function getBaseAuthorizeData()
{
$this->validate('transactionId', 'amount', 'accept');

// Start with the authorisation and API version details.
$data = $this->getBaseData();

// Money formatted as major unit decimal.
$data['VPSTxId'] = $this->getTransactionId();
$data['Amount'] = $this->getAmount();
$data['Accept'] = !$this->getAccept() || strtoupper($this->getAccept()) === 'NO' ? 'NO' : 'YES';

return $data;
}

/**
* @return string
*/
public function getAccept()
{
return $this->getParameter('accept');
}

/**
* Override the MD passed into the current request.
*
* @param string $value
* @return $this
*/
public function setAccept($value)
{
return $this->setParameter('accept', $value);
}
}
2 changes: 1 addition & 1 deletion src/Message/DirectTokenRegistrationRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function getData()
$data['CV2'] = $this->getCard()->getCvv();
$data['CardType'] = $this->getCardBrand();

// The account type only comes into play when a transation is requested.
// The account type only comes into play when a transaction is requested.
unset($data['AccountType']);

return $data;
Expand Down
4 changes: 2 additions & 2 deletions src/Message/Form/AuthorizeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public function generateCrypt(array $data)
// is used to submit the form, because that is how the gateway treats
// the data internally.
// This package assumes input data will be UTF-8 by default, and will
// comvert it accordingly. This can be disabled if the data is already
// convert it accordingly. This can be disabled if the data is already
// ISO8859-1.
// For the Server and Direct gateway methods, the POST encoding type
// will tell the gateway how to interpret the character encoding, and
Expand All @@ -211,7 +211,7 @@ public function generateCrypt(array $data)

$key = $this->getEncryptionKey();

// Normally IV (paramert 5, initialization vector) would be a kind of salt.
// Normally IV (parameter 5, initialization vector) would be a kind of salt.
// That is more relevant when encrypting user details where multiple users
// could have identical passwords. But this is a one-off transport of a message
// that will always be unique, so no variable IV is needed.
Expand Down
45 changes: 32 additions & 13 deletions src/Message/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Omnipay\Common\Message\AbstractResponse;
use Omnipay\Common\Message\RedirectResponseInterface;
use Omnipay\Common\Message\RequestInterface;
use Omnipay\SagePay\Traits\ResponseFieldsTrait;
use Omnipay\SagePay\ConstantsInterface;

Expand Down Expand Up @@ -43,7 +42,7 @@ public function getTransactionReference()
// The reference is null if we have no transaction details.

if (empty($reference)) {
return;
return null;
}

// Remaining transaction details supplied by the merchant site
Expand All @@ -66,42 +65,62 @@ public function getTransactionReference()
*/
public function isRedirect()
{
return $this->getStatus() === static::SAGEPAY_STATUS_3DAUTH;
return $this->getStatus() === static::SAGEPAY_STATUS_3DAUTH || $this->getStatus() === static::SAGEPAY_STATUS_PPREDIRECT;
}

/**
* @return string URL to 3D Secure endpoint.
* @return string|null URL to 3D Secure endpoint.
*/
public function getRedirectUrl()
{
if ($this->isRedirect()) {
return $this->getDataItem('ACSURL');
if (!$this->isRedirect()) {
return null;
}

if ($this->getStatus() === static::SAGEPAY_STATUS_PPREDIRECT) {
return $this->getDataItem('PayPalRedirectURL');
}

return $this->getDataItem('ACSURL');
}

/**
* @return string The redirect method.
*/
public function getRedirectMethod()
{
if (!$this->isRedirect()) {
return null;
}

if ($this->getStatus() === static::SAGEPAY_STATUS_PPREDIRECT) {
return 'GET';
}

return 'POST';
}

/**
* The usual reason for a redirect is for a 3D Secure check.
* Note: when PayPal is supported, a different set of data will be returned.
*
* @return array Collected 3D Secure POST data.
* @return array|null Collected 3D Secure POST data.
*/
public function getRedirectData()
{
if ($this->isRedirect()) {
return array(
'PaReq' => $this->getDataItem('PAReq'),
'TermUrl' => $this->getRequest()->getReturnUrl(),
'MD' => $this->getDataItem('MD'),
);
if (!$this->isRedirect()) {
return null;
}

if ($this->getStatus() === static::SAGEPAY_STATUS_PPREDIRECT) {
return array();
}

return array(
'PaReq' => $this->getDataItem('PAReq'),
'TermUrl' => $this->getRequest()->getReturnUrl(),
'MD' => $this->getDataItem('MD'),
);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Message/ServerAuthorizeResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function getRedirectMethod()
}

/**
* @return array empy array; all the data is in the GET URL
* @return array empty array; all the data is in the GET URL
*/
public function getRedirectData()
{
Expand Down
Loading