Skip to content

Commit

Permalink
use XmlBuilder in Worldpay gateway #62
Browse files Browse the repository at this point in the history
  • Loading branch information
akDeveloper committed Apr 9, 2016
1 parent 9ac5b4e commit c48a81f
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 103 deletions.
217 changes: 120 additions & 97 deletions lib/AktiveMerchant/Billing/Gateways/Worldpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
use AktiveMerchant\Billing\Gateway;
use AktiveMerchant\Billing\CreditCard;
use AktiveMerchant\Billing\Response;
use AktiveMerchant\Billing\Gateways\Worldpay\XmlNormalizer;
use AktiveMerchant\Common\XmlBuilder;
use AktiveMerchant\Common\Options;

/**
* Integration of WorldPay gateway
Expand All @@ -20,6 +21,12 @@ class Worldpay extends Gateway
const TEST_URL = 'https://secure-test.worldpay.com/jsp/merchant/xml/paymentService.jsp';
const LIVE_URL = 'https://secure.worldpay.com/jsp/merchant/xml/paymentService.jsp';

const VERSION = '1.4';

const SUCCESS_OK = 'ok';

const SUCCESS_AUTHORISED = 'AUTHORISED';

public static $default_currency = 'GBP';
public static $money_format = 'cents';
public static $supported_countries = array('HK', 'US', 'GB', 'AU', 'AD', 'BE', 'CH', 'CY', 'CZ', 'DE', 'DK', 'ES', 'FI', 'FR', 'GI', 'GR', 'HU', 'IE', 'IL', 'IT', 'LI', 'LU', 'MC', 'MT', 'NL', 'NO', 'NZ', 'PL', 'PT', 'SE', 'SG', 'SI', 'SM', 'TR', 'UM', 'VA');
Expand Down Expand Up @@ -64,128 +71,112 @@ public function authorize($money, CreditCard $creditcard, $options = array())
{
$this->required_options('order_id', $options);
$this->build_authorization_request($money, $creditcard, $options);
return $this->commit('AUTHORISED');

return $this->commit(self::SUCCESS_AUTHORISED);
}

public function capture($money, $authorization, $options = array())
{
$this->build_capture_request($money, $authorization, $options);
return $this->commit('ok');

return $this->commit(self::SUCCESS_OK);
}

public function build_authorization_request($money, $creditcard, $options, $testingXmlGeneration = false)
{
$this->xml = $this->createXmlBuilder();

$this->xml->load(array(
'merchantCode' => $this->options['login'],
'version' => '1.4',
'submit' => array(
'order' => $this->addOrder($money, $creditcard, $options)
)
));
$this->xml->paymentService(function ($xml) use ($money, $creditcard, $options) {
$xml->submit(function ($xml) use ($money, $creditcard, $options) {
$this->addOrder($money, $creditcard, $options);
});
}, array('merchantCode' => $this->options['login'], 'version' => self::VERSION));

if ($testingXmlGeneration) {
return $this->xml->createXML(true);
}
return $this->xml;
}

public function build_capture_request($money, $authorization, $options, $testingXmlGeneration = false)
{
$this->xml = $this->createXmlBuilder();

$this->xml->load(array(
'merchantCode' => $this->options['login'],
'version' => '1.4',
'modify' => $this->addCaptureModification($money, $authorization, $options)
));
$this->xml->paymentService(function ($xml) use ($money, $authorization, $options) {
$xml->modify(function ($xml) use ($money, $authorization, $options) {
$this->addCaptureModification($money, $authorization, $options);
});
}, array('merchantCode' => $this->options['login'], 'version' => self::VERSION));

if ($testingXmlGeneration) {
return $this->xml->createXML(true);
}
return $this->xml;
}

private function createXmlBuilder()
{
$xml = new \Thapp\XmlBuilder\XmlBuilder('paymentService', new XmlNormalizer);
$xml->setDocType(
$xml = new XmlBuilder();

$xml->instruct('1.0', 'UTF-8');
$xml->docType(
'paymentService',
'-//WorldPay//DTD WorldPay PaymentService v1//EN',
'http://dtd.worldpay.com/paymentService_v1.dtd'
);

$xml->setRenderTypeAttributes(false);
$xml->setAttributeMapp(array('paymentService' => array('merchantCode', 'version')));

return $xml;
}

private function addOrder($money, $creditcard, $options)
{
$attrs = array('orderCode' => $options['order_id']);
$attrs['installationId'] = $this->options['inst_id'];

return array(
'@attributes' => $attrs,
array(
'description' => 'Purchase',
'amount' => $this->addAmount($money, $options),
'paymentDetails' => $this->addPaymentMethod($money, $creditcard, $options)
)
);
$this->xml->order(function ($xml) use ($money, $creditcard, $options) {
$xml->description('Purchase');
$this->addAmount($money, $options);
$this->addPaymentMethod($money, $creditcard, $options);
}, array('orderCode' => $options['order_id'], 'installationId' => 'inst_id'));
}

private function addCaptureModification($money, $authorization, $options)
{
$now = new \DateTime(null, new \DateTimeZone('UTC'));

return array(
'orderModification' => array(
'@attributes' => array('orderCode' => $authorization),
array(
'capture' => array(
'date' => array(
'@attributes' => array(
'dayOfMonth' => $now->format('d'),
'month' => $now->format('m'),
'year' => $now->format('Y')
)
),
'amount' => $this->addAmount($money, $options)
$this->xml->orderModification(function ($xml) use ($money, $authorization, $options) {
$xml->capture(function ($xml) use ($money, $authorization, $options) {
$now = new \DateTime(null, new \DateTimeZone('UTC'));
$xml->date(
null,
array(
'dayOfMonth' => $now->format('d'),
'month' => $now->format('m'),
'year' => $now->format('Y'),
)
)
)
);
);

$this->addAmount($money, $options);
});
}, array('orderCode' => $authorization));
}

private function addPaymentMethod($money, $creditcard, $options)
{
$cardCode = self::$card_codes[$creditcard->type];

return array(
$cardCode => array(
'cardNumber' => $creditcard->number,
'expiryDate' => array(
'date' => array(
'@attributes' => array(
'month' => $this->cc_format($creditcard->month, 'two_digits'),
'year' => $this->cc_format($creditcard->year, 'four_digits')
)
)
),
'cardHolderName' => $creditcard->name(),
'cvc' => $creditcard->verification_value,
'cardAddress' => $this->addAddress($options)
)
);
$this->xml->paymentDetails(function ($xml) use ($money, $creditcard, $options, $cardCode) {
$xml->$cardCode(function ($xml) use ($money, $creditcard, $options) {
$xml->cardNumber($creditcard->number);
$xml->expiryDate(function ($xml) use ($money, $creditcard, $options) {
$month = $this->cc_format($creditcard->month, 'two_digits');
$year = $this->cc_format($creditcard->year, 'four_digits');
$xml->date(null, array('month' => $month, 'year' => $year));
});

$xml->cardHolderName($creditcard->name());
$xml->cvc($creditcard->verification_value);
$this->addAddress($options);
});
});
}

private function addAmount($money, $options)
{
$currency = isset($options['currency']) ? $options['currency'] : self::$default_currency;

return array(
'@attributes' => array(
$this->xml->amount(
null,
array(
'value' => $this->amount($money),
'currencyCode' => $currency,
'exponent' => 2
Expand Down Expand Up @@ -237,7 +228,13 @@ private function addAddress($options)
$out['telephoneNumber'] = $address['phone'];
}

return array('address' => $out);
$this->xml->cardAddress(function ($xml) use ($out) {
$xml->address(function ($xml) use ($out) {
foreach ($out as $name => $value) {
$xml->$name($value);
}
});
});
}

private function commit($successCriteria)
Expand All @@ -248,31 +245,64 @@ private function commit($successCriteria)
"Authorization: {$this->encodedCredentials()}"
));

$response = $this->parse($this->ssl_post($url, $this->xml->createXML(true), $options));
$response = $this->parse(
$this->ssl_post($url, $this->xml->createXML(true), $options)
);

$success = $this->successFrom($response, $successCriteria);

return new Response(
$success,
$this->messageFrom($success, $response, $successCriteria),
$this->paramsFrom($response),
$response->getArrayCopy(),
$this->optionsFrom($response)
);
}

private function parse($response_xml)
/**
* Parse the raw data response from gateway
*
* @param string $body
*/
private function parse($body)
{
$response = array();

$data = simplexml_load_string($body);

foreach ($data as $node) {
$this->parseElement($response, $node);
}

return new Options($response);
}

private function parseElement(&$response, $node)
{
$xml = new \Thapp\XmlBuilder\XmlBuilder();
$dom = $xml->loadXml($response_xml, true, false);
return $xml->toArray($dom);
foreach ($node->attributes() as $k => $v) {
$response[$node->getName() . '_' . $k] = $v->__toString();
}

if ($node->count() > 0) {
if ($node->getName()) {
$response[$node->getName()] = true;
foreach ($node as $n) {
$this->parseElement($response, $n);
}
}
} else {
$response[$node->getName()] = $node->__toString();
}
}

private function successFrom($response, $successCriteria)
{
if ($successCriteria == 'ok') {
return isset($response['paymentService']['reply']['ok']);
return isset($response['ok']);
}

if (isset($response['paymentService']['reply']['orderStatus'])) {
return $response['paymentService']['reply']['orderStatus']['payment']['lastEvent'] == $successCriteria;
if (isset($response['lastEvent'])) {
return $response['lastEvent'] == $successCriteria;
}

return false;
Expand All @@ -284,29 +314,21 @@ private function messageFrom($success, $response, $successCriteria)
return "SUCCESS";
}

if (isset($response['paymentService']['reply']['error'])) {
return $response['paymentService']['reply']['error']['nodevalue'];
if (isset($response['error'])) {
return trim($response['error']);
}

return "A transaction status of $successCriteria is required.";
}

private function paramsFrom($response)
{
return $response['paymentService']['reply'];
}

private function optionsFrom($response)
{
$options = array('test' => $this->isTest());

if (isset($response['paymentService']['reply']['orderStatus'])) {
foreach ($response['paymentService']['reply']['orderStatus']['@attributes'] as $key => $value) {
if (preg_match('/orderCode$/', $key)) {
$options['authorization'] = $value;
}
}
}
$options['authorization'] = $response['orderStatus_orderCode'];
$options['fraud_review'] = null;
$options['avs_result'] = array('code' => $response['AVSResultCode']);
$options['cvv_result'] = $response['CVCResultCode'];

return $options;
}
Expand All @@ -315,6 +337,7 @@ private function encodedCredentials()
{
$credentials = $this->options['login'] . ':' . $this->options['password'];
$encoded = base64_encode($credentials);

return "Basic $encoded";
}
}
8 changes: 8 additions & 0 deletions lib/AktiveMerchant/Common/XmlBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ public function instruct($version, $encoding)
$this->writer->setIndent(true);
}

public function docType($qualifiedName, $publicId = null, $systemId = null)
{
$this->writer->startDTD($qualifiedName, $publicId, $systemId);
$this->writer->endDTD();
}

public function build()
{
$args = func_get_args();
Expand Down Expand Up @@ -75,12 +81,14 @@ public function build()
public function __call($name, $args)
{
$args = array_merge([$name], $args);

return $this->build($args);
}

public function __toString()
{
$this->writer->endDocument();

return $this->writer->outputMemory();
}
}
Loading

0 comments on commit c48a81f

Please sign in to comment.