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

Commit

Permalink
feat: fetch update
Browse files Browse the repository at this point in the history
  • Loading branch information
brokeyourbike committed Mar 3, 2024
1 parent 5685dde commit fcad40c
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 26 deletions.
15 changes: 15 additions & 0 deletions src/AccessBankServiceProvider.php
Expand Up @@ -3,6 +3,7 @@
namespace GloCurrency\AccessBank;

use Illuminate\Support\ServiceProvider;
use GloCurrency\AccessBank\Console\FetchTransactionsUpdateCommand;
use GloCurrency\AccessBank\Config;
use BrokeYourBike\AccessBank\Interfaces\ConfigInterface;

Expand Down Expand Up @@ -81,4 +82,18 @@ protected function registerPublishing()
], 'access-bank-migrations');
}
}

/**
* Register the package's commands.
*
* @return void
*/
protected function registerCommands()
{
if ($this->app->runningInConsole()) {
$this->commands([
FetchTransactionsUpdateCommand::class,
]);
}
}
}
68 changes: 68 additions & 0 deletions src/Console/FetchTransactionsUpdateCommand.php
@@ -0,0 +1,68 @@
<?php

namespace GloCurrency\AccessBank\Console;

use Illuminate\Console\Command;
use GloCurrency\AccessBank\Models\Transaction;
use GloCurrency\AccessBank\Jobs\FetchTransactionUpdateJob;
use GloCurrency\AccessBank\Enums\TransactionStateCodeEnum;

class FetchTransactionsUpdateCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'access-bank:fetch-update';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Dispatch fetch jobs for unfinished AccessBank/Transaction';

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}

/**
* Execute the console command.
*
* @return void
* @todo add actual implemetation
*/
public function handle()
{
$transactionsQuery = Transaction::where('state_code', TransactionStateCodeEnum::PROCESSING->value);

Check failure on line 44 in src/Console/FetchTransactionsUpdateCommand.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1)

Call to an undefined static method GloCurrency\AccessBank\Models\Transaction::where().

$count = $transactionsQuery->count();

if (!$count) {
$this->error('You do not have any unfinished AccessBank/Transaction');
return;
}

$this->info("Dispatching fetch jobs for {$count} AccessBank/Transaction");

$bar = $this->output->createProgressBar($count);

$bar->start();

foreach ($transactionsQuery->cursor() as $transaction) {
FetchTransactionUpdateJob::dispatch($transaction);
}

$bar->finish();

$this->newLine();
$this->info("Job dispatching done");
}
}
76 changes: 76 additions & 0 deletions src/Exceptions/FetchTransactionUpdateException.php
@@ -0,0 +1,76 @@
<?php

namespace GloCurrency\AccessBank\Exceptions;

use GloCurrency\AccessBank\Models\Transaction;
use GloCurrency\AccessBank\Enums\TransactionStateCodeEnum;
use BrokeYourBike\AccessBank\Models\TransactionResponse;
use BrokeYourBike\AccessBank\Enums\StatusCodeEnum;
use BrokeYourBike\AccessBank\Enums\ErrorCodeEnum;
use BrokeYourBike\AccessBank\Client;

final class FetchTransactionUpdateException extends \RuntimeException
{
private TransactionStateCodeEnum $stateCode;
private string $stateCodeReason;

public function __construct(TransactionStateCodeEnum $stateCode, string $stateCodeReason, ?\Throwable $previous = null)
{
$this->stateCode = $stateCode;
$this->stateCodeReason = $stateCodeReason;

parent::__construct($stateCodeReason, 0, $previous);
}

public function getStateCode(): TransactionStateCodeEnum
{
return $this->stateCode;
}

public function getStateCodeReason(): string
{
return $this->stateCodeReason;
}

public static function stateNotAllowed(Transaction $transaction): self
{
$className = $transaction::class;
$message = "{$className} state_code `{$transaction->getStateCode()->value}` not allowed";
return new static(TransactionStateCodeEnum::STATE_NOT_ALLOWED, $message);
}

public static function apiRequestException(\Throwable $e): self
{
$className = Client::class;
$message = "Exception during {$className} request with message: `{$e->getMessage()}`";
return new static(TransactionStateCodeEnum::API_REQUEST_EXCEPTION, $message);
}

public static function noErrorCode(TransactionResponse $response): self
{
$className = $response::class;
$message = "{$className} do not have `error_code` property: `{$response->getRawResponse()->getBody()}`";
return new static(TransactionStateCodeEnum::NO_ERROR_CODE_PROPERTY, $message);
}

public static function unexpectedErrorCode(string $code): self
{
$className = ErrorCodeEnum::class;
$message = "Unexpected {$className}: `{$code}`";
return new static(TransactionStateCodeEnum::UNEXPECTED_ERROR_CODE, $message);
}

public static function noStatusCode(TransactionResponse $response): self
{
$className = $response::class;
$message = "{$className} do not have `payment.status` property: `{$response->getRawResponse()->getBody()}`";
return new static(TransactionStateCodeEnum::NO_STATUS_CODE_PROPERTY, $message);
}

public static function unexpectedStatusCode(string $code): self
{
$className = StatusCodeEnum::class;
$message = "Unexpected {$className}: `{$code}`";
return new static(TransactionStateCodeEnum::UNEXPECTED_STATUS_CODE, $message);
}
}
14 changes: 0 additions & 14 deletions src/Exceptions/SendTransactionException.php
Expand Up @@ -59,18 +59,4 @@ public static function unexpectedErrorCode(string $code): self
$message = "Unexpected {$className}: `{$code}`";
return new static(TransactionStateCodeEnum::UNEXPECTED_ERROR_CODE, $message);
}

public static function noStatusCode(TransactionResponse $response): self
{
$className = $response::class;
$message = "{$className} do not have `payment.status` property: `{$response->getRawResponse()->getBody()}`";
return new static(TransactionStateCodeEnum::NO_STATUS_CODE_PROPERTY, $message);
}

public static function unexpectedStatusCode(string $code): self
{
$className = StatusCodeEnum::class;
$message = "Unexpected {$className}: `{$code}`";
return new static(TransactionStateCodeEnum::UNEXPECTED_STATUS_CODE, $message);
}
}
108 changes: 108 additions & 0 deletions src/Jobs/FetchTransactionUpdateJob.php
@@ -0,0 +1,108 @@
<?php

namespace GloCurrency\AccessBank\Jobs;

use Illuminate\Support\Str;
use Illuminate\Support\Facades\App;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Bus\Queueable;
use GloCurrency\MiddlewareBlocks\Enums\QueueTypeEnum as MQueueTypeEnum;
use GloCurrency\AccessBank\Models\Transaction;
use GloCurrency\AccessBank\Exceptions\SendTransactionException;
use GloCurrency\AccessBank\Exceptions\FetchTransactionUpdateException;
use GloCurrency\AccessBank\Enums\TransactionStateCodeEnum;
use BrokeYourBike\AccessBank\Enums\StatusCodeEnum;
use BrokeYourBike\AccessBank\Enums\ErrorCodeEnum;
use BrokeYourBike\AccessBank\Client;

class FetchTransactionUpdateJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncrypted
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;

/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 1;

private Transaction $targetTransaction;

/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Transaction $targetTransaction)
{
$this->targetTransaction = $targetTransaction;
$this->afterCommit();
$this->onQueue(MQueueTypeEnum::SERVICES->value);
}

/**
* The unique ID of the job.
*
* @return string
*/
public function uniqueId()
{
return $this->targetTransaction->id;
}

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
if (TransactionStateCodeEnum::PROCESSING !== $this->targetTransaction->state_code) {
throw FetchTransactionUpdateException::stateNotAllowed($this->targetTransaction);
}

try {
/** @var Client */
$api = App::makeWith(Client::class);


if (in_array($this->targetTransaction->getBankCode(), ['044', '063'])) {
$response = $api->fetchDomesticTransactionStatus((string) Str::uuid(), $this->targetTransaction->getReference());
} else {
$response = $api->fetchOtheBankTransactionStatus((string) Str::uuid(), $this->targetTransaction->getReference());
}
} catch (\Throwable $e) {
report($e);
throw FetchTransactionUpdateException::apiRequestException($e);
}

$errorCode = ErrorCodeEnum::tryFrom($response->errorCode);

Check failure on line 87 in src/Jobs/FetchTransactionUpdateJob.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1)

Parameter #1 $value of static method BrokeYourBike\AccessBank\Enums\ErrorCodeEnum::tryFrom() expects int|string, string|null given.
if (ErrorCodeEnum::NO_ERROR === $errorCode) {
$statusCode = StatusCodeEnum::tryFrom($response->transactionStatus);

Check failure on line 89 in src/Jobs/FetchTransactionUpdateJob.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1)

Parameter #1 $value of static method BrokeYourBike\AccessBank\Enums\StatusCodeEnum::tryFrom() expects int|string, string|null given.
if ($statusCode) {
$this->targetTransaction->state_code = TransactionStateCodeEnum::makeFromStatusCode($statusCode);
$this->targetTransaction->state_code_reason = $response->transactionInformation;
}
$this->targetTransaction->save();
}
}

/**
* Handle a job failure.
*
* @param \Throwable $exception
* @return void
*/
public function failed(\Throwable $exception)
{
report($exception);
}
}
15 changes: 4 additions & 11 deletions src/Jobs/SendTransactionJob.php
Expand Up @@ -95,19 +95,12 @@ public function handle()
$this->targetTransaction->state_code = TransactionStateCodeEnum::makeFromErrorCode($errorCode);

if (ErrorCodeEnum::NO_ERROR === $errorCode) {
if ($response->transactionStatus === null) {
throw SendTransactionException::noStatusCode($response);
}

$statusCode = StatusCodeEnum::tryFrom($response->transactionStatus);

Check failure on line 98 in src/Jobs/SendTransactionJob.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1)

Parameter #1 $value of static method BrokeYourBike\AccessBank\Enums\StatusCodeEnum::tryFrom() expects int|string, string|null given.

if (!$statusCode) {
throw SendTransactionException::unexpectedStatusCode($response->transactionStatus);
if ($statusCode) {
$this->targetTransaction->status_code = $statusCode;
$this->targetTransaction->status_code_description = $response->transactionInformation;
$this->targetTransaction->state_code = TransactionStateCodeEnum::makeFromStatusCode($statusCode);
}

$this->targetTransaction->status_code = $statusCode;
$this->targetTransaction->status_code_description = $response->transactionInformation;
$this->targetTransaction->state_code = TransactionStateCodeEnum::makeFromStatusCode($statusCode);
}

$this->targetTransaction->save();
Expand Down
2 changes: 1 addition & 1 deletion tests/Feature/Jobs/SendTransactionJobTest.php
Expand Up @@ -63,7 +63,7 @@ public function it_will_throw_if_response_code_is_unexpected(): void
/** @var Transaction */
$targetTransaction = $targetTransaction->fresh();

$this->assertEquals(TransactionStateCodeEnum::UNEXPECTED_STATUS_CODE, $targetTransaction->state_code);
$this->assertEquals(TransactionStateCodeEnum::PROCESSING, $targetTransaction->state_code);
}

/** @test */
Expand Down
40 changes: 40 additions & 0 deletions tests/Unit/Jobs/FetchTransactionUpdateJobTest.php
@@ -0,0 +1,40 @@
<?php

namespace GloCurrency\AccessBank\Tests\Unit\Jobs;

use PHPUnit\Framework\TestCase;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use GloCurrency\AccessBank\Models\Transaction;
use GloCurrency\AccessBank\Jobs\FetchTransactionUpdateJob;

class FetchTransactionUpdateJobTest extends TestCase
{
/** @test */
public function it_has_tries_defined(): void
{
$transaction = new Transaction();

$job = (new FetchTransactionUpdateJob($transaction));
$this->assertSame(1, $job->tries);
}

/** @test */
public function it_implements_should_be_unique(): void
{
$transaction = new Transaction();

$job = (new FetchTransactionUpdateJob($transaction));
$this->assertInstanceOf(ShouldBeUnique::class, $job);
$this->assertSame($transaction->id, $job->uniqueId());
}

/** @test */
public function it_implements_should_be_encrypted(): void
{
$transaction = new Transaction();

$job = (new FetchTransactionUpdateJob($transaction));
$this->assertInstanceOf(ShouldBeEncrypted::class, $job);
}
}

0 comments on commit fcad40c

Please sign in to comment.