diff --git a/.gitignore b/.gitignore index aa9bf3d2..b36c5239 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,8 @@ composer.phar .phpunit.result.cache test/unit/_html -PrivateKey.key \ No newline at end of file +PrivateKey.key +BitPay.config.json +**/BitPay.config.json +BitPay.config.yml +**/BitPay.config.yml \ No newline at end of file diff --git a/composer.json b/composer.json index c5b9dc6b..300e046a 100644 --- a/composer.json +++ b/composer.json @@ -16,10 +16,10 @@ "ext-json": "*", "ext-reflection": "*", "bitpay/key-utils": "^2.1", - "guzzlehttp/guzzle": "^7.0", - "symfony/yaml": "^5.0 || ^6.0 || ^7.0", + "guzzlehttp/guzzle": "^7.9", + "symfony/yaml": "^5.4 || ^6.4 || ^7.0", "netresearch/jsonmapper": "^5.0", - "symfony/console": "^4.4 || ^5.4 || ^6.0" + "symfony/console": "^4.4 || ^5.4 || ^6.4" }, "authors": [ { @@ -28,7 +28,8 @@ } ], "require-dev": { - "phpunit/phpunit": "^10.5 || ^11.5 || ^12.0" + "phpunit/phpunit": "^10.5 || ^11.5 || ^12.0", + "squizlabs/php_codesniffer": "^3.13" }, "scripts": { "setup": [ @@ -47,4 +48,4 @@ "BitPaySDK\\Functional\\": "test/functional/BitPaySDK" } } -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index d36711db..d0ceeeb7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "af9f627d574f3f90e7c50bb876010dec", + "content-hash": "196bfb0a01807670ed28b1127c96190d", "packages": [ { "name": "bitpay/key-utils", @@ -1415,16 +1415,16 @@ "packages-dev": [ { "name": "myclabs/deep-copy", - "version": "1.13.0", + "version": "1.13.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", "shasum": "" }, "require": { @@ -1463,7 +1463,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" }, "funding": [ { @@ -1471,20 +1471,20 @@ "type": "tidelift" } ], - "time": "2025-02-12T12:17:51+00:00" + "time": "2025-07-05T12:25:42+00:00" }, { "name": "nikic/php-parser", - "version": "v5.4.0", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", "shasum": "" }, "require": { @@ -1527,9 +1527,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-07-27T20:03:57+00:00" }, { "name": "phar-io/manifest", @@ -1972,16 +1972,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.45", + "version": "10.5.48", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" + "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e0a2bc39f6fae7617989d690d76c48e6d2eb541", + "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541", "shasum": "" }, "require": { @@ -1991,7 +1991,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.1", + "myclabs/deep-copy": "^1.13.3", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.1", @@ -2053,7 +2053,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.48" }, "funding": [ { @@ -2064,12 +2064,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2025-02-06T16:08:12+00:00" + "time": "2025-07-11T04:07:17+00:00" }, { "name": "sebastian/cli-parser", @@ -2987,6 +2995,90 @@ ], "time": "2023-02-07T11:34:05+00:00" }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.13.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-06-17T22:17:01+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.3", @@ -3040,7 +3132,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -3048,6 +3140,6 @@ "ext-json": "*", "ext-reflection": "*" }, - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/ruleset.xml b/ruleset.xml index d510f668..c34779fd 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -2,4 +2,8 @@ BitPay coding standard, based on PSR-12, temporarily excluding some rules. + */vendor/* + */node_modules/* + *.css + *.js diff --git a/test/functional/BitPaySDK/AbstractClientTestCase.php b/test/functional/BitPaySDK/AbstractClientTestCase.php index 2bdf85e7..932dd03c 100644 --- a/test/functional/BitPaySDK/AbstractClientTestCase.php +++ b/test/functional/BitPaySDK/AbstractClientTestCase.php @@ -12,13 +12,36 @@ abstract class AbstractClientTestCase extends TestCase { protected Client $client; + // Default delay in seconds between API calls + private const API_CALL_DELAY = 0.5; + private static $lastApiCallTime = 0; + /** * @throws BitPayGenericException */ public function setUp(): void { + // Add delay to respect rate limits + $this->respectRateLimit(); + $this->client = Client::createWithFile( Config::FUNCTIONAL_TEST_PATH . DIRECTORY_SEPARATOR . Config::BITPAY_CONFIG_FILE ); } + + /** + * Delays execution if needed to respect rate limits + */ + protected function respectRateLimit(): void + { + $currentTime = microtime(true); + $timeSinceLastCall = $currentTime - self::$lastApiCallTime; + + if (self::$lastApiCallTime > 0 && $timeSinceLastCall < self::API_CALL_DELAY) { + $sleepTime = (self::API_CALL_DELAY - $timeSinceLastCall); + usleep((int)($sleepTime * 1000000)); // Convert to microseconds + } + + self::$lastApiCallTime = microtime(true); + } } diff --git a/test/functional/BitPaySDK/SettlementsClientTest.php b/test/functional/BitPaySDK/SettlementsClientTest.php index ce08eebc..12d510df 100644 --- a/test/functional/BitPaySDK/SettlementsClientTest.php +++ b/test/functional/BitPaySDK/SettlementsClientTest.php @@ -34,6 +34,17 @@ public function testGetSettlement(): void $settlements = $this->client->getSettlements($currency, $dateStart, $dateEnd, $status); + // Skip test if no settlements exist + if (empty($settlements)) { + error_log(PHP_EOL . 'No settlements found in test account. ' . + 'Skipping test. To test this functionality, ensure your test account has processed transactions.'); + $this->markTestSkipped( + 'No settlements found in test account. ' . + 'To test this functionality, ensure your test account has processed transactions.' + ); + return; + } + $settlement = $this->client->getSettlement($settlements[0]->getId()); self::assertNotNull($settlement); @@ -50,12 +61,25 @@ public function testGetReconciliationReport(): void $currency = 'USD'; $settlements = $this->client->getSettlements($currency, $dateStart, $dateEnd, $status); + + if (empty($settlements)) { + error_log( PHP_EOL . 'No settlements found in test account. ' . + 'Skipping test. To test this functionality, ensure your test account has processed transactions. + '); + $this->markTestSkipped( + 'No settlements found in test account. ' . + 'To test this functionality, ensure your test account has processed transactions.' + ); + return; + } + $settlement = $this->client->getSettlement($settlements[0]->getId()); - $settlement = $this->client->getSettlementReconciliationReport($settlement); + $settlementId = $settlement->getId(); + $token = $settlement->getToken(); + $reconciliationReport = $this->client->getSettlementReconciliationReport($settlementId, $token); - self::assertEquals('processing', $settlement->getStatus()); - self::assertNotNull($settlement); - self::assertEquals('USD', $settlement->getCurrency()); - self::assertEquals($status, $settlement->getStatus()); + self::assertNotNull($reconciliationReport); + self::assertEquals($currency, $reconciliationReport->getCurrency()); + self::assertEquals($status, $reconciliationReport->getStatus()); } }