feat(seeder): add Mutual SMEP category seeder and test cases
This commit is contained in:
@@ -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(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -30,6 +30,7 @@ class DatabaseSeeder extends Seeder
|
|||||||
DesfilePuraTendenciaSeeder::class,
|
DesfilePuraTendenciaSeeder::class,
|
||||||
AttributeSeeder::class,
|
AttributeSeeder::class,
|
||||||
CategorySeeder::class,
|
CategorySeeder::class,
|
||||||
|
MutualSmepCategorySeeder::class,
|
||||||
BrandSeeder::class,
|
BrandSeeder::class,
|
||||||
ProductCatalogFromImagesSeeder::class,
|
ProductCatalogFromImagesSeeder::class,
|
||||||
FiestaFutbolInfantilProductSeeder::class,
|
FiestaFutbolInfantilProductSeeder::class,
|
||||||
|
|||||||
123
database/seeders/MutualSmepCategorySeeder.php
Normal file
123
database/seeders/MutualSmepCategorySeeder.php
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
119
tests/Feature/Seeders/MutualSmepCategorySeederTest.php
Normal file
119
tests/Feature/Seeders/MutualSmepCategorySeederTest.php
Normal 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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user