feat(desfile): list paginated entry reservations

This commit is contained in:
2026-09-24 10:02:26 -03:00
parent 5bb61fc74c
commit d8d8354070
6 changed files with 157 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Domains\Ticketing\Desfile\Controllers;
use App\Domains\Ticketing\Desfile\Requests\IndexEntryReservationsRequest;
use App\Domains\Ticketing\Desfile\Requests\StoreEntryReservationsRequest;
use App\Domains\Ticketing\Desfile\Resources\EntryReservationResource;
use App\Domains\Ticketing\Desfile\Services\EntryReservationService;
@@ -10,6 +11,13 @@ use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
class EntryReservationController extends Controller
{
public function index(IndexEntryReservationsRequest $request, EntryReservationService $service): AnonymousResourceCollection
{
return EntryReservationResource::collection(
$service->reservations($request->user(), $request->validated()),
);
}
public function store(StoreEntryReservationsRequest $request, EntryReservationService $service): AnonymousResourceCollection
{
return EntryReservationResource::collection($service->reserve(

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Domains\Ticketing\Desfile\Requests;
use App\Domains\Ticketing\Desfile\Enums\EntryReservationPaymentType;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexEntryReservationsRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()?->tenant_codigo === 'desfile_pura_tendencia';
}
public function rules(): array
{
return [
'tipo_pago' => ['sometimes', 'nullable', Rule::enum(EntryReservationPaymentType::class)],
'page' => ['sometimes', 'integer', 'min:1'],
'per_page' => ['sometimes', 'integer', 'min:1', 'max:100'],
];
}
}

View File

@@ -9,13 +9,39 @@ class EntryReservationResource extends JsonResource
{
public function toArray(Request $request): array
{
$selection = $this->relationLoaded('variant')
? $this->variant->selectionOptions()
: collect();
return [
'id' => $this->id,
'variant_id' => $this->variant_id,
'ticket_id' => $this->ticket_id,
'fecha_reserva' => $this->fecha_reserva->toIso8601String(),
'tipo_pago' => $this->tipo_pago->value,
'tipo_pago_label' => $this->tipo_pago->label(),
'importe' => $this->importe,
'entrada' => [
'tipo' => $this->selectionLabel($selection->get('tipo')),
'sector' => $this->selectionLabel($selection->get('sector')),
'fila' => $this->selectionLabel($selection->get('fila')),
'asiento' => $this->selectionLabel($selection->get('asiento')),
],
];
}
private function selectionLabel(mixed $selection): ?string
{
if (! is_array($selection)) {
return null;
}
if (array_is_list($selection)) {
$labels = collect($selection)->pluck('label')->filter()->implode(', ');
return $labels !== '' ? $labels : null;
}
return isset($selection['label']) ? (string) $selection['label'] : null;
}
}

View File

@@ -11,6 +11,8 @@ use App\Domains\Ticketing\Desfile\Enums\EntryReservationPaymentType;
use App\Domains\Ticketing\Desfile\Models\EntryReservation;
use App\Domains\Ticketing\Ticket\Exceptions\TicketGenerationException;
use App\Domains\Ticketing\Ticket\Services\TicketGeneratorService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
@@ -19,6 +21,38 @@ class EntryReservationService
{
public function __construct(private readonly TicketGeneratorService $tickets) {}
/**
* @param array{tipo_pago?: string|null, page?: int, per_page?: int} $filters
* @return LengthAwarePaginator<EntryReservation>
*/
public function reservations(User $user, array $filters = []): LengthAwarePaginator
{
abort_unless($user->tenant_codigo === 'desfile_pura_tendencia', 403);
return EntryReservation::query()
->whereHas('variant.catalogItem', fn (Builder $query): Builder => $query
->where('tenant_code', $user->tenant_codigo)
->where('slug', 'entrada'))
->when(
$filters['tipo_pago'] ?? null,
fn (Builder $query, string $paymentType): Builder => $query->where('tipo_pago', $paymentType),
)
->with([
'variant.catalogItem.itemAttributes.attribute.options',
'variant.definitions.itemAttribute.attribute.options',
'variant.eventDates',
'variant.eventDate',
])
->orderByDesc('fecha_reserva')
->orderByDesc('id')
->paginate(
perPage: $filters['per_page'] ?? 15,
pageName: 'page',
page: $filters['page'] ?? 1,
)
->withQueryString();
}
/** @param list<array{variant_id: int, tipo_pago: string}> $rows */
public function reserve(User $user, string $key, array $rows): Collection
{

View File

@@ -4,6 +4,9 @@ use App\Domains\Ticketing\Desfile\Controllers\EntryController;
use App\Domains\Ticketing\Desfile\Controllers\EntryReservationController;
use Illuminate\Support\Facades\Route;
Route::get('v1/adminapp/tenant/desfile/entry-reservations', [EntryReservationController::class, 'index'])
->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas'])
->name('adminapp.desfile.entry-reservations.index');
Route::post('v1/adminapp/tenant/desfile/entry-reservations', [EntryReservationController::class, 'store'])
->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas'])
->name('adminapp.desfile.entry-reservations.store');