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

Rosen4o/master #7

Merged
merged 4 commits into from
Jul 16, 2024
Merged
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ $saleRequest = (new SaleRequest())
->setTerminalID('<TID - V*******>')
->setMerchantId('<MID - 15 chars>')
->setPrivateKey('\<path to certificate.key>', '<password / or use method from bottom>')
->setMInfo(array( // Mandatory cardholderName and ( email or MobilePhone )
'email'=>'[email protected]',
'cardholderName'=>'CARDHOLDER NAME', // Max 45 chars
'mobilePhone'=> array(
'cc'=>'359', // Country code
'subscriber'=>'8939999888', // Subscriber number
),
'threeDSRequestorChallengeInd'=>'04', // Optional for Additional Authentication
))
//->setSigningSchemaMacGeneral(); // use MAC_GENERAL
//->setSigningSchemaMacExtended(); // use MAC_EXTENDED
//->setSigningSchemaMacAdvanced(); // use MAC_ADVANCED
Expand Down
24 changes: 13 additions & 11 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
~ Copyright (c) 2023. Venelin Iliev.
~ https://veneliniliev.com
-->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" cacheDirectory=".phpunit.cache">
<coverage includeUncoveredFiles="true">
<include>
<directory suffix=".php">./tests/Unit</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Borica3ds">
<directory suffix=".php">./tests/Unit</directory>
</testsuite>
</testsuites>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false"
colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.2/phpunit.xsd"
cacheDirectory=".phpunit.cache">
<testsuites>
<testsuite name="Borica3ds">
<directory suffix=".php">./tests/Unit</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">./tests/Unit</directory>
</include>
</source>
</phpunit>
69 changes: 60 additions & 9 deletions src/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace VenelinIliev\Borica3ds;

use InvalidArgumentException;
use VenelinIliev\Borica3ds\Enums\TransactionType;
use VenelinIliev\Borica3ds\Exceptions\ParameterValidationException;

Expand Down Expand Up @@ -55,10 +56,15 @@ abstract class Request extends Base
*/
private $nonce;

/**
* @array
*/
private $mInfo;

/**
* Get description
*
* @return mixed
* @return string
*/
public function getDescription()
{
Expand All @@ -68,7 +74,7 @@ public function getDescription()
/**
* Set description
*
* @param string $description Описание на поръчката.
* @param string $description Описание на поръчката.
*
* @return Request
* @throws ParameterValidationException
Expand All @@ -95,7 +101,7 @@ public function getBackRefUrl()
/**
* Set back ref url
*
* @param string $backRefUrl URL на търговеца за изпращане на резултата от авторизацията.
* @param string $backRefUrl URL на търговеца за изпращане на резултата от авторизацията.
*
* @return Request
* @throws ParameterValidationException
Expand Down Expand Up @@ -123,7 +129,7 @@ public function getOrder()
/**
* Set order
*
* @param string|integer $order Номер на поръчката за търговеца, 6 цифри, който трябва да бъде уникален за деня.
* @param string|integer $order Номер на поръчката за търговеца, 6 цифри, който трябва да бъде уникален за деня.
*
* @return Request
* @throws ParameterValidationException
Expand Down Expand Up @@ -151,7 +157,7 @@ public function getTransactionType()
/**
* Set transaction type
*
* @param TransactionType $transactionType Тип на транзакцията.
* @param TransactionType $transactionType Тип на транзакцията.
*
* @return Request
*/
Expand All @@ -174,7 +180,7 @@ public function getAmount()
/**
* Set amount
*
* @param string|float|integer $amount Обща стойност на поръчката по стандарт ISO_4217 с десетичен разделител точка.
* @param string|float|integer $amount Обща стойност на поръчката по стандарт ISO_4217 с десетичен разделител точка.
*
* @return Request
*/
Expand All @@ -197,7 +203,7 @@ public function getCurrency()
/**
* Set currency
*
* @param string $currency Валута на поръчката: три буквен код на валута по стандарт ISO 4217.
* @param string $currency Валута на поръчката: три буквен код на валута по стандарт ISO 4217.
*
* @return Request
* @throws ParameterValidationException
Expand Down Expand Up @@ -228,7 +234,7 @@ public function getSignatureTimestamp()
/**
* Set signature timestamp
*
* @param string|null $signatureTimestamp Дата на подпис/изпращане на данните.
* @param string|null $signatureTimestamp Дата на подпис/изпращане на данните.
*
* @return Request
*/
Expand Down Expand Up @@ -256,7 +262,7 @@ public function getNonce()
}

/**
* @param string $nonce Nonce.
* @param string $nonce Nonce.
*
* @return Request
*/
Expand All @@ -265,4 +271,49 @@ public function setNonce($nonce)
$this->nonce = $nonce;
return $this;
}

/**
* @return string
*/
public function getMInfo()
{
if (!empty($this->mInfo)) {
return base64_encode(json_encode($this->mInfo));
}
return '';
}

/**
* @param array $mInfo
*
* @return Request
*/
public function setMInfo($mInfo)
{
// Check for required fields (cardholderName and email or mobilePhone)
if (!isset($mInfo['cardholderName']) ||
(!isset($mInfo['email']) && !isset($mInfo['mobilePhone']))) {
throw new InvalidArgumentException('CardholderName and email or MobilePhone must be provided');
}

// Check the maximum length of cardholderName
if (strlen($mInfo['cardholderName']) > 45) {
throw new InvalidArgumentException('CardHolderName must be at most 45 characters');
}

// Check for a valid email address format
if (isset($mInfo['email']) && !filter_var($mInfo['email'], FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Email must be a valid email address');
}

// Check the structure for the mobile phone
if (isset($mInfo['mobilePhone'])) {
if (!isset($mInfo['mobilePhone']['cc']) || !isset($mInfo['mobilePhone']['subscriber'])) {
throw new InvalidArgumentException('MobilePhone must contain both cc and subscriber');
}
}

$this->mInfo = $mInfo;
return $this;
}
}
7 changes: 5 additions & 2 deletions src/SaleRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public function generateForm()
*/
public function getData()
{
return [
return array_filter([
'NONCE' => $this->getNonce(),
'P_SIGN' => $this->generateSignature(),

Expand All @@ -126,7 +126,10 @@ public function getData()

'TERMINAL' => $this->getTerminalID(),
'BACKREF' => $this->getBackRefUrl(),
] + $this->generateAdCustBorOrderId();

'M_INFO' => $this->getMInfo(),

]) + $this->generateAdCustBorOrderId();
}

/**
Expand Down
68 changes: 68 additions & 0 deletions tests/Unit/SaleRequestMInfoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/*
* Copyright (c) 2024. Venelin Iliev.
* https://veneliniliev.com
*/

namespace VenelinIliev\Borica3ds\Tests\Unit;

use PHPUnit\Framework\TestCase;
use VenelinIliev\Borica3ds\SaleRequest;

class SaleRequestMInfoTest extends TestCase
{
public function testGetMInfo()
{
$request = new SaleRequest();
$request->setMInfo([
'cardholderName' => 'John Doe',
'email' => '[email protected]'
]);
$expected = base64_encode(json_encode([
'cardholderName' => 'John Doe',
'email' => '[email protected]'
]));
$this->assertEquals($expected, $request->getMInfo());
}

public function testMInfoWithInvalidEmail()
{
$this->expectException(\InvalidArgumentException::class);

$request = new SaleRequest();
$request->setMInfo([
'cardholderName' => 'John Doe',
'email' => 'invalid',
]);
}

public function testMInfoWithInvalidCardholderNameLength()
{
$this->expectException(\InvalidArgumentException::class);

$request = new SaleRequest();
$request->setMInfo([
'cardholderName' => str_repeat('a', 46),
'email' => '[email protected]',
]);
}

public function testMInfoWithMissingRequiredFields()
{
$this->expectException(\InvalidArgumentException::class);

$request = new SaleRequest();
$request->setMInfo(['email' => '[email protected]']);
}

public function testMInfoWithInvalidMobilePhoneStructure()
{
$this->expectException(\InvalidArgumentException::class);

$request = new SaleRequest();
$request->setMInfo([
'cardholderName' => 'John Doe',
'mobilePhone' => ['invalid' => 'invalid'],
]);
}
}
66 changes: 62 additions & 4 deletions tests/Unit/SaleRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public function testDataMacGeneral()

$this->assertEquals([
'TRTYPE' => 1,
'COUNTRY' => null,
//'COUNTRY' => null,
'CURRENCY' => 'BGN',
'MERCH_GMT' => '+03',
'ORDER' => '145659',
Expand All @@ -108,7 +108,7 @@ public function testDataMacGeneral()
'TIMESTAMP' => '20201013115715',
'TERMINAL' => self::TERMINAL_ID,
'MERCH_URL' => 'https://test.com',
'MERCH_NAME' => null,
//'MERCH_NAME' => null,
'EMAIL' => '[email protected]',
'BACKREF' => 'https://test.com/back-ref-url',
'AD.CUST_BOR_ORDER_ID' => 'test',
Expand Down Expand Up @@ -145,7 +145,7 @@ public function testData()

$this->assertEquals([
'TRTYPE' => 1,
'COUNTRY' => null,
//'COUNTRY' => null,
'CURRENCY' => 'BGN',
'MERCH_GMT' => '+03',
'ORDER' => '145659',
Expand All @@ -154,7 +154,7 @@ public function testData()
'TIMESTAMP' => '20201013115715',
'TERMINAL' => self::TERMINAL_ID,
'MERCH_URL' => 'https://test.com',
'MERCH_NAME' => null,
//'MERCH_NAME' => null,
'EMAIL' => '[email protected]',
'BACKREF' => 'https://test.com/back-ref-url',
'AD.CUST_BOR_ORDER_ID' => 'test',
Expand All @@ -165,6 +165,64 @@ public function testData()
], $saleData);
}

/**
* @throws ParameterValidationException|SignatureException
*/
public function testDataWithMInfo()
{
$mInfo = [
'email' => '[email protected]',
'cardholderName' => 'CARDHOLDER NAME',
'mobilePhone' => [
'cc' => '359',
'subscriber' => '8939999888'
],
'threeDSRequestorChallengeInd' => '04',
];

$saleData = (new SaleRequest())
->setAmount(1)
->setCurrency('BGN')
->setOrder(145659)
->setDescription('Детайли плащане.')
->setMerchantGMT('+03')
->setMerchantUrl('https://test.com')
->setBackRefUrl('https://test.com/back-ref-url')
->setTerminalID(self::TERMINAL_ID)
->setMerchantId(self::MERCHANT_ID)
->setPrivateKey(__DIR__ . '/../certificates/test.key')
->setPrivateKeyPassword('test')
->setSignatureTimestamp('20201013115715')
->setNonce('FC8AC36A9FDADCB6127D273CD15DAEC3')
->setEmailAddress('[email protected]')
->setAdCustBorOrderId('test')
->setSigningSchemaMacExtended()
->setMInfo($mInfo)
->getData();

$this->assertEquals([
'TRTYPE' => 1,
//'COUNTRY' => null,
'CURRENCY' => 'BGN',
'MERCH_GMT' => '+03',
'ORDER' => '145659',
'AMOUNT' => '1.00',
'DESC' => 'Детайли плащане.',
'TIMESTAMP' => '20201013115715',
'TERMINAL' => self::TERMINAL_ID,
'MERCH_URL' => 'https://test.com',
//'MERCH_NAME' => null,
'EMAIL' => '[email protected]',
'BACKREF' => 'https://test.com/back-ref-url',
'AD.CUST_BOR_ORDER_ID' => 'test',
'ADDENDUM' => 'AD,TD',
'NONCE' => 'FC8AC36A9FDADCB6127D273CD15DAEC3',
'MERCHANT' => self::MERCHANT_ID,
'M_INFO' => 'eyJlbWFpbCI6InVzZXJAc2FtcGxlLmNvbSIsImNhcmRob2xkZXJOYW1lIjoiQ0FSREhPTERFUiBOQU1FIiwibW9iaWxlUGhvbmUiOnsiY2MiOiIzNTkiLCJzdWJzY3JpYmVyIjoiODkzOTk5OTg4OCJ9LCJ0aHJlZURTUmVxdWVzdG9yQ2hhbGxlbmdlSW5kIjoiMDQifQ==',
'P_SIGN' => '8125E0E604B8BC6430B03B1365B63D91ACB7210F2777776D7587A633D222368CB36936855090C81020318503998499503595EBB32092014A2843C7E6DB75C1AD7FCB018BB4CDA98B379B411E74C62881529A7787B73D8D0E00D1406E1D2A64ADD1A298CCDF3B5A13C14825990010541444122F4A8FBB23BB3747B962BEFB5C57C5737FCF8DC9E61F377777B661B04FFE604EE5E49EB87CA49737FD39AA27639DE0CEF11B527B630070BE97ECC81F0D14D355F37C5C684A040C615563C962CE137A0B7C7F0B3567DEB0A05C4D79F373D7938D4CBFCE86CA6AA5DBAC99081F3AB4C52E0A3B35748A7600ECE4278060B14F5D3ACE5D964A73F49CF8844B6C86E10E'
], $saleData);
}

/**
* @return void
* @throws ParameterValidationException|SignatureException
Expand Down
Loading