From 6bda3bf013f7c6b596a4651aeb32a69d0e2fd98b Mon Sep 17 00:00:00 2001 From: ncoronel Date: Mon, 6 Jul 2026 11:47:04 -0300 Subject: [PATCH] feat: add payment intent handling in PurchaseController with validation and QR generation --- .../Services/TelepagosIntegrationService.php | 2 +- .../Controllers/PurchaseController.php | 60 +++++++++++++++++++ .../Requests/PaymentIntentRequest.php | 24 ++++++++ .../Requests/StorePurchaseRequest.php | 1 - .../Purchase/Services/CheckoutService.php | 3 + app/Domains/Purchase/routes/api.php | 1 + 6 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 app/Domains/Purchase/Requests/PaymentIntentRequest.php diff --git a/app/Domains/Integration/Services/TelepagosIntegrationService.php b/app/Domains/Integration/Services/TelepagosIntegrationService.php index 0440e60..fbfda83 100644 --- a/app/Domains/Integration/Services/TelepagosIntegrationService.php +++ b/app/Domains/Integration/Services/TelepagosIntegrationService.php @@ -21,7 +21,7 @@ class TelepagosIntegrationService extends BaseIntegrationService if ($integrationCode === 'telepagos' && !app()->environment('production')) { $integrationCode = 'telepagos_homo'; } - + $this->integrationCode = $integrationCode; } diff --git a/app/Domains/Purchase/Controllers/PurchaseController.php b/app/Domains/Purchase/Controllers/PurchaseController.php index ef5cac3..1d75712 100644 --- a/app/Domains/Purchase/Controllers/PurchaseController.php +++ b/app/Domains/Purchase/Controllers/PurchaseController.php @@ -50,7 +50,67 @@ class PurchaseController extends Controller ); } + public function paymentIntent(\App\Domains\Purchase\Requests\PaymentIntentRequest $request, Tenant $tenant, Purchase $compra): JsonResponse + { + $compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra); + $method = $request->validated('method'); + $compra->update([ + 'payment_method' => $method, + ]); + + if ($method === 'transfer') { + $bankAccount = $tenant->selectedBankAccount; + + return response()->json([ + 'payment_method' => 'transfer', + 'transfer_data' => $bankAccount ? [ + 'titular' => $bankAccount->titular, + 'entidad' => $bankAccount->entidad, + 'alias' => $bankAccount->alias, + 'cvu' => $bankAccount->cvu, + ] : null, + ]); + } + + if ($method === 'qr') { + $telepagosQr = $compra->telepagosQr; + + if (!$telepagosQr) { + $telepagosService = new \App\Domains\Integration\Services\TelepagosIntegrationService(); + $telepagosService->forTenant($tenant->codigo); + + try { + $qrResponse = $telepagosService->generateQr( + $compra->getTotalAmount(), + 'Compra', + "Compra #{$compra->id}" + ); + + $telepagosQr = $compra->telepagosQr()->create([ + 'qr_order_id' => (string) ($qrResponse['id'] ?? $qrResponse['order_id'] ?? $qrResponse['cashin_id'] ?? ''), + 'qr_code' => $qrResponse['qr'] ?? $qrResponse['qr_code'] ?? $qrResponse['qr_data'] ?? '', + ]); + } catch (\Exception $e) { + return response()->json([ + 'message' => 'Error generating QR: ' . $e->getMessage() + ], 500); + } + } + + return response()->json([ + 'payment_method' => 'qr', + 'qr_data' => [ + 'qr_code' => $telepagosQr->qr_code, + 'qr_order_id' => $telepagosQr->qr_order_id, + ], + ]); + } + + return response()->json([ + 'message' => 'Invalid payment method.', + ], 400); + } protected function resolveScopedPurchase(Tenant $tenant, int $userId, Purchase $purchase): Purchase { diff --git a/app/Domains/Purchase/Requests/PaymentIntentRequest.php b/app/Domains/Purchase/Requests/PaymentIntentRequest.php new file mode 100644 index 0000000..cfb7b65 --- /dev/null +++ b/app/Domains/Purchase/Requests/PaymentIntentRequest.php @@ -0,0 +1,24 @@ +user() !== null; + } + + /** + * @return array + */ + public function rules(): array + { + return [ + 'method' => ['required', 'string', Rule::in(['qr', 'transfer'])], + ]; + } +} diff --git a/app/Domains/Purchase/Requests/StorePurchaseRequest.php b/app/Domains/Purchase/Requests/StorePurchaseRequest.php index 8b768d9..1bb33af 100644 --- a/app/Domains/Purchase/Requests/StorePurchaseRequest.php +++ b/app/Domains/Purchase/Requests/StorePurchaseRequest.php @@ -19,7 +19,6 @@ class StorePurchaseRequest extends FormRequest { return [ 'status' => ['sometimes', 'string', Rule::in(['pending', 'paid', 'cancelled'])], - 'payment_method' => ['required', 'string'], 'dni' => ['required', 'string'], 'telefono' => ['required', 'string'], 'nombre_apellido' => ['required', 'string'], diff --git a/app/Domains/Purchase/Services/CheckoutService.php b/app/Domains/Purchase/Services/CheckoutService.php index 32423e8..413457e 100644 --- a/app/Domains/Purchase/Services/CheckoutService.php +++ b/app/Domains/Purchase/Services/CheckoutService.php @@ -26,6 +26,9 @@ class CheckoutService ...$purchaseData, 'tenant_codigo' => $tenant->codigo, 'user_id' => $userId, + 'status' => 'pending', + 'payment_status' => 'pending', + 'payment_method' => null, ]); $purchase->items()->createMany($purchaseItemsPayload); diff --git a/app/Domains/Purchase/routes/api.php b/app/Domains/Purchase/routes/api.php index ed5f43b..b7d0774 100644 --- a/app/Domains/Purchase/routes/api.php +++ b/app/Domains/Purchase/routes/api.php @@ -5,4 +5,5 @@ use Illuminate\Support\Facades\Route; Route::prefix('tenants/{tenant:codigo}')->middleware('auth:sanctum')->group(function (): void { Route::apiResource('compras', PurchaseController::class)->only(['index', 'store', 'show']); + Route::post('compras/{compra}/payment-intent', [PurchaseController::class, 'paymentIntent']); });