Skip to content
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

PR #107 fixes character stripping allowed chars and adds tests ar… #108

Merged
merged 7 commits into from
Sep 17, 2018
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Table of Contents
* [Generating a Token or CardReference](#generating-a-token-or-cardreference)
* [Using a Token or CardRererence](#using-a-token-or-cardrererence)
* [Basket format](#basket-format)
* [Sage 50 Accounts Software Integration](#sage-50-accounts-software-integration)
* [Account Types](#account-types)
* [VAT](#vat)
* [Support](#support)
Expand Down Expand Up @@ -722,6 +723,26 @@ but is also the only format currently supported by some of the Sage accounting p
For applications that require this type of integration, an optional parameter `useOldBasketFormat`
with a value of `true` can be passed in the driver's `initialize()` method.


## Sage 50 Accounts Software Integration

The Basket format can be used for Sage 50 Accounts Software Integration:

> It is possible to integrate your Sage Pay account with Sage Accounting products to ensure you can
> reconcile the transactions on your account within your financial software.
> If you wish to link a transaction to a specific product record this can be done through the Basket field
in the transaction registration post.
> Please note the following integration is not currently available when using BasketXML fields.
> In order for the download of transactions to affect a product record the first entry in a basket line needs
to be the product code of the item within square brackets. For example:

```
4:[PR001]Pioneer NSDV99 DVD-Surround Sound System:1:424.68:74.32:499.00:499.00
```

You can either prepend this onto the description or using `\Omnipay\SagePay\Extend\Item` you can use `setProductCode`
which will take care of pre-pending `[]` for you.

# Account Types

Your Sage Pay account will use separate merchant accounts for difference transaction sources.
Expand Down
20 changes: 20 additions & 0 deletions src/Extend/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,24 @@ public function setVat($value)
{
return $this->setParameter('vat', $value);
}

/**
* Product Code is used for the Product Sage 50 Accounts Software Integration
* It allows reconcile the transactions on your account within the financial software
* by linking the product record to a specific transaction.
* This is not available for BasketXML and only Basket Integration. See docs for more info.
* {@inheritDoc}
*/
public function getProductCode()
{
return $this->getParameter('productCode');
}

/**
* {@inheritDoc}
*/
public function setProductCode($value)
{
return $this->setParameter('productCode', $value);
}
}
34 changes: 29 additions & 5 deletions src/Message/AbstractRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,23 @@ protected function filterItemName($name)
return $name;
}

/**
* Filters out any characters that SagePay does not support from the item name for
* the non-xml basket integration
*
* @param string $name
* @return string
*/
protected function filterNonXmlItemName($name)
{
$standardChars = '0-9a-zA-Z';
$allowedSpecialChars = " +'/\\,.-{};_@()^\"~$=!#?|[]";
$pattern = '`[^'.$standardChars.preg_quote($allowedSpecialChars, '/').']`';
$name = trim(substr(preg_replace($pattern, '', $name), 0, 100));

return $name;
}

/**
* Filters out any characters that SagePay does not support from the discount name.
*
Expand Down Expand Up @@ -479,18 +496,25 @@ protected function getItemDataNonXML()
$count = 0;

foreach ($items as $basketItem) {
$description = $this->filterNonXmlItemName($basketItem->getName());
$vat = '0.00';

if ($basketItem instanceof ExtendItem) {
$vat = $basketItem->getVat();

/**
* Product Code is used for the Product Sage 50 Accounts Software Integration
* It allows reconcile the transactions on your account within the financial software
* by linking the product record to a specific transaction.
* This is not available for BasketXML and only Basket Integration. See docs for more info.
*/
if (!is_null($basketItem->getProductCode())) {
$description = '[' . $basketItem->getProductCode() . ']' . $description;
}
}

$lineTotal = ($basketItem->getQuantity() * ($basketItem->getPrice() + $vat));

$description = $this->filterItemName($basketItem->getName());

// Make sure there aren't any colons in the name
// Perhaps ":" should be replaced with '-' or other symbol?
$description = str_replace(':', ' ', $description);
$result .= ':' . $description . // Item name
':' . $basketItem->getQuantity() . // Quantity
':' . number_format($basketItem->getPrice(), 2, '.', '') . // Unit cost (without tax)
Expand Down
87 changes: 82 additions & 5 deletions tests/Message/DirectAuthorizeRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Omnipay\SagePay\Message;

use Omnipay\Tests\TestCase;
//use Money\Money;

class DirectAuthorizeRequestTest extends TestCase
{
Expand All @@ -13,7 +12,7 @@ class DirectAuthorizeRequestTest extends TestCase
. '</surcharge></surcharges>';

/**
* @var \Omnipay\Common\Message\AbstractRequest $request
* @var DirectAuthorizeRequest
*/
protected $request;

Expand Down Expand Up @@ -325,9 +324,87 @@ public function testMixedBasketWithSpecialChars()
$this->assertContains($expected, $data['BasketXML'], 'Basket XML does not match the expected output');
}

/**
*
*/
public function testNonXmlBasket()
{
$this->request->setUseOldBasketFormat(true);

$items = new \Omnipay\Common\ItemBag(array(
new \Omnipay\SagePay\Extend\Item(array(
'name' => "Pioneer NSDV99 DVD-Surround Sound System",
'quantity' => 3,
'price' => 4.35,
)),
));

$this->request->setItems($items);
$data = $this->request->getData();

$this->assertArrayNotHasKey('BasketXML', $data);
$this->assertSame('1:Pioneer NSDV99 DVD-Surround Sound System:3:4.35::4.35:13.05', $data['Basket']);
}

public function testNonXmlBasketWithVat()
{
$this->request->setUseOldBasketFormat(true);

$items = new \Omnipay\Common\ItemBag(array(
new \Omnipay\SagePay\Extend\Item(array(
'name' => "Pioneer NSDV99 DVD-Surround Sound System",
'quantity' => 3,
'price' => 4.35,
'vat' => 2
)),
));

$this->request->setItems($items);
$data = $this->request->getData();

$this->assertArrayHasKey('Basket', $data);
$this->assertArrayNotHasKey('BasketXML', $data);

$this->assertSame('1:Pioneer NSDV99 DVD-Surround Sound System:3:4.35:2:6.35:19.05', $data['Basket']);
}

public function testNonXmlBasketWithProductCode()
{
$this->request->setUseOldBasketFormat(true);

$items = new \Omnipay\Common\ItemBag(array(
new \Omnipay\SagePay\Extend\Item(array(
'name' => "Pioneer NSDV99 DVD-Surround Sound System",
'quantity' => 3,
'price' => 4.35,
'vat' => 2,
'productCode' => 'DVD-123'
)),
));

$this->request->setItems($items);
$data = $this->request->getData();

$this->assertSame('1:[DVD-123]Pioneer NSDV99 DVD-Surround Sound System:3:4.35:2:6.35:19.05', $data['Basket']);
}

public function testNonXmlBasketWithSpecialAndNonSpecialCharacters()
{
$this->request->setUseOldBasketFormat(true);

$items = new \Omnipay\Common\ItemBag(array(
new \Omnipay\SagePay\Extend\Item(array(
// [] and ::: are reserved
'name' => "[SKU-ABC]Pioneer::: NSDV99 DVD-Surround Sound System .-{};_@()",
'quantity' => 3,
'price' => 4.35,
'vat' => 2,
)),
));

$this->request->setItems($items);
$data = $this->request->getData();

$this->assertSame('1:[SKU-ABC]Pioneer NSDV99 DVD-Surround Sound System .-{};_@():3:4.35:2:6.35:19.05', $data['Basket']);
}

public function testCreateTokenCanBeSetInRequest()
{
$this->request->setCreateToken(true);
Expand Down