*/ public function generate(CatalogItem $catalogItem, User $user, int $quantity = 1): Collection { if ($quantity < 1) { throw TicketGenerationException::invalidQuantity(); } $now = now(); return DB::transaction(function () use ($catalogItem, $user, $quantity, $now): Collection { $catalogItems = $this->resolveCatalogItems($catalogItem, $quantity, $now); return $catalogItems->map(fn (CatalogItem $item): Ticket => Ticket::query()->create([ 'tenant_code' => $item->tenant_code, 'ticket' => (string) Str::uuid(), 'name' => $item->nombre, 'description' => (string) ($item->descripcion ?? ''), 'starts_at' => $item->minimum_use_date, 'expires_at' => $item->maximum_use_date, 'used_at' => null, 'user_id' => $user->getKey(), ])); }); } /** * @return Collection */ private function resolveCatalogItems( CatalogItem $catalogItem, int $quantity, CarbonInterface $now, ): Collection { if (! $catalogItem->isBundle()) { $this->validateCatalogItem($catalogItem, $now); return Collection::times($quantity, fn (): CatalogItem => $catalogItem); } $catalogItem->loadMissing('bundleComponents.catalogItem'); if ($catalogItem->bundleComponents->isEmpty()) { throw TicketGenerationException::emptyBundle($catalogItem); } return $catalogItem->bundleComponents ->flatMap(function ($component) use ($quantity, $now): Collection { $componentItem = $component->catalogItem; $this->validateCatalogItem($componentItem, $now); return Collection::times( $quantity * $component->quantity, fn (): CatalogItem => $componentItem, ); }) ->values(); } private function validateCatalogItem(CatalogItem $catalogItem, CarbonInterface $now): void { if (! $catalogItem->has_tickets) { throw TicketGenerationException::ticketsDisabled($catalogItem); } if ($catalogItem->maximum_use_date?->lessThanOrEqualTo($now)) { throw TicketGenerationException::maximumUseDateReached($catalogItem); } } }