feat(seeder): implement Mutual SMEP attribute seeder and associated tests

This commit is contained in:
2026-09-24 11:52:45 -03:00
parent 6b0efbc6ee
commit 16e2ca679c
5 changed files with 386 additions and 1 deletions

View File

@@ -0,0 +1,139 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
private const TENANT_CODE = 'mutual_smep';
/** @var list<array<string, mixed>> */
private const ATTRIBUTES = [
[
'codigo' => 'color',
'nombre' => 'Color',
'metadata_schema' => [
'hex' => ['type' => 'string'],
],
'options' => [
['value' => 'Negro', 'label' => 'Negro', 'metadata' => ['hex' => '#000000']],
['value' => 'Blanco', 'label' => 'Blanco', 'metadata' => ['hex' => '#FFFFFF']],
['value' => 'Gris', 'label' => 'Gris', 'metadata' => ['hex' => '#808080']],
['value' => 'Plata', 'label' => 'Plata', 'metadata' => ['hex' => '#C0C0C0']],
['value' => 'Azul', 'label' => 'Azul', 'metadata' => ['hex' => '#0000FF']],
['value' => 'Rojo', 'label' => 'Rojo', 'metadata' => ['hex' => '#DC3545']],
['value' => 'Rosa', 'label' => 'Rosa', 'metadata' => ['hex' => '#FFC0CB']],
['value' => 'Multicolor', 'label' => 'Multicolor'],
],
],
[
'codigo' => 'medida_cama',
'nombre' => 'Medida',
'options' => [
['value' => 'Cuna', 'label' => 'Cuna'],
['value' => '1 Plaza', 'label' => '1 Plaza'],
['value' => '1 1/2 Plazas', 'label' => '1 1/2 Plazas'],
['value' => '2 Plazas', 'label' => '2 Plazas'],
['value' => '2 1/2 Plazas', 'label' => '2 1/2 Plazas'],
['value' => 'Queen', 'label' => 'Queen'],
['value' => 'King', 'label' => 'King'],
],
],
[
'codigo' => 'almacenamiento',
'nombre' => 'Almacenamiento',
'options' => [
['value' => '128 GB', 'label' => '128 GB'],
['value' => '256 GB', 'label' => '256 GB'],
['value' => '512 GB', 'label' => '512 GB'],
['value' => '1 TB', 'label' => '1 TB'],
],
],
[
'codigo' => 'memoria_ram',
'nombre' => 'Memoria RAM',
'options' => [
['value' => '4 GB', 'label' => '4 GB'],
['value' => '8 GB', 'label' => '8 GB'],
['value' => '16 GB', 'label' => '16 GB'],
],
],
[
'codigo' => 'rodado',
'nombre' => 'Rodado',
'options' => [
['value' => '16', 'label' => '16'],
['value' => '26', 'label' => '26'],
['value' => '29', 'label' => '29'],
],
],
];
public function up(): void
{
if (! DB::table('tenants')->where('codigo', self::TENANT_CODE)->exists()) {
return;
}
DB::transaction(function (): void {
foreach (self::ATTRIBUTES as $definition) {
$attributeId = $this->upsertAttribute($definition);
DB::table('attribute_options')->where('attribute_id', $attributeId)->delete();
foreach ($definition['options'] as $index => $option) {
DB::table('attribute_options')->insert([
'attribute_id' => $attributeId,
'value' => $option['value'],
'label' => $option['label'],
'sort_order' => $index + 1,
'metadata' => isset($option['metadata'])
? json_encode($option['metadata'], JSON_THROW_ON_ERROR)
: null,
'created_at' => now(),
'updated_at' => now(),
]);
}
}
});
}
public function down(): void
{
DB::table('attribute')
->where('tenant_codigo', self::TENANT_CODE)
->whereIn('codigo', array_column(self::ATTRIBUTES, 'codigo'))
->delete();
}
/** @param array<string, mixed> $definition */
private function upsertAttribute(array $definition): int
{
$attributeId = DB::table('attribute')
->where('tenant_codigo', self::TENANT_CODE)
->where('codigo', $definition['codigo'])
->value('id');
$values = [
'nombre' => $definition['nombre'],
'is_required' => false,
'metadata_schema' => isset($definition['metadata_schema'])
? json_encode($definition['metadata_schema'], JSON_THROW_ON_ERROR)
: null,
'type' => 'select',
'updated_at' => now(),
];
if ($attributeId !== null) {
DB::table('attribute')->where('id', $attributeId)->update($values);
return (int) $attributeId;
}
return (int) DB::table('attribute')->insertGetId([
'tenant_codigo' => self::TENANT_CODE,
'codigo' => $definition['codigo'],
...$values,
'created_at' => now(),
]);
}
};

View File

@@ -3,10 +3,10 @@
namespace Database\Seeders;
use App\Domains\Commerce\Catalog\Models\Attribute;
use App\Shared\Enums\FieldType;
use App\Domains\Core\Tenant\Models\Tenant;
use App\Domains\Ticketing\Ticket\Enums\ValidityTimeType;
use App\Domains\Ticketing\Ticket\Models\ValidityTime;
use App\Shared\Enums\FieldType;
use Illuminate\Database\Seeder;
class AttributeSeeder extends Seeder
@@ -25,6 +25,10 @@ class AttributeSeeder extends Seeder
continue;
}
if ($tenant->codigo === 'mutual_smep') {
continue;
}
$this->seedAttribute($tenant, [
'codigo' => 'color',
'nombre' => 'Color',

View File

@@ -29,6 +29,7 @@ class DatabaseSeeder extends Seeder
TenantSeeder::class,
DesfilePuraTendenciaSeeder::class,
AttributeSeeder::class,
MutualSmepAttributeSeeder::class,
CategorySeeder::class,
MutualSmepCategorySeeder::class,
BrandSeeder::class,

View File

@@ -0,0 +1,122 @@
<?php
namespace Database\Seeders;
use App\Domains\Commerce\Catalog\Models\Attribute;
use App\Domains\Core\Tenant\Models\Tenant;
use App\Shared\Enums\FieldType;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class MutualSmepAttributeSeeder extends Seeder
{
private const TENANT_CODE = 'mutual_smep';
/** @var list<array<string, mixed>> */
private const ATTRIBUTES = [
[
'codigo' => 'color',
'nombre' => 'Color',
'metadata_schema' => [
'hex' => ['type' => 'string'],
],
'options' => [
['value' => 'Negro', 'label' => 'Negro', 'metadata' => ['hex' => '#000000']],
['value' => 'Blanco', 'label' => 'Blanco', 'metadata' => ['hex' => '#FFFFFF']],
['value' => 'Gris', 'label' => 'Gris', 'metadata' => ['hex' => '#808080']],
['value' => 'Plata', 'label' => 'Plata', 'metadata' => ['hex' => '#C0C0C0']],
['value' => 'Azul', 'label' => 'Azul', 'metadata' => ['hex' => '#0000FF']],
['value' => 'Rojo', 'label' => 'Rojo', 'metadata' => ['hex' => '#DC3545']],
['value' => 'Rosa', 'label' => 'Rosa', 'metadata' => ['hex' => '#FFC0CB']],
['value' => 'Multicolor', 'label' => 'Multicolor'],
],
],
[
'codigo' => 'medida_cama',
'nombre' => 'Medida',
'options' => [
['value' => 'Cuna', 'label' => 'Cuna'],
['value' => '1 Plaza', 'label' => '1 Plaza'],
['value' => '1 1/2 Plazas', 'label' => '1 1/2 Plazas'],
['value' => '2 Plazas', 'label' => '2 Plazas'],
['value' => '2 1/2 Plazas', 'label' => '2 1/2 Plazas'],
['value' => 'Queen', 'label' => 'Queen'],
['value' => 'King', 'label' => 'King'],
],
],
[
'codigo' => 'almacenamiento',
'nombre' => 'Almacenamiento',
'options' => [
['value' => '128 GB', 'label' => '128 GB'],
['value' => '256 GB', 'label' => '256 GB'],
['value' => '512 GB', 'label' => '512 GB'],
['value' => '1 TB', 'label' => '1 TB'],
],
],
[
'codigo' => 'memoria_ram',
'nombre' => 'Memoria RAM',
'options' => [
['value' => '4 GB', 'label' => '4 GB'],
['value' => '8 GB', 'label' => '8 GB'],
['value' => '16 GB', 'label' => '16 GB'],
],
],
[
'codigo' => 'rodado',
'nombre' => 'Rodado',
'options' => [
['value' => '16', 'label' => '16'],
['value' => '26', 'label' => '26'],
['value' => '29', 'label' => '29'],
],
],
];
public function run(): void
{
if (! Tenant::query()->where('codigo', self::TENANT_CODE)->exists()) {
return;
}
DB::transaction(function (): void {
foreach (self::ATTRIBUTES as $definition) {
$options = $definition['options'];
unset($definition['options']);
$attribute = Attribute::query()->updateOrCreate(
[
'tenant_codigo' => self::TENANT_CODE,
'codigo' => $definition['codigo'],
],
[
...$definition,
'type' => FieldType::Select->value,
'is_required' => false,
'metadata_schema' => $definition['metadata_schema'] ?? null,
],
);
$attribute->options()->delete();
$attribute->options()->createMany(
collect($options)
->values()
->map(fn (array $option, int $index): array => [
...$option,
'sort_order' => $index + 1,
])
->all()
);
}
});
}
public function down(): void
{
Attribute::query()
->where('tenant_codigo', self::TENANT_CODE)
->whereIn('codigo', array_column(self::ATTRIBUTES, 'codigo'))
->delete();
}
}

View File

@@ -0,0 +1,119 @@
<?php
namespace Tests\Feature\Seeders;
use Database\Seeders\MutualSmepAttributeSeeder;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;
class MutualSmepAttributeSeederTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
Schema::create('tenants', function (Blueprint $table): void {
$table->string('codigo')->primary();
});
Schema::create('attribute', function (Blueprint $table): void {
$table->id();
$table->string('tenant_codigo');
$table->string('codigo');
$table->string('nombre');
$table->boolean('is_required')->default(false);
$table->json('metadata_schema')->nullable();
$table->string('type');
$table->timestamps();
$table->unique(['tenant_codigo', 'codigo']);
});
Schema::create('attribute_options', function (Blueprint $table): void {
$table->id();
$table->foreignId('attribute_id')->constrained('attribute')->cascadeOnDelete();
$table->string('value');
$table->string('label');
$table->unsignedInteger('sort_order')->default(0);
$table->json('metadata')->nullable();
$table->timestamps();
});
}
protected function tearDown(): void
{
Schema::dropIfExists('attribute_options');
Schema::dropIfExists('attribute');
Schema::dropIfExists('tenants');
parent::tearDown();
}
public function test_it_creates_the_attributes_and_options_idempotently(): void
{
$this->createTenant('mutual_smep');
$this->seed(MutualSmepAttributeSeeder::class);
$this->seed(MutualSmepAttributeSeeder::class);
$this->assertSame(5, DB::table('attribute')->where('tenant_codigo', 'mutual_smep')->count());
$this->assertSame(25, DB::table('attribute_options')->count());
$this->assertDatabaseHas('attribute', [
'tenant_codigo' => 'mutual_smep',
'codigo' => 'medida_cama',
'nombre' => 'Medida',
'type' => 'select',
'is_required' => false,
]);
$this->assertDatabaseHas('attribute_options', [
'value' => '512 GB',
'label' => '512 GB',
]);
}
public function test_down_only_removes_mutual_smep_attributes(): void
{
$this->createTenant('mutual_smep');
$this->createTenant('other');
DB::table('attribute')->insert([
'tenant_codigo' => 'other',
'codigo' => 'color',
'nombre' => 'Color',
'type' => 'select',
'created_at' => now(),
'updated_at' => now(),
]);
$seeder = app(MutualSmepAttributeSeeder::class);
$seeder->run();
$seeder->down();
$this->assertDatabaseMissing('attribute', ['tenant_codigo' => 'mutual_smep']);
$this->assertDatabaseHas('attribute', [
'tenant_codigo' => 'other',
'codigo' => 'color',
]);
}
public function test_the_data_migration_runs_and_rolls_back_the_attributes(): void
{
$this->createTenant('mutual_smep');
$migration = require database_path(
'migrations/2026_09_24_020000_seed_mutual_smep_attributes.php'
);
$migration->up();
$this->assertSame(5, DB::table('attribute')->where('tenant_codigo', 'mutual_smep')->count());
$this->assertSame(25, DB::table('attribute_options')->count());
$migration->down();
$this->assertDatabaseMissing('attribute', ['tenant_codigo' => 'mutual_smep']);
$this->assertSame(0, DB::table('attribute_options')->count());
}
private function createTenant(string $code): void
{
DB::table('tenants')->insert(['codigo' => $code]);
}
}