diff --git a/src/Client.php b/src/Client.php index 47c003e..e0e9ce7 100644 --- a/src/Client.php +++ b/src/Client.php @@ -139,7 +139,7 @@ public function transferCash(TransactionInterface $transaction): TransferCashRes return new TransferCashResponse($response); } - public function cashStatus(string $transactionId, string $country): TransferCashStatusResponse + public function transferCashStatus(string $transactionId): TransferCashStatusResponse { $options = [ \GuzzleHttp\RequestOptions::HEADERS => [ @@ -150,7 +150,7 @@ public function cashStatus(string $transactionId, string $country): TransferCash 'agent_msisdn' => $this->config->getAgentMsisdn(), 'agent_pin' => $this->config->getAgentPin(), 'transaction_id' => $transactionId, - 'country' => $country, + 'country' => $this->config->getCountry(), ], ]; diff --git a/src/Responses/TransferCashStatusResponse.php b/src/Responses/TransferCashStatusResponse.php index 900f7a7..cef07cc 100644 --- a/src/Responses/TransferCashStatusResponse.php +++ b/src/Responses/TransferCashStatusResponse.php @@ -14,6 +14,9 @@ */ class TransferCashStatusResponse extends JsonResponse { + public ?string $code; + public ?string $error; + #[MapFrom('TokenStatus')] public ?string $status; diff --git a/tests/FetchAuthTokenRawTest.php b/tests/FetchAuthTokenRawTest.php new file mode 100644 index 0000000..78c6cf0 --- /dev/null +++ b/tests/FetchAuthTokenRawTest.php @@ -0,0 +1,76 @@ +. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +namespace BrokeYourBike\Wizall\Tests; + +use Psr\SimpleCache\CacheInterface; +use Psr\Http\Message\ResponseInterface; +use BrokeYourBike\Wizall\Responses\TokenResponse; +use BrokeYourBike\Wizall\Interfaces\ConfigInterface; +use BrokeYourBike\Wizall\Client; + +/** + * @author Ivan Stasiuk + */ +class FetchAuthTokenRawTest extends TestCase +{ + /** @test */ + public function it_can_prepare_request(): void + { + $mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock(); + $mockedConfig->method('getUrl')->willReturn('https://auth.example/'); + $mockedConfig->method('getClientId')->willReturn('client-id'); + $mockedConfig->method('getClientSecret')->willReturn('super-secret-value'); + $mockedConfig->method('getUsername')->willReturn('john'); + $mockedConfig->method('getPassword')->willReturn('p@ssword'); + $mockedConfig->method('getCountry')->willReturn('SN'); + + $mockedResponse = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mockedResponse->method('getStatusCode')->willReturn(200); + $mockedResponse->method('getBody') + ->willReturn('{ + "access_token": "token123", + "expires_in": 86400, + "token_type": "Bearer", + "country": "SN" + }'); + + /** @var \Mockery\MockInterface $mockedClient */ + $mockedClient = \Mockery::mock(\GuzzleHttp\Client::class); + $mockedClient->shouldReceive('request')->withArgs([ + 'POST', + 'https://auth.example/token/', + [ + \GuzzleHttp\RequestOptions::HEADERS => [ + 'Accept' => 'application/json', + ], + \GuzzleHttp\RequestOptions::JSON => [ + 'grant_type' => 'password', + 'country' => 'SN', + 'client_id' => 'client-id', + 'client_secret' => 'super-secret-value', + 'client_type' => 'client_type', + 'username' => 'john', + 'password' => 'p@ssword', + ], + ], + ])->once()->andReturn($mockedResponse); + + $mockedCache = $this->getMockBuilder(CacheInterface::class)->getMock(); + + /** + * @var ConfigInterface $mockedConfig + * @var \GuzzleHttp\Client $mockedClient + * @var CacheInterface $mockedCache + * */ + $api = new Client($mockedConfig, $mockedClient, $mockedCache); + $requestResult = $api->fetchAuthTokenRaw(); + + $this->assertInstanceOf(TokenResponse::class, $requestResult); + $this->assertEquals('token123', $requestResult->access_token); + $this->assertEquals(86400, $requestResult->expires_in); + } +} \ No newline at end of file diff --git a/tests/GetAuthTokenTest.php b/tests/GetAuthTokenTest.php new file mode 100644 index 0000000..5664a37 --- /dev/null +++ b/tests/GetAuthTokenTest.php @@ -0,0 +1,89 @@ +. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +namespace BrokeYourBike\Wizall\Tests; + +use Psr\SimpleCache\CacheInterface; +use Psr\Http\Message\ResponseInterface; +use BrokeYourBike\Wizall\Interfaces\ConfigInterface; +use BrokeYourBike\Wizall\Client; + +/** + * @author Ivan Stasiuk + */ +class GetAuthTokenTest extends TestCase +{ + private string $tokenValue = 'super-secure-token'; + + /** @test */ + public function it_can_cache_and_return_auth_token() + { + $mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock(); + + $mockedResponse = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mockedResponse->method('getStatusCode')->willReturn(200); + $mockedResponse->method('getBody') + ->willReturn('{ + "expires_in": "3600", + "access_token": "' . $this->tokenValue . '" + }'); + + /** @var \GuzzleHttp\Client $mockedClient */ + $mockedClient = $this->createPartialMock(\GuzzleHttp\Client::class, ['request']); + $mockedClient->method('request')->willReturn($mockedResponse); + + /** @var \Mockery\MockInterface $mockedCache */ + $mockedCache = \Mockery::spy(CacheInterface::class); + + /** + * @var ConfigInterface $mockedConfig + * @var \GuzzleHttp\Client $mockedClient + * @var CacheInterface $mockedCache + * */ + $api = new Client($mockedConfig, $mockedClient, $mockedCache); + $requestResult = $api->getAuthToken(); + + $this->assertSame($this->tokenValue, $requestResult); + + /** @var \Mockery\MockInterface $mockedCache */ + $mockedCache->shouldHaveReceived('set') + ->once() + ->with( + $api->authTokenCacheKey(), + $this->tokenValue, + 1800 + ); + } + + /** @test */ + public function it_can_return_cached_value() + { + $mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock(); + + /** @var \Mockery\MockInterface $mockedClient */ + $mockedClient = \Mockery::mock(\GuzzleHttp\Client::class); + $mockedClient->shouldNotReceive('request'); + + /** @var \Mockery\MockInterface $mockedCache */ + $mockedCache = \Mockery::mock(CacheInterface::class); + $mockedCache->shouldReceive('has') + ->once() + ->andReturn(true); + $mockedCache->shouldReceive('get') + ->once() + ->andReturn($this->tokenValue); + + /** + * @var ConfigInterface $mockedConfig + * @var \GuzzleHttp\Client $mockedClient + * @var CacheInterface $mockedCache + * */ + $api = new Client($mockedConfig, $mockedClient, $mockedCache); + $requestResult = $api->getAuthToken(); + + $this->assertSame($this->tokenValue, $requestResult); + } +} \ No newline at end of file diff --git a/tests/TransferCashStatusTest.php b/tests/TransferCashStatusTest.php new file mode 100644 index 0000000..4c13e82 --- /dev/null +++ b/tests/TransferCashStatusTest.php @@ -0,0 +1,113 @@ +. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +namespace BrokeYourBike\Wizall\Tests; + +use Psr\SimpleCache\CacheInterface; +use Psr\Http\Message\ResponseInterface; +use BrokeYourBike\Wizall\Responses\TransferCashStatusResponse; +use BrokeYourBike\Wizall\Responses\TransferCashResponse; +use BrokeYourBike\Wizall\Interfaces\TransactionInterface; +use BrokeYourBike\Wizall\Interfaces\ConfigInterface; +use BrokeYourBike\Wizall\Enums\TransactionStatusEnum; +use BrokeYourBike\Wizall\Client; + +/** + * @author Ivan Stasiuk + */ +class TransferCashStatusTest extends TestCase +{ + /** @test */ + public function it_can_prepare_request(): void + { + $transaction = $this->getMockBuilder(TransactionInterface::class)->getMock(); + + /** @var TransactionInterface $transaction */ + $this->assertInstanceOf(TransactionInterface::class, $transaction); + + $mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock(); + $mockedConfig->method('getUrl')->willReturn('https://api.example/'); + $mockedConfig->method('getAgentMsisdn')->willReturn('123456789'); + $mockedConfig->method('getAgentPin')->willReturn('0088'); + + $mockedResponse = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mockedResponse->method('getStatusCode')->willReturn(200); + $mockedResponse->method('getBody') + ->willReturn('{ + "Operation": "Check_status_bon_cash", + "transactionid": "274126155", + "SenderPhone": "0182491234", + "Amount": "100.000000", + "ReedemWalletType": "", + "ReedemTransactionID": "", + "ReedemPhone": "", + "ReceiverPhone": "0182491234", + "TokenStatus": "Initiated", + "ReedemTime": "", + "code": "200" + }'); + + /** @var \Mockery\MockInterface $mockedClient */ + $mockedClient = \Mockery::mock(\GuzzleHttp\Client::class); + $mockedClient->shouldReceive('request')->once()->andReturn($mockedResponse); + + $mockedCache = $this->getMockBuilder(CacheInterface::class)->getMock(); + $mockedCache->method('has')->willReturn(true); + $mockedCache->method('get')->willReturn('secure-token'); + + /** + * @var ConfigInterface $mockedConfig + * @var \GuzzleHttp\Client $mockedClient + * @var CacheInterface $mockedCache + * */ + $api = new Client($mockedConfig, $mockedClient, $mockedCache); + + $requestResult = $api->transferCashStatus('274126155'); + $this->assertInstanceOf(TransferCashStatusResponse::class, $requestResult); + $this->assertEquals(TransactionStatusEnum::INITIATED->value, $requestResult->status); + } + + /** @test */ + public function it_can_handle_failure(): void + { + $transaction = $this->getMockBuilder(TransactionInterface::class)->getMock(); + + /** @var TransactionInterface $transaction */ + $this->assertInstanceOf(TransactionInterface::class, $transaction); + + $mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock(); + $mockedConfig->method('getUrl')->willReturn('https://api.example/'); + $mockedConfig->method('getAgentMsisdn')->willReturn('123456789'); + $mockedConfig->method('getAgentPin')->willReturn('0088'); + + $mockedResponse = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mockedResponse->method('getStatusCode')->willReturn(400); + $mockedResponse->method('getBody') + ->willReturn('{ + "code": 400, + "error": "transaction_id not valide" + }'); + + /** @var \Mockery\MockInterface $mockedClient */ + $mockedClient = \Mockery::mock(\GuzzleHttp\Client::class); + $mockedClient->shouldReceive('request')->once()->andReturn($mockedResponse); + + $mockedCache = $this->getMockBuilder(CacheInterface::class)->getMock(); + $mockedCache->method('has')->willReturn(true); + $mockedCache->method('get')->willReturn('secure-token'); + + /** + * @var ConfigInterface $mockedConfig + * @var \GuzzleHttp\Client $mockedClient + * @var CacheInterface $mockedCache + * */ + $api = new Client($mockedConfig, $mockedClient, $mockedCache); + + $requestResult = $api->transferCashStatus('274126155'); + $this->assertInstanceOf(TransferCashStatusResponse::class, $requestResult); + $this->assertEquals('transaction_id not valide', $requestResult->error); + } +} \ No newline at end of file diff --git a/tests/TransferCashTest.php b/tests/TransferCashTest.php new file mode 100644 index 0000000..02a9801 --- /dev/null +++ b/tests/TransferCashTest.php @@ -0,0 +1,125 @@ +. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +namespace BrokeYourBike\Wizall\Tests; + +use Psr\SimpleCache\CacheInterface; +use Psr\Http\Message\ResponseInterface; +use BrokeYourBike\Wizall\Responses\TransferCashResponse; +use BrokeYourBike\Wizall\Interfaces\TransactionInterface; +use BrokeYourBike\Wizall\Interfaces\ConfigInterface; +use BrokeYourBike\Wizall\Client; + +/** + * @author Ivan Stasiuk + */ +class TransferCashTest extends TestCase +{ + /** @test */ + public function it_can_prepare_request(): void + { + $transaction = $this->getMockBuilder(TransactionInterface::class)->getMock(); + + /** @var TransactionInterface $transaction */ + $this->assertInstanceOf(TransactionInterface::class, $transaction); + + $mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock(); + $mockedConfig->method('getUrl')->willReturn('https://api.example/'); + $mockedConfig->method('getAgentMsisdn')->willReturn('123456789'); + $mockedConfig->method('getAgentPin')->willReturn('0088'); + + $mockedResponse = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mockedResponse->method('getStatusCode')->willReturn(200); + $mockedResponse->method('getBody') + ->willReturn('{ + "Operation": "PickUpCode", + "id": 124512345, + "code": "200", + "status": "valid", + "value": "100.0", + "currency_code": 952, + "paid_value": 100, + "paid_value_currency_code": 952, + "is_cash": 0, + "fee": "0", + "commission": "0.0", + "timestamp": "1889-02-08T10:51:42", + "solde": 12434, + "details": { + "message": "PickUpCode successful", + "service": "customer-sell-good-voucher", + "rid": "1lj2h34lj1234h" + } + }'); + + /** @var \Mockery\MockInterface $mockedClient */ + $mockedClient = \Mockery::mock(\GuzzleHttp\Client::class); + $mockedClient->shouldReceive('request')->once()->andReturn($mockedResponse); + + $mockedCache = $this->getMockBuilder(CacheInterface::class)->getMock(); + $mockedCache->method('has')->willReturn(true); + $mockedCache->method('get')->willReturn('secure-token'); + + /** + * @var ConfigInterface $mockedConfig + * @var \GuzzleHttp\Client $mockedClient + * @var CacheInterface $mockedCache + * */ + $api = new Client($mockedConfig, $mockedClient, $mockedCache); + + $requestResult = $api->transferCash($transaction); + $this->assertInstanceOf(TransferCashResponse::class, $requestResult); + $this->assertEquals('124512345', $requestResult->id); + } + + /** @test */ + public function it_can_handle_failure(): void + { + $transaction = $this->getMockBuilder(TransactionInterface::class)->getMock(); + + /** @var TransactionInterface $transaction */ + $this->assertInstanceOf(TransactionInterface::class, $transaction); + + $mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock(); + $mockedConfig->method('getUrl')->willReturn('https://api.example/'); + $mockedConfig->method('getAgentMsisdn')->willReturn('123456789'); + $mockedConfig->method('getAgentPin')->willReturn('0088'); + + $mockedResponse = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mockedResponse->method('getStatusCode')->willReturn(400); + $mockedResponse->method('getBody') + ->willReturn('{ + "code": "WZ0001", + "error": "this transaction already exist", + "external_trx_id": "GL00003", + "trans_id": "124512345", + "details": { + "message": null, + "service": "customer-sell-good-voucher", + "rid": "1kl24jl1k24j1" + } + }'); + + /** @var \Mockery\MockInterface $mockedClient */ + $mockedClient = \Mockery::mock(\GuzzleHttp\Client::class); + $mockedClient->shouldReceive('request')->once()->andReturn($mockedResponse); + + $mockedCache = $this->getMockBuilder(CacheInterface::class)->getMock(); + $mockedCache->method('has')->willReturn(true); + $mockedCache->method('get')->willReturn('secure-token'); + + /** + * @var ConfigInterface $mockedConfig + * @var \GuzzleHttp\Client $mockedClient + * @var CacheInterface $mockedCache + * */ + $api = new Client($mockedConfig, $mockedClient, $mockedCache); + + $requestResult = $api->transferCash($transaction); + $this->assertInstanceOf(TransferCashResponse::class, $requestResult); + $this->assertEquals('this transaction already exist', $requestResult->error); + } +} \ No newline at end of file