diff --git a/captainhook.json b/captainhook.json index c32c88e..861398d 100644 --- a/captainhook.json +++ b/captainhook.json @@ -19,7 +19,7 @@ } }, { - "action": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff", + "action": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --diff", "options": {} } ], diff --git a/composer.json b/composer.json index f5a613c..4117c75 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": "^7.4", + "php": ">=7.4", "payplug/payplug-php": "^4.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 2f79b53..aa1de2d 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": "0a4398cc6e87cedea47d0efd7031f4aa", + "content-hash": "31a08bc92d7c7c5d4662a29094eccd62", "packages": [ { "name": "payplug/payplug-php", @@ -1153,11 +1153,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.2.2", + "version": "2.2.3", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5cc34d491a90e79c216d824f60fe21fd4d93bd6", - "reference": "e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4048833dd47b377287818841877fb3087289509c", + "reference": "4048833dd47b377287818841877fb3087289509c", "shasum": "" }, "require": { @@ -1213,7 +1213,7 @@ "type": "github" } ], - "time": "2026-06-05T09:00:01+00:00" + "time": "2026-06-30T21:15:26+00:00" }, { "name": "phpstan/phpstan-mockery", @@ -1266,21 +1266,22 @@ }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.16", + "version": "2.0.17", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32" + "reference": "c2f977551f0736d60467b3d754b2e0cf4e337b3f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6ab598e1bc106e6827fd346ae4a12b4a5d634c32", - "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/c2f977551f0736d60467b3d754b2e0cf4e337b3f", + "reference": "c2f977551f0736d60467b3d754b2e0cf4e337b3f", "shasum": "" }, "require": { + "phar-io/version": "^3.2", "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.1.32" + "phpstan/phpstan": "^2.2.3" }, "conflict": { "phpunit/phpunit": "<7.0" @@ -1290,7 +1291,8 @@ "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/phpstan-deprecation-rules": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6" + "phpunit/phpunit": "^9.6", + "shipmonk/name-collision-detector": "^2.1" }, "type": "phpstan-extension", "extra": { @@ -1316,9 +1318,9 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.16" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.17" }, - "time": "2026-02-14T09:05:21+00:00" + "time": "2026-06-29T05:32:23+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5148,12 +5150,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.4" + "php": ">=7.4" }, - "platform-dev": {}, - "plugin-api-version": "2.9.0" + "platform-dev": [], + "plugin-api-version": "2.2.0" } diff --git a/phpstan.neon b/phpstan.neon index 656a6d0..04ca573 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,5 +7,6 @@ parameters: paths: - src - tests - ignoreErrors: - - '#Access to an undefined property Payplug\\Resource\\Payment::\$#' + stubFiles: + - stubs/PayplugPayment.stub + treatPhpDocTypesAsCertain: false diff --git a/src/Actions/PaymentAction.php b/src/Actions/PaymentAction.php index d5e7908..11fe3cc 100644 --- a/src/Actions/PaymentAction.php +++ b/src/Actions/PaymentAction.php @@ -81,7 +81,7 @@ public function refundAction(RefundInputDTO $refund_inputDTO): ?RefundOutputDTO $validator = new PaymentResourceValidator(); $validator->validate($resource); $validator->validateIsPaid($resource); - $resource_id = $resource->id; + $resource_id = (string) $resource->id; // Format the attributes for the refund request $refund_gateway = $this->get_refund_gateway(); @@ -94,6 +94,20 @@ public function refundAction(RefundInputDTO $refund_inputDTO): ?RefundOutputDTO return RefundOutputDTO::create($refund); } + /** + * @param string $resource_id + * @param string $api_bearer + * + * @return ?PaymentOutputDTO + * @throws \Exception + */ + public function retrieveAction(string $resource_id, string $api_bearer): ?PaymentOutputDTO + { + $resource = $this->get_api()->load($api_bearer)->retrievePaymentResource($resource_id); + + return PaymentOutputDTO::create($resource); + } + public function get_payment_gateway(): PaymentGatewayManager { return new PaymentGatewayManager(); diff --git a/src/Utilities/Services/Api.php b/src/Utilities/Services/Api.php index bcaa6f3..17f0ab5 100644 --- a/src/Utilities/Services/Api.php +++ b/src/Utilities/Services/Api.php @@ -73,6 +73,34 @@ public function refundPaymentResource(string $resource_id, array $datas): array return $response; } + /** + * @param string $resource_id + * @return array + */ + public function retrievePaymentResource(string $resource_id): array + { + try { + if (null === $this->payplug_api) { + throw new \RuntimeException('API Payplug must be initialized.'); + } + $response = [ + 'code' => 200, + 'message' => 'OK', + 'resource' => Payment::retrieve($resource_id, $this->payplug_api), + 'result' => true, + ]; + } catch (\Exception $e) { + $response = [ + 'code' => $e->getCode(), + 'message' => $e->getMessage(), + 'resource' => null, + 'result' => false, + ]; + } + + return $response; + } + public function getBearerToken(): string { return $this->bearer_token; diff --git a/stubs/PayplugPayment.stub b/stubs/PayplugPayment.stub new file mode 100644 index 0000000..0178171 --- /dev/null +++ b/stubs/PayplugPayment.stub @@ -0,0 +1,66 @@ +action = Mockery::mock(PaymentAction::class, [])->makePartial(); + $this->payment_api = \Mockery::mock('alias:Payplug\Payment'); + } + + public function tearDown(): void + { + Mockery::close(); + } + + public function testWhenResourceCantBeRetrieved(): void + { + $error_msg = 'An error occurred during the process'; + $error_code = 500; + $this->payment_api + ->shouldReceive('retrieve') + ->once() + ->andThrow(new \Exception($error_msg, $error_code)); + + $error_output_props = [ + 'code' => $error_code, + 'message' => $error_msg, + 'result' => false, + 'resource' => null, + ]; + $this->assertEquals( + PaymentOutputDTOMock::get($error_output_props), + $this->action->retrieveAction('pay_5iHMDxy4ABR4YBVW4UscIn', 'sk_test_bearer_token') + ); + } + + public function testWhenResourceIsRetrieved(): void + { + $resource = PaymentMock::getStandard(['is_paid' => true]); + $this->payment_api + ->shouldReceive('retrieve') + ->once() + ->andReturn($resource); + + $this->assertEquals( + PaymentOutputDTOMock::get(['resource' => $resource]), + $this->action->retrieveAction('pay_5iHMDxy4ABR4YBVW4UscIn', 'sk_test_bearer_token') + ); + } +} diff --git a/tests/Units/Actions/PaymentAction/retrieveActionTest.php b/tests/Units/Actions/PaymentAction/retrieveActionTest.php new file mode 100644 index 0000000..f615f42 --- /dev/null +++ b/tests/Units/Actions/PaymentAction/retrieveActionTest.php @@ -0,0 +1,105 @@ +api = \Mockery::mock(Api::class); + $this->action->shouldReceive('get_api') + ->andReturn($this->api); + + $this->api_service = \Mockery::mock(Api::class); + } + + public function testWhenApiServiceLoadingThrowsException(): void + { + $exception_msg = 'Payplug API can\'t be initialized.'; + $this->api + ->shouldReceive('load') + ->once() + ->with(self::API_BEARER) + ->andThrow(new \Exception($exception_msg)); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage($exception_msg); + $this->action->retrieveAction(self::RESOURCE_ID, self::API_BEARER); + } + + public function testWhenPaymentResourceCantBeRetrieved(): void + { + $this->api + ->shouldReceive('load') + ->once() + ->with(self::API_BEARER) + ->andReturn($this->api_service); + + $api_return = [ + 'code' => 404, + 'message' => 'Payment not found.', + 'resource' => null, + 'result' => false, + ]; + $this->api_service + ->shouldReceive('retrievePaymentResource') + ->once() + ->with(self::RESOURCE_ID) + ->andReturn($api_return); + + $this->assertEquals( + PaymentOutputDTOMock::get($api_return), + $this->action->retrieveAction(self::RESOURCE_ID, self::API_BEARER) + ); + } + + public function testWhenPaymentOutputDTOIsReturnedWithSuccess(): void + { + $this->api + ->shouldReceive('load') + ->once() + ->with(self::API_BEARER) + ->andReturn($this->api_service); + + $payment = PaymentMock::getStandard(['is_paid' => true]); + $api_return = [ + 'code' => 200, + 'message' => 'OK', + 'resource' => $payment, + 'result' => true, + ]; + $this->api_service + ->shouldReceive('retrievePaymentResource') + ->once() + ->with(self::RESOURCE_ID) + ->andReturn($api_return); + + $this->assertEquals( + PaymentOutputDTOMock::get(['resource' => $payment]), + $this->action->retrieveAction(self::RESOURCE_ID, self::API_BEARER) + ); + } +}