From 738b21e18281798829cd53bbc3560ec39f9e9434 Mon Sep 17 00:00:00 2001 From: hasanzaki Date: Fri, 22 May 2026 19:18:11 +0330 Subject: [PATCH] just shape sth stage1 --- backend/app/Models/FibTransaction.php | 2 + backend/app/Services/FIB/FIBClient.php | 34 ++++++++- .../Payments/DTO/FIBPaymentCreateDTO.php | 38 ++++++++++ .../Payments/DTO/PaymentCreateDTO.php | 46 +++++++++++++ .../app/Services/Payments/PaymentService.php | 69 ++++++++++++++----- .../Payment/DTO/PaymentCreateDTO.php | 58 ---------------- .../Controllers/Payment/PaymentController.php | 5 +- .../Requests/Payment/FIB/StoreRequest.php | 36 ++++++++++ ...05_18_095610_create_transactions_table.php | 17 +++-- ...8_104524_create_fib_transactions_table.php | 35 +++++----- .../seeders/FibTransactionStatusSeeder.php | 9 ++- backend/routes/api.php | 8 ++- 12 files changed, 248 insertions(+), 109 deletions(-) create mode 100644 backend/app/Services/Payments/DTO/FIBPaymentCreateDTO.php create mode 100644 backend/app/Services/Payments/DTO/PaymentCreateDTO.php delete mode 100644 backend/app/User/Controllers/Payment/DTO/PaymentCreateDTO.php create mode 100644 backend/app/User/Requests/Payment/FIB/StoreRequest.php diff --git a/backend/app/Models/FibTransaction.php b/backend/app/Models/FibTransaction.php index 23c37102..c208c0a7 100644 --- a/backend/app/Models/FibTransaction.php +++ b/backend/app/Models/FibTransaction.php @@ -9,4 +9,6 @@ class FibTransaction extends Model { /** @use HasFactory<\Database\Factories\FibTransactionFactory> */ use HasFactory; + + protected $guarded = ['id']; } diff --git a/backend/app/Services/FIB/FIBClient.php b/backend/app/Services/FIB/FIBClient.php index e96a7e9b..be22b64c 100755 --- a/backend/app/Services/FIB/FIBClient.php +++ b/backend/app/Services/FIB/FIBClient.php @@ -22,9 +22,14 @@ class FIBClient ->timeout(30); } - public function getAccessToken(): string + public function getAccessToken() { try { + if ($this->isNotProduction()) { + return json_decode( + file_get_contents(storage_path('app/mock/fib/token.json')) + ); + } $response = Http::withOptions([ 'proxy' => 'http://host.docker.internal:10808', ])->asForm()->post('https://fib-stage.fib.iq/auth/realms/fib-online-shop/protocol/openid-connect/token', [ @@ -51,4 +56,31 @@ class FIBClient return $exception->getMessage(); } } + + public function createPaymentService() + { + if ($this->isNotProduction()) { + return json_decode( + file_get_contents(storage_path('app/mock/fib/payment_create_success.json')) + ); + } + $response = $this->client()->post("https://fib-stage.fib.iq/protected/v1/payments"); + if ($response->failed()) { + throw new \Exception( + 'Unable to authenticate with FIB: ' . + $response->body() + ); + } + + $data = $response->json(); + if (!isset($data['paymentId'])) { + throw new \Exception('FIB paymentId missing in response'); + } + return $data; + } + + public function isNotProduction() + { + return env('APP_ENV') === 'local'; + } } diff --git a/backend/app/Services/Payments/DTO/FIBPaymentCreateDTO.php b/backend/app/Services/Payments/DTO/FIBPaymentCreateDTO.php new file mode 100644 index 00000000..e09cab6b --- /dev/null +++ b/backend/app/Services/Payments/DTO/FIBPaymentCreateDTO.php @@ -0,0 +1,38 @@ +paymentId = $data['paymentId']; + $this->readableCode = $data['readableCode']; + $this->qrCode = $data['qrCode']; + $this->validUntil = $data['validUntil']; + $this->personalAppLink = $data['personalAppLink']; + $this->businessAppLink = $data['businessAppLink']; + $this->corporateAppLink = $data['corporateAppLink']; + } + + public static function fromResponse($data): FIBPaymentCreateDTO + { + return new self([ + 'paymentId' => $data->paymentId, + 'readableCode' => $data->readableCode, + 'qrCode' => $data->qrCode, + 'validUntil' => $data->validUntil, + 'personalAppLink' => $data->personalAppLink, + 'businessAppLink' => $data->businessAppLink, + 'corporateAppLink' => $data->corporateAppLink, + ]); + } +} diff --git a/backend/app/Services/Payments/DTO/PaymentCreateDTO.php b/backend/app/Services/Payments/DTO/PaymentCreateDTO.php new file mode 100644 index 00000000..a3129a3a --- /dev/null +++ b/backend/app/Services/Payments/DTO/PaymentCreateDTO.php @@ -0,0 +1,46 @@ +username = $data['username']; + $this->user_id = $data['user_id']; + $this->track_id = $data['track_id']; + $this->amount = $data['amount']; + $this->currency = $data['currency']; + $this->callback_url = $data['callback_url']; + $this->ip = $data['ip']; + $this->user_gateway_id = $data['user_gateway_id']; + + } + + public static function fromRequest(Request $request): PaymentCreateDTO + { + return new self([ + 'username' => $request->username, + 'user_id' => '2', + 'track_id' => uuid_create(), + 'amount' => $request->amount, + 'currency' => $request->currency, + 'callback_url' => $request->callback_url, + 'ip' => $request->getClientIp(), + 'user_gateway_id' => $request->user_gateway_id, + ]); + } +} diff --git a/backend/app/Services/Payments/PaymentService.php b/backend/app/Services/Payments/PaymentService.php index e5dd86fa..d50d8b7f 100644 --- a/backend/app/Services/Payments/PaymentService.php +++ b/backend/app/Services/Payments/PaymentService.php @@ -2,9 +2,13 @@ namespace App\Services\Payments; +use App\Enums\PaymentStatusEnum; +use App\Models\FibTransaction; use App\Models\Payment; +use App\Models\Transaction; use App\Services\FIB\FIBClient; -use App\User\Controllers\Payment\DTO\PaymentCreateDTO; +use App\Services\Payments\DTO\FIBPaymentCreateDTO; +use App\Services\Payments\DTO\PaymentCreateDTO; class PaymentService { @@ -17,21 +21,52 @@ class PaymentService public function createPayment(PaymentCreateDTO $dto) { -// Payment::query()->create([ -// 'user_id' => $dto->user_id, -// 'username' => $dto->username, -// 'track_id' => $dto->track_id, -// 'amount' => $dto->amount, -// 'currency' => $dto->currency, -// 'callback_url' => $dto->callback_url, -// 'expires_at' => $dto->expires_at, -// 'status_id' => $dto->status_id, -// 'status_name' => $dto->status_name, -// 'ip' => $dto->ip, -// 'user_gateway_id' => $dto->user_gateway_id, -// 'created_at' => $dto->created_at, -// 'updated_at' => $dto->updated_at, -// ]); - return $this->fib_client->getAccessToken(); + try { + $payment = Payment::query()->create([ + 'user_id' => $dto->user_id, + 'username' => $dto->username, + 'track_id' => $dto->track_id, + 'amount' => $dto->amount, + 'currency' => $dto->currency, + 'callback_url' => $dto->callback_url, + 'status_id' => PaymentStatusEnum::Unpaid->value, + 'status_name' => PaymentStatusEnum::Unpaid->name, + 'ip' => $dto->ip, + 'user_gateway_id' => $dto->user_gateway_id, + ]); + + $response = $this->fib_client->createPaymentService(); + $fib_response_dto = FIBPaymentCreateDTO::fromResponse($response); + + $transaction = Transaction::query()->create([ + 'user_id' => $payment->user_id, + 'amount' => $payment->amount, + 'currency' => $payment->currency, + 'callback_url' => $payment->callback_url, +// 'description' => '', +// 'expires_in' => '', + 'payment_id' => $payment->id, + 'payment_track_id' => $payment->track_id, + 'user_gateway_id' => $payment->user_gateway_id, +// 'status' => '', + ]); + + $fib_transactions = FibTransaction::query()->create([ + 'transaction_id' => $transaction->id, + 'qrcode' => $fib_response_dto->qrCode, + 'readable_code' => $fib_response_dto->readableCode, + 'personalAppLink' => $fib_response_dto->personalAppLink, + 'businessAppLink' => $fib_response_dto->businessAppLink, + 'corporateAppLink' => $fib_response_dto->corporateAppLink, + 'paymentId' => $fib_response_dto->paymentId, + 'paymentMethod' => 'fib', + 'validUntil' => $fib_response_dto->validUntil, + 'status_id' => PaymentStatusEnum::Unpaid->value, + 'status_name' => PaymentStatusEnum::Unpaid->name, + ]); + return $payment; + } catch (\Exception $exception) { + throw new \Exception($exception->getMessage()); + } } } diff --git a/backend/app/User/Controllers/Payment/DTO/PaymentCreateDTO.php b/backend/app/User/Controllers/Payment/DTO/PaymentCreateDTO.php deleted file mode 100644 index 30725e34..00000000 --- a/backend/app/User/Controllers/Payment/DTO/PaymentCreateDTO.php +++ /dev/null @@ -1,58 +0,0 @@ -username = $data['username'] ?? null; - $this->user_id = $data['user_id'] ?? null; - $this->track_id = $data['track_id'] ?? null; - $this->amount = $data['amount'] ?? null; - $this->currency = $data['currency'] ?? null; - $this->callback_url = $data['callback_url'] ?? null; - $this->expires_at = $data['expires_at'] ?? null; - $this->status_id = $data['status_id'] ?? null; - $this->status_name = $data['status_name'] ?? null; - $this->ip = $data['ip'] ?? null; - $this->user_gateway_id = $data['user_gateway_id'] ?? null; - $this->created_at = $data['created_at'] ?? null; - $this->updated_at = $data['updated_at'] ?? null; - } - - public static function fromRequest(Request $request): PaymentCreateDTO - { - return new self([ - 'username' => $request->username ?? null, - 'track_id' => $request->track_id ?? null, - 'amount' => $request->amount ?? null, - 'currency' => $request->currency ?? null, - 'callback_url' => $request->callback_url ?? null, - 'expires_at' => $request->expires_at ?? null, - 'status_id' => $request->status_id ?? null, - 'status_name' => $request->status_name ?? null, - 'ip' => $request->ip ?? null, - 'user_gateway_id' => $request->user_gateway_id ?? null, - 'created_at' => $request->created_at ?? null, - 'updated_at' => $request->updated_at ?? null, - ]); - } -} diff --git a/backend/app/User/Controllers/Payment/PaymentController.php b/backend/app/User/Controllers/Payment/PaymentController.php index 4ec9251b..69e7cd97 100644 --- a/backend/app/User/Controllers/Payment/PaymentController.php +++ b/backend/app/User/Controllers/Payment/PaymentController.php @@ -3,9 +3,10 @@ namespace App\User\Controllers\Payment; use App\Http\Controllers\Controller; +use App\Services\Payments\DTO\PaymentCreateDTO; use App\Services\Payments\PaymentService; use App\Traits\ApiResponse; -use App\User\Controllers\Payment\DTO\PaymentCreateDTO; +use App\User\Requests\Payment\FIB\StoreRequest; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -21,7 +22,7 @@ class PaymentController extends Controller $this->payment_service = $payment_service; } - public function createPayment(Request $request): JsonResponse + public function createPayment(StoreRequest $request): JsonResponse { try { $dto = PaymentCreateDTO::fromRequest($request); diff --git a/backend/app/User/Requests/Payment/FIB/StoreRequest.php b/backend/app/User/Requests/Payment/FIB/StoreRequest.php new file mode 100644 index 00000000..7ef61312 --- /dev/null +++ b/backend/app/User/Requests/Payment/FIB/StoreRequest.php @@ -0,0 +1,36 @@ +user()->kyc_status; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules(): array + { + return [ + 'username' => ['required'], + 'track_id' => ['required'], + 'amount' => ['required'], + 'currency' => ['required'], + 'callback_url' => ['required'], + 'user_gateway_id' => ['required'], + ]; + } +} diff --git a/backend/database/migrations/2026_05_18_095610_create_transactions_table.php b/backend/database/migrations/2026_05_18_095610_create_transactions_table.php index 208f6f8e..0ffccd66 100644 --- a/backend/database/migrations/2026_05_18_095610_create_transactions_table.php +++ b/backend/database/migrations/2026_05_18_095610_create_transactions_table.php @@ -4,8 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration -{ +return new class extends Migration { /** * Run the migrations. */ @@ -14,15 +13,15 @@ return new class extends Migration Schema::create('transactions', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained('users'); - $table->string('amount'); - $table->string('currency'); - $table->string('callback_url'); - $table->string('description'); - $table->dateTime('expires_in'); + $table->string('amount')->nullable(); + $table->string('currency')->nullable(); + $table->string('callback_url')->nullable(); + $table->string('description')->nullable(); + $table->dateTime('expires_in')->nullable(); $table->foreignId('payment_id')->constrained('payments'); - $table->string('payment_track_id'); + $table->string('payment_track_id')->nullable(); $table->foreignId('user_gateway_id')->constrained('user_gateways'); - $table->integer('status'); + $table->integer('status')->nullable(); $table->timestamps(); }); } diff --git a/backend/database/migrations/2026_05_18_104524_create_fib_transactions_table.php b/backend/database/migrations/2026_05_18_104524_create_fib_transactions_table.php index 3e914953..2b346264 100644 --- a/backend/database/migrations/2026_05_18_104524_create_fib_transactions_table.php +++ b/backend/database/migrations/2026_05_18_104524_create_fib_transactions_table.php @@ -4,8 +4,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration -{ +return new class extends Migration { /** * Run the migrations. */ @@ -14,23 +13,23 @@ return new class extends Migration Schema::create('fib_transactions', function (Blueprint $table) { $table->id(); $table->foreignId('transaction_id')->constrained('transactions'); - $table->text('qrcode'); - $table->string('readable_code'); - $table->string('personalAppLink'); - $table->string('businessAppLink'); - $table->string('corporateAppLink'); - $table->string('paymentId'); - $table->string('paymentMethod'); - $table->timestamp('validUntil'); + $table->text('qrcode')->nullable(); + $table->string('readable_code')->nullable(); + $table->string('personalAppLink')->nullable(); + $table->string('businessAppLink')->nullable(); + $table->string('corporateAppLink')->nullable(); + $table->string('paymentId')->nullable(); + $table->string('paymentMethod')->nullable(); + $table->timestamp('validUntil')->nullable(); $table->foreignId('status_id')->constrained('fib_transaction_statuses'); - $table->string('status_name'); - $table->timestamp('paidAt'); - $table->string('paidAmount'); - $table->string('paidCurrency'); - $table->string('decliningReason'); - $table->timestamp('declinedAt'); - $table->string('paidByName'); - $table->string('paidByIban'); + $table->string('status_name')->nullable(); + $table->timestamp('paidAt')->nullable(); + $table->string('paidAmount')->nullable(); + $table->string('paidCurrency')->nullable(); + $table->string('decliningReason')->nullable(); + $table->timestamp('declinedAt')->nullable(); + $table->string('paidByName')->nullable(); + $table->string('paidByIban')->nullable(); $table->timestamps(); }); } diff --git a/backend/database/seeders/FibTransactionStatusSeeder.php b/backend/database/seeders/FibTransactionStatusSeeder.php index 0949ff45..f634b061 100644 --- a/backend/database/seeders/FibTransactionStatusSeeder.php +++ b/backend/database/seeders/FibTransactionStatusSeeder.php @@ -4,6 +4,7 @@ namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; +use Illuminate\Support\Facades\DB; class FibTransactionStatusSeeder extends Seeder { @@ -12,6 +13,12 @@ class FibTransactionStatusSeeder extends Seeder */ public function run(): void { - // + DB::table('fib_transaction_statuses')->insert([ + ['id' => 0, 'name' => 'unpaid', 'created_at' => now(), 'updated_at' => now(),], + ['id' => 1, 'name' => 'cancelled', 'created_at' => now(), 'updated_at' => now(),], + ['id' => 2, 'name' => 'expired', 'created_at' => now(), 'updated_at' => now(),], + ['id' => 3, 'name' => 'paid', 'created_at' => now(), 'updated_at' => now(),], + ['id' => 4, 'name' => 'refunded', 'created_at' => now(), 'updated_at' => now(),], + ]); } } diff --git a/backend/routes/api.php b/backend/routes/api.php index a511350e..5eaa6efa 100755 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -10,8 +10,10 @@ Route::get('/user', function (Request $request) { })->middleware('auth:api'); Route::prefix('v1')->group(function () { - Route::prefix('payment')->group(function () { - Route::get('/create_payment', [PaymentController::class, 'createPayment']); - }); + Route::prefix('payment') +// ->middleware('auth:api') + ->group(function () { + Route::post('/create_payment', [PaymentController::class, 'createPayment'])->name('create_payment'); + }); });