feat(seeder): add Mutual SMEP category seeder and test cases

This commit is contained in:
2026-09-24 11:42:45 -03:00
parent 2db83271fa
commit 6b0efbc6ee
4 changed files with 384 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
private const TENANT_CODE = 'mutual_smep';
/** @var array<string, list<string>> */
private const CATEGORIES = [
'Dormitorio y Blanco' => [
'Colchones',
'Bases y Sommiers',
'Acolchados y Edredones',
'Frazadas y Mantas',
'Infantil y Cuna',
],
'Electrodomésticos' => [
'Heladeras',
'Lavarropas y Secarropas',
'Cocinas',
'Microondas',
'Hornos Eléctricos',
'Calefones y Termotanques',
'Purificadores y Extractores de Cocina',
'Preparación de Alimentos',
'Café y Desayuno',
'Freidoras y Cocción',
'Cuidado Personal',
'Limpieza y Planchado',
],
'Climatización' => [
'Aires Acondicionados',
'Calefactores a Gas con Salida',
'Calefactores a Gas sin Salida',
'Calefacción Eléctrica',
],
'Tecnología' => [
'Celulares',
'Notebooks',
'Smart TV',
'Audio',
'Accesorios de Computación',
'Soportes para TV',
],
'Bicicletas y Aire Libre' => [
'Bicicletas Infantiles',
'Bicicletas para Adultos',
'Piletas',
],
'Bazar' => [
'Termos',
],
];
public function up(): void
{
if (! DB::table('tenants')->where('codigo', self::TENANT_CODE)->exists()) {
return;
}
DB::transaction(function (): void {
foreach (self::CATEGORIES as $parentName => $subcategoryNames) {
$parentId = $this->upsertCategory($parentName, null);
foreach ($subcategoryNames as $subcategoryName) {
$this->upsertCategory($subcategoryName, $parentId);
}
}
});
}
public function down(): void
{
DB::transaction(function (): void {
foreach (self::CATEGORIES as $parentName => $subcategoryNames) {
$parentId = DB::table('categorias')
->where('tenant_code', self::TENANT_CODE)
->where('nombre', $parentName)
->whereNull('categoria_id')
->value('id');
if ($parentId === null) {
continue;
}
$subcategoryIds = DB::table('categorias')
->where('tenant_code', self::TENANT_CODE)
->where('categoria_id', $parentId)
->whereIn('nombre', $subcategoryNames)
->pluck('id');
foreach ($subcategoryIds as $subcategoryId) {
$hasChildren = DB::table('categorias')
->where('categoria_id', $subcategoryId)
->exists();
if (! $hasChildren) {
DB::table('categorias')->where('id', $subcategoryId)->delete();
}
}
$hasChildren = DB::table('categorias')
->where('categoria_id', $parentId)
->exists();
if (! $hasChildren) {
DB::table('categorias')->where('id', $parentId)->delete();
}
}
});
}
private function upsertCategory(string $name, ?int $parentId): int
{
$categoryId = DB::table('categorias')
->where('tenant_code', self::TENANT_CODE)
->where('nombre', $name)
->value('id');
if ($categoryId !== null) {
DB::table('categorias')->where('id', $categoryId)->update([
'categoria_id' => $parentId,
'is_enabled' => true,
'updated_at' => now(),
]);
return (int) $categoryId;
}
return (int) DB::table('categorias')->insertGetId([
'tenant_code' => self::TENANT_CODE,
'categoria_id' => $parentId,
'nombre' => $name,
'is_enabled' => true,
'created_at' => now(),
'updated_at' => now(),
]);
}
};

View File

@@ -30,6 +30,7 @@ class DatabaseSeeder extends Seeder
DesfilePuraTendenciaSeeder::class,
AttributeSeeder::class,
CategorySeeder::class,
MutualSmepCategorySeeder::class,
BrandSeeder::class,
ProductCatalogFromImagesSeeder::class,
FiestaFutbolInfantilProductSeeder::class,

View File

@@ -0,0 +1,123 @@
<?php
namespace Database\Seeders;
use App\Domains\Commerce\Catalog\Models\Category;
use App\Domains\Core\Tenant\Models\Tenant;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class MutualSmepCategorySeeder extends Seeder
{
private const TENANT_CODE = 'mutual_smep';
/** @var array<string, list<string>> */
private const CATEGORIES = [
'Dormitorio y Blanco' => [
'Colchones',
'Bases y Sommiers',
'Acolchados y Edredones',
'Frazadas y Mantas',
'Infantil y Cuna',
],
'Electrodomésticos' => [
'Heladeras',
'Lavarropas y Secarropas',
'Cocinas',
'Microondas',
'Hornos Eléctricos',
'Calefones y Termotanques',
'Purificadores y Extractores de Cocina',
'Preparación de Alimentos',
'Café y Desayuno',
'Freidoras y Cocción',
'Cuidado Personal',
'Limpieza y Planchado',
],
'Climatización' => [
'Aires Acondicionados',
'Calefactores a Gas con Salida',
'Calefactores a Gas sin Salida',
'Calefacción Eléctrica',
],
'Tecnología' => [
'Celulares',
'Notebooks',
'Smart TV',
'Audio',
'Accesorios de Computación',
'Soportes para TV',
],
'Bicicletas y Aire Libre' => [
'Bicicletas Infantiles',
'Bicicletas para Adultos',
'Piletas',
],
'Bazar' => [
'Termos',
],
];
public function run(): void
{
if (! Tenant::query()->where('codigo', self::TENANT_CODE)->exists()) {
return;
}
DB::transaction(function (): void {
foreach (self::CATEGORIES as $parentName => $subcategoryNames) {
$parent = Category::query()->updateOrCreate(
[
'tenant_code' => self::TENANT_CODE,
'nombre' => $parentName,
],
[
'categoria_id' => null,
'is_enabled' => true,
],
);
foreach ($subcategoryNames as $subcategoryName) {
Category::query()->updateOrCreate(
[
'tenant_code' => self::TENANT_CODE,
'nombre' => $subcategoryName,
],
[
'categoria_id' => $parent->id,
'is_enabled' => true,
],
);
}
}
});
}
public function down(): void
{
DB::transaction(function (): void {
foreach (self::CATEGORIES as $parentName => $subcategoryNames) {
$parent = Category::query()
->where('tenant_code', self::TENANT_CODE)
->where('nombre', $parentName)
->whereNull('categoria_id')
->first();
if (! $parent instanceof Category) {
continue;
}
Category::query()
->where('tenant_code', self::TENANT_CODE)
->where('categoria_id', $parent->id)
->whereIn('nombre', $subcategoryNames)
->whereDoesntHave('subCategories')
->delete();
if (! $parent->subCategories()->exists()) {
$parent->delete();
}
}
});
}
}

View File

@@ -0,0 +1,119 @@
<?php
namespace Tests\Feature\Seeders;
use App\Domains\Commerce\Catalog\Models\Category;
use Database\Seeders\MutualSmepCategorySeeder;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;
class MutualSmepCategorySeederTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
Schema::create('tenants', function (Blueprint $table): void {
$table->string('codigo')->primary();
});
Schema::create('categorias', function (Blueprint $table): void {
$table->id();
$table->string('tenant_code')->nullable();
$table->unsignedBigInteger('categoria_id')->nullable();
$table->string('nombre');
$table->boolean('is_enabled')->default(true);
$table->timestamps();
});
}
protected function tearDown(): void
{
Schema::dropIfExists('categorias');
Schema::dropIfExists('tenants');
parent::tearDown();
}
public function test_it_creates_the_mutual_smep_category_hierarchy_idempotently(): void
{
$this->createTenant('mutual_smep');
$this->seed(MutualSmepCategorySeeder::class);
$this->seed(MutualSmepCategorySeeder::class);
$parents = Category::query()
->where('tenant_code', 'mutual_smep')
->whereNull('categoria_id')
->with('subCategories')
->get()
->keyBy('nombre');
$this->assertCount(6, $parents);
$this->assertCount(37, Category::query()->where('tenant_code', 'mutual_smep')->get());
$this->assertEqualsCanonicalizing([
'Colchones',
'Bases y Sommiers',
'Acolchados y Edredones',
'Frazadas y Mantas',
'Infantil y Cuna',
], $parents->get('Dormitorio y Blanco')->subCategories->pluck('nombre')->all());
$this->assertEqualsCanonicalizing([
'Celulares',
'Notebooks',
'Smart TV',
'Audio',
'Accesorios de Computación',
'Soportes para TV',
], $parents->get('Tecnología')->subCategories->pluck('nombre')->all());
}
public function test_down_removes_only_the_seeded_mutual_smep_hierarchy(): void
{
$this->createTenant('mutual_smep');
$this->createTenant('other');
Category::query()->create([
'tenant_code' => 'other',
'nombre' => 'Tecnología',
]);
$seeder = app(MutualSmepCategorySeeder::class);
$seeder->run();
$seeder->down();
$this->assertDatabaseMissing('categorias', [
'tenant_code' => 'mutual_smep',
]);
$this->assertDatabaseHas('categorias', [
'tenant_code' => 'other',
'nombre' => 'Tecnología',
]);
}
public function test_the_data_migration_runs_and_rolls_back_the_seeder(): void
{
$this->createTenant('mutual_smep');
$migration = require database_path(
'migrations/2026_09_24_010000_seed_mutual_smep_categories.php'
);
$migration->up();
$this->assertCount(37, Category::query()->where('tenant_code', 'mutual_smep')->get());
$migration->down();
$this->assertDatabaseMissing('categorias', [
'tenant_code' => 'mutual_smep',
]);
}
private function createTenant(string $code): void
{
DB::table('tenants')->insert([
'codigo' => $code,
]);
}
}