refactor(ticket): implement fixed validity time generation for event date and time windows in TicketGeneratorService
This commit is contained in:
@@ -5,6 +5,7 @@ namespace App\Domains\Ticket\Services;
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Exceptions\TicketGenerationException;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
@@ -34,14 +35,21 @@ class TicketGeneratorService
|
||||
$quantity,
|
||||
$sourceVariantId,
|
||||
);
|
||||
$fixedValidityTimes = [];
|
||||
|
||||
return $targets->map(function (array $target) use (
|
||||
&$fixedValidityTimes,
|
||||
$sourcePurchaseId,
|
||||
$user,
|
||||
): Ticket {
|
||||
$item = $target['catalog_item'];
|
||||
$variant = $target['variant'];
|
||||
$validityTime = $this->resolveValidityTime($item, $variant);
|
||||
$validityTime = $this->materializeEventDateValidityTime(
|
||||
$variant,
|
||||
$validityTime,
|
||||
$fixedValidityTimes,
|
||||
);
|
||||
|
||||
return Ticket::query()->create([
|
||||
'tenant_code' => $item->tenant_code,
|
||||
@@ -168,4 +176,56 @@ class TicketGeneratorService
|
||||
|
||||
return $validityTimes->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a recurring time window into the fixed date and time purchased by
|
||||
* the customer. Equal tickets generated together share the same snapshot.
|
||||
*
|
||||
* @param array<string, ValidityTime> $fixedValidityTimes
|
||||
*/
|
||||
private function materializeEventDateValidityTime(
|
||||
?Variant $variant,
|
||||
?ValidityTime $validityTime,
|
||||
array &$fixedValidityTimes,
|
||||
): ?ValidityTime {
|
||||
if (
|
||||
$variant === null
|
||||
|| $validityTime === null
|
||||
|| $validityTime->type !== ValidityTimeType::TimeWindow
|
||||
) {
|
||||
return $validityTime;
|
||||
}
|
||||
|
||||
$variant->loadMissing('eventDate');
|
||||
$eventDate = $variant->eventDate;
|
||||
|
||||
if ($eventDate === null) {
|
||||
return $validityTime;
|
||||
}
|
||||
|
||||
$cacheKey = $eventDate->getKey().':'.$validityTime->getKey();
|
||||
|
||||
if (isset($fixedValidityTimes[$cacheKey])) {
|
||||
return $fixedValidityTimes[$cacheKey];
|
||||
}
|
||||
|
||||
$startsAt = $validityTime->startsAt($eventDate->date);
|
||||
$expiresAt = $validityTime->expiresAt($eventDate->date);
|
||||
|
||||
if (
|
||||
$startsAt !== null
|
||||
&& $expiresAt !== null
|
||||
&& $expiresAt->lessThanOrEqualTo($startsAt)
|
||||
) {
|
||||
$expiresAt = $expiresAt->addDay();
|
||||
}
|
||||
|
||||
return $fixedValidityTimes[$cacheKey] = ValidityTime::query()->create([
|
||||
'type' => ValidityTimeType::FixedWindow,
|
||||
'start_time' => null,
|
||||
'end_time' => null,
|
||||
'fixed_starts_at' => $startsAt,
|
||||
'fixed_expires_at' => $expiresAt,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
33
app/Domains/Ticket/documentacion/README.md
Normal file
33
app/Domains/Ticket/documentacion/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Dominio Ticket
|
||||
|
||||
## Propósito
|
||||
|
||||
Genera, valida, consulta y exporta entradas asociadas a compras pagadas de productos o variantes ticketables.
|
||||
|
||||
## Modelo
|
||||
|
||||
- `Ticket`: pertenece a tenant y usuario, conserva referencias a compra, producto, variante, validez y usuario escáner.
|
||||
- `ValidityTime`: define ventanas absolutas o relativas de vigencia para productos, opciones y tickets.
|
||||
- `ValidityTimeType`: enum de estrategias de vigencia.
|
||||
|
||||
El modelo calcula si un ticket está vigente, vencido o usado, y resuelve sus fechas efectivas de inicio y fin.
|
||||
|
||||
## Flujo de generación
|
||||
|
||||
1. `Purchase` emite `PurchasePaid` al confirmarse el pago.
|
||||
2. `GenerateTicketsForPaidPurchase` atiende el evento.
|
||||
3. `TicketGeneratorService` crea los tickets requeridos según ítems, cantidades y vigencia.
|
||||
4. El flujo puede emitir disponibilidad para que `Notification` informe al comprador.
|
||||
|
||||
## Endpoints
|
||||
|
||||
Bajo `/tenants/{tenant:codigo}`, protegidos por `auth:sanctum`:
|
||||
|
||||
- `GET /tickets`.
|
||||
- `POST /tickets/pdf`.
|
||||
|
||||
`TicketPdfService` genera la descarga y `TicketResource`/`ValidityTimeResource` definen las respuestas.
|
||||
|
||||
## Dependencias y reglas
|
||||
|
||||
Depende de `Purchase`, `Catalog`, `Tenant` y `Auth`. La generación debe ser idempotente ante reintentos del evento. `TicketNotAvailableException` y `TicketGenerationException` separan indisponibilidad de errores de generación.
|
||||
Reference in New Issue
Block a user