feat(seeder): add Desfile Pura Tendencia seeder and corresponding test
This commit is contained in:
@@ -27,6 +27,7 @@ class DatabaseSeeder extends Seeder
|
|||||||
AuthorizationSeeder::class,
|
AuthorizationSeeder::class,
|
||||||
SocialMediaSeeder::class,
|
SocialMediaSeeder::class,
|
||||||
TenantSeeder::class,
|
TenantSeeder::class,
|
||||||
|
DesfilePuraTendenciaSeeder::class,
|
||||||
AttributeSeeder::class,
|
AttributeSeeder::class,
|
||||||
CategorySeeder::class,
|
CategorySeeder::class,
|
||||||
BrandSeeder::class,
|
BrandSeeder::class,
|
||||||
|
|||||||
251
database/seeders/DesfilePuraTendenciaSeeder.php
Normal file
251
database/seeders/DesfilePuraTendenciaSeeder.php
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||||
|
use App\Domains\Catalog\Enums\GroupLayout;
|
||||||
|
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||||
|
use App\Domains\Catalog\Enums\InventorySubject;
|
||||||
|
use App\Domains\Catalog\Enums\ProductLayout;
|
||||||
|
use App\Domains\Catalog\Models\Attribute;
|
||||||
|
use App\Domains\Catalog\Models\CatalogItem;
|
||||||
|
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||||
|
use App\Domains\Catalog\Services\CatalogService;
|
||||||
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
|
use App\Domains\Tenant\Services\TenantService;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
class DesfilePuraTendenciaSeeder extends Seeder
|
||||||
|
{
|
||||||
|
private const TENANT_CODE = 'desfile_pura_tendencia';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly TenantService $tenantService,
|
||||||
|
private readonly CatalogService $catalogService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
if (Tenant::query()->where('codigo', self::TENANT_CODE)->exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::transaction(function (): void {
|
||||||
|
$this->createTenant();
|
||||||
|
$this->createEventDate();
|
||||||
|
$this->createEntryCatalog();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createTenant(): void
|
||||||
|
{
|
||||||
|
$this->tenantService->create([
|
||||||
|
'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,
|
||||||
|
'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' => '<h1>LA NOCHE DE LA MODA</h1>',
|
||||||
|
'description_html' => 'Viví una experiencia de <b>Alta Costura con conducción exclusiva de Pampita</b> 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),
|
||||||
|
'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<array<string, mixed>> */
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Tests\Feature\Migrations;
|
namespace Tests\Feature\Seeders;
|
||||||
|
|
||||||
|
use Database\Seeders\DesfilePuraTendenciaSeeder;
|
||||||
use Database\Seeders\MenuSeeder;
|
use Database\Seeders\MenuSeeder;
|
||||||
use Database\Seeders\SocialMediaSeeder;
|
use Database\Seeders\SocialMediaSeeder;
|
||||||
use Database\Seeders\TenantSeeder;
|
use Database\Seeders\TenantSeeder;
|
||||||
@@ -11,7 +12,7 @@ use Illuminate\Support\Facades\DB;
|
|||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
class CreateDesfilePuraTendenciaTenantTest extends TestCase
|
class DesfilePuraTendenciaSeederTest extends TestCase
|
||||||
{
|
{
|
||||||
use RefreshDatabase;
|
use RefreshDatabase;
|
||||||
|
|
||||||
@@ -23,34 +24,10 @@ class CreateDesfilePuraTendenciaTenantTest extends TestCase
|
|||||||
WebsiteTypeSeeder::class,
|
WebsiteTypeSeeder::class,
|
||||||
SocialMediaSeeder::class,
|
SocialMediaSeeder::class,
|
||||||
TenantSeeder::class,
|
TenantSeeder::class,
|
||||||
|
DesfilePuraTendenciaSeeder::class,
|
||||||
MenuSeeder::class,
|
MenuSeeder::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$migration = require database_path(
|
|
||||||
'migrations/2026_08_12_020000_create_desfile_pura_tendencia_tenant.php'
|
|
||||||
);
|
|
||||||
$migration->up();
|
|
||||||
|
|
||||||
$rowAndSeatMigration = require database_path(
|
|
||||||
'migrations/2026_08_14_030000_swap_desfile_row_and_seat_semantics.php'
|
|
||||||
);
|
|
||||||
$rowAndSeatMigration->up();
|
|
||||||
|
|
||||||
$seatOptionsMigration = require database_path(
|
|
||||||
'migrations/2026_08_14_040000_expand_desfile_seat_options.php'
|
|
||||||
);
|
|
||||||
$seatOptionsMigration->up();
|
|
||||||
|
|
||||||
$footerBackgroundMigration = require database_path(
|
|
||||||
'migrations/2026_08_12_060000_set_desfile_footer_background_image.php'
|
|
||||||
);
|
|
||||||
$footerBackgroundMigration->up();
|
|
||||||
|
|
||||||
$browserBrandingMigration = require database_path(
|
|
||||||
'migrations/2026_08_14_010000_set_seeded_tenant_browser_branding.php'
|
|
||||||
);
|
|
||||||
$browserBrandingMigration->up();
|
|
||||||
|
|
||||||
$this->assertDatabaseHas('tenants', [
|
$this->assertDatabaseHas('tenants', [
|
||||||
'codigo' => 'desfile_pura_tendencia',
|
'codigo' => 'desfile_pura_tendencia',
|
||||||
'nombre' => 'Desfile Pura Tendencia',
|
'nombre' => 'Desfile Pura Tendencia',
|
||||||
Reference in New Issue
Block a user