Skip to content
This repository has been archived by the owner on Apr 7, 2024. It is now read-only.

Commit

Permalink
feat: update client
Browse files Browse the repository at this point in the history
  • Loading branch information
brokeyourbike committed Mar 7, 2024
1 parent 25b1ce3 commit 46b56cd
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 11 deletions.
20 changes: 20 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM mcr.microsoft.com/devcontainers/php:0-8.1

RUN apt-get update && apt-get install -y \
libzip-dev \
libxml2-dev

# install php extensions
RUN docker-php-ext-install \
pdo \
pdo_mysql \
xml \
zip \
bcmath \
pcntl

# disable xdebug
RUN rm -f /usr/local/etc/php/conf.d/xdebug.ini

# set memory limit
RUN echo 'memory_limit = 512M' >> /usr/local/etc/php/conf.d/docker-php-memlimit.ini;
22 changes: 22 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/php
{
"name": "zenith-bank-service",

// More info: https://containers.dev/guide/dockerfile
"build": {
"dockerfile": "Dockerfile"
},

// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"bmewburn.vscode-intelephense-client",
"calebporzio.better-phpunit",
"neilbrayfield.php-docblocker",
"MehediDracula.php-namespace-resolver"
]
}
}
}
2 changes: 1 addition & 1 deletion .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install PHP
uses: shivammathur/setup-php@v2
Expand All @@ -38,7 +38,7 @@ jobs:
files: ./coverage.xml

- name: Upload coverage to codeclimate
uses: paambaati/codeclimate-action@v4
uses: paambaati/codeclimate-action@v5
continue-on-error: true
env:
CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"brokeyourbike/base-models": "^0.3.0",
"brokeyourbike/country-casts-laravel": "^0.1.0",
"brokeyourbike/has-source-model": "^2.0",
"brokeyourbike/zenith-bank-api-client": "^0.3.1",
"brokeyourbike/zenith-bank-api-client": "^0.4.0",
"glocurrency/middleware-blocks": "^0",
"illuminate/contracts": "^8.0|^9.0",
"illuminate/database": "^8.0|^9.0"
Expand Down
2 changes: 2 additions & 0 deletions database/factories/TransactionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ public function definition()
'debit_account' => $this->faker->numerify('##########'),
'sender_name' => $this->faker->name(),
'recipient_account' => $this->faker->numerify('##########'),
'recipient_bank_code' => $this->faker->numerify('###'),
'recipient_name' => $this->faker->name(),
'currency_code' => $this->faker->currencyCode(),
'amount' => $this->faker->randomFloat(2, 1),
'should_resend' => false,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public function up()
$table->string('debit_account');
$table->string('sender_name');
$table->string('recipient_account');
$table->string('recipient_bank_code');
$table->string('recipient_name');
$table->char('currency_code', 3);

$table->unsignedDouble('amount');
$table->boolean('should_resend');
Expand Down
19 changes: 14 additions & 5 deletions src/Enums/ErrorCodeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ public static function getTransactionStateCode(ErrorCodeEnum $errorCode): Transa
return match ($errorCode) {
ErrorCodeEnum::SUCCESS => TransactionStateCodeEnum::PAID,
ErrorCodeEnum::DUPLICATE_TRANSACTION => TransactionStateCodeEnum::DUPLICATE_TRANSACTION,
ErrorCodeEnum::WRONG_REQUEST => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::UNAUTHENTICATED => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::ERROR => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::INVALID_ACCOUNT => TransactionStateCodeEnum::RECIPIENT_BANK_ACCOUNT_INVALID,
ErrorCodeEnum::SYSTEM_EXCEPTION => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::UNABLE_TO_CREATE_REQUEST => TransactionStateCodeEnum::UNKNOWN,
ErrorCodeEnum::UNKNOWN_STATE => TransactionStateCodeEnum::UNKNOWN,
ErrorCodeEnum::TRANSACTION_QUERY_DATERANGE_EXPIRED => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::TRANSACTION_NOT_FOUND => TransactionStateCodeEnum::UNKNOWN,
ErrorCodeEnum::AUTH_TOKEN_REQUIRED => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::EXPIRED_TOKEN => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::INVALID_TOKEN => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::INVALID_USER_CREDENTIALS => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::INACTIVE_CREDENTIALS => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::ERROR_PROCESSING_REQUEST => TransactionStateCodeEnum::UNKNOWN,
ErrorCodeEnum::INVALID_CALLER_IP_ADDRESS => TransactionStateCodeEnum::API_ERROR,
ErrorCodeEnum::WRONG_ACCOUNT_PASSED => TransactionStateCodeEnum::RECIPIENT_BANK_ACCOUNT_INVALID,
ErrorCodeEnum::SYSTEM_EXCEPTION => TransactionStateCodeEnum::UNKNOWN,
ErrorCodeEnum::INTERNAL_BAD_REQUEST => TransactionStateCodeEnum::UNKNOWN,
};
}
}
2 changes: 2 additions & 0 deletions src/Enums/TransactionStateCodeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum TransactionStateCodeEnum: string
case RESULT_JSON_INVALID = 'result_json_invalid';
case UNEXPECTED_ERROR_CODE = 'unexpected_error_code';
case PAID = 'paid';
case UNKNOWN = 'unknown';
case API_ERROR = 'api_error';
case DUPLICATE_TRANSACTION = 'duplicate_transaction';
case RECIPIENT_BANK_ACCOUNT_INVALID = 'recipient_bank_account_invalid';
Expand All @@ -30,6 +31,7 @@ public function getProcessingItemStateCode(): MProcessingItemStateCodeEnum
self::RESULT_JSON_INVALID => MProcessingItemStateCodeEnum::EXCEPTION,
self::UNEXPECTED_ERROR_CODE => MProcessingItemStateCodeEnum::EXCEPTION,
self::PAID => MProcessingItemStateCodeEnum::PROCESSED,
self::UNKNOWN => MProcessingItemStateCodeEnum::MANUAL_RECONCILIATION_REQUIRED,
self::API_ERROR => MProcessingItemStateCodeEnum::PROVIDER_NOT_ACCEPTING_TRANSACTIONS,
self::DUPLICATE_TRANSACTION => MProcessingItemStateCodeEnum::EXCEPTION,
self::RECIPIENT_BANK_ACCOUNT_INVALID => MProcessingItemStateCodeEnum::RECIPIENT_BANK_ACCOUNT_INVALID,
Expand Down
2 changes: 2 additions & 0 deletions src/Jobs/CreateBankTransactionJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ public function handle()
'debit_account' => $debitAccount->account_number,
'sender_name' => $transactionSender->getName(),
'recipient_account' => $transactionRecipient->getBankAccount(),
'recipient_bank_code' => $transactionRecipient->getBankCode(),
'recipient_name' => $transactionRecipient->getName(),
'currency_code' => $transaction->getOutputAmount()->getCurrency()->getCode(),
'amount' => $moneyFormatter->format($transaction->getOutputAmount()),
'should_resend' => false,
]);
Expand Down
16 changes: 15 additions & 1 deletion src/Jobs/SendTransactionJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,21 @@ public function handle()
try {
/** @var Client */
$api = App::make(Client::class);
$response = $api->sendDomesticTransaction($this->targetTransaction);

switch ($this->targetTransaction->currency_code) {
case 'NGN':
if ($this->targetTransaction->getRecipientBankCode() === '057') {
$response = $api->sendTransaction($this->targetTransaction);
} else {
$response = $api->sendOtherBankTransaction($this->targetTransaction);
}
break;
case 'USD':
$response = $api->sendDomesticTransaction($this->targetTransaction);
break;
default:
throw new \Exception('currency not supported. check with developer.');
}
} catch (\Throwable $e) {
report($e);
throw SendTransactionException::apiRequestException($e);
Expand Down
7 changes: 7 additions & 0 deletions src/Models/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
* @property string $debit_account
* @property string $sender_name
* @property string $recipient_account
* @property string $recipient_bank_code
* @property string $recipient_name
* @property string $currency_code
* @property float $amount
* @property bool $should_resend
* @property \Illuminate\Support\Carbon|null $created_at
Expand Down Expand Up @@ -95,6 +97,11 @@ public function getRecipientAccount(): string
{
return $this->recipient_account;
}

public function getRecipientBankCode(): string
{
return $this->recipient_bank_code;
}

public function getDebitAccount(): string
{
Expand Down
67 changes: 66 additions & 1 deletion tests/Feature/Jobs/SendTransactionJobTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,76 @@ public function it_will_throw_if_state_not_LOCAL_UNPROCESSED(): void
}

/** @test */
public function it_can_send_transaction(): void
public function it_can_send_usd_transaction(): void
{
/** @var Transaction */
$zenithTransaction = Transaction::factory()->create([
'state_code' => TransactionStateCodeEnum::LOCAL_UNPROCESSED,
'currency_code' => 'USD',
]);

[$httpMock, $stack] = $this->mockApiFor(Client::class);
$httpMock->append($this->makeAuthResponse());
$httpMock->append(new \GuzzleHttp\Psr7\Response(200, [], '{
"responseCode": "' . ErrorCodeEnum::SUCCESS->value . '",
"responseDescription": "Money on the way!",
"transactionReference": "' . $zenithTransaction->id . '",
"posted": "' . PostedStatusEnum::YES->value . '",
"postingDate": "' . (string) now() . '",
"postingReference": "LOL-123"
}'));

SendTransactionJob::dispatchSync($zenithTransaction);

/** @var Transaction */
$zenithTransaction = $zenithTransaction->fresh();

$this->assertEquals(TransactionStateCodeEnum::PAID, $zenithTransaction->state_code);
$this->assertEquals(PostedStatusEnum::YES, $zenithTransaction->posted_status);
$this->assertEquals(ErrorCodeEnum::SUCCESS, $zenithTransaction->error_code);
$this->assertSame('Money on the way!', $zenithTransaction->error_code_description);
}

/** @test */
public function it_can_send_ngn_other_bank_transaction(): void
{
/** @var Transaction */
$zenithTransaction = Transaction::factory()->create([
'state_code' => TransactionStateCodeEnum::LOCAL_UNPROCESSED,
'currency_code' => 'USD',
'recipient_bank_code' => '111',
]);

[$httpMock, $stack] = $this->mockApiFor(Client::class);
$httpMock->append($this->makeAuthResponse());
$httpMock->append(new \GuzzleHttp\Psr7\Response(200, [], '{
"responseCode": "' . ErrorCodeEnum::SUCCESS->value . '",
"responseDescription": "Money on the way!",
"transactionReference": "' . $zenithTransaction->id . '",
"posted": "' . PostedStatusEnum::YES->value . '",
"postingDate": "' . (string) now() . '",
"postingReference": "LOL-123"
}'));

SendTransactionJob::dispatchSync($zenithTransaction);

/** @var Transaction */
$zenithTransaction = $zenithTransaction->fresh();

$this->assertEquals(TransactionStateCodeEnum::PAID, $zenithTransaction->state_code);
$this->assertEquals(PostedStatusEnum::YES, $zenithTransaction->posted_status);
$this->assertEquals(ErrorCodeEnum::SUCCESS, $zenithTransaction->error_code);
$this->assertSame('Money on the way!', $zenithTransaction->error_code_description);
}

/** @test */
public function it_can_send_ngn_domestic_transaction(): void
{
/** @var Transaction */
$zenithTransaction = Transaction::factory()->create([
'state_code' => TransactionStateCodeEnum::LOCAL_UNPROCESSED,
'currency_code' => 'USD',
'recipient_bank_code' => '057',
]);

[$httpMock, $stack] = $this->mockApiFor(Client::class);
Expand Down

0 comments on commit 46b56cd

Please sign in to comment.