feat: add migration to expand tenant_codigo in bundles and update related seeders and tests
This commit is contained in:
parent
b8eb71896c
commit
d3182fbd13
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('bundles', function (Blueprint $table) {
|
||||
$table->dropForeign(['tenant_codigo']);
|
||||
});
|
||||
|
||||
Schema::table('bundles', function (Blueprint $table) {
|
||||
$table->string('tenant_codigo')->change();
|
||||
$table->foreign('tenant_codigo')->references('codigo')->on('tenants')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('bundles', function (Blueprint $table) {
|
||||
$table->dropForeign(['tenant_codigo']);
|
||||
});
|
||||
|
||||
Schema::table('bundles', function (Blueprint $table) {
|
||||
$table->string('tenant_codigo', 10)->change();
|
||||
$table->foreign('tenant_codigo')->references('codigo')->on('tenants')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -18,7 +18,7 @@ class AttributeSeeder extends Seeder
|
|||
$tenants = Tenant::all();
|
||||
|
||||
foreach ($tenants as $tenant) {
|
||||
// Seed Color attribute
|
||||
// Fiesta Futbol Infantil only uses the Fecha attribute.
|
||||
$existingColor = Attribute::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->where('codigo', 'color')
|
||||
|
|
@ -28,41 +28,43 @@ class AttributeSeeder extends Seeder
|
|||
Product::deleteAttribute($existingColor);
|
||||
}
|
||||
|
||||
Product::createAttribute($tenant, [
|
||||
'codigo' => 'color',
|
||||
'nombre' => 'Color',
|
||||
'type' => FieldType::Select->value,
|
||||
'is_required' => true,
|
||||
'metadata_schema' => [
|
||||
'hex' => ['type' => 'string'],
|
||||
],
|
||||
'options' => [
|
||||
[
|
||||
'value' => 'Negro',
|
||||
'label' => 'Negro',
|
||||
'sort_order' => 1,
|
||||
'metadata' => ['hex' => '#000000'],
|
||||
if ($tenant->codigo !== 'fiesta_futbol_infantil') {
|
||||
Product::createAttribute($tenant, [
|
||||
'codigo' => 'color',
|
||||
'nombre' => 'Color',
|
||||
'type' => FieldType::Select->value,
|
||||
'is_required' => true,
|
||||
'metadata_schema' => [
|
||||
'hex' => ['type' => 'string'],
|
||||
],
|
||||
[
|
||||
'value' => 'Gris',
|
||||
'label' => 'Gris',
|
||||
'sort_order' => 2,
|
||||
'metadata' => ['hex' => '#808080'],
|
||||
'options' => [
|
||||
[
|
||||
'value' => 'Negro',
|
||||
'label' => 'Negro',
|
||||
'sort_order' => 1,
|
||||
'metadata' => ['hex' => '#000000'],
|
||||
],
|
||||
[
|
||||
'value' => 'Gris',
|
||||
'label' => 'Gris',
|
||||
'sort_order' => 2,
|
||||
'metadata' => ['hex' => '#808080'],
|
||||
],
|
||||
[
|
||||
'value' => 'Blanco',
|
||||
'label' => 'Blanco',
|
||||
'sort_order' => 3,
|
||||
'metadata' => ['hex' => '#FFFFFF'],
|
||||
],
|
||||
[
|
||||
'value' => 'Azul',
|
||||
'label' => 'Azul',
|
||||
'sort_order' => 4,
|
||||
'metadata' => ['hex' => '#0000FF'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'value' => 'Blanco',
|
||||
'label' => 'Blanco',
|
||||
'sort_order' => 3,
|
||||
'metadata' => ['hex' => '#FFFFFF'],
|
||||
],
|
||||
[
|
||||
'value' => 'Azul',
|
||||
'label' => 'Azul',
|
||||
'sort_order' => 4,
|
||||
'metadata' => ['hex' => '#0000FF'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
]);
|
||||
}
|
||||
|
||||
// Seed Talle (Size - Text options) attribute
|
||||
$existingTalle = Attribute::query()
|
||||
|
|
@ -74,18 +76,20 @@ class AttributeSeeder extends Seeder
|
|||
Product::deleteAttribute($existingTalle);
|
||||
}
|
||||
|
||||
Product::createAttribute($tenant, [
|
||||
'codigo' => 'talle',
|
||||
'nombre' => 'Talle',
|
||||
'type' => FieldType::Select->value,
|
||||
'is_required' => true,
|
||||
'options' => [
|
||||
['value' => 'S', 'label' => 'S', 'sort_order' => 1],
|
||||
['value' => 'M', 'label' => 'M', 'sort_order' => 2],
|
||||
['value' => 'L', 'label' => 'L', 'sort_order' => 3],
|
||||
['value' => 'XL', 'label' => 'XL', 'sort_order' => 4],
|
||||
],
|
||||
]);
|
||||
if ($tenant->codigo !== 'fiesta_futbol_infantil') {
|
||||
Product::createAttribute($tenant, [
|
||||
'codigo' => 'talle',
|
||||
'nombre' => 'Talle',
|
||||
'type' => FieldType::Select->value,
|
||||
'is_required' => true,
|
||||
'options' => [
|
||||
['value' => 'S', 'label' => 'S', 'sort_order' => 1],
|
||||
['value' => 'M', 'label' => 'M', 'sort_order' => 2],
|
||||
['value' => 'L', 'label' => 'L', 'sort_order' => 3],
|
||||
['value' => 'XL', 'label' => 'XL', 'sort_order' => 4],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Seed Talle Numérico (Numeric Size options) attribute
|
||||
$existingTalleNumerico = Attribute::query()
|
||||
|
|
@ -97,18 +101,20 @@ class AttributeSeeder extends Seeder
|
|||
Product::deleteAttribute($existingTalleNumerico);
|
||||
}
|
||||
|
||||
Product::createAttribute($tenant, [
|
||||
'codigo' => 'talle_numerico',
|
||||
'nombre' => 'Talle Numérico',
|
||||
'type' => FieldType::Select->value,
|
||||
'is_required' => true,
|
||||
'options' => [
|
||||
['value' => '38', 'label' => '38', 'sort_order' => 1],
|
||||
['value' => '40', 'label' => '40', 'sort_order' => 2],
|
||||
['value' => '42', 'label' => '42', 'sort_order' => 3],
|
||||
['value' => '44', 'label' => '44', 'sort_order' => 4],
|
||||
],
|
||||
]);
|
||||
if ($tenant->codigo !== 'fiesta_futbol_infantil') {
|
||||
Product::createAttribute($tenant, [
|
||||
'codigo' => 'talle_numerico',
|
||||
'nombre' => 'Talle Numérico',
|
||||
'type' => FieldType::Select->value,
|
||||
'is_required' => true,
|
||||
'options' => [
|
||||
['value' => '38', 'label' => '38', 'sort_order' => 1],
|
||||
['value' => '40', 'label' => '40', 'sort_order' => 2],
|
||||
['value' => '42', 'label' => '42', 'sort_order' => 3],
|
||||
['value' => '44', 'label' => '44', 'sort_order' => 4],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Seed Fecha attribute
|
||||
$existingFecha = Attribute::query()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Domains\Bundle\Models\Bundle;
|
||||
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
|
|
@ -24,6 +25,9 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
|||
throw new RuntimeException("Tenant 'fiesta_futbol_infantil' no encontrado.");
|
||||
}
|
||||
|
||||
// Bundles reference product variants, so remove them before reseeding products.
|
||||
Bundle::query()->where('tenant_codigo', $tenant->codigo)->delete();
|
||||
|
||||
// Delete existing products for this tenant
|
||||
$existingProducts = Product::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
|
|
@ -37,6 +41,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
|||
$category = Category::firstOrCreate(['nombre' => 'Entradas', 'tenant_code' => null]);
|
||||
|
||||
$dates = ['2026-10-09', '2026-10-10', '2026-10-11', '2026-10-12'];
|
||||
$entradaVariants = [];
|
||||
|
||||
// 1. Entrada General
|
||||
$entrada = $this->productService->create($tenant, [
|
||||
|
|
@ -51,7 +56,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
|||
]);
|
||||
|
||||
foreach ($dates as $date) {
|
||||
$this->productService->createVariant($entrada, [
|
||||
$entradaVariants[] = $this->productService->createVariant($entrada, [
|
||||
'stock' => 0,
|
||||
'inventory_policy' => InventoryPolicy::Unlimited->value,
|
||||
'has_tickets' => true,
|
||||
|
|
@ -80,8 +85,10 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
|||
['slug' => 'estacionamiento-moto', 'nombre' => 'Estacionamiento Moto', 'precio' => 2000, 'cat' => $category->id],
|
||||
];
|
||||
|
||||
$createdProducts = [];
|
||||
|
||||
foreach ($simpleProducts as $p) {
|
||||
$this->productService->create($tenant, [
|
||||
$createdProducts[$p['slug']] = $this->productService->create($tenant, [
|
||||
'categoria_id' => $p['cat'],
|
||||
'slug' => $p['slug'],
|
||||
'nombre' => $p['nombre'],
|
||||
|
|
@ -91,5 +98,37 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
|||
'inventory_policy' => InventoryPolicy::Unlimited->value,
|
||||
]);
|
||||
}
|
||||
|
||||
$allDaysBundle = Bundle::query()->create([
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
'nombre' => 'Entrada General - Todos los días',
|
||||
'descripcion' => 'Incluye una entrada para cada día de la Fiesta Nacional del Fútbol Infantil.',
|
||||
'precio' => 40000,
|
||||
]);
|
||||
|
||||
foreach ($entradaVariants as $variant) {
|
||||
$allDaysBundle->items()->create([
|
||||
'producto_variante_id' => $variant->id,
|
||||
'cantidad' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
$foodBundle = Bundle::query()->create([
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
'nombre' => 'Combo 2 Panchos + 2 Hamburguesas',
|
||||
'descripcion' => 'Incluye 2 panchos y 2 hamburguesas con papa frita.',
|
||||
'precio' => 24000,
|
||||
]);
|
||||
|
||||
$foodBundle->items()->createMany([
|
||||
[
|
||||
'producto_variante_id' => $createdProducts['pancho']->variants()->sole()->id,
|
||||
'cantidad' => 2,
|
||||
],
|
||||
[
|
||||
'producto_variante_id' => $createdProducts['hamburguesa-papa-frita']->variants()->sole()->id,
|
||||
'cantidad' => 2,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ class TenantSeeder extends Seeder
|
|||
'secondary_color' => '#A0A0A0',
|
||||
'danger_color' => '#FF8888',
|
||||
'success_color' => '#198754',
|
||||
'header_bg_color' => '#015327',
|
||||
'header_bg_color' => '#ffffff',
|
||||
'footer_bg_color' => '#015327',
|
||||
'header_logo' => $fiestaHeaderLogo,
|
||||
'footer_logo' => $fiestaFooterLogo,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Seeders;
|
||||
|
||||
use App\Domains\Attachable\Enums\AttachmentType;
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Bundle\Models\Bundle;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Database\Seeders\AttributeSeeder;
|
||||
use Database\Seeders\FiestaFutbolInfantilProductSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FiestaFutbolInfantilProductSeederTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_it_seeds_event_attributes_and_bundles(): void
|
||||
{
|
||||
$headerLogo = Attachment::query()->create([
|
||||
'path' => 'tests/header.png',
|
||||
'filename' => 'header.png',
|
||||
'type' => AttachmentType::Image,
|
||||
'mime_type' => 'image/png',
|
||||
]);
|
||||
$footerLogo = Attachment::query()->create([
|
||||
'path' => 'tests/footer.png',
|
||||
'filename' => 'footer.png',
|
||||
'type' => AttachmentType::Image,
|
||||
'mime_type' => 'image/png',
|
||||
]);
|
||||
|
||||
$tenant = Tenant::query()->create([
|
||||
'codigo' => 'fiesta_futbol_infantil',
|
||||
'nombre' => 'Fiesta Fútbol Infantil',
|
||||
'dominio' => 'fiesta-futbol-infantil.localhost',
|
||||
'primary_color' => '#00973F',
|
||||
'secondary_color' => '#A0A0A0',
|
||||
'danger_color' => '#FF8888',
|
||||
'success_color' => '#198754',
|
||||
'header_bg_color' => '#ffffff',
|
||||
'footer_bg_color' => '#015327',
|
||||
'header_logo_id' => $headerLogo->id,
|
||||
'footer_logo_id' => $footerLogo->id,
|
||||
]);
|
||||
|
||||
$this->seed([
|
||||
AttributeSeeder::class,
|
||||
FiestaFutbolInfantilProductSeeder::class,
|
||||
]);
|
||||
|
||||
$this->assertFalse(Attribute::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->whereIn('codigo', ['color', 'talle', 'talle_numerico'])
|
||||
->exists());
|
||||
$this->assertSame(
|
||||
['fecha'],
|
||||
Attribute::query()->where('tenant_codigo', $tenant->codigo)->pluck('codigo')->all()
|
||||
);
|
||||
|
||||
$allDaysBundle = Bundle::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->where('nombre', 'Entrada General - Todos los días')
|
||||
->with('items.variant.product', 'items.variant.definitions')
|
||||
->sole();
|
||||
|
||||
$this->assertSame('40000.00', $allDaysBundle->precio);
|
||||
$this->assertCount(4, $allDaysBundle->items);
|
||||
$this->assertEqualsCanonicalizing(
|
||||
['2026-10-09', '2026-10-10', '2026-10-11', '2026-10-12'],
|
||||
$allDaysBundle->items->map(fn ($item) => $item->variant->definitions->sole()->value)->all()
|
||||
);
|
||||
$this->assertTrue($allDaysBundle->items->every(
|
||||
fn ($item) => $item->cantidad === 1 && $item->variant->product->slug === 'entrada-general'
|
||||
));
|
||||
|
||||
$foodBundle = Bundle::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->where('nombre', 'Combo 2 Panchos + 2 Hamburguesas')
|
||||
->with('items.variant.product')
|
||||
->sole();
|
||||
|
||||
$this->assertSame('24000.00', $foodBundle->precio);
|
||||
$this->assertEqualsCanonicalizing(
|
||||
[
|
||||
'pancho' => 2,
|
||||
'hamburguesa-papa-frita' => 2,
|
||||
],
|
||||
$foodBundle->items->mapWithKeys(
|
||||
fn ($item) => [$item->variant->product->slug => $item->cantidad]
|
||||
)->all()
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue