firstOrCreate( ['code' => self::ONTICKET_CLIENT_CODE], ['name' => 'OnTicket'], ); $tenant = Tenant::query()->where('codigo', self::TENANT_CODE)->first(); if ($tenant) { $tenant->update(['client_id' => $client->id]); } else { DB::transaction(function () use ($client): void { $this->createTenant($client); $this->createEventDate(); $this->createEntryCatalog(); }); } $this->invitationPurchaseProvisioner->provision(); } private function createTenant(Client $client): void { $this->tenantService->create([ 'client_id' => $client->id, 'codigo' => self::TENANT_CODE, 'nombre' => 'Desfile Pura Tendencia', 'dominio' => 'desfile-pura-tendencia.localhost', 'site_title' => 'Desfile Pura Tendencia', 'event_title' => 'Desfile Pura Tendencia', 'event_location' => 'Salón Centro Recreativo Luz y Fuerza', 'event_date_text' => '16 de Octubre 2026', 'primary_color' => '#BA69A9', 'secondary_color' => '#A0A0A0', 'danger_color' => '#FF8888', 'success_color' => '#198754', 'header_bg_color' => '#ffffff', 'footer_bg_color' => '#D4441C', 'display_categories' => false, 'display_seach_bar' => false, 'display_cart' => true, 'cart_editing_enabled' => false, 'display_cart_item_images' => false, 'scanner_category_validation_enabled' => false, 'website_type_code' => 'onticket', 'header_logo' => $this->uploadedImage( 'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_header.png', 'desfile_pura_tendencia_header.png', ), 'footer_logo' => $this->uploadedImage( 'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_footer.png', 'desfile_pura_tendencia_footer.png', ), 'favicon' => $this->uploadedImage( 'images/tennants/desfile_pura_tendencia/pura_tendencia_favicon.png', 'pura_tendencia_favicon.png', ), 'footer_bg_image' => $this->uploadedImage( 'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_footer_background.png', 'desfile_pura_tendencia_footer_background.png', ), 'extras' => [ 'heroConfig' => [ 'title_html' => '

LA NOCHE DE LA MODA

', 'description_html' => 'Viví una experiencia de Alta Costura con conducción exclusiva de Pampita y las colecciones de Pucheta-Paz.', 'background_image_id' => $this->uploadedImage( 'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_hero.png', 'desfile_pura_tendencia_hero.png', ), ], ], ]); } private function createEventDate(): void { $now = now(); $validityTimeId = DB::table('validity_times')->insertGetId([ 'type' => 'fixed_window', 'start_time' => null, 'end_time' => null, 'fixed_starts_at' => '2026-10-16 20:30:00', 'fixed_expires_at' => '2026-10-16 23:59:00', 'created_at' => $now, 'updated_at' => $now, ]); DB::table('event_dates')->insert([ 'tenant_code' => self::TENANT_CODE, 'validity_time_id' => $validityTimeId, 'date' => '2026-10-16', 'time_start' => '20:30:00', 'time_end' => '23:59:00', ]); } private function createEntryCatalog(): void { $attributes = [ 'tipo' => ['name' => 'Tipo', 'options' => ['VIP + LUNCH', 'NORMAL']], 'sector' => ['name' => 'Sector', 'options' => ['A', 'B', 'C', 'D']], 'fila' => ['name' => 'Fila', 'options' => array_map('strval', range(1, 5))], 'asiento' => ['name' => 'Asiento', 'options' => array_map('strval', range(1, 100))], ]; foreach ($attributes as $code => $definition) { $attribute = Attribute::query()->create([ 'tenant_codigo' => self::TENANT_CODE, 'codigo' => $code, 'nombre' => $definition['name'], 'is_required' => true, 'metadata_schema' => null, 'type' => 'select', ]); $attribute->options()->createMany(array_map( fn (string $option, int $index): array => [ 'value' => $option, 'label' => $option, 'sort_order' => $index + 1, 'metadata' => null, ], $definition['options'], array_keys($definition['options']), )); } $catalogItem = $this->catalogService->create([ 'tenant_code' => self::TENANT_CODE, 'category_id' => null, 'brand_id' => null, 'slug' => 'entrada', 'nombre' => 'Entrada', 'descripcion' => 'Entrada para Desfile Pura Tendencia', 'precio' => 40000, 'inventory_policy' => InventoryPolicy::Tracked->value, 'inventory_subject' => InventorySubject::Seat->value, 'has_tickets' => true, 'attribute_codes' => array_keys($attributes), 'ticket_attribute_labels' => [ 'sector' => 'Lado', 'fila' => 'Fila', 'asiento' => 'Asiento', ], 'variants' => $this->entryVariants(), 'images' => [ $this->uploadedImage( 'images/tennants/desfile_pura_tendencia/catalog/entrada_pasarela.png', 'entrada_pasarela.png', ), ], ]); $this->setAttributeOrder($catalogItem); FeaturedGroup::query()->create([ 'tenant_code' => self::TENANT_CODE, 'source_type' => FeaturedGroupSource::All, 'category_id' => null, 'product_layout' => ProductLayout::TicketSelector, 'group_layout' => GroupLayout::Single, 'group_name' => 'Entradas', 'group_order' => 0, ]); } /** @return list> */ private function entryVariants(): array { $variants = []; foreach (['A', 'B', 'C', 'D'] as $sector) { $lastSeat = in_array($sector, ['B', 'D'], true) ? 16 : 17; foreach (range(1, 5) as $row) { foreach (range(1, $lastSeat) as $seat) { [$type, $price] = $this->entryTypeAndPrice($sector, $row); $variants[] = [ 'real_stock' => 1, 'descripcion' => "Sector {$sector} - Fila {$row} - Asiento {$seat} - {$type}", 'precio' => $price, 'values' => [ 'tipo' => $type, 'sector' => $sector, 'fila' => (string) $row, 'asiento' => (string) $seat, ], ]; } } } return $variants; } private function setAttributeOrder(CatalogItem $catalogItem): void { $sortOrders = ['tipo' => 1, 'sector' => 2, 'fila' => 3, 'asiento' => 4]; $catalogItem->itemAttributes() ->with('attribute:id,codigo') ->get() ->each(function ($itemAttribute) use ($sortOrders): void { $itemAttribute->update([ 'sort_order' => $sortOrders[$itemAttribute->attribute->codigo], ]); }); } /** @return array{string, int} */ private function entryTypeAndPrice(string $sector, int $row): array { $prices = in_array($sector, ['A', 'C'], true) ? [1 => 250000, 2 => 200000, 3 => 100000, 4 => 75000, 5 => 50000] : [1 => 240000, 2 => 190000, 3 => 90000, 4 => 65000, 5 => 40000]; return [$row <= 2 ? 'VIP + LUNCH' : 'NORMAL', $prices[$row]]; } private function uploadedImage(string $relativePath, string $filename): UploadedFile { $path = public_path($relativePath); if (! is_file($path)) { throw new RuntimeException("Image not found at path: {$path}"); } $mimeType = mime_content_type($path); return new UploadedFile( $path, $filename, is_string($mimeType) ? $mimeType : null, null, true, ); } }