Skip to content

Commit

Permalink
feat: add methods
Browse files Browse the repository at this point in the history
  • Loading branch information
brokeyourbike committed Aug 16, 2023
1 parent 894000c commit 331cc6a
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 29 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"brokeyourbike/resolve-uri": "^1.0",
"brokeyourbike/http-enums": "^2.0",
"brokeyourbike/has-source-model": "^2.0",
"brokeyourbike/data-transfer-object": "^0.2.0"
"brokeyourbike/data-transfer-object": "^0.2.0",
"psr/simple-cache": "^1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
Expand Down
99 changes: 78 additions & 21 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@

namespace BrokeYourBike\ParallexBank;

use Psr\SimpleCache\CacheInterface;
use GuzzleHttp\ClientInterface;
use Carbon\Carbon;
use BrokeYourBike\ResolveUri\ResolveUriTrait;
use BrokeYourBike\ParallexBank\Models\TransactionResponse;
use BrokeYourBike\ParallexBank\Responses\TransactionResponse;
use BrokeYourBike\ParallexBank\Responses\LoginResponse;
use BrokeYourBike\ParallexBank\Interfaces\TransactionInterface;
use BrokeYourBike\ParallexBank\Interfaces\ConfigInterface;
use BrokeYourBike\HttpEnums\HttpMethodEnum;
Expand All @@ -29,51 +32,105 @@ class Client implements HttpClientInterface
use HasSourceModelTrait;

private ConfigInterface $config;
private CacheInterface $cache;

public function __construct(ConfigInterface $config, ClientInterface $httpClient)
public function __construct(ConfigInterface $config, ClientInterface $httpClient, CacheInterface $cache)
{
$this->config = $config;
$this->httpClient = $httpClient;
$this->cache = $cache;
}

public function getConfig(): ConfigInterface
{
return $this->config;
}

public function postTransaction(string $requestId, TransactionInterface $transaction): TransactionResponse
public function getCache(): CacheInterface
{
return $this->cache;
}

public function authTokenCacheKey(): string
{
return get_class($this) . ':authToken:';
}

public function getAuthToken(): ?string
{
if ($this->cache->has($this->authTokenCacheKey())) {
$cachedToken = $this->cache->get($this->authTokenCacheKey());

if (is_string($cachedToken)) {
return $cachedToken;
}
}

$response = $this->fetchAuthTokenRaw();

if ($response->token === null) {
return $response->token;
}

$expireAt = Carbon::parse($response->expiration);

$this->cache->set(
$this->authTokenCacheKey(),
$response->token,
(Carbon::now())->diffInSeconds($expireAt) - 60
);

return $response->token;
}

public function fetchAuthTokenRaw(): LoginResponse
{
$options = [
\GuzzleHttp\RequestOptions::HEADERS => [
'Accept' => 'application/json',
'Client-Id' => $this->config->getClientId(),
'Client-Key' => $this->config->getClientSecret(),
],
\GuzzleHttp\RequestOptions::JSON => [
'BankId' => $transaction->getBankCode(),
'TrnType' => 'T',
'TrnSubType' => 'CI',
'RequestID' => $requestId,
'PartTrnRec' => [
[
'AcctId' => $transaction->getBankAccount(),
'CreditDebitFlg' => 'D',
'TrnAmt' => $transaction->getAmount(),
'CurrencyCode' => $transaction->getCurrencyCode(),
'TrnParticulars' => $transaction->getReference(),
'ValueDt' => $transaction->getValueDate()->format('Y-m-d\TH:i:s.uP'),
]
],
'username' => $this->config->getUsername(),
'password' => $this->config->getPassword(),
],
];

$uri = (string) $this->resolveUriFor($this->config->getUrl(), 'api/ThirdPartyTransfer/Login');
$response = $this->httpClient->request(HttpMethodEnum::POST->value, $uri, $options);
return new LoginResponse($response);
}

public function postTransaction(TransactionInterface $transaction): TransactionResponse
{
$options = [
\GuzzleHttp\RequestOptions::HEADERS => [
'Accept' => 'application/json',
'Authorization' => "Bearer {$this->getAuthToken()}",
],
\GuzzleHttp\RequestOptions::JSON => [
'transactionDate' => $transaction->getTransactionDate()->format('Y-m-d'),
'transactionID' => $transaction->getReference(),
'credits' => [[
'accountToDebit' => $transaction->getAccountNumber(),
'accountName' => $transaction->getRecipientName(),
'amount' => $transaction->getAmount(),
'naration' => $transaction->getReference(),
]],
'debits' => [[
'accountToDebit' => $this->config->getDebitAccountNumber(),
'accountName' => $this->config->getDebitAccountName(),
'amount' => $transaction->getAmount(),
'naration' => $transaction->getReference(),
]],
],
];

if ($transaction instanceof SourceModelInterface){
$options[\BrokeYourBike\HasSourceModel\Enums\RequestOptions::SOURCE_MODEL] = $transaction;
}

$uri = (string) $this->resolveUriFor($this->config->getUrl(), 'coreapi/api/finacle/PostingTransaction');
$uri = (string) $this->resolveUriFor($this->config->getUrl(), 'api/ThirdPartyTransfer/BulkTransfer');
$response = $this->httpClient->request(HttpMethodEnum::POST->value, $uri, $options);

return new TransactionResponse($response);
}
}
6 changes: 5 additions & 1 deletion src/Enums/ErrorCodeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@
* @author Ivan Stasiuk <[email protected]>
*/
enum ErrorCodeEnum: string
{}
{
case SUCCESS = '00';
case DUPLICATE_TRANSACTION = '41';
case INVALID_DEBIT_ACCOUNT = '45';
}
6 changes: 3 additions & 3 deletions src/Interfaces/TransactionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface TransactionInterface
{
public function getReference(): string;
public function getAmount(): float;
public function getBankCode(): string;
public function getBankAccount(): string;
public function getValueDate(): CarbonImmutable;
public function getAccountNumber(): string;
public function getRecipientName(): string;
public function getTransactionDate(): CarbonImmutable;
}
22 changes: 22 additions & 0 deletions src/Responses/LoginResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

// Copyright (C) 2023 Ivan Stasiuk <[email protected]>.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

namespace BrokeYourBike\ParallexBank\Responses;

use BrokeYourBike\DataTransferObject\JsonResponse;

/**
* @author Ivan Stasiuk <[email protected]>
*/
class LoginResponse extends JsonResponse
{
public string $responseCode;
public string $responseMessage;
public ?string $token;
public ?string $expiration;
}
10 changes: 7 additions & 3 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ public function it_implemets_http_client_interface(): void
/** @var \GuzzleHttp\ClientInterface */
$mockedHttpClient = $this->getMockBuilder(\GuzzleHttp\ClientInterface::class)->getMock();

$api = new Client($mockedConfig, $mockedHttpClient);
/** @var \Psr\SimpleCache\CacheInterface */
$mockedCache = $this->getMockBuilder(\Psr\SimpleCache\CacheInterface::class)->getMock();

$this->assertInstanceOf(HttpClientInterface::class, $api);
$this->assertSame($mockedConfig, $api->getConfig());
$client = new Client($mockedConfig, $mockedHttpClient, $mockedCache);

$this->assertInstanceOf(HttpClientInterface::class, $client);
$this->assertSame($mockedConfig, $client->getConfig());
$this->assertSame($mockedCache, $client->getCache());
}

/** @test */
Expand Down
72 changes: 72 additions & 0 deletions tests/FetchAuthTokenRawTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

// Copyright (C) 2023 Ivan Stasiuk <[email protected]>.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

namespace BrokeYourBike\ParallexBank\Tests;

use Psr\SimpleCache\CacheInterface;
use Psr\Http\Message\ResponseInterface;
use BrokeYourBike\ParallexBank\Responses\LoginResponse;
use BrokeYourBike\ParallexBank\Interfaces\ConfigInterface;
use BrokeYourBike\ParallexBank\Client;

/**
* @author Ivan Stasiuk <[email protected]>
*/
class FetchAuthTokenRawTest extends TestCase
{
private string $username = 'john';
private string $password = 'secret';

/** @test */
public function it_can_prepare_request(): void
{
$mockedConfig = $this->getMockBuilder(ConfigInterface::class)->getMock();
$mockedConfig->method('getUrl')->willReturn('https://api.example/');
$mockedConfig->method('getUsername')->willReturn($this->username);
$mockedConfig->method('getPassword')->willReturn($this->password);

$mockedResponse = $this->getMockBuilder(ResponseInterface::class)->getMock();
$mockedResponse->method('getStatusCode')->willReturn(200);
$mockedResponse->method('getBody')
->willReturn('{
"responseCode": "00",
"responseMessage": "OK",
"token": "123456789",
"expiration": "2023-08-16T22:20:54Z"
}');

/** @var \Mockery\MockInterface $mockedClient */
$mockedClient = \Mockery::mock(\GuzzleHttp\Client::class);
$mockedClient->shouldReceive('request')->withArgs([
'POST',
'https://api.example/api/ThirdPartyTransfer/Login',
[
\GuzzleHttp\RequestOptions::HEADERS => [
'Accept' => 'application/json',
],
\GuzzleHttp\RequestOptions::JSON => [
'username' => $this->username,
'password' => $this->password,
],
],
])->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(LoginResponse::class, $requestResult);
$this->assertEquals('123456789', $requestResult->token);
}
}

0 comments on commit 331cc6a

Please sign in to comment.