- Added localization support for API responses in English and Spanish. - Introduced a middleware to set the API locale based on the Accept-Language header. - Updated various exception messages and validation responses to use localized strings. - Created new language files for English and Spanish translations. - Refactored existing code to replace hardcoded messages with localized strings. - Added tests to verify localization functionality and response correctness.
244 lines
8.6 KiB
PHP
244 lines
8.6 KiB
PHP
<?php
|
|
|
|
namespace App\Domains\Purchase\Controllers;
|
|
|
|
use App\Domains\Integration\Services\TelepagosIntegrationService;
|
|
use App\Domains\Purchase\Models\Purchase;
|
|
use App\Domains\Purchase\Models\PurchaseItem;
|
|
use App\Domains\Purchase\Requests\PaymentIntentRequest;
|
|
use App\Domains\Purchase\Requests\StartCheckoutRequest;
|
|
use App\Domains\Purchase\Requests\UpdatePurchaseCustomerRequest;
|
|
use App\Domains\Purchase\Requests\UpdatePurchaseItemQuantityRequest;
|
|
use App\Domains\Purchase\Resources\PurchaseResource;
|
|
use App\Domains\Purchase\Services\CheckoutService;
|
|
use App\Domains\Tenant\Models\Tenant;
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
|
|
class PurchaseController extends Controller
|
|
{
|
|
public function index(Request $request, Tenant $tenant): JsonResponse
|
|
{
|
|
return PurchaseResource::collection(
|
|
Purchase::query()
|
|
->where('tenant_codigo', $tenant->codigo)
|
|
->where('user_id', $request->user()->id)
|
|
->when($request->query('status'), function ($query, $status) {
|
|
$query->where('status', $status);
|
|
})
|
|
->latest()
|
|
->paginateFromRequest()
|
|
)->response();
|
|
}
|
|
|
|
public function startCheckout(
|
|
StartCheckoutRequest $request,
|
|
Tenant $tenant,
|
|
CheckoutService $checkoutService,
|
|
): JsonResponse {
|
|
$data = $request->validated();
|
|
|
|
$purchase = $checkoutService->startCheckout(
|
|
$tenant,
|
|
$request->user()->id,
|
|
$data
|
|
);
|
|
|
|
return PurchaseResource::make($purchase)->response()->setStatusCode(201);
|
|
}
|
|
|
|
public function show(Request $request, Tenant $tenant, Purchase $compra): PurchaseResource
|
|
{
|
|
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
|
|
|
$compra->loadMissing('items');
|
|
$compra->items->load('imageAttachment');
|
|
|
|
return PurchaseResource::make($compra);
|
|
}
|
|
|
|
public function updateCustomerData(
|
|
UpdatePurchaseCustomerRequest $request,
|
|
Tenant $tenant,
|
|
Purchase $compra,
|
|
CheckoutService $checkoutService,
|
|
): PurchaseResource {
|
|
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
|
|
|
return PurchaseResource::make(
|
|
$checkoutService->updateCustomerData($compra, $request->validated()),
|
|
);
|
|
}
|
|
|
|
public function updateItemQuantity(
|
|
UpdatePurchaseItemQuantityRequest $request,
|
|
Tenant $tenant,
|
|
Purchase $compra,
|
|
PurchaseItem $item,
|
|
CheckoutService $checkoutService,
|
|
): PurchaseResource {
|
|
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
|
|
|
return PurchaseResource::make(
|
|
$checkoutService->updateItemQuantity(
|
|
$compra,
|
|
$item,
|
|
(int) $request->validated('quantity'),
|
|
),
|
|
);
|
|
}
|
|
|
|
public function prepareItemEditing(
|
|
Request $request,
|
|
Tenant $tenant,
|
|
Purchase $compra,
|
|
CheckoutService $checkoutService,
|
|
): PurchaseResource {
|
|
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
|
|
|
return PurchaseResource::make(
|
|
$checkoutService->prepareItemEditing($compra),
|
|
);
|
|
}
|
|
|
|
public function paymentIntent(PaymentIntentRequest $request, Tenant $tenant, Purchase $compra): JsonResponse
|
|
{
|
|
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
|
$method = $request->validated('method');
|
|
$totalAmount = $compra->calculateCurrentTotalAmount();
|
|
|
|
$purchaseUpdate = [
|
|
'payment_method' => $method,
|
|
'status' => Purchase::STATUS_PENDING_PAYMENT,
|
|
'expires_at' => now()->addMinutes(
|
|
max(1, (int) config("purchase.payment_expiration_minutes.{$method}", 30))
|
|
),
|
|
'total' => $totalAmount,
|
|
];
|
|
|
|
if ($method === 'transfer') {
|
|
$purchaseUpdate['transfer_payer_dni'] = preg_replace('/\D+/', '', (string) $request->validated('transfer_payer_dni'));
|
|
}
|
|
|
|
$updated = Purchase::query()
|
|
->whereKey($compra->getKey())
|
|
->whereIn('status', [Purchase::STATUS_CREATED, Purchase::STATUS_PENDING_PAYMENT])
|
|
->where(function ($query): void {
|
|
$query->whereNull('expires_at')
|
|
->orWhere('expires_at', '>', now());
|
|
})
|
|
->update($purchaseUpdate);
|
|
|
|
if ($updated === 0) {
|
|
throw ValidationException::withMessages([
|
|
'purchase' => __('api.purchase.not_available_for_payment'),
|
|
]);
|
|
}
|
|
|
|
$compra->refresh();
|
|
|
|
if ($method === 'transfer') {
|
|
$telepagosService = new TelepagosIntegrationService;
|
|
$telepagosService->forTenant($tenant->codigo);
|
|
|
|
try {
|
|
$accountInfo = $telepagosService->getAccountInfo();
|
|
|
|
return response()->json([
|
|
'payment_method' => 'transfer',
|
|
'transfer_data' => [
|
|
'titular' => $accountInfo['holder'] ?? null,
|
|
'cvu' => $accountInfo['cvu'] ?? null,
|
|
'alias' => $accountInfo['alias'] ?? null,
|
|
'cuit' => $accountInfo['cuit'] ?? null,
|
|
'entidad' => $accountInfo['entity'] ?? 'Telepagos S.A.',
|
|
],
|
|
]);
|
|
} catch (\Exception $e) {
|
|
Log::error('Unable to retrieve TelePagos account information.', [
|
|
'purchase_id' => $compra->id,
|
|
'exception' => $e,
|
|
]);
|
|
|
|
return response()->json([
|
|
'code' => 'integration.account_info_failed',
|
|
'message' => __('api.integration.account_info_failed'),
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
if ($method === 'qr') {
|
|
$telepagosService = new TelepagosIntegrationService;
|
|
$telepagosService->forTenant($tenant->codigo);
|
|
|
|
try {
|
|
Log::info("Generating QR for purchase ID: {$compra->id}, amount: {$totalAmount}");
|
|
$qrResponse = $telepagosService->generateQr(
|
|
$totalAmount,
|
|
'Compra',
|
|
"Compra #{$compra->id}"
|
|
);
|
|
|
|
$telepagosQr = $compra->telepagosQr()->create([
|
|
'qr_order_id' => (string) ($qrResponse['qr_order_id'] ?? ''),
|
|
'qr_code' => $qrResponse['qr_code'] ?? '',
|
|
]);
|
|
} catch (\Exception $e) {
|
|
Log::error('Unable to generate TelePagos QR code.', [
|
|
'purchase_id' => $compra->id,
|
|
'exception' => $e,
|
|
]);
|
|
|
|
return response()->json([
|
|
'code' => 'integration.qr_generation_failed',
|
|
'message' => __('api.integration.qr_generation_failed'),
|
|
], 500);
|
|
}
|
|
|
|
return response()->json([
|
|
'payment_method' => 'qr',
|
|
'qr_data' => [
|
|
'qr_code' => $telepagosQr->qr_code,
|
|
'qr_order_id' => $telepagosQr->qr_order_id,
|
|
],
|
|
]);
|
|
}
|
|
|
|
return response()->json([
|
|
'code' => 'integration.invalid_payment_method',
|
|
'message' => __('api.integration.invalid_payment_method'),
|
|
], 400);
|
|
}
|
|
|
|
public function complete(Request $request, Tenant $tenant, Purchase $compra, CheckoutService $checkoutService): PurchaseResource
|
|
{
|
|
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
|
|
|
return PurchaseResource::make(
|
|
$checkoutService->completePurchase($compra)
|
|
);
|
|
}
|
|
|
|
public function cancel(Request $request, Tenant $tenant, Purchase $compra, CheckoutService $checkoutService): PurchaseResource
|
|
{
|
|
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
|
|
|
return PurchaseResource::make(
|
|
$checkoutService->cancelPurchase($compra)
|
|
);
|
|
}
|
|
|
|
protected function resolveScopedPurchase(Tenant $tenant, int $userId, Purchase $purchase): Purchase
|
|
{
|
|
if ($purchase->tenant_codigo !== $tenant->codigo || $purchase->user_id !== $userId) {
|
|
throw new NotFoundHttpException(__('api.errors.not_found'));
|
|
}
|
|
|
|
return $purchase;
|
|
}
|
|
}
|