From 77dd0e271573f1cd6fe5e18d5874947ac72b2f38 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Wed, 30 Sep 2026 13:29:41 -0300 Subject: [PATCH] feat(menu): update contact menu to dynamic content type and preserve legacy data for rollback --- .../Core/Tenant/Resources/TenantResource.php | 4 +- ...09_30_000600_make_contact_menu_dynamic.php | 39 +++++++++++ database/seeders/MenuSeeder.php | 67 +------------------ .../Migrations/DynamicContactMenuTest.php | 48 +++++++++++++ tests/Feature/Seeders/MenuSeederTest.php | 51 +------------- .../Tenant/BootstrapTenantControllerTest.php | 2 +- .../Bootstrap/TenantContactResourceTest.php | 54 +++++++++++++++ 7 files changed, 149 insertions(+), 116 deletions(-) create mode 100644 database/migrations/2026_09_30_000600_make_contact_menu_dynamic.php create mode 100644 tests/Feature/Migrations/DynamicContactMenuTest.php create mode 100644 tests/Unit/Bootstrap/TenantContactResourceTest.php diff --git a/app/Domains/Core/Tenant/Resources/TenantResource.php b/app/Domains/Core/Tenant/Resources/TenantResource.php index 1571930c..fbd51c11 100644 --- a/app/Domains/Core/Tenant/Resources/TenantResource.php +++ b/app/Domains/Core/Tenant/Resources/TenantResource.php @@ -4,8 +4,8 @@ namespace App\Domains\Core\Tenant\Resources; use App\Domains\Commerce\Catalog\Models\Category; use App\Domains\Core\Address\Resources\AddressResource; -use App\Domains\Core\PhoneNumber\Resources\PhoneNumberResource; use App\Domains\Core\Menu\Models\Menu; +use App\Domains\Core\PhoneNumber\Resources\PhoneNumberResource; use App\Domains\Core\Tenant\Models\StorefrontWebsiteType; use App\Domains\Core\Tenant\Models\Tenant; use App\Domains\Ticketing\Event\Models\Event; @@ -233,7 +233,7 @@ class TenantResource extends JsonResource 'route' => $menu->route, ]; - if ($menu->pivot?->static_content !== null) { + if ($menu->content_type === Menu::CONTENT_TYPE_STATIC && $menu->pivot?->static_content !== null) { $formatted['static_content'] = $menu->pivot->static_content; } diff --git a/database/migrations/2026_09_30_000600_make_contact_menu_dynamic.php b/database/migrations/2026_09_30_000600_make_contact_menu_dynamic.php new file mode 100644 index 00000000..ed06fda2 --- /dev/null +++ b/database/migrations/2026_09_30_000600_make_contact_menu_dynamic.php @@ -0,0 +1,39 @@ +where('code', 'help.contact')->update([ + 'content_type' => 'dynamic', + 'static_content_schema' => null, + ]); + // Preserve legacy pivot content for rollback; dynamic menus do not expose it. + } + + public function down(): void + { + DB::table('menues')->where('code', 'help.contact')->update([ + 'content_type' => 'static', + 'static_content_schema' => json_encode([ + 'whatsapp' => 'required|array', + 'whatsapp.whatsapp_url' => 'required|url', + 'whatsapp.whatsapp_label' => 'required|string', + 'phone' => 'required|string', + 'locations' => 'required|array|min:1', + 'locations.*.label' => 'required|string', + 'locations.*.addresses' => 'required|array|min:1', + 'locations.*.addresses.*' => 'required|array:label,address,coordinates', + 'locations.*.addresses.*.label' => 'required|string', + 'locations.*.addresses.*.address' => 'required|string', + 'locations.*.addresses.*.coordinates' => 'required|array|size:2', + 'locations.*.addresses.*.coordinates.0' => 'required|numeric|between:-90,90', + 'locations.*.addresses.*.coordinates.1' => 'required|numeric|between:-180,180', + 'map_locations' => 'prohibited', + ], JSON_THROW_ON_ERROR), + ]); + } +}; diff --git a/database/seeders/MenuSeeder.php b/database/seeders/MenuSeeder.php index 95d0eabf..3932eeac 100644 --- a/database/seeders/MenuSeeder.php +++ b/database/seeders/MenuSeeder.php @@ -224,23 +224,8 @@ class MenuSeeder extends Seeder 'code' => 'help.contact', 'label' => 'Contacto', 'parent_menu_code' => 'help', - 'content_type' => Menu::CONTENT_TYPE_STATIC, - 'static_content_schema' => [ - 'whatsapp' => 'required|array', - 'whatsapp.whatsapp_url' => 'required|url', - 'whatsapp.whatsapp_label' => 'required|string', - 'phone' => 'required|string', - 'locations' => 'required|array|min:1', - 'locations.*.label' => 'required|string', - 'locations.*.addresses' => 'required|array|min:1', - 'locations.*.addresses.*' => 'required|array:label,address,coordinates', - 'locations.*.addresses.*.label' => 'required|string', - 'locations.*.addresses.*.address' => 'required|string', - 'locations.*.addresses.*.coordinates' => 'required|array|size:2', - 'locations.*.addresses.*.coordinates.0' => 'required|numeric|between:-90,90', - 'locations.*.addresses.*.coordinates.1' => 'required|numeric|between:-180,180', - 'map_locations' => 'prohibited', - ], + 'content_type' => Menu::CONTENT_TYPE_DYNAMIC, + 'static_content_schema' => null, 'route' => '/ayuda/contacto', ], [ @@ -399,30 +384,6 @@ class MenuSeeder extends Seeder 'is_active' => false, ], ]; - $contactContent = [ - 'whatsapp' => [ - 'whatsapp_url' => 'https://wa.me/543412602222', - 'whatsapp_label' => 'Chatea con nosotros', - ], - 'phone' => '+54 9 (0341) 6658247', - 'locations' => [ - 'rosario' => [ - 'label' => 'Rosario', - 'addresses' => [ - [ - 'label' => 'Gigante de Arroyito', - 'address' => 'Av. Génova 640, Rosario', - 'coordinates' => [-32.913997, -60.674567], - ], - [ - 'label' => 'Telepagos', - 'address' => 'Rioja 1150, piso 12, dpto. 3, Rosario', - 'coordinates' => [-32.946820, -60.639320], - ], - ], - ], - ], - ]; $mutualSmepFrequentlyAskedQuestions = [ [ 'pregunta' => '¿Hay algún límite de compra?', @@ -440,25 +401,6 @@ class MenuSeeder extends Seeder 'is_active' => false, ], ]; - $mutualSmepContactContent = [ - 'whatsapp' => [ - 'whatsapp_url' => 'https://wa.me/5493412474530', - 'whatsapp_label' => 'Chateá con Mutual SMEP', - ], - 'phone' => '+54 9 341 247-4530', - 'locations' => [ - 'rosario' => [ - 'label' => 'Rosario', - 'addresses' => [ - [ - 'label' => 'Mutual SMEP', - 'address' => 'San Lorenzo 1543, Rosario, Santa Fe', - 'coordinates' => [-32.9431184, -60.6437991], - ], - ], - ], - ], - ]; foreach ($tenants as $tenant) { $menuCodes = $allMenus; @@ -511,11 +453,6 @@ class MenuSeeder extends Seeder ? $mutualSmepFrequentlyAskedQuestions : $frequentlyAskedQuestions, ]); - $tenant->menues()->updateExistingPivot('help.contact', [ - 'static_content' => $tenant->codigo === 'mutual_smep' - ? $mutualSmepContactContent - : $contactContent, - ]); } } } diff --git a/tests/Feature/Migrations/DynamicContactMenuTest.php b/tests/Feature/Migrations/DynamicContactMenuTest.php new file mode 100644 index 00000000..b4cada4d --- /dev/null +++ b/tests/Feature/Migrations/DynamicContactMenuTest.php @@ -0,0 +1,48 @@ +string('code')->primary(); + $table->string('content_type'); + $table->json('static_content_schema')->nullable(); + }); + Schema::create('tenants_menues', function (Blueprint $table): void { + $table->string('tenant_code'); + $table->string('menu_code'); + $table->json('static_content')->nullable(); + }); + DB::table('menues')->insert([ + ['code' => 'help.contact', 'content_type' => 'static', 'static_content_schema' => '{}'], + ['code' => 'help.faq', 'content_type' => 'static', 'static_content_schema' => '{}'], + ]); + $legacy = json_encode(['whatsapp' => ['whatsapp_url' => 'https://wa.me/123']], JSON_THROW_ON_ERROR); + DB::table('tenants_menues')->insert([ + 'tenant_code' => 'test', 'menu_code' => 'help.contact', 'static_content' => $legacy, + ]); + $migration = require database_path('migrations/2026_09_30_000600_make_contact_menu_dynamic.php'); + $migration->up(); + $migration->up(); + + $this->assertDatabaseHas('menues', [ + 'code' => 'help.contact', 'content_type' => 'dynamic', 'static_content_schema' => null, + ]); + $this->assertDatabaseHas('menues', ['code' => 'help.faq', 'content_type' => 'static', 'static_content_schema' => '{}']); + $this->assertDatabaseHas('tenants_menues', ['menu_code' => 'help.contact', 'static_content' => $legacy]); + + $migration->down(); + $this->assertDatabaseHas('menues', ['code' => 'help.contact', 'content_type' => 'static']); + $schema = json_decode(DB::table('menues')->where('code', 'help.contact')->value('static_content_schema'), true, flags: JSON_THROW_ON_ERROR); + $this->assertSame('required|url', $schema['whatsapp.whatsapp_url']); + $this->assertDatabaseHas('tenants_menues', ['menu_code' => 'help.contact', 'static_content' => $legacy]); + } +} diff --git a/tests/Feature/Seeders/MenuSeederTest.php b/tests/Feature/Seeders/MenuSeederTest.php index f7ef95ad..6f1d4bc0 100644 --- a/tests/Feature/Seeders/MenuSeederTest.php +++ b/tests/Feature/Seeders/MenuSeederTest.php @@ -338,26 +338,8 @@ class MenuSeederTest extends TestCase ], $faq->static_content_schema); $contact = Menu::query()->where('code', 'help.contact')->firstOrFail(); - $this->assertSame(Menu::CONTENT_TYPE_STATIC, $contact->content_type); - $this->assertSame('required|url', $contact->static_content_schema['whatsapp.whatsapp_url']); - $this->assertSame('required|string', $contact->static_content_schema['phone']); - $this->assertSame( - 'required|array|min:1', - $contact->static_content_schema['locations.*.addresses'] - ); - $this->assertSame( - 'required|array|size:2', - $contact->static_content_schema['locations.*.addresses.*.coordinates'] - ); - $this->assertSame( - 'required|string', - $contact->static_content_schema['locations.*.addresses.*.address'] - ); - $this->assertSame( - 'required|numeric|between:-90,90', - $contact->static_content_schema['locations.*.addresses.*.coordinates.0'] - ); - $this->assertSame('prohibited', $contact->static_content_schema['map_locations']); + $this->assertSame(Menu::CONTENT_TYPE_DYNAMIC, $contact->content_type); + $this->assertNull($contact->static_content_schema); } public function test_it_assigns_help_to_the_supported_tenants_with_faq_content(): void @@ -385,30 +367,6 @@ class MenuSeederTest extends TestCase 'is_active' => false, ], ]; - $expectedContact = [ - 'whatsapp' => [ - 'whatsapp_url' => 'https://wa.me/543412602222', - 'whatsapp_label' => 'Chatea con nosotros', - ], - 'phone' => '+54 9 (0341) 6658247', - 'locations' => [ - 'rosario' => [ - 'label' => 'Rosario', - 'addresses' => [ - [ - 'label' => 'Gigante de Arroyito', - 'address' => 'Av. Génova 640, Rosario', - 'coordinates' => [-32.913997, -60.674567], - ], - [ - 'label' => 'Telepagos', - 'address' => 'Rioja 1150, piso 12, dpto. 3, Rosario', - 'coordinates' => [-32.946820, -60.639320], - ], - ], - ], - ], - ]; foreach ([$sonder, $fiesta] as $tenant) { $helpMenus = $tenant->menues() @@ -422,10 +380,7 @@ class MenuSeederTest extends TestCase $expectedQuestions, $helpMenus->firstWhere('code', 'help.faq')->pivot->static_content ); - $this->assertEquals( - $expectedContact, - $helpMenus->firstWhere('code', 'help.contact')->pivot->static_content - ); + $this->assertNull($helpMenus->firstWhere('code', 'help.contact')->pivot->static_content); } $this->assertFalse( diff --git a/tests/Feature/Tenant/BootstrapTenantControllerTest.php b/tests/Feature/Tenant/BootstrapTenantControllerTest.php index 2cb2d97a..8a4fa4d3 100644 --- a/tests/Feature/Tenant/BootstrapTenantControllerTest.php +++ b/tests/Feature/Tenant/BootstrapTenantControllerTest.php @@ -510,7 +510,7 @@ class BootstrapTenantControllerTest extends TestCase $tenant->menues()->sync([ $parent->code, $staticChild->code => ['static_content' => $staticContent], - $dynamicChild->code, + $dynamicChild->code => ['static_content' => ['legacy' => 'must not be returned']], ]); $userRole->menus()->sync([ $parent->code, diff --git a/tests/Unit/Bootstrap/TenantContactResourceTest.php b/tests/Unit/Bootstrap/TenantContactResourceTest.php new file mode 100644 index 00000000..d2d2b904 --- /dev/null +++ b/tests/Unit/Bootstrap/TenantContactResourceTest.php @@ -0,0 +1,54 @@ + 'test']); + foreach (['favicon', 'headerLogo', 'footerLogo', 'headerBackgroundImage', 'footerBackgroundImage', 'storefrontWebsiteType'] as $relation) { + $tenant->setRelation($relation, null); + } + $contact = new Menu([ + 'code' => 'help.contact', 'label' => 'Contacto', 'content_type' => 'dynamic', 'route' => '/ayuda/contacto', + ]); + $contact->setRelation('pivot', new TenantMenu(['static_content' => ['whatsapp' => 'legacy']])); + $faq = new Menu(['code' => 'help.faq', 'label' => 'FAQ', 'content_type' => 'static']); + $faq->setRelation('pivot', new TenantMenu(['static_content' => ['question' => 'Example']])); + $tenant->setRelation('menues', collect([$contact, $faq])); + $tenantSocial = new SocialMedia(['code' => 'whatsapp', 'name' => 'WhatsApp', 'icon' => 'fa-brands fa-whatsapp']); + $tenantSocial->setRelation('pivot', new Pivot(['url' => 'https://wa.me/111'])); + $eventSocial = new SocialMedia(['code' => 'whatsapp', 'name' => 'WhatsApp', 'icon' => 'fa-brands fa-whatsapp']); + $eventSocial->setRelation('pivot', new Pivot(['url' => 'https://wa.me/222'])); + $tenant->setRelation('socialMedia', collect([$tenantSocial])); + $event = new Event; + $event->setRelation('socialMedia', collect([$eventSocial])); + $event->setRelation('address', null); + $event->setRelation('dates', collect()); + $tenant->setRelation('activeEvent', $event); + + $data = TenantResource::make($tenant)->resolve(request()); + $this->assertSame('dynamic', $data['menues'][0]['content_type']); + $this->assertArrayNotHasKey('static_content', $data['menues'][0]); + $this->assertSame(['question' => 'Example'], $data['menues'][1]['static_content']); + $this->assertSame('https://wa.me/222', $data['social_media'][0]['url']); + + $event->setRelation('socialMedia', collect()); + $data = TenantResource::make($tenant)->resolve(request()); + $this->assertCount(0, $data['social_media']); + + $tenant->setRelation('activeEvent', null); + $data = TenantResource::make($tenant)->resolve(request()); + $this->assertSame('https://wa.me/111', $data['social_media'][0]['url']); + } +}