Skip to content
This repository was archived by the owner on Dec 10, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 2 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
22 changes: 22 additions & 0 deletions src/Omnipay/WorldPayXML/Gateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,28 @@ public function setPaResponse($value)
return $this->setParameter('pa_response', $value);
}


/**
* Get the separate username if configured (more secure approach for basic auth) or fallback to merchant if not
*
* @return string
*/
public function getUsername()
{
return $this->parameters->get('username', $this->getParameter('merchant'));
}

/**
* Set basic auth username
*
* @param string $value
* @return Gateway
*/
public function setUsername($value)
{
return $this->setParameter('username', $value);
}

/**
* Get password
*
Expand Down
23 changes: 22 additions & 1 deletion src/Omnipay/WorldPayXML/Message/PurchaseRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,27 @@ public function setMerchant($value)
return $this->setParameter('merchant', $value);
}

/**
* Get the separate username if configured (more secure approach for basic auth) or fallback to merchant if not
*
* @return string
*/
public function getUsername()
{
return $this->parameters->get('username', $this->getParameter('merchant'));
}

/**
* Set basic auth username
*
* @param string $value
* @return AbstractRequest
*/
public function setUsername($value)
{
return $this->setParameter('username', $value);
}

/**
* Get pa response
*
Expand Down Expand Up @@ -444,7 +465,7 @@ public function sendData($data)
$document->appendChild($node);

$authorisation = base64_encode(
$this->getMerchant() . ':' . $this->getPassword()
$this->getUsername() . ':' . $this->getPassword()
);

$headers = [
Expand Down
125 changes: 92 additions & 33 deletions src/Omnipay/WorldPayXML/Message/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@
*/
class Response extends AbstractResponse
{
/** @var string */
const PAYMENT_STATUS_AUTHORISED = 'AUTHORISED';
/** @var string */
const PAYMENT_STATUS_CAPTURED = 'CAPTURED';
/** @var string */
const PAYMENT_STATUS_SETTLED_BY_MERCHANT = 'SETTLED_BY_MERCHANT';
/** @var string */
const PAYMENT_STATUS_SENT_FOR_AUTHORISATION = 'SENT_FOR_AUTHORISATION';
/** @var string */
const PAYMENT_STATUS_CANCELLED = 'CANCELLED';

/**
* Constructor
*
* @param RequestInterface $request Request
* @param string $data Data
*
* @access public
* @throws InvalidResponseException if non-XML response received
*/
public function __construct(RequestInterface $request, $data)
{
Expand All @@ -29,11 +37,17 @@ public function __construct(RequestInterface $request, $data)
}

$responseDom = new DOMDocument;
$responseDom->loadXML($data);
if (!@$responseDom->loadXML($data)) {
throw new InvalidResponseException('Non-XML notification response received');
}

$this->data = simplexml_import_dom(
$responseDom->documentElement->firstChild->firstChild
$this->data = @simplexml_import_dom(
$responseDom->documentElement->firstChild // <notify> or <reply>
);

if (empty($this->data)) {
throw new InvalidResponseException('Could not import response XML: ' . $data);
}
}

/**
Expand Down Expand Up @@ -92,73 +106,118 @@ public function getMessage()
97 => 'SECURITY BREACH'
];

$message = 'PENDING';

if (isset($this->data->error)) {
$message = 'ERROR: ' . $this->data->error;
return 'ERROR: ' . $this->data->error; // Cast to string to get CDATA content
}

if (isset($this->data->payment->ISO8583ReturnCode)) {
$returnCode = $this->data->payment->ISO8583ReturnCode->attributes();
$payment = $this->getOrder()->payment;
if (isset($payment->ISO8583ReturnCode)) {
$returnCode = $payment->ISO8583ReturnCode->attributes();

foreach ($returnCode as $name => $value) {
if ($name == 'code') {
$message = $codes[intval($value)];
return $codes[intval($value)];
}
}
}

if ($this->isSuccessful()) {
$message = $codes[0];
return $codes[0];
}

return $message;
return 'PENDING';
}

/**
* Get transaction reference
* Get transaction reference provided with order (the ID in Omnipay parlance), and sent back with notifications.
*
* @access public
* @return string
* @return string|null
*/
public function getTransactionReference()
public function getTransactionId()
{
$attributes = $this->data->attributes();
if (empty($this->getOrder())) {
return null;
}

$attributes = $this->getOrder()->attributes();

if (isset($attributes['orderCode'])) {
return $attributes['orderCode'];
}

return null;
}

/**
* Get is redirect
* Get *your* reference a.k.a Omnipay transaction ID (!)
*
* @access public
* @return boolean
* @return string
* @deprecated This was named inconsistently with other Omnipay adapters. Use getTransactionId(), whose name
* reflects the actual contents returned.
*/
public function isRedirect()
public function getTransactionReference()
{
return $this->getTransactionId();
}

/**
* @return string|null
*/
public function getErrorCode()
{
if (isset($this->data->requestInfo->request3DSecure->issuerURL)) {
return true;
if (!isset($this->data->error) || empty($this->data->error->attributes()['code'])) {
return null;
}

return (string) $this->data->error->attributes()['code'];
}

/**
* @return null|\SimpleXMLElement
*/
public function getOrder()
{
if (isset($this->data->orderStatusEvent)) {
return $this->data->orderStatusEvent; // Notifications
}

if (isset($this->data->orderStatus)) {
return $this->data->orderStatus; // Order responses
}

return false;
return null;
}

/**
* Get is successful
* Get is redirect
*
* @access public
* @return boolean
*/
public function isRedirect()
{
return isset($this->data->requestInfo->request3DSecure->issuerURL);
}

/**
* Whether transaction's last state indicates success
*
* @return bool
*/
public function isSuccessful()
{
if (isset($this->data->payment->lastEvent)) {
if (strtoupper($this->data->payment->lastEvent) == 'AUTHORISED') {
return true;
}
if (!isset($this->getOrder()->payment->lastEvent)) {
return false;
}

return false;
return in_array(
strtoupper($this->getOrder()->payment->lastEvent),
[
self::PAYMENT_STATUS_AUTHORISED,
self::PAYMENT_STATUS_CAPTURED,
self::PAYMENT_STATUS_SETTLED_BY_MERCHANT,
],
true
);
}
}
42 changes: 38 additions & 4 deletions tests/Omnipay/WorldPayXML/GatewayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@

class GatewayTest extends GatewayTestCase
{
/** @var Gateway */
protected $gateway;
/** @var array */
private $parameters;
/** @var CreditCard */
private $card;

public function setUp()
{
parent::setUp();
Expand All @@ -15,8 +22,11 @@ public function setUp()
$this->getHttpClient(),
$this->getHttpRequest()
);
$this->gateway->setMerchant('ACMECO');
$this->gateway->setTestMode(true);
$this->gateway->setInstallation('ABC123');

$this->options = [
$this->parameters = [
'amount' => '10.00',
'card' => new CreditCard([
'firstName' => 'Example',
Expand All @@ -34,7 +44,12 @@ public function testPurchaseSuccess()
{
$this->setMockHttpResponse('PurchaseSuccess.txt');

$response = $this->gateway->purchase($this->options)->send();
$purchase = $this->gateway->purchase($this->parameters);

// Confirm basic auth uses merchant code to authenticate when there's no username.
$this->assertEquals('ACMECO', $purchase->getUsername());

$response = $purchase->send();

$this->assertTrue($response->isSuccessful());
$this->assertEquals('T0211010', $response->getTransactionReference());
Expand All @@ -44,7 +59,7 @@ public function testPurchaseError()
{
$this->setMockHttpResponse('PurchaseFailure.txt');

$response = $this->gateway->purchase($this->options)->send();
$response = $this->gateway->purchase($this->parameters)->send();

$this->assertFalse($response->isSuccessful());
$this->assertSame('CARD EXPIRED', $response->getMessage());
Expand Down Expand Up @@ -78,9 +93,28 @@ public function testApplePaySuccess()

$this->setMockHttpResponse('PurchaseSuccessApplePay.txt');

$response = $this->gateway->purchase($applePayOptions)->send();
$purchase = $this->gateway->purchase($applePayOptions);

// Confirm basic auth uses merchant code to authenticate when there's no username.
$this->assertEquals('ACMECO', $purchase->getUsername());

$response = $purchase->send();

$this->assertTrue($response->isSuccessful());
$this->assertEquals('T0211011', $response->getTransactionReference());
}

/**
* Confirm basic auth uses a username when set rather than merchant code.
*/
public function testUsernameAuthSetup()
{
$gatewayWithUsername = clone $this->gateway;
$gatewayWithUsername->setUsername('MYSECRETUSERNAME987');

$purchase = $gatewayWithUsername->purchase($this->parameters);
$purchase->setCard($this->card);

$this->assertEquals('MYSECRETUSERNAME987', $purchase->getUsername());
}
}
Loading