From 575fb4ac0701aed4c505902189946840c8a9ef2f Mon Sep 17 00:00:00 2001 From: Matt Glaman Date: Mon, 22 Mar 2021 20:31:47 -0500 Subject: [PATCH 01/19] Support Guzzle 7 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e33d217..402ce42 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "ext-json": "*", "ext-simplexml": "*", "ext-xmlwriter": "*", - "guzzlehttp/guzzle": "~6.2" + "guzzlehttp/guzzle": "^6.2 || ^7.0" }, "require-dev": { "phpunit/phpunit": "~4.8", From c276d05c399f4e103893858e4871b54f2c09102f Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 14:47:28 +0200 Subject: [PATCH 02/19] Fix the tests, require PHP 7.3+ and run tests via Github workflows. --- .travis.yml | 20 ------- README.md | 4 +- composer.json | 4 +- phpunit.xml.dist | 64 ++++++++++----------- src/ARBCancelSubscriptionRequest.php | 2 - src/ARBGetSubscriptionRequest.php | 2 - src/ARBGetSubscriptionStatusRequest.php | 2 - src/ARBSubscriptionRequest.php | 5 -- src/ARBUpdateSubscriptionRequest.php | 3 +- src/BaseApiRequest.php | 1 - src/UpdateHeldTransactionRequest.php | 1 - tests/ARBCreateSubscriptionRequestTest.php | 38 ++++++------ tests/ConfigurationTest.php | 3 +- tests/CustomerPaymentProfileRequestTest.php | 7 ++- tests/CustomerProfileRequestTest.php | 3 +- tests/DataType/IntervalTest.php | 28 +++++---- tests/DataType/TransactionRequestTest.php | 3 +- tests/DataTypeTest.php | 8 ++- tests/Request/JsonRequestTest.php | 5 +- tests/Request/XmlRequestTest.php | 5 +- tests/RequestFactoryTest.php | 12 ++-- tests/Response/JsonResponseTest.php | 3 +- tests/Response/XmlResponseTest.php | 4 +- tests/TestBase.php | 5 +- 24 files changed, 102 insertions(+), 130 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2a063f4..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: php -php: - - 5.5 - - 5.6 - - 7.0 - - 7.1 -matrix: - fast_finish: true -sudo: false -cache: - directories: - - $HOME/.composer/cache -before_install: - - composer self-update - - composer global require "hirak/prestissimo:^0.3" -install: - - composer install --no-interaction -script: - - composer cs - - composer test diff --git a/README.md b/README.md index 1975de7..e93ec31 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,14 @@ An SDK for Authorize.net, using Guzzle. ## Dependencies -PHP version >= 5.5.0 is required. +PHP version >= 7.3 is required. The following PHP extensions are required: * json * simplexml * xmlwrite -This library also uses Guzzle 6. +This library uses Guzzle, v6 minimum. ## Testing diff --git a/composer.json b/composer.json index 402ce42..751ce4d 100644 --- a/composer.json +++ b/composer.json @@ -4,14 +4,14 @@ "type": "library", "keywords": ["authorizenet", "authorize.net", "payment", "ecommerce"], "require": { - "php": ">=5.5", + "php": ">=7.3", "ext-json": "*", "ext-simplexml": "*", "ext-xmlwriter": "*", "guzzlehttp/guzzle": "^6.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.8", + "phpunit/phpunit": "^9.5", "squizlabs/php_codesniffer": "~2" }, "license": "MIT", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 41302fe..7025257 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,36 +1,32 @@ - - - - - ./tests - - - - - - - - - - - ./src - - ./vendor - ./tests - ./build - - - - - - - - - - - - - - + + + + ./src + + + ./vendor + ./tests + ./build + + + + + + + + + ./tests + + + + + + + + + + + + diff --git a/src/ARBCancelSubscriptionRequest.php b/src/ARBCancelSubscriptionRequest.php index 6c014b7..9a8a5f7 100644 --- a/src/ARBCancelSubscriptionRequest.php +++ b/src/ARBCancelSubscriptionRequest.php @@ -3,8 +3,6 @@ namespace CommerceGuys\AuthNet; use GuzzleHttp\Client; -use CommerceGuys\AuthNet\DataTypes\Paging; -use CommerceGuys\AuthNet\DataTypes\Sorting; use CommerceGuys\AuthNet\Request\RequestInterface; /** diff --git a/src/ARBGetSubscriptionRequest.php b/src/ARBGetSubscriptionRequest.php index ebe4093..ab2bb30 100644 --- a/src/ARBGetSubscriptionRequest.php +++ b/src/ARBGetSubscriptionRequest.php @@ -3,8 +3,6 @@ namespace CommerceGuys\AuthNet; use GuzzleHttp\Client; -use CommerceGuys\AuthNet\DataTypes\Paging; -use CommerceGuys\AuthNet\DataTypes\Sorting; use CommerceGuys\AuthNet\Request\RequestInterface; /** diff --git a/src/ARBGetSubscriptionStatusRequest.php b/src/ARBGetSubscriptionStatusRequest.php index 4f37fe2..52c8c62 100644 --- a/src/ARBGetSubscriptionStatusRequest.php +++ b/src/ARBGetSubscriptionStatusRequest.php @@ -3,8 +3,6 @@ namespace CommerceGuys\AuthNet; use GuzzleHttp\Client; -use CommerceGuys\AuthNet\DataTypes\Paging; -use CommerceGuys\AuthNet\DataTypes\Sorting; use CommerceGuys\AuthNet\Request\RequestInterface; /** diff --git a/src/ARBSubscriptionRequest.php b/src/ARBSubscriptionRequest.php index 5f10c33..f43a30c 100644 --- a/src/ARBSubscriptionRequest.php +++ b/src/ARBSubscriptionRequest.php @@ -2,11 +2,6 @@ namespace CommerceGuys\AuthNet; -use GuzzleHttp\Client; -use CommerceGuys\AuthNet\DataTypes\Paging; -use CommerceGuys\AuthNet\DataTypes\Sorting; -use CommerceGuys\AuthNet\Request\RequestInterface; - /** * Use this method to create subscriptions using Automated Recurring Billing. * diff --git a/src/ARBUpdateSubscriptionRequest.php b/src/ARBUpdateSubscriptionRequest.php index 32c0054..665ce4f 100644 --- a/src/ARBUpdateSubscriptionRequest.php +++ b/src/ARBUpdateSubscriptionRequest.php @@ -3,7 +3,6 @@ namespace CommerceGuys\AuthNet; use GuzzleHttp\Client; -use CommerceGuys\AuthNet\DataTypes\Subscription; use CommerceGuys\AuthNet\Request\RequestInterface; /** @@ -19,7 +18,7 @@ public function __construct( $subscriptionId ) { parent::__construct($configuration, $client); - $this->subscriptionId = $subscription; + $this->subscriptionId = $subscriptionId; } protected function attachData(RequestInterface $request) diff --git a/src/BaseApiRequest.php b/src/BaseApiRequest.php index 75b73cf..7707c41 100644 --- a/src/BaseApiRequest.php +++ b/src/BaseApiRequest.php @@ -7,7 +7,6 @@ use CommerceGuys\AuthNet\Request\JsonRequest; use CommerceGuys\AuthNet\Request\RequestInterface; use CommerceGuys\AuthNet\Request\XmlRequest; -use CommerceGuys\AuthNet\Response\JsonResponse; abstract class BaseApiRequest implements ApiRequestInterface { diff --git a/src/UpdateHeldTransactionRequest.php b/src/UpdateHeldTransactionRequest.php index 41bca7d..fed711d 100644 --- a/src/UpdateHeldTransactionRequest.php +++ b/src/UpdateHeldTransactionRequest.php @@ -2,7 +2,6 @@ namespace CommerceGuys\AuthNet; -use GuzzleHttp\Client; use CommerceGuys\AuthNet\Request\RequestInterface; /** diff --git a/tests/ARBCreateSubscriptionRequestTest.php b/tests/ARBCreateSubscriptionRequestTest.php index edacc4b..ad0dc56 100644 --- a/tests/ARBCreateSubscriptionRequestTest.php +++ b/tests/ARBCreateSubscriptionRequestTest.php @@ -7,32 +7,20 @@ use CommerceGuys\AuthNet\ARBGetSubscriptionListRequest; use CommerceGuys\AuthNet\ARBGetSubscriptionRequest; use CommerceGuys\AuthNet\ARBGetSubscriptionStatusRequest; -use CommerceGuys\AuthNet\CreateCustomerProfileRequest; -use CommerceGuys\AuthNet\DataTypes\BillTo; -use CommerceGuys\AuthNet\DataTypes\CreditCard; use CommerceGuys\AuthNet\DataTypes\CustomerProfileId; use CommerceGuys\AuthNet\DataTypes\Interval; -use CommerceGuys\AuthNet\DataTypes\OpaqueData; -use CommerceGuys\AuthNet\DataTypes\Order; use CommerceGuys\AuthNet\DataTypes\Paging; -use CommerceGuys\AuthNet\DataTypes\PaymentProfile; use CommerceGuys\AuthNet\DataTypes\PaymentSchedule; -use CommerceGuys\AuthNet\DataTypes\Profile; use CommerceGuys\AuthNet\DataTypes\Sorting; use CommerceGuys\AuthNet\DataTypes\Subscription; -use CommerceGuys\AuthNet\DataTypes\SubscriptionRequest; -use CommerceGuys\AuthNet\DeleteCustomerProfileRequest; -use CommerceGuys\AuthNet\GetCustomerProfileIdsRequest; -use CommerceGuys\AuthNet\GetCustomerProfileRequest; -use CommerceGuys\AuthNet\UpdateCustomerProfileRequest; class ARBCreateSubscriptionRequestTest extends TestBase { public function testARBCreateSubscriptionRequestCRUD() { - $interval = new Interval(['length' => 1, 'unit' => 'months']); + $interval = new Interval(['length' => 7, 'unit' => 'days']); $paymentSchedule = new PaymentSchedule([ - 'startDate' => '2018-08-30', + 'startDate' => '2024-08-30', 'totalOccurrences' => 9999, ]); $paymentSchedule->addInterval($interval); @@ -46,9 +34,11 @@ public function testARBCreateSubscriptionRequestCRUD() $request = new ARBCreateSubscriptionRequest($this->configurationXml, $this->client, $subscription); $request->setSubscription($subscription); $response = $request->execute(); - $this->assertObjectHasAttribute('profile', $response->contents()); + $response_contents = $response->contents(); + $this->assertIsObject($response_contents); + $this->assertTrue(property_exists($response_contents, 'profile')); $this->assertResponse($response, 'I00001', 'Successful.', 'Ok'); - $subscriptionId = $response->contents()->subscriptionId; + $subscriptionId = $response_contents->subscriptionId; // Test Get. $get = new ARBGetSubscriptionRequest($this->configurationXml, $this->client, $subscriptionId); $response = $get->execute(); @@ -64,20 +54,22 @@ public function testARBCreateSubscriptionRequestCRUD() // Retrieve a list of subscriptions. $sorting = new Sorting([ 'orderBy' => 'id', - 'orderDescending' => false, + 'orderDescending' => true, ]); $paging = new Paging([ - 'limit' => 100, + 'limit' => 50, 'offset' => 1, ]); $request = new ARBGetSubscriptionListRequest($this->configurationXml, $this->client, 'subscriptionActive'); $request->setSorting($sorting); $request->setPaging($paging); $response = $request->execute(); - $this->assertObjectHasAttribute('totalNumInResultSet', $response->contents()); + $response_contents = $response->contents(); + $this->assertIsObject($response_contents); + $this->assertTrue(property_exists($response_contents, 'totalNumInResultSet'));; $this->assertResponse($response, 'I00001', 'Successful.', 'Ok'); // If something has caused a lot of built-up subscriptions, remove them. - if ($response->contents()->totalNumInResultSet > 100) { + if ($response_contents->totalNumInResultSet > 100) { $this->cleanupSubscriptions(); } } @@ -87,6 +79,7 @@ protected function cleanupSubscriptions() $request = new ARBGetSubscriptionListRequest($this->configurationXml, $this->client, 'subscriptionActive'); $response = $request->execute(); $contents = $response->contents(); + $canceled_count = 0; while ($contents->totalNumInResultSet) { $subscriptions = $contents->subscriptionDetails->subscriptionDetail; if (!is_array($subscriptions)) { @@ -96,6 +89,11 @@ protected function cleanupSubscriptions() $cancel = new ARBCancelSubscriptionRequest($this->configurationXml, $this->client, $subscription->id); $response = $cancel->execute(); $this->assertEquals('Ok', $response->getResultCode()); + $canceled_count++; + // Stop after canceling 100 subscriptions. + if ($canceled_count > 100) { + break 2; + } } $response = $request->execute(); $contents = $response->contents(); diff --git a/tests/ConfigurationTest.php b/tests/ConfigurationTest.php index 76e9be1..43696d8 100644 --- a/tests/ConfigurationTest.php +++ b/tests/ConfigurationTest.php @@ -3,11 +3,12 @@ namespace CommerceGuys\AuthNet\Tests; use CommerceGuys\AuthNet\Configuration; +use PHPUnit\Framework\TestCase; /** * Tests the configuration class. */ -class ConfigurationTest extends \PHPUnit_Framework_TestCase +class ConfigurationTest extends TestCase { public function testConfiguration() { diff --git a/tests/CustomerPaymentProfileRequestTest.php b/tests/CustomerPaymentProfileRequestTest.php index d30a400..ac9b3fa 100644 --- a/tests/CustomerPaymentProfileRequestTest.php +++ b/tests/CustomerPaymentProfileRequestTest.php @@ -51,9 +51,10 @@ public function testCreateCustomerPaymentProfileWithCreditCard() 'country' => 'US', 'phoneNumber' => '5555555555', ])); + $nextYear = ((int) date('Y')) + 1; $paymentProfile->addPayment(new CreditCard([ 'cardNumber' => '4111111111111111', - 'expirationDate' => '2020-12', + 'expirationDate' => "$nextYear-12", ])); $request->setPaymentProfile($paymentProfile); @@ -83,7 +84,7 @@ public function testCreateCustomerPaymentProfileWithCreditCard() $response = $request->execute(); $this->assertEquals('I00001', $response->getMessages()[0]->getCode()); $this->assertEquals('XXXX1111', $response->paymentProfile->payment->creditCard->cardNumber); - $this->assertEquals('2020-12', $response->paymentProfile->payment->creditCard->expirationDate); + $this->assertEquals("$nextYear-12", $response->paymentProfile->payment->creditCard->expirationDate); $request = new ValidateCustomerPaymentProfileRequest($this->configurationXml, $this->client); $request->setCustomerProfileId($customerProfileId); @@ -112,7 +113,7 @@ public function testCreateCustomerPaymentProfileWithCreditCard() // ])); $paymentProfile->addPayment(new CreditCard([ 'cardNumber' => 'XXXX1111', - 'expirationDate' => '2022-06', + 'expirationDate' => "$nextYear-06", ])); $request->setPaymentProfile($paymentProfile); $request->setValidationMode('none'); diff --git a/tests/CustomerProfileRequestTest.php b/tests/CustomerProfileRequestTest.php index 6c87d75..d40b28f 100644 --- a/tests/CustomerProfileRequestTest.php +++ b/tests/CustomerProfileRequestTest.php @@ -39,9 +39,10 @@ public function testCreateCustomerProfileCRUDRequests() 'country' => 'US', 'phoneNumber' => '5555555555', ])); + $nextYear = ((int) date('Y')) + 1; $paymentProfile->addPayment(new CreditCard([ 'cardNumber' => '4111111111111111', - 'expirationDate' => '2020-12', + 'expirationDate' => "$nextYear-12", ])); $profile = new Profile([ diff --git a/tests/DataType/IntervalTest.php b/tests/DataType/IntervalTest.php index 733ba6c..12885be 100644 --- a/tests/DataType/IntervalTest.php +++ b/tests/DataType/IntervalTest.php @@ -6,11 +6,12 @@ use CommerceGuys\AuthNet\DataTypes\Interval; use CommerceGuys\AuthNet\DataTypes\LineItem; use CommerceGuys\AuthNet\DataTypes\TransactionRequest; +use PHPUnit\Framework\TestCase; /** * Tests Intervals. */ -class IntervalTest extends \PHPUnit_Framework_TestCase +class IntervalTest extends TestCase { /** @@ -18,8 +19,9 @@ class IntervalTest extends \PHPUnit_Framework_TestCase */ public function testMissingLength() { - $this->setExpectedException(\InvalidArgumentException::class, 'Interval must have a length.'); - $interval = new Interval(); + $this->expectExceptionMessage('Interval must have a length.'); + $this->expectException(\InvalidArgumentException::class); + new Interval(); } /** @@ -27,8 +29,9 @@ public function testMissingLength() */ public function testMissingUnit() { - $this->setExpectedException(\InvalidArgumentException::class, 'Interval must have a unit.'); - $interval = new Interval(['length' => '1']); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Interval must have a unit.'); + new Interval(['length' => '1']); } /** @@ -36,8 +39,9 @@ public function testMissingUnit() */ public function testInvalidUnit() { - $this->setExpectedException(\InvalidArgumentException::class, 'Interval unit must be days or months.'); - $interval = new Interval(['length' => '1', 'unit' => 'foo']); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Interval unit must be days or months.'); + new Interval(['length' => '1', 'unit' => 'foo']); } /** @@ -45,8 +49,9 @@ public function testInvalidUnit() */ public function testUnitDays() { - $this->setExpectedException(\InvalidArgumentException::class, 'Interval length for days must be between 7 and 365, inclusive.'); - $interval = new Interval(['length' => '1', 'unit' => 'days']); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Interval length for days must be between 7 and 365, inclusive.'); + new Interval(['length' => '1', 'unit' => 'days']); } /** @@ -54,7 +59,8 @@ public function testUnitDays() */ public function testUnitMonths() { - $this->setExpectedException(\InvalidArgumentException::class, 'Interval length for months must be between 1 and 12, inclusive.'); - $interval = new Interval(['length' => '13', 'unit' => 'months']); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Interval length for months must be between 1 and 12, inclusive.'); + new Interval(['length' => '13', 'unit' => 'months']); } } diff --git a/tests/DataType/TransactionRequestTest.php b/tests/DataType/TransactionRequestTest.php index 4ce08c2..f0bef6a 100644 --- a/tests/DataType/TransactionRequestTest.php +++ b/tests/DataType/TransactionRequestTest.php @@ -5,11 +5,12 @@ use CommerceGuys\AuthNet\DataTypes\CreditCard; use CommerceGuys\AuthNet\DataTypes\LineItem; use CommerceGuys\AuthNet\DataTypes\TransactionRequest; +use PHPUnit\Framework\TestCase; /** * Tests the transaction request */ -class TransactionRequestTest extends \PHPUnit_Framework_TestCase +class TransactionRequestTest extends TestCase { /** diff --git a/tests/DataTypeTest.php b/tests/DataTypeTest.php index 3a9d317..1ea9a1a 100644 --- a/tests/DataTypeTest.php +++ b/tests/DataTypeTest.php @@ -12,7 +12,7 @@ public function testBaseDataType() // Tests methods provided by \CommerceGuys\AuthNet\DataTypes\BaseDataType $creditCard = new CreditCard([ 'cardNumber' => '4111111111111111', - 'expirationDate' => '2020-12', + 'expirationDate' => '2025-12', ]); unset($creditCard->cardNumber); $this->assertTrue(!isset($creditCard->cardNumber)); @@ -22,13 +22,15 @@ public function testBaseDataType() public function testMessageValidationCode() { - $this->setExpectedException(\InvalidArgumentException::class, 'Messages must have a code'); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Messages must have a code'); new Message(['message' => 'Test']); } public function testMessageValidationTest() { - $this->setExpectedException(\InvalidArgumentException::class, 'Messages must have a text'); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Messages must have a text'); new Message(['code' => 'I00122']); } } diff --git a/tests/Request/JsonRequestTest.php b/tests/Request/JsonRequestTest.php index 4189830..b04ff2d 100644 --- a/tests/Request/JsonRequestTest.php +++ b/tests/Request/JsonRequestTest.php @@ -6,8 +6,9 @@ use CommerceGuys\AuthNet\Configuration; use CommerceGuys\AuthNet\DataTypes\MerchantAuthentication; use CommerceGuys\AuthNet\Request\JsonRequest; +use PHPUnit\Framework\TestCase; -class JsonRequestTest extends \PHPUnit_Framework_TestCase +class JsonRequestTest extends TestCase { /** * @var \CommerceGuys\AuthNet\Configuration @@ -18,7 +19,7 @@ class JsonRequestTest extends \PHPUnit_Framework_TestCase */ protected $client; - protected function setUp() + protected function setUp(): void { parent::setUp(); $this->configuration = new Configuration([ diff --git a/tests/Request/XmlRequestTest.php b/tests/Request/XmlRequestTest.php index 5a11264..52f740f 100644 --- a/tests/Request/XmlRequestTest.php +++ b/tests/Request/XmlRequestTest.php @@ -6,8 +6,9 @@ use CommerceGuys\AuthNet\Configuration; use CommerceGuys\AuthNet\DataTypes\MerchantAuthentication; use CommerceGuys\AuthNet\Request\XmlRequest; +use PHPUnit\Framework\TestCase; -class XmlRequestTest extends \PHPUnit_Framework_TestCase +class XmlRequestTest extends TestCase { /** * @var \CommerceGuys\AuthNet\Configuration @@ -18,7 +19,7 @@ class XmlRequestTest extends \PHPUnit_Framework_TestCase */ protected $client; - protected function setUp() + protected function setUp(): void { parent::setUp(); $this->configuration = new Configuration([ diff --git a/tests/RequestFactoryTest.php b/tests/RequestFactoryTest.php index c4a3365..8a71808 100644 --- a/tests/RequestFactoryTest.php +++ b/tests/RequestFactoryTest.php @@ -14,19 +14,15 @@ public function testRequestFactory() public function testInvalidServiceRequest() { - $this->setExpectedException( - \InvalidArgumentException::class, - "Request createNonExistantRequest does not exist" - ); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage("Request createNonExistantRequest does not exist"); $this->xmlRequestFactory->createNonExistantRequest(); } public function testNotInstanceOf() { - $this->setExpectedException( - \InvalidArgumentException::class, - "Request configuration is not a valid request" - ); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage("Request configuration is not a valid request"); $this->xmlRequestFactory->configuration(); } } diff --git a/tests/Response/JsonResponseTest.php b/tests/Response/JsonResponseTest.php index ef43f9c..95dbb68 100644 --- a/tests/Response/JsonResponseTest.php +++ b/tests/Response/JsonResponseTest.php @@ -4,8 +4,9 @@ use GuzzleHttp\Psr7\Response; use CommerceGuys\AuthNet\Response\JsonResponse; +use PHPUnit\Framework\TestCase; -class JsonResponseTest extends \PHPUnit_Framework_TestCase +class JsonResponseTest extends TestCase { public function testJsonResponse() { diff --git a/tests/Response/XmlResponseTest.php b/tests/Response/XmlResponseTest.php index 880c61d..f132131 100644 --- a/tests/Response/XmlResponseTest.php +++ b/tests/Response/XmlResponseTest.php @@ -3,10 +3,10 @@ namespace CommerceGuys\AuthNet\Tests\Response; use GuzzleHttp\Psr7\Response; -use CommerceGuys\AuthNet\Response\JsonResponse; use CommerceGuys\AuthNet\Response\XmlResponse; +use PHPUnit\Framework\TestCase; -class XmlResponseTest extends \PHPUnit_Framework_TestCase +class XmlResponseTest extends TestCase { public function testXmlResponse() { diff --git a/tests/TestBase.php b/tests/TestBase.php index c2d9696..b248cbf 100644 --- a/tests/TestBase.php +++ b/tests/TestBase.php @@ -6,8 +6,9 @@ use GuzzleHttp\Client; use CommerceGuys\AuthNet\Configuration; use CommerceGuys\AuthNet\RequestFactory; +use PHPUnit\Framework\TestCase; -abstract class TestBase extends \PHPUnit_Framework_TestCase +abstract class TestBase extends TestCase { /** * @var \CommerceGuys\AuthNet\Configuration @@ -34,7 +35,7 @@ abstract class TestBase extends \PHPUnit_Framework_TestCase */ protected $jsonRequestFactory; - protected function setUp() + protected function setUp(): void { parent::setUp(); $this->configurationXml = new Configuration([ From 20bb107d11cfe99a38612f31fcb02cb23d529a3d Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 14:51:39 +0200 Subject: [PATCH 03/19] Commit the Github workflows. --- .github/workflows/build.yml | 46 +++++++++++++++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..d570e08 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,46 @@ +name: Build +on: [push, pull_request] + +jobs: + build-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: php-actions/composer@v6 + + - name: PHPUnit Tests PHP 7.3 + uses: php-actions/phpunit@master + with: + bootstrap: vendor/autoload.php + configuration: phpunit.xml.dist + args: --coverage-text + php_extensions: xdebug bcmath + php_version: 7.3 + version: 9 + env: + XDEBUG_MODE: coverage + + - name: PHPUnit Tests PHP 8.0 + uses: php-actions/phpunit@master + with: + bootstrap: vendor/autoload.php + configuration: phpunit.xml.dist + args: --coverage-text + php_extensions: xdebug bcmath + php_version: 8.0 + version: 9 + env: + XDEBUG_MODE: coverage + + - name: PHPUnit Tests PHP 8.1 + uses: php-actions/phpunit@master + with: + bootstrap: vendor/autoload.php + configuration: phpunit.xml.dist + args: --coverage-text + php_extensions: xdebug bcmath + php_version: 8.1 + version: 9 + env: + XDEBUG_MODE: coverage diff --git a/README.md b/README.md index e93ec31..76553ce 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Authorize.net PHP SDK ===================== -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/commerceguys/authnet/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/commerceguys/authnet/?branch=master) [![Build Status](https://travis-ci.org/commerceguys/authnet.svg?branch=master)](https://travis-ci.org/commerceguys/authnet) [![Code Coverage](https://scrutinizer-ci.com/g/commerceguys/authnet/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/commerceguys/authnet/?branch=master) [![Packagist](https://img.shields.io/packagist/dm/commerceguys/authnet.svg)](https://packagist.org/packages/commerceguys/authnet)[![Packagist](https://img.shields.io/packagist/v/commerceguys/authnet.svg)](https://packagist.org/packages/commerceguys/authnet) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/commerceguys/authnet/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/commerceguys/authnet/?branch=master) [![Build Status](https://github.com/commerceguys/authnet/actions/workflows/build.yml/badge.svg)](https://github.com/commerceguys/authnet/actions/workflows/build.yml) [![Code Coverage](https://scrutinizer-ci.com/g/commerceguys/authnet/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/commerceguys/authnet/?branch=master) [![Packagist](https://img.shields.io/packagist/dm/commerceguys/authnet.svg)](https://packagist.org/packages/commerceguys/authnet)[![Packagist](https://img.shields.io/packagist/v/commerceguys/authnet.svg)](https://packagist.org/packages/commerceguys/authnet) An SDK for Authorize.net, using Guzzle. From c9fad58130b29cbb7d21f96f73959942138af4b6 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 15:06:06 +0200 Subject: [PATCH 04/19] Changes to test. --- README.md | 2 +- composer.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 76553ce..4bbb3e0 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ An SDK for Authorize.net, using Guzzle. ## Dependencies -PHP version >= 7.3 is required. +PHP version >= 7.2 is required. The following PHP extensions are required: * json diff --git a/composer.json b/composer.json index 751ce4d..ad9daa0 100644 --- a/composer.json +++ b/composer.json @@ -4,14 +4,14 @@ "type": "library", "keywords": ["authorizenet", "authorize.net", "payment", "ecommerce"], "require": { - "php": ">=7.3", + "php": ">=7.2", "ext-json": "*", "ext-simplexml": "*", "ext-xmlwriter": "*", "guzzlehttp/guzzle": "^6.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^9.5", + "phpunit/phpunit": "^8.5.29 || ^9.5.23", "squizlabs/php_codesniffer": "~2" }, "license": "MIT", From 4ed7c10227a190624b2b8e01f6ba9849ff289cb9 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 15:20:58 +0200 Subject: [PATCH 05/19] Attempt fixing the builds. --- .github/workflows/build.yml | 33 ++++++++++++++++----------------- composer.json | 2 +- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d570e08..d54b9c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,12 +2,14 @@ name: Build on: [push, pull_request] jobs: - build-test: + run-test-php7.3: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - - uses: php-actions/composer@v6 + - name: Install dependencies + uses: php-actions/composer@v6 + with: + php_version: "7.3" - name: PHPUnit Tests PHP 7.3 uses: php-actions/phpunit@master @@ -15,32 +17,29 @@ jobs: bootstrap: vendor/autoload.php configuration: phpunit.xml.dist args: --coverage-text - php_extensions: xdebug bcmath + php_extensions: xdebug php_version: 7.3 version: 9 env: XDEBUG_MODE: coverage - - name: PHPUnit Tests PHP 8.0 - uses: php-actions/phpunit@master + run-test-php8.1: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + uses: php-actions/composer@v6 with: - bootstrap: vendor/autoload.php - configuration: phpunit.xml.dist - args: --coverage-text - php_extensions: xdebug bcmath - php_version: 8.0 - version: 9 - env: - XDEBUG_MODE: coverage + php_version: "8.1" - - name: PHPUnit Tests PHP 8.1 + - name: PHPUnit Tests PHP 78.1 uses: php-actions/phpunit@master with: bootstrap: vendor/autoload.php configuration: phpunit.xml.dist args: --coverage-text - php_extensions: xdebug bcmath + php_extensions: xdebug php_version: 8.1 version: 9 env: - XDEBUG_MODE: coverage + XDEBUG_MODE: coverage \ No newline at end of file diff --git a/composer.json b/composer.json index ad9daa0..fc3713f 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "guzzlehttp/guzzle": "^6.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "phpunit/phpunit": "^9.5.23", "squizlabs/php_codesniffer": "~2" }, "license": "MIT", From 36e415d6e39206973f6f90cb0b9e0ff5fee4c2a0 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 15:21:55 +0200 Subject: [PATCH 06/19] Attempt fixing the builds. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d54b9c9..10e0394 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build on: [push, pull_request] jobs: - run-test-php7.3: + run-test-php73: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -23,7 +23,7 @@ jobs: env: XDEBUG_MODE: coverage - run-test-php8.1: + run-test-php81: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 From c3f5877aa9615884b23f948073c57ee787b2fb4a Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 15:27:53 +0200 Subject: [PATCH 07/19] Attempt fixing the builds. --- .github/workflows/build.yml | 2 ++ README.md | 2 +- composer.json | 2 +- tests/ARBCreateSubscriptionRequestTest.php | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10e0394..c81f1c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,7 @@ jobs: args: --coverage-text php_extensions: xdebug php_version: 7.3 + memory_limit: "192M" version: 9 env: XDEBUG_MODE: coverage @@ -40,6 +41,7 @@ jobs: args: --coverage-text php_extensions: xdebug php_version: 8.1 + memory_limit: "192M" version: 9 env: XDEBUG_MODE: coverage \ No newline at end of file diff --git a/README.md b/README.md index 4bbb3e0..76553ce 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ An SDK for Authorize.net, using Guzzle. ## Dependencies -PHP version >= 7.2 is required. +PHP version >= 7.3 is required. The following PHP extensions are required: * json diff --git a/composer.json b/composer.json index fc3713f..355c26d 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "library", "keywords": ["authorizenet", "authorize.net", "payment", "ecommerce"], "require": { - "php": ">=7.2", + "php": ">=7.3", "ext-json": "*", "ext-simplexml": "*", "ext-xmlwriter": "*", diff --git a/tests/ARBCreateSubscriptionRequestTest.php b/tests/ARBCreateSubscriptionRequestTest.php index ad0dc56..5ced203 100644 --- a/tests/ARBCreateSubscriptionRequestTest.php +++ b/tests/ARBCreateSubscriptionRequestTest.php @@ -90,8 +90,8 @@ protected function cleanupSubscriptions() $response = $cancel->execute(); $this->assertEquals('Ok', $response->getResultCode()); $canceled_count++; - // Stop after canceling 100 subscriptions. - if ($canceled_count > 100) { + // Stop after canceling 50 subscriptions. + if ($canceled_count > 50) { break 2; } } From 399b24d306596db2c7e3cd8c490db0ea9418ff28 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 16:12:59 +0200 Subject: [PATCH 08/19] Attempt to configure scrutinizer. --- .scrutinizer.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 599f33a..0b80d59 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -14,10 +14,9 @@ filter: paths: - src/* build: - tests: - override: - - - command: phpunit --coverage-clover=my-coverage-file - coverage: - file: my-coverage-file - format: php-clover + nodes: + analysis: + tests: + override: + - php-scrutinizer-run + - phpcs-run From 63f05aa51496713e336922b4fb2ef9db06fcda65 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 16:16:07 +0200 Subject: [PATCH 09/19] Fix phpcs violations. --- composer.json | 2 +- src/GetSettledBatchListRequest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 355c26d..31fe794 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ }, "require-dev": { "phpunit/phpunit": "^9.5.23", - "squizlabs/php_codesniffer": "~2" + "squizlabs/php_codesniffer": "~3" }, "license": "MIT", "authors": [ diff --git a/src/GetSettledBatchListRequest.php b/src/GetSettledBatchListRequest.php index a39d75f..5f8f9f5 100644 --- a/src/GetSettledBatchListRequest.php +++ b/src/GetSettledBatchListRequest.php @@ -13,11 +13,11 @@ class GetSettledBatchListRequest extends BaseApiRequest { - protected $includeStatistics; + protected $includeStatistics; - protected $firstSettlementDate; + protected $firstSettlementDate; - protected $lastSettlementDate; + protected $lastSettlementDate; public function __construct( Configuration $configuration, From 94f1bde021f652e397c3acfcd726439ed1e06415 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 16:17:52 +0200 Subject: [PATCH 10/19] Add a phpcs.xml. --- phpcs.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 phpcs.yml diff --git a/phpcs.yml b/phpcs.yml new file mode 100644 index 0000000..4baab64 --- /dev/null +++ b/phpcs.yml @@ -0,0 +1,6 @@ + + + ./ + ./vendor/* + + \ No newline at end of file From 3747ce0e9d0a665fa81e6c4c69e276f16150438d Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 2 Mar 2023 16:21:52 +0200 Subject: [PATCH 11/19] Fix the phpcs file extension. --- phpcs.yml => phpcs.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename phpcs.yml => phpcs.xml (90%) diff --git a/phpcs.yml b/phpcs.xml similarity index 90% rename from phpcs.yml rename to phpcs.xml index 4baab64..7dde899 100644 --- a/phpcs.yml +++ b/phpcs.xml @@ -1,5 +1,5 @@ - + ./ ./vendor/* From a016726b5c9b5fecd725389b2e76fb9e5368cd2c Mon Sep 17 00:00:00 2001 From: "Adrian M." Date: Mon, 7 Jul 2025 19:38:38 -0500 Subject: [PATCH 12/19] Add support for Accept Hosted payment form and customer profile creation from transactions: - Introduced 'GetHostedPaymentPageRequest' to retrieve a token for launching the Accept Hosted payment form. - Added 'HostedPaymentSettings' and 'Setting' data types to manage hosted payment configuration settings. - Created 'CreateCustomerProfileFromTransactionRequest' to generate a customer profile, payment profile, and shipping address from an existing transaction. - Extended 'GetCustomerProfileRequest' with support for 'unmaskExpirationDate' flag. - Added comprehensive tests for: - 'HostedPaymentSettings' and 'Setting' functionality. - 'GetHostedPaymentPageRequest' with various configuration scenarios. - 'CreateCustomerProfileFromTransactionRequest' using both XML and JSON formats. - Minor update in 'CustomerProfileRequestTest' to explicitly set 'unmaskExpirationDate'. This commit enhances integration with Authorize.Net Accept Suite and customer profile APIs, enabling hosted form usage and simplifying profile management. --- ...eCustomerProfileFromTransactionRequest.php | 50 +++++++ src/DataTypes/HostedPaymentSettings.php | 20 +++ src/DataTypes/Setting.php | 37 +++++ src/GetCustomerProfileRequest.php | 14 +- src/GetHostedPaymentPageRequest.php | 91 ++++++++++++ ...tomerProfileFromTransactionRequestTest.php | 135 ++++++++++++++++++ tests/CustomerProfileRequestTest.php | 1 + tests/DataType/HostedPaymentSettingsTest.php | 70 +++++++++ tests/GetHostedPaymentPageRequestTest.php | 89 ++++++++++++ 9 files changed, 506 insertions(+), 1 deletion(-) create mode 100644 src/CreateCustomerProfileFromTransactionRequest.php create mode 100644 src/DataTypes/HostedPaymentSettings.php create mode 100644 src/DataTypes/Setting.php create mode 100644 src/GetHostedPaymentPageRequest.php create mode 100644 tests/CustomerProfileFromTransactionRequestTest.php create mode 100644 tests/DataType/HostedPaymentSettingsTest.php create mode 100644 tests/GetHostedPaymentPageRequestTest.php diff --git a/src/CreateCustomerProfileFromTransactionRequest.php b/src/CreateCustomerProfileFromTransactionRequest.php new file mode 100644 index 0000000..3e4856d --- /dev/null +++ b/src/CreateCustomerProfileFromTransactionRequest.php @@ -0,0 +1,50 @@ +transId = $transId; + } + + /** + * {@inheritdoc} + */ + protected function attachData(RequestInterface $request) + { + $request->addData('transId', $this->transId); + } +} diff --git a/src/DataTypes/HostedPaymentSettings.php b/src/DataTypes/HostedPaymentSettings.php new file mode 100644 index 0000000..a02713f --- /dev/null +++ b/src/DataTypes/HostedPaymentSettings.php @@ -0,0 +1,20 @@ +properties[] = ['setting' => $setting->toArray()]; + } +} diff --git a/src/DataTypes/Setting.php b/src/DataTypes/Setting.php new file mode 100644 index 0000000..5fdc528 --- /dev/null +++ b/src/DataTypes/Setting.php @@ -0,0 +1,37 @@ +properties['settingName'] = $name; + // Encode the value. + if (is_array($value)) { + $value = json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT); + } + $this->properties['settingValue'] = $value; + } + +} diff --git a/src/GetCustomerProfileRequest.php b/src/GetCustomerProfileRequest.php index 91d4783..5faa48d 100644 --- a/src/GetCustomerProfileRequest.php +++ b/src/GetCustomerProfileRequest.php @@ -13,6 +13,7 @@ class GetCustomerProfileRequest extends BaseApiRequest { protected $customerProfileId; + protected $unmaskExpirationDate = false; public function __construct( Configuration $configuration, @@ -23,8 +24,19 @@ public function __construct( $this->customerProfileId = $customerProfileId; } - protected function attachData(RequestInterface $request) + /** + * @param boolean $unmaskExpirationDate + */ + public function setUnmaskExpirationDate($unmaskExpirationDate) + { + $this->unmaskExpirationDate = $unmaskExpirationDate; + } + + protected function attachData(RequestInterface $request) { $request->addData('customerProfileId', $this->customerProfileId); + if ($this->unmaskExpirationDate) { + $request->addData('unmaskExpirationDate', $this->unmaskExpirationDate); + } } } diff --git a/src/GetHostedPaymentPageRequest.php b/src/GetHostedPaymentPageRequest.php new file mode 100644 index 0000000..cf35a7b --- /dev/null +++ b/src/GetHostedPaymentPageRequest.php @@ -0,0 +1,91 @@ +transactionRequest = $transactionRequest; + $this->hostedPaymentSettings = $hostedPaymentSettings; + } + + /** + * {@inheritdoc} + */ + protected function attachData(RequestInterface $request) + { + // Attach transaction details. + if ($this->transactionRequest) { + $request->addDataType($this->transactionRequest); + } + // Add hosted payment settings. + if ($this->hostedPaymentSettings) { + $request->addDataType($this->hostedPaymentSettings); + } + } + + /** + * Sets the transaction request. + * + * @param \CommerceGuys\AuthNet\DataTypes\TransactionRequest $transactionRequest + * The transaction details. + * + * @return $this + */ + public function setTransactionRequest(TransactionRequest $transactionRequest) + { + $this->transactionRequest = $transactionRequest; + return $this; + } + + /** + * Sets the hosted payment settings. + * + * @param \CommerceGuys\AuthNet\DataTypes\HostedPaymentSettings $hostedPaymentSettings + * + * @return $this + */ + public function setHostedPaymentSettings(HostedPaymentSettings $hostedPaymentSettings) + { + $this->hostedPaymentSettings = $hostedPaymentSettings; + return $this; + } +} diff --git a/tests/CustomerProfileFromTransactionRequestTest.php b/tests/CustomerProfileFromTransactionRequestTest.php new file mode 100644 index 0000000..c12dde4 --- /dev/null +++ b/tests/CustomerProfileFromTransactionRequestTest.php @@ -0,0 +1,135 @@ +createChargableTransactionRequest(TransactionRequest::AUTH_ONLY); + $transactionRequest->addData('customer', [ + 'email' => 'xml_test@example.com', + ]); + $transactionRequest->addData('billTo', [ + 'firstName' => 'Jane', + 'lastName' => 'Doe', + 'address' => '456 Elm St', + 'city' => 'Springfield', + 'state' => 'IL', + 'zip' => '62704', + 'country' => 'US', + 'phoneNumber' => '5555555555', + ]); + + $transactionResponse = $this->xmlRequestFactory + ->createTransactionRequest() + ->setTransactionRequest($transactionRequest) + ->execute(); + + $this->assertEquals('Ok', $transactionResponse->getResultCode()); + $transId = $transactionResponse->transactionResponse->transId ?? null; + + $this->assertNotEmpty($transId, 'Transaction ID should not be empty'); + + $request = new CreateCustomerProfileFromTransactionRequest( + $this->configurationXml, + $this->client, + $transId + ); + /** @var \CommerceGuys\AuthNet\Response\XmlResponse $response */ + $response = $request->execute(); + $contents = $response->contents(); + + $this->assertEquals('Ok', $response->getResultCode()); + $this->assertEquals('I00001', $response->getMessages()[0]->getCode()); + $this->assertEquals('Successful.', $response->getMessages()[0]->getText()); + + $this->assertTrue(property_exists($contents, 'customerProfileId')); + $this->assertNotEmpty($contents->customerProfileId); + + $this->assertListFieldContainsData($contents, 'customerPaymentProfileIdList'); + $this->assertListFieldContainsData($contents, 'customerShippingAddressIdList'); + + $this->assertTrue(property_exists($contents, 'validationDirectResponseList')); + $this->assertInstanceOf(\stdClass::class, $contents->validationDirectResponseList); + } + + /** + * Tests the request with JSON format. + */ + public function testCreateCustomerProfileFromTransactionJson() + { + // Use a new number, otherwise a duplicate transaction is flagged. + $transactionRequest = $this->createChargableTransactionRequest( + TransactionRequest::AUTH_ONLY, + '4007000000027' + ); + $transactionRequest->addData('customer', [ + 'email' => 'json_test@example.com', + ]); + $transactionRequest->addData('billTo', [ + 'firstName' => 'John', + 'lastName' => 'Smith', + 'address' => '789 Oak St', + 'city' => 'Columbus', + 'state' => 'OH', + 'zip' => '43004', + 'country' => 'US', + 'phoneNumber' => '5555555555', + ]); + // Create the transaction. + $transactionResponse = $this->jsonRequestFactory + ->createTransactionRequest() + ->setTransactionRequest($transactionRequest) + ->execute(); + + $this->assertEquals('Ok', $transactionResponse->getResultCode()); + $transId = $transactionResponse->transactionResponse->transId ?? null; + + $this->assertNotEmpty($transId, 'Transaction ID should not be empty'); + + // Create the customer profile from the transaction. + $request = new CreateCustomerProfileFromTransactionRequest( + $this->configurationJson, + $this->client, + $transId + ); + /** @var \CommerceGuys\AuthNet\Response\JsonResponse $response */ + $response = $request->execute(); + $contents = $response->contents(); + + $this->assertEquals('Ok', $response->getResultCode()); + $this->assertEquals('I00001', $response->getMessages()[0]->getCode()); + $this->assertEquals('Successful.', $response->getMessages()[0]->getText()); + + $this->assertTrue(property_exists($contents, 'customerProfileId')); + $this->assertNotEmpty($contents->customerProfileId); + + $this->assertIsArray($contents->customerPaymentProfileIdList); + $this->assertNotEmpty($contents->customerPaymentProfileIdList); + + $this->assertIsArray($contents->customerShippingAddressIdList); + $this->assertNotEmpty($contents->customerShippingAddressIdList); + + $this->assertIsArray($contents->validationDirectResponseList); + } + + /** + * Helper for handling list fields that return stdClass with numericString in XML. + */ + protected function assertListFieldContainsData($object, string $fieldName): void + { + $this->assertTrue(property_exists($object, $fieldName)); + $list = (array) $object->{$fieldName}; + $this->assertArrayHasKey('numericString', $list, "$fieldName must contain numericString key"); + $this->assertNotEmpty($list['numericString'], "$fieldName.numericString must not be empty"); + } +} diff --git a/tests/CustomerProfileRequestTest.php b/tests/CustomerProfileRequestTest.php index d40b28f..93925e8 100644 --- a/tests/CustomerProfileRequestTest.php +++ b/tests/CustomerProfileRequestTest.php @@ -59,6 +59,7 @@ public function testCreateCustomerProfileCRUDRequests() $this->assertTrue(isset($response->validationDirectResponseList)); $request = new GetCustomerProfileRequest($this->configurationXml, $this->client, $response->customerProfileId); + $request->setUnmaskExpirationDate(false); $response = $request->execute(); $this->assertResponse($response, 'I00001', 'Successful.', 'Ok'); $this->assertTrue(isset($response->profile)); diff --git a/tests/DataType/HostedPaymentSettingsTest.php b/tests/DataType/HostedPaymentSettingsTest.php new file mode 100644 index 0000000..c4a4bcc --- /dev/null +++ b/tests/DataType/HostedPaymentSettingsTest.php @@ -0,0 +1,70 @@ + false, + 'url' => 'https://example.com/return', + ]; + $settings = new HostedPaymentSettings(); + $settings->addSetting(new Setting($settingName, $settingValue)); + + $array = $settings->toArray(); + + $this->assertCount(1, $array); + $this->assertArrayHasKey('setting', $array[0]); + $this->assertEquals('hostedPaymentReturnOptions', $array[0]['setting']['settingName']); + + $expectedValue = json_encode($settingValue); + $this->assertJsonStringEqualsJsonString($expectedValue, $array[0]['setting']['settingValue']); + } + + /** + * Tests adding multiple settings. + */ + public function testAddMultipleSettings() + { + $settings = new HostedPaymentSettings(); + + $settings->addSetting(new Setting('hostedPaymentBillingAddressOptions', ['show' => false])); + $settings->addSetting(new Setting('hostedPaymentSecurityOptions', ['captcha' => true])); + + $array = $settings->toArray(); + + $this->assertCount(2, $array); + + $this->assertEquals('hostedPaymentBillingAddressOptions', $array[0]['setting']['settingName']); + $this->assertEquals(json_encode(['show' => false]), $array[0]['setting']['settingValue']); + + $this->assertEquals('hostedPaymentSecurityOptions', $array[1]['setting']['settingName']); + $this->assertEquals(json_encode(['captcha' => true]), $array[1]['setting']['settingValue']); + } + + /** + * Tests that a scalar string value does not get double-encoded. + */ + public function testScalarSettingValue() + { + $settings = new HostedPaymentSettings(); + $settings->addSetting(new Setting('customLabel', 'Some Value')); + + $array = $settings->toArray(); + + $this->assertEquals('Some Value', $array[0]['setting']['settingValue']); + } +} diff --git a/tests/GetHostedPaymentPageRequestTest.php b/tests/GetHostedPaymentPageRequestTest.php new file mode 100644 index 0000000..3cf475b --- /dev/null +++ b/tests/GetHostedPaymentPageRequestTest.php @@ -0,0 +1,89 @@ + TransactionRequest::AUTH_ONLY, + 'amount' => '50.00', + ]); + // Minimal hosted payment settings. + $hostedSettings = new HostedPaymentSettings(); + $hostedSettings->addSetting(new Setting('hostedPaymentReturnOptions', [ + 'showReceipt' => true, + 'url' => 'https://mysite.com/receipt', + 'urlText' => 'Continue', + 'cancelUrl' => 'https://mysite.com/cancel', + 'cancelUrlText' => 'Cancel', + ])); + $request = new GetHostedPaymentPageRequest( + $this->configurationXml, + $this->client, + $transactionRequest, + $hostedSettings + ); + + /** @var \CommerceGuys\AuthNet\Response\XmlResponse $response */ + $response = $request->execute(); + $contents = $response->contents(); + + $this->assertEquals('Ok', $response->getResultCode()); + $this->assertEquals('I00001', $response->getMessages()[0]->getCode()); + $this->assertEquals('Successful.', $response->getMessages()[0]->getText()); + + $this->assertTrue(property_exists($contents, 'token')); + $this->assertNotEmpty($contents->token); + } + + /** + * Tests the Accept Hosted request with JSON format. + */ + public function testGetHostedPaymentPageJson() + { + // Minimal valid transaction request for Accept Hosted. + $transactionRequest = new TransactionRequest([ + 'transactionType' => TransactionRequest::AUTH_CAPTURE, + 'amount' => '20.00', + ]); + // Minimal hosted payment settings. + $hostedSettings = new HostedPaymentSettings(); + $hostedSettings->addSetting(new Setting('hostedPaymentReturnOptions', [ + 'showReceipt' => true, + 'url' => 'https://mysite.com/receipt', + 'urlText' => 'Continue', + 'cancelUrl' => 'https://mysite.com/cancel', + 'cancelUrlText' => 'Cancel' + ])); + + $request = new GetHostedPaymentPageRequest( + $this->configurationJson, + $this->client + ); + $request->setTransactionRequest($transactionRequest); + $request->setHostedPaymentSettings($hostedSettings); + + /** @var \CommerceGuys\AuthNet\Response\JsonResponse $response */ + $response = $request->execute(); + $contents = $response->contents(); + + $this->assertEquals('Ok', $response->getResultCode()); + $this->assertEquals('I00001', $response->getMessages()[0]->getCode()); + $this->assertEquals('Successful.', $response->getMessages()[0]->getText()); + + $this->assertTrue(property_exists($contents, 'token')); + $this->assertNotEmpty($contents->token); + } +} From 97af9f83e0daa7b688b746ff48ec83984d7f7cb7 Mon Sep 17 00:00:00 2001 From: "Adrian M." Date: Mon, 7 Jul 2025 20:03:41 -0500 Subject: [PATCH 13/19] Fix ARB subscription test failure due to past startDate: - Updated hardcoded 'startDate' in ARBCreateSubscriptionRequestTest to use a dynamic future date (1 day ahead) instead of a fixed date. - This resolves the API error: E00017: Start Date must not occur before the submission date. --- tests/ARBCreateSubscriptionRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ARBCreateSubscriptionRequestTest.php b/tests/ARBCreateSubscriptionRequestTest.php index 5ced203..c1d6245 100644 --- a/tests/ARBCreateSubscriptionRequestTest.php +++ b/tests/ARBCreateSubscriptionRequestTest.php @@ -20,7 +20,7 @@ public function testARBCreateSubscriptionRequestCRUD() { $interval = new Interval(['length' => 7, 'unit' => 'days']); $paymentSchedule = new PaymentSchedule([ - 'startDate' => '2024-08-30', + 'startDate' => (new \DateTime('+1 day'))->format('Y-m-d'), 'totalOccurrences' => 9999, ]); $paymentSchedule->addInterval($interval); From 9a41157374cc90475065c62c2da2c270319c6525 Mon Sep 17 00:00:00 2001 From: "Adrian M." Date: Tue, 8 Jul 2025 17:53:17 -0500 Subject: [PATCH 14/19] Add AuthenticateTestRequest to validate API credentials - Introduced `AuthenticateTestRequest` class to support the `authenticateTestRequest` endpoint from Authorize.Net. - Allows verification of merchant API login and transaction key via the SDK. - Added `setMerchantAuthentication()` and `getMerchantAuthentication()` methods for credential injection. - Includes full test coverage with `AuthenticateTestRequestTest` for both XML and JSON request formats. --- src/AuthenticateTestRequest.php | 54 ++++++++++++++++++++++++++ tests/AuthenticateRequestTest.php | 63 +++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/AuthenticateTestRequest.php create mode 100644 tests/AuthenticateRequestTest.php diff --git a/src/AuthenticateTestRequest.php b/src/AuthenticateTestRequest.php new file mode 100644 index 0000000..63a023f --- /dev/null +++ b/src/AuthenticateTestRequest.php @@ -0,0 +1,54 @@ +merchantAuthentication = $merchantAuthentication; + return $this; + } + + /** + * Gets the merchant authentication credentials. + * + * @return \CommerceGuys\AuthNet\DataTypes\MerchantAuthentication|null + */ + public function getMerchantAuthentication(): ?MerchantAuthentication + { + return $this->merchantAuthentication; + } + + /** + * {@inheritdoc} + */ + protected function attachData(RequestInterface $request): void + { + // Only attach merchant authentication if available. + if ($this->merchantAuthentication) { + $request->addDataType($this->merchantAuthentication); + } + } +} diff --git a/tests/AuthenticateRequestTest.php b/tests/AuthenticateRequestTest.php new file mode 100644 index 0000000..a0fa46c --- /dev/null +++ b/tests/AuthenticateRequestTest.php @@ -0,0 +1,63 @@ +configurationXml, + $this->client + ); + + // Explicitly set authentication in case configuration does not preload it. + $request->setMerchantAuthentication(new MerchantAuthentication([ + 'name' => $this->configurationXml->getApiLogin(), + 'transactionKey' => $this->configurationXml->getTransactionKey(), + ])); + + /** @var \CommerceGuys\AuthNet\Response\XmlResponse $response */ + $response = $request->execute(); + + $this->assertEquals('Ok', $response->getResultCode()); + $this->assertEquals('I00001', $response->getMessages()[0]->getCode()); + $this->assertEquals('Successful.', $response->getMessages()[0]->getText()); + } + + /** + * Tests the authenticateTestRequest using JSON format. + */ + public function testAuthenticateTestJson(): void + { + $request = new AuthenticateTestRequest( + $this->configurationJson, + $this->client + ); + + $request->setMerchantAuthentication(new MerchantAuthentication([ + 'name' => $this->configurationJson->getApiLogin(), + 'transactionKey' => $this->configurationJson->getTransactionKey(), + ])); + + /** @var \CommerceGuys\AuthNet\Response\JsonResponse $response */ + $response = $request->execute(); + + $this->assertEquals('Ok', $response->getResultCode()); + $this->assertEquals('I00001', $response->getMessages()[0]->getCode()); + $this->assertEquals('Successful.', $response->getMessages()[0]->getText()); + } +} From 1c8fd458fcc76911286538ad8b3c96fdc059a6f1 Mon Sep 17 00:00:00 2001 From: "Adrian M." Date: Wed, 22 Oct 2025 08:18:38 -0500 Subject: [PATCH 15/19] Add method to remove settings from HostedPaymentSettings Introduces the removeSetting() method to allow removing a specific hosted payment configuration setting by name. Iterates through existing properties and unsets the matching entry based on 'settingName'. --- src/DataTypes/HostedPaymentSettings.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/DataTypes/HostedPaymentSettings.php b/src/DataTypes/HostedPaymentSettings.php index a02713f..04d55f6 100644 --- a/src/DataTypes/HostedPaymentSettings.php +++ b/src/DataTypes/HostedPaymentSettings.php @@ -17,4 +17,18 @@ public function addSetting(Setting $setting): void { $this->properties[] = ['setting' => $setting->toArray()]; } + + /** + * Removes setting from the hosted payment configuration. + * + * @param string $name + */ + public function removeSetting(string $name): void + { + foreach ($this->properties as $key => $property) { + if ($property['setting']['settingName'] == $name) { + unset($this->properties[$key]); + } + } + } } From 7c5ce9cbd32369edbdced133907d982c9f369376 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 23 Oct 2025 14:48:19 +0300 Subject: [PATCH 16/19] Stop testing PHP 7.3 and test newer PHP versions. --- .github/workflows/build.yml | 60 ++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c81f1c3..90ac8db 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,36 +2,36 @@ name: Build on: [push, pull_request] jobs: - run-test-php73: + run-test-php81: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install dependencies uses: php-actions/composer@v6 with: - php_version: "7.3" + php_version: "8.1" - - name: PHPUnit Tests PHP 7.3 + - name: PHPUnit Tests PHP 78.1 uses: php-actions/phpunit@master with: bootstrap: vendor/autoload.php configuration: phpunit.xml.dist args: --coverage-text php_extensions: xdebug - php_version: 7.3 + php_version: 8.1 memory_limit: "192M" version: 9 env: XDEBUG_MODE: coverage - run-test-php81: + run-test-php82: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install dependencies uses: php-actions/composer@v6 with: - php_version: "8.1" + php_version: "8.2" - name: PHPUnit Tests PHP 78.1 uses: php-actions/phpunit@master @@ -40,8 +40,52 @@ jobs: configuration: phpunit.xml.dist args: --coverage-text php_extensions: xdebug - php_version: 8.1 + php_version: 8.2 + memory_limit: "192M" + version: 9 + env: + XDEBUG_MODE: coverage + + run-test-php83: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + uses: php-actions/composer@v6 + with: + php_version: "8.3" + + - name: PHPUnit Tests PHP 78.1 + uses: php-actions/phpunit@master + with: + bootstrap: vendor/autoload.php + configuration: phpunit.xml.dist + args: --coverage-text + php_extensions: xdebug + php_version: 8.3 memory_limit: "192M" version: 9 env: - XDEBUG_MODE: coverage \ No newline at end of file + XDEBUG_MODE: coverage + + run-test-php84: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + uses: php-actions/composer@v6 + with: + php_version: "8.4" + + - name: PHPUnit Tests PHP 78.1 + uses: php-actions/phpunit@master + with: + bootstrap: vendor/autoload.php + configuration: phpunit.xml.dist + args: --coverage-text + php_extensions: xdebug + php_version: 8.4 + memory_limit: "192M" + version: 9 + env: + XDEBUG_MODE: coverage From e819096bb8a18430bd0cbd55e24b6052d397abd8 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 23 Oct 2025 14:54:10 +0300 Subject: [PATCH 17/19] Update .scrutinizer.yml --- .scrutinizer.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 0b80d59..5a81b76 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -16,6 +16,9 @@ filter: build: nodes: analysis: + environment: + php: + version: 8.3 tests: override: - php-scrutinizer-run From 59f1fd185dcffb4965fbbbed07264cf9a85cf6ed Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 23 Oct 2025 14:56:00 +0300 Subject: [PATCH 18/19] Change PHP version from 8.3 to 8.2 --- .scrutinizer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 5a81b76..5440f7a 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -18,7 +18,7 @@ build: analysis: environment: php: - version: 8.3 + version: 8.2 tests: override: - php-scrutinizer-run From d0aa6087e103b53b9c65c7a7867e92f824b53df8 Mon Sep 17 00:00:00 2001 From: Jonathan Sacksick Date: Thu, 23 Oct 2025 15:00:53 +0300 Subject: [PATCH 19/19] Implicitly marking parameter as nullable is deprecated. --- src/ARBCreateSubscriptionRequest.php | 2 +- src/CreateCustomerProfileRequest.php | 2 +- src/CreateTransactionRequest.php | 2 +- src/DecryptPaymentDataRequest.php | 2 +- src/GetHostedPaymentPageRequest.php | 4 ++-- src/UpdateCustomerProfileRequest.php | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ARBCreateSubscriptionRequest.php b/src/ARBCreateSubscriptionRequest.php index ca7340f..3b1993e 100644 --- a/src/ARBCreateSubscriptionRequest.php +++ b/src/ARBCreateSubscriptionRequest.php @@ -16,7 +16,7 @@ class ARBCreateSubscriptionRequest extends ARBSubscriptionRequest public function __construct( Configuration $configuration, Client $client, - Subscription $subscription = null + ?Subscription $subscription = null ) { parent::__construct($configuration, $client); $this->subscription = $subscription; diff --git a/src/CreateCustomerProfileRequest.php b/src/CreateCustomerProfileRequest.php index a6e00f4..8c17a90 100644 --- a/src/CreateCustomerProfileRequest.php +++ b/src/CreateCustomerProfileRequest.php @@ -19,7 +19,7 @@ class CreateCustomerProfileRequest extends BaseApiRequest public function __construct( Configuration $configuration, Client $client, - Profile $profile = null + ?Profile $profile = null ) { parent::__construct($configuration, $client); $this->profile = $profile; diff --git a/src/CreateTransactionRequest.php b/src/CreateTransactionRequest.php index 6c6e011..2032362 100644 --- a/src/CreateTransactionRequest.php +++ b/src/CreateTransactionRequest.php @@ -18,7 +18,7 @@ class CreateTransactionRequest extends BaseApiRequest public function __construct( Configuration $configuration, Client $client, - TransactionRequest $transactionRequest = null + ?TransactionRequest $transactionRequest = null ) { parent::__construct($configuration, $client); $this->transactionRequest = $transactionRequest; diff --git a/src/DecryptPaymentDataRequest.php b/src/DecryptPaymentDataRequest.php index 401b947..0abe570 100644 --- a/src/DecryptPaymentDataRequest.php +++ b/src/DecryptPaymentDataRequest.php @@ -20,7 +20,7 @@ class DecryptPaymentDataRequest extends BaseApiRequest public function __construct( Configuration $configuration, Client $client, - OpaqueData $opaqueData = null, + ?OpaqueData $opaqueData = null, $refId, $callId ) { diff --git a/src/GetHostedPaymentPageRequest.php b/src/GetHostedPaymentPageRequest.php index cf35a7b..70a77e9 100644 --- a/src/GetHostedPaymentPageRequest.php +++ b/src/GetHostedPaymentPageRequest.php @@ -39,8 +39,8 @@ class GetHostedPaymentPageRequest extends BaseApiRequest public function __construct( Configuration $configuration, Client $client, - TransactionRequest $transactionRequest = null, - HostedPaymentSettings $hostedPaymentSettings = null + ?TransactionRequest $transactionRequest = null, + ?HostedPaymentSettings $hostedPaymentSettings = null ) { parent::__construct($configuration, $client); $this->transactionRequest = $transactionRequest; diff --git a/src/UpdateCustomerProfileRequest.php b/src/UpdateCustomerProfileRequest.php index 7f376cb..0e17ce8 100644 --- a/src/UpdateCustomerProfileRequest.php +++ b/src/UpdateCustomerProfileRequest.php @@ -18,7 +18,7 @@ class UpdateCustomerProfileRequest extends BaseApiRequest public function __construct( Configuration $configuration, Client $client, - Profile $profile = null + ?Profile $profile = null ) { parent::__construct($configuration, $client); $this->profile = $profile;