From d42896e956e35448d6da008207b5f9415781a77b Mon Sep 17 00:00:00 2001 From: ncoronel Date: Tue, 29 Sep 2026 09:04:50 -0300 Subject: [PATCH] feat(menus): separate shopit and onticket admin menus --- app/Domains/Ticketing/Desfile/routes/api.php | 14 +- .../FiestaFutbolInfantil/routes/api.php | 34 +-- .../Ticketing/Ticket/documentacion/README.md | 2 +- .../Ticketing/Ticket/routes/adminapp.php | 12 +- app/Shared/Forms/routes/adminapp.php | 4 +- ...eparate_adminapp_menus_by_website_type.php | 236 ++++++++++++++++++ database/seeders/MenuSeeder.php | 111 ++++++-- .../Feature/Auth/ScannerMeControllerTest.php | 2 +- tests/Feature/Desfile/EntryControllerTest.php | 2 +- .../AccommodationControllerTest.php | 2 +- .../EntryControllerTest.php | 10 +- .../FoodControllerTest.php | 2 +- .../MerchandiseControllerTest.php | 2 +- ...fileEntryReservationFormControllerTest.php | 2 +- ...AdminAppTicketFilterFormControllerTest.php | 2 +- ...SeparateAdminAppMenusByWebsiteTypeTest.php | 201 +++++++++++++++ .../DesfilePuraTendenciaSeederTest.php | 6 +- tests/Feature/Seeders/MenuSeederTest.php | 104 ++++++-- .../Ticket/AdminAppTicketControllerTest.php | 2 +- 19 files changed, 657 insertions(+), 93 deletions(-) create mode 100644 database/migrations/2026_09_29_000000_separate_adminapp_menus_by_website_type.php create mode 100644 tests/Feature/Migrations/SeparateAdminAppMenusByWebsiteTypeTest.php diff --git a/app/Domains/Ticketing/Desfile/routes/api.php b/app/Domains/Ticketing/Desfile/routes/api.php index f588ecdf..fdf83b81 100644 --- a/app/Domains/Ticketing/Desfile/routes/api.php +++ b/app/Domains/Ticketing/Desfile/routes/api.php @@ -5,28 +5,28 @@ use App\Domains\Ticketing\Desfile\Controllers\EntryReservationController; use Illuminate\Support\Facades\Route; Route::get('v1/adminapp/tenant/desfile/entry-reservations', [EntryReservationController::class, 'index']) - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.reservas']) ->name('adminapp.desfile.entry-reservations.index'); Route::get('v1/adminapp/tenant/desfile/entry-reservations/pdf', [EntryReservationController::class, 'downloadPdf']) - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.reservas']) ->name('adminapp.desfile.entry-reservations.pdf'); Route::get('v1/adminapp/tenant/desfile/entry-reservations/excel', [EntryReservationController::class, 'downloadExcel']) - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.reservas']) ->name('adminapp.desfile.entry-reservations.excel'); Route::get('v1/adminapp/tenant/desfile/entry-reservations/{reservation}/ticket/pdf', [EntryReservationController::class, 'downloadTicketPdf']) ->whereNumber('reservation') - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.reservas']) ->name('adminapp.desfile.entry-reservations.ticket.pdf'); Route::post('v1/adminapp/tenant/desfile/entry-reservations', [EntryReservationController::class, 'store']) - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.reservas']) ->name('adminapp.desfile.entry-reservations.store'); Route::delete('v1/adminapp/tenant/desfile/entry-reservations/{reservation}', [EntryReservationController::class, 'destroy']) ->whereNumber('reservation') - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.reservas']) ->name('adminapp.desfile.entry-reservations.destroy'); Route::prefix('v1/adminapp/tenant/desfile') - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.entradas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.entradas']) ->group(function (): void { Route::get('entries', [EntryController::class, 'show']) ->name('adminapp.desfile.entries.show'); diff --git a/app/Domains/Ticketing/FiestaFutbolInfantil/routes/api.php b/app/Domains/Ticketing/FiestaFutbolInfantil/routes/api.php index ff248d9c..75f1ef9f 100644 --- a/app/Domains/Ticketing/FiestaFutbolInfantil/routes/api.php +++ b/app/Domains/Ticketing/FiestaFutbolInfantil/routes/api.php @@ -19,48 +19,48 @@ Route::prefix('v1/adminapp/tenant') ->middleware("tenant.menu:{$menuCode}"); }; - $visibilityRoutes('entries', 'entries', 'adminapp.fiesta-futbol-infantil.entradas'); - $visibilityRoutes('foods', 'foods', 'adminapp.fiesta-futbol-infantil.comida'); - $visibilityRoutes('accommodations', 'accommodations', 'adminapp.fiesta-futbol-infantil.alojamientos'); - $visibilityRoutes('merchandise', 'merchandise', 'adminapp.fiesta-futbol-infantil.merchandising'); + $visibilityRoutes('entries', 'entries', 'onticket.adminapp.fiesta-futbol-infantil.entradas'); + $visibilityRoutes('foods', 'foods', 'onticket.adminapp.fiesta-futbol-infantil.comida'); + $visibilityRoutes('accommodations', 'accommodations', 'onticket.adminapp.fiesta-futbol-infantil.alojamientos'); + $visibilityRoutes('merchandise', 'merchandise', 'onticket.adminapp.fiesta-futbol-infantil.merchandising'); Route::get('entries', [EntryController::class, 'index']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.entradas') ->name('adminapp.fiesta-futbol-infantil.entries.index'); Route::post('entries', [EntryController::class, 'store']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.entradas') ->name('adminapp.fiesta-futbol-infantil.entries.store'); Route::delete('entries/{entry}', [EntryController::class, 'destroy']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.entradas') ->name('adminapp.fiesta-futbol-infantil.entries.destroy'); Route::get('foods', [FoodController::class, 'index']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.index'); Route::post('foods', [FoodController::class, 'store']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.store'); Route::patch('foods/history-stock', [FoodController::class, 'updateHistoricalStock']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.history-stock.update'); Route::delete('foods/{food}', [FoodController::class, 'destroy']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.destroy'); Route::get('accommodations', [AccommodationController::class, 'index']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.alojamientos') ->name('adminapp.fiesta-futbol-infantil.accommodations.index'); Route::post('accommodations', [AccommodationController::class, 'store']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.alojamientos') ->name('adminapp.fiesta-futbol-infantil.accommodations.store'); Route::delete('accommodations/{accommodation}', [AccommodationController::class, 'destroy']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.alojamientos') ->name('adminapp.fiesta-futbol-infantil.accommodations.destroy'); Route::get('merchandise', [MerchandiseController::class, 'index']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.merchandising') ->name('adminapp.fiesta-futbol-infantil.merchandise.index'); Route::post('merchandise', [MerchandiseController::class, 'store']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.merchandising') ->name('adminapp.fiesta-futbol-infantil.merchandise.store'); Route::delete('merchandise/{merchandise}', [MerchandiseController::class, 'destroy']) - ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising') + ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.merchandising') ->name('adminapp.fiesta-futbol-infantil.merchandise.destroy'); }); diff --git a/app/Domains/Ticketing/Ticket/documentacion/README.md b/app/Domains/Ticketing/Ticket/documentacion/README.md index e460d5c3..fafd61d9 100644 --- a/app/Domains/Ticketing/Ticket/documentacion/README.md +++ b/app/Domains/Ticketing/Ticket/documentacion/README.md @@ -82,7 +82,7 @@ Bajo `/tenants/{tenant:codigo}`, protegidos por `auth:sanctum`: - `POST /tickets/pdf`. Bajo `/v1/adminapp/tenant`, protegido por `auth:sanctum`, `adminapp.tenant` y el menú -`adminapp.tickets`: +`onticket.adminapp.tickets`: - `GET /tickets`, paginado y con búsqueda opcional mediante `q`. La respuesta incluye `scanned_tickets` y `total_tickets` para el tenant autenticado. diff --git a/app/Domains/Ticketing/Ticket/routes/adminapp.php b/app/Domains/Ticketing/Ticket/routes/adminapp.php index b785612a..17e0329a 100644 --- a/app/Domains/Ticketing/Ticket/routes/adminapp.php +++ b/app/Domains/Ticketing/Ticket/routes/adminapp.php @@ -7,24 +7,24 @@ Route::prefix('v1/adminapp/tenant') ->middleware(['auth:sanctum', 'adminapp.tenant']) ->group(function (): void { Route::get('tickets', [TicketController::class, 'index']) - ->middleware('tenant.menu:adminapp.tickets') + ->middleware('tenant.menu:onticket.adminapp.tickets') ->name('adminapp.tickets.index'); Route::post('tickets/{ticket}/cancel', [TicketController::class, 'cancel']) ->whereNumber('ticket') - ->middleware('tenant.menu:adminapp.tickets') + ->middleware('tenant.menu:onticket.adminapp.tickets') ->name('adminapp.tickets.cancel'); Route::get('tickets/{ticket}/refund', [TicketController::class, 'calculateRefund']) ->whereNumber('ticket') - ->middleware('tenant.menu:adminapp.tickets') + ->middleware('tenant.menu:onticket.adminapp.tickets') ->name('adminapp.tickets.calculate-refund'); Route::post('tickets/{ticket}/refund', [TicketController::class, 'refund']) ->whereNumber('ticket') - ->middleware('tenant.menu:adminapp.tickets') + ->middleware('tenant.menu:onticket.adminapp.tickets') ->name('adminapp.tickets.refund'); Route::get('tickets/pdf', [TicketController::class, 'downloadPdf']) - ->middleware('tenant.menu:adminapp.tickets') + ->middleware('tenant.menu:onticket.adminapp.tickets') ->name('adminapp.tickets.pdf'); Route::get('tickets/excel', [TicketController::class, 'downloadExcel']) - ->middleware('tenant.menu:adminapp.tickets') + ->middleware('tenant.menu:onticket.adminapp.tickets') ->name('adminapp.tickets.excel'); }); diff --git a/app/Shared/Forms/routes/adminapp.php b/app/Shared/Forms/routes/adminapp.php index 6517d639..ed7d070e 100644 --- a/app/Shared/Forms/routes/adminapp.php +++ b/app/Shared/Forms/routes/adminapp.php @@ -18,12 +18,12 @@ Route::prefix('v1/adminapp/forms') Route::get( 'desfile/entry-reservation', DesfileEntryReservationFormController::class - )->middleware('tenant.menu:adminapp.desfile.reservas') + )->middleware('tenant.menu:onticket.adminapp.desfile.reservas') ->name('adminapp.forms.desfile.entry-reservation'); Route::get('sale', SaleFormController::class); Route::get('staff', StaffFormController::class); Route::get('tickets-filter', TicketFilterFormController::class) - ->middleware('tenant.menu:adminapp.tickets') + ->middleware('tenant.menu:onticket.adminapp.tickets') ->name('adminapp.forms.tickets-filter'); Route::get( 'fiesta-futbol-infantil/ticket', diff --git a/database/migrations/2026_09_29_000000_separate_adminapp_menus_by_website_type.php b/database/migrations/2026_09_29_000000_separate_adminapp_menus_by_website_type.php new file mode 100644 index 00000000..8f972599 --- /dev/null +++ b/database/migrations/2026_09_29_000000_separate_adminapp_menus_by_website_type.php @@ -0,0 +1,236 @@ + ['onticket.adminapp.event', 'Eventos', '/admin/event'], + 'adminapp.inicio' => ['onticket.adminapp.inicio', 'Inicio', '/admin/inicio'], + 'adminapp.catalog' => ['onticket.adminapp.catalog', 'Catálogo', '/admin/catalog'], + 'adminapp.combos' => ['onticket.adminapp.combos', 'Combos', '/admin/combos'], + 'adminapp.categories' => ['onticket.adminapp.categories', 'Categorías', '/admin/categories'], + 'adminapp.ventas' => ['onticket.adminapp.ventas', 'Ventas', '/admin/ventas'], + 'adminapp.staff' => ['onticket.adminapp.staff', 'Usuarios', '/admin/staff'], + 'adminapp.tickets' => ['onticket.adminapp.tickets', 'Tickets', '/admin/tickets'], + 'adminapp.fiesta-futbol-infantil.entradas' => [ + 'onticket.adminapp.fiesta-futbol-infantil.entradas', + 'Entradas', + '/admin/entradas', + ], + 'adminapp.fiesta-futbol-infantil.alojamientos' => [ + 'onticket.adminapp.fiesta-futbol-infantil.alojamientos', + 'Alojamientos', + '/admin/alojamientos', + ], + 'adminapp.fiesta-futbol-infantil.merchandising' => [ + 'onticket.adminapp.fiesta-futbol-infantil.merchandising', + 'Merchandising', + '/admin/merchandising', + ], + 'adminapp.fiesta-futbol-infantil.comida' => [ + 'onticket.adminapp.fiesta-futbol-infantil.comida', + 'Comida', + '/admin/comidas', + ], + 'adminapp.desfile.entradas' => [ + 'onticket.adminapp.desfile.entradas', + 'Entradas', + '/admin/desfile/entradas', + ], + 'adminapp.desfile.reservas' => [ + 'onticket.adminapp.desfile.reservas', + 'Reserva de Tickets', + '/admin/desfile/reservas', + ], + ]; + + private const SHOPIT_MENUS = [ + 'shopit.adminapp.marca' => ['Marca', '/admin/marca'], + 'shopit.adminapp.contacto' => ['Contacto', '/admin/contacto'], + 'shopit.adminapp.productos' => ['Productos', '/admin/productos'], + 'shopit.adminapp.categorias' => ['Categorías', '/admin/categorias'], + 'shopit.adminapp.transacciones' => ['Transacciones', '/admin/transacciones'], + 'shopit.adminapp.reportes' => ['Reportes', '/admin/reportes'], + 'shopit.adminapp.usuarios_roles' => ['Usuarios y roles', '/admin/usuarios-roles'], + ]; + + private const LEGACY_SHOPIT_ADMIN_MENUS = [ + 'adminapp.event', + 'adminapp.inicio', + 'adminapp.catalog', + 'adminapp.combos', + 'adminapp.categories', + 'adminapp.ventas', + 'adminapp.staff', + ]; + + public function up(): void + { + DB::transaction(function (): void { + if (! DB::table('menues')->where('code', 'main.adminapp')->exists()) { + return; + } + + foreach (self::ONTICKET_MENUS as $legacyCode => [$code, $label, $route]) { + $this->replaceMenuCode($legacyCode, $code, $label, $route); + $this->assignMenuToAdminRoles($code); + } + + foreach (self::SHOPIT_MENUS as $code => [$label, $route]) { + $this->upsertMenu($code, $label, $route); + $this->assignMenuToAdminRoles($code); + } + + $shopItTenantCodes = DB::table('tenants') + ->where('admin_website_type_code', 'shopit') + ->pluck('codigo'); + + if ($shopItTenantCodes->isEmpty()) { + return; + } + + $adminMenuCodes = DB::table('menues') + ->where('parent_menu_code', 'main.adminapp') + ->pluck('code'); + + DB::table('tenants_menues') + ->whereIn('tenant_code', $shopItTenantCodes) + ->whereIn('menu_code', $adminMenuCodes) + ->delete(); + + foreach ($shopItTenantCodes as $tenantCode) { + $this->assignMenuToTenant($tenantCode, 'main.adminapp'); + + foreach (array_keys(self::SHOPIT_MENUS) as $menuCode) { + $this->assignMenuToTenant($tenantCode, $menuCode); + } + } + }); + } + + public function down(): void + { + DB::transaction(function (): void { + if (! DB::table('menues')->where('code', 'main.adminapp')->exists()) { + return; + } + + $shopItTenantCodes = DB::table('tenants') + ->where('admin_website_type_code', 'shopit') + ->pluck('codigo'); + + DB::table('tenants_menues') + ->whereIn('tenant_code', $shopItTenantCodes) + ->whereIn('menu_code', array_keys(self::SHOPIT_MENUS)) + ->delete(); + DB::table('roles_menues') + ->whereIn('menu_codigo', array_keys(self::SHOPIT_MENUS)) + ->delete(); + DB::table('menues') + ->whereIn('code', array_keys(self::SHOPIT_MENUS)) + ->delete(); + + foreach (self::ONTICKET_MENUS as $legacyCode => [$code, $label, $route]) { + $this->replaceMenuCode($code, $legacyCode, $label, $route); + } + + foreach ($shopItTenantCodes as $tenantCode) { + foreach (self::LEGACY_SHOPIT_ADMIN_MENUS as $menuCode) { + $this->assignMenuToTenant($tenantCode, $menuCode); + } + } + }); + } + + private function replaceMenuCode( + string $sourceCode, + string $targetCode, + string $label, + string $route, + ): void { + $source = DB::table('menues')->where('code', $sourceCode)->first(); + + $this->upsertMenu($targetCode, $label, $route, $source); + + if ($source === null) { + return; + } + + DB::table('tenants_menues') + ->where('menu_code', $sourceCode) + ->get() + ->each(function (object $assignment) use ($targetCode): void { + DB::table('tenants_menues')->updateOrInsert( + [ + 'tenant_code' => $assignment->tenant_code, + 'menu_code' => $targetCode, + ], + [ + 'static_content' => $assignment->static_content, + 'created_at' => $assignment->created_at ?? now(), + 'updated_at' => now(), + ], + ); + }); + + DB::table('roles_menues') + ->where('menu_codigo', $sourceCode) + ->pluck('rol_codigo') + ->each(fn (string $roleCode) => DB::table('roles_menues')->updateOrInsert([ + 'rol_codigo' => $roleCode, + 'menu_codigo' => $targetCode, + ])); + + DB::table('tenants_menues')->where('menu_code', $sourceCode)->delete(); + DB::table('roles_menues')->where('menu_codigo', $sourceCode)->delete(); + DB::table('menues')->where('code', $sourceCode)->delete(); + } + + private function upsertMenu( + string $code, + string $label, + string $route, + ?object $source = null, + ): void { + DB::table('menues')->updateOrInsert( + ['code' => $code], + [ + 'label' => $source->label ?? $label, + 'parent_menu_code' => 'main.adminapp', + 'content_type' => $source->content_type ?? 'dynamic', + 'static_content_schema' => $source->static_content_schema ?? null, + 'route' => $source->route ?? $route, + 'created_at' => $source->created_at ?? now(), + 'updated_at' => now(), + ], + ); + } + + private function assignMenuToAdminRoles(string $menuCode): void + { + DB::table('roles') + ->whereIn('codigo', ['admin', 'adminapp']) + ->pluck('codigo') + ->each(fn (string $roleCode) => DB::table('roles_menues')->updateOrInsert([ + 'rol_codigo' => $roleCode, + 'menu_codigo' => $menuCode, + ])); + } + + private function assignMenuToTenant(string $tenantCode, string $menuCode): void + { + DB::table('tenants_menues')->updateOrInsert( + [ + 'tenant_code' => $tenantCode, + 'menu_code' => $menuCode, + ], + [ + 'static_content' => null, + 'created_at' => now(), + 'updated_at' => now(), + ], + ); + } +}; diff --git a/database/seeders/MenuSeeder.php b/database/seeders/MenuSeeder.php index 25a61dcb..5974e633 100644 --- a/database/seeders/MenuSeeder.php +++ b/database/seeders/MenuSeeder.php @@ -53,89 +53,131 @@ class MenuSeeder extends Seeder 'route' => '/scanner/detail/:id', ], [ - 'code' => 'adminapp.event', + 'code' => 'onticket.adminapp.event', 'label' => 'Eventos', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/event', ], [ - 'code' => 'adminapp.inicio', + 'code' => 'onticket.adminapp.inicio', 'label' => 'Inicio', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/inicio', ], [ - 'code' => 'adminapp.catalog', + 'code' => 'onticket.adminapp.catalog', 'label' => 'Catálogo', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/catalog', ], [ - 'code' => 'adminapp.combos', + 'code' => 'onticket.adminapp.combos', 'label' => 'Combos', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/combos', ], [ - 'code' => 'adminapp.categories', + 'code' => 'onticket.adminapp.categories', 'label' => 'Categorías', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/categories', ], [ - 'code' => 'adminapp.ventas', + 'code' => 'onticket.adminapp.ventas', 'label' => 'Ventas', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/ventas', ], [ - 'code' => 'adminapp.staff', + 'code' => 'onticket.adminapp.staff', 'label' => 'Usuarios', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/staff', ], [ - 'code' => 'adminapp.tickets', + 'code' => 'onticket.adminapp.tickets', 'label' => 'Tickets', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/tickets', ], [ - 'code' => 'adminapp.fiesta-futbol-infantil.entradas', + 'code' => 'onticket.adminapp.fiesta-futbol-infantil.entradas', 'label' => 'Entradas', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/entradas', ], [ - 'code' => 'adminapp.fiesta-futbol-infantil.alojamientos', + 'code' => 'onticket.adminapp.fiesta-futbol-infantil.alojamientos', 'label' => 'Alojamientos', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/alojamientos', ], [ - 'code' => 'adminapp.fiesta-futbol-infantil.merchandising', + 'code' => 'onticket.adminapp.fiesta-futbol-infantil.merchandising', 'label' => 'Merchandising', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/merchandising', ], [ - 'code' => 'adminapp.fiesta-futbol-infantil.comida', + 'code' => 'onticket.adminapp.fiesta-futbol-infantil.comida', 'label' => 'Comida', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/comidas', ], [ - 'code' => 'adminapp.desfile.entradas', + 'code' => 'onticket.adminapp.desfile.entradas', 'label' => 'Entradas', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/desfile/entradas', ], [ - 'code' => 'adminapp.desfile.reservas', + 'code' => 'onticket.adminapp.desfile.reservas', 'label' => 'Reserva de Tickets', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/desfile/reservas', ], + [ + 'code' => 'shopit.adminapp.marca', + 'label' => 'Marca', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/marca', + ], + [ + 'code' => 'shopit.adminapp.contacto', + 'label' => 'Contacto', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/contacto', + ], + [ + 'code' => 'shopit.adminapp.productos', + 'label' => 'Productos', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/productos', + ], + [ + 'code' => 'shopit.adminapp.categorias', + 'label' => 'Categorías', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/categorias', + ], + [ + 'code' => 'shopit.adminapp.transacciones', + 'label' => 'Transacciones', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/transacciones', + ], + [ + 'code' => 'shopit.adminapp.reportes', + 'label' => 'Reportes', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/reportes', + ], + [ + 'code' => 'shopit.adminapp.usuarios_roles', + 'label' => 'Usuarios y roles', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/usuarios-roles', + ], [ 'code' => 'account', 'label' => 'Mi cuenta', @@ -255,6 +297,10 @@ class MenuSeeder extends Seeder ]) ->delete(); + Menu::query() + ->where('code', 'like', 'adminapp.%') + ->delete(); + $allRoleMenuCodes = Menu::query()->pluck('code'); $adminAppMenuCodes = Menu::query() ->where('code', 'main.adminapp') @@ -299,24 +345,32 @@ class MenuSeeder extends Seeder 'mutual_smep', ]; $ticketAdminMenuCodes = [ - 'adminapp.tickets', + 'onticket.adminapp.tickets', ]; $fiestaCategoryMenuCodes = [ - 'adminapp.fiesta-futbol-infantil.entradas', - 'adminapp.fiesta-futbol-infantil.alojamientos', - 'adminapp.fiesta-futbol-infantil.merchandising', - 'adminapp.fiesta-futbol-infantil.comida', + 'onticket.adminapp.fiesta-futbol-infantil.entradas', + 'onticket.adminapp.fiesta-futbol-infantil.alojamientos', + 'onticket.adminapp.fiesta-futbol-infantil.merchandising', + 'onticket.adminapp.fiesta-futbol-infantil.comida', ]; $fiestaExcludedAdminMenuCodes = [ - 'adminapp.inicio', - 'adminapp.catalog', - 'adminapp.categories', - 'adminapp.combos', + 'onticket.adminapp.inicio', + 'onticket.adminapp.catalog', + 'onticket.adminapp.categories', + 'onticket.adminapp.combos', ]; $desfileMenuCodes = [ - 'adminapp.desfile.entradas', - 'adminapp.desfile.reservas', + 'onticket.adminapp.desfile.entradas', + 'onticket.adminapp.desfile.reservas', ]; + $shopItAdminMenuCodes = Menu::query() + ->where('code', 'like', 'shopit.adminapp.%') + ->pluck('code') + ->all(); + $onTicketAdminMenuCodes = Menu::query() + ->where('code', 'like', 'onticket.adminapp.%') + ->pluck('code') + ->all(); $onTicketMenuCodes = [ 'event.index', 'event.category', @@ -406,6 +460,13 @@ class MenuSeeder extends Seeder foreach ($tenants as $tenant) { $menuCodes = $allMenus; + $menuCodes = array_diff( + $menuCodes, + $tenant->admin_website_type_code === 'shopit' + ? $onTicketAdminMenuCodes + : $shopItAdminMenuCodes, + ); + if ($tenant->codigo === 'sonder') { // Sonder NO tiene tickets $menuCodes = array_diff($menuCodes, ['account.tickets']); diff --git a/tests/Feature/Auth/ScannerMeControllerTest.php b/tests/Feature/Auth/ScannerMeControllerTest.php index 576725de..7f9564f8 100644 --- a/tests/Feature/Auth/ScannerMeControllerTest.php +++ b/tests/Feature/Auth/ScannerMeControllerTest.php @@ -43,7 +43,7 @@ class ScannerMeControllerTest extends TestCase 'route' => '/scanner/scan', ]); $foreign = Menu::query()->create([ - 'code' => 'adminapp.inicio', + 'code' => 'onticket.adminapp.inicio', 'label' => 'Administración', 'route' => '/admin/inicio', ]); diff --git a/tests/Feature/Desfile/EntryControllerTest.php b/tests/Feature/Desfile/EntryControllerTest.php index 7484a2c4..5d98972c 100644 --- a/tests/Feature/Desfile/EntryControllerTest.php +++ b/tests/Feature/Desfile/EntryControllerTest.php @@ -186,7 +186,7 @@ class EntryControllerTest extends TestCase 'admin_website_type_code' => 'onticket', ]); $menu = Menu::query()->firstOrCreate( - ['code' => 'adminapp.desfile.entradas'], + ['code' => 'onticket.adminapp.desfile.entradas'], ['label' => 'Entradas', 'route' => '/admin/desfile/entradas'], ); $tenant->menues()->attach($menu->code); diff --git a/tests/Feature/FiestaFutbolInfantil/AccommodationControllerTest.php b/tests/Feature/FiestaFutbolInfantil/AccommodationControllerTest.php index 3050ac09..5d28ecce 100644 --- a/tests/Feature/FiestaFutbolInfantil/AccommodationControllerTest.php +++ b/tests/Feature/FiestaFutbolInfantil/AccommodationControllerTest.php @@ -236,7 +236,7 @@ class AccommodationControllerTest extends TestCase if ($withMenu) { $menu = Menu::query()->firstOrCreate( - ['code' => 'adminapp.fiesta-futbol-infantil.alojamientos'], + ['code' => 'onticket.adminapp.fiesta-futbol-infantil.alojamientos'], ['label' => 'Alojamientos', 'route' => '/admin/alojamientos'], ); $tenant->menues()->syncWithoutDetaching([$menu->code]); diff --git a/tests/Feature/FiestaFutbolInfantil/EntryControllerTest.php b/tests/Feature/FiestaFutbolInfantil/EntryControllerTest.php index b6066fe9..8938333d 100644 --- a/tests/Feature/FiestaFutbolInfantil/EntryControllerTest.php +++ b/tests/Feature/FiestaFutbolInfantil/EntryControllerTest.php @@ -43,10 +43,10 @@ class EntryControllerTest extends TestCase { $tenant = $this->createFiestaTenant(); $categories = [ - 'entries' => ['Entradas', 'adminapp.fiesta-futbol-infantil.entradas'], - 'foods' => ['Comidas', 'adminapp.fiesta-futbol-infantil.comida'], - 'accommodations' => ['Alojamientos', 'adminapp.fiesta-futbol-infantil.alojamientos'], - 'merchandise' => ['Merchandising', 'adminapp.fiesta-futbol-infantil.merchandising'], + 'entries' => ['Entradas', 'onticket.adminapp.fiesta-futbol-infantil.entradas'], + 'foods' => ['Comidas', 'onticket.adminapp.fiesta-futbol-infantil.comida'], + 'accommodations' => ['Alojamientos', 'onticket.adminapp.fiesta-futbol-infantil.alojamientos'], + 'merchandise' => ['Merchandising', 'onticket.adminapp.fiesta-futbol-infantil.merchandising'], ]; foreach ($categories as [$label, $menuCode]) { @@ -405,7 +405,7 @@ class EntryControllerTest extends TestCase { $tenant = $this->createTenant('fiesta_futbol_infantil'); $menu = Menu::query()->create([ - 'code' => 'adminapp.fiesta-futbol-infantil.entradas', + 'code' => 'onticket.adminapp.fiesta-futbol-infantil.entradas', 'label' => 'Entradas', 'route' => '/admin/entradas', ]); diff --git a/tests/Feature/FiestaFutbolInfantil/FoodControllerTest.php b/tests/Feature/FiestaFutbolInfantil/FoodControllerTest.php index c0339163..f90b70ff 100644 --- a/tests/Feature/FiestaFutbolInfantil/FoodControllerTest.php +++ b/tests/Feature/FiestaFutbolInfantil/FoodControllerTest.php @@ -367,7 +367,7 @@ class FoodControllerTest extends TestCase 'time_end' => '23:59', ]); $menu = Menu::query()->create([ - 'code' => 'adminapp.fiesta-futbol-infantil.comida', + 'code' => 'onticket.adminapp.fiesta-futbol-infantil.comida', 'label' => 'Comida', 'route' => '/admin/comidas', ]); diff --git a/tests/Feature/FiestaFutbolInfantil/MerchandiseControllerTest.php b/tests/Feature/FiestaFutbolInfantil/MerchandiseControllerTest.php index 7f8ddcf8..39aeaf3c 100644 --- a/tests/Feature/FiestaFutbolInfantil/MerchandiseControllerTest.php +++ b/tests/Feature/FiestaFutbolInfantil/MerchandiseControllerTest.php @@ -293,7 +293,7 @@ class MerchandiseControllerTest extends TestCase ['value' => 'XL', 'label' => 'XL', 'sort_order' => 4], ]); $menu = Menu::query()->create([ - 'code' => 'adminapp.fiesta-futbol-infantil.merchandising', + 'code' => 'onticket.adminapp.fiesta-futbol-infantil.merchandising', 'label' => 'Merchandising', 'route' => '/admin/merchandising', ]); diff --git a/tests/Feature/Forms/AdminAppDesfileEntryReservationFormControllerTest.php b/tests/Feature/Forms/AdminAppDesfileEntryReservationFormControllerTest.php index d7a90e93..92b63c82 100644 --- a/tests/Feature/Forms/AdminAppDesfileEntryReservationFormControllerTest.php +++ b/tests/Feature/Forms/AdminAppDesfileEntryReservationFormControllerTest.php @@ -135,7 +135,7 @@ class AdminAppDesfileEntryReservationFormControllerTest extends TestCase private function grantReservationsMenu(Tenant $tenant): void { $menu = Menu::query()->create([ - 'code' => 'adminapp.desfile.reservas', + 'code' => 'onticket.adminapp.desfile.reservas', 'label' => 'Reserva de Tickets', 'route' => '/admin/desfile/reservas', ]); diff --git a/tests/Feature/Forms/AdminAppTicketFilterFormControllerTest.php b/tests/Feature/Forms/AdminAppTicketFilterFormControllerTest.php index b6d873b0..64d33a85 100644 --- a/tests/Feature/Forms/AdminAppTicketFilterFormControllerTest.php +++ b/tests/Feature/Forms/AdminAppTicketFilterFormControllerTest.php @@ -349,7 +349,7 @@ class AdminAppTicketFilterFormControllerTest extends TestCase private function grantTicketsMenu(Tenant $tenant): void { $menu = Menu::query()->create([ - 'code' => 'adminapp.tickets', + 'code' => 'onticket.adminapp.tickets', 'label' => 'Tickets', 'route' => '/admin/tickets', ]); diff --git a/tests/Feature/Migrations/SeparateAdminAppMenusByWebsiteTypeTest.php b/tests/Feature/Migrations/SeparateAdminAppMenusByWebsiteTypeTest.php new file mode 100644 index 00000000..be71df6d --- /dev/null +++ b/tests/Feature/Migrations/SeparateAdminAppMenusByWebsiteTypeTest.php @@ -0,0 +1,201 @@ +id(); + $table->string('code')->unique(); + $table->string('label'); + $table->string('parent_menu_code')->nullable(); + $table->string('content_type')->default('dynamic'); + $table->json('static_content_schema')->nullable(); + $table->string('route'); + $table->timestamps(); + }); + Schema::create('tenants', function (Blueprint $table): void { + $table->string('codigo')->primary(); + $table->string('admin_website_type_code')->nullable(); + }); + Schema::create('roles', function (Blueprint $table): void { + $table->string('codigo')->primary(); + }); + Schema::create('tenants_menues', function (Blueprint $table): void { + $table->id(); + $table->string('tenant_code'); + $table->string('menu_code'); + $table->json('static_content')->nullable(); + $table->timestamps(); + $table->unique(['tenant_code', 'menu_code']); + }); + Schema::create('roles_menues', function (Blueprint $table): void { + $table->id(); + $table->string('rol_codigo'); + $table->string('menu_codigo'); + $table->unique(['rol_codigo', 'menu_codigo']); + }); + + $now = now(); + DB::table('menues')->insert([ + [ + 'code' => 'main.adminapp', + 'label' => 'Administración', + 'parent_menu_code' => null, + 'route' => '/', + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'code' => 'adminapp.inicio', + 'label' => 'Inicio', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/inicio', + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'code' => 'adminapp.tickets', + 'label' => 'Tickets', + 'parent_menu_code' => 'main.adminapp', + 'route' => '/admin/tickets', + 'created_at' => $now, + 'updated_at' => $now, + ], + [ + 'code' => 'account', + 'label' => 'Mi cuenta', + 'parent_menu_code' => null, + 'route' => '/mi-cuenta', + 'created_at' => $now, + 'updated_at' => $now, + ], + ]); + DB::table('tenants')->insert([ + ['codigo' => 'sonder', 'admin_website_type_code' => 'shopit'], + ['codigo' => 'mutual_smep', 'admin_website_type_code' => 'shopit'], + ['codigo' => 'fiesta_futbol_infantil', 'admin_website_type_code' => 'onticket'], + ]); + DB::table('roles')->insert([ + ['codigo' => 'admin'], + ['codigo' => 'adminapp'], + ['codigo' => 'user'], + ]); + + foreach (['sonder', 'mutual_smep', 'fiesta_futbol_infantil'] as $tenantCode) { + foreach (['main.adminapp', 'adminapp.inicio', 'account'] as $menuCode) { + DB::table('tenants_menues')->insert([ + 'tenant_code' => $tenantCode, + 'menu_code' => $menuCode, + 'created_at' => $now, + 'updated_at' => $now, + ]); + } + } + + DB::table('tenants_menues')->insert([ + 'tenant_code' => 'fiesta_futbol_infantil', + 'menu_code' => 'adminapp.tickets', + 'created_at' => $now, + 'updated_at' => $now, + ]); + DB::table('roles_menues')->insert([ + ['rol_codigo' => 'admin', 'menu_codigo' => 'adminapp.inicio'], + ['rol_codigo' => 'adminapp', 'menu_codigo' => 'adminapp.inicio'], + ['rol_codigo' => 'adminapp', 'menu_codigo' => 'adminapp.tickets'], + ]); + } + + protected function tearDown(): void + { + Schema::dropIfExists('roles_menues'); + Schema::dropIfExists('tenants_menues'); + Schema::dropIfExists('roles'); + Schema::dropIfExists('tenants'); + Schema::dropIfExists('menues'); + + parent::tearDown(); + } + + public function test_it_separates_admin_menus_by_admin_website_type_and_rolls_back(): void + { + $migration = require database_path( + 'migrations/2026_09_29_000000_separate_adminapp_menus_by_website_type.php' + ); + + $migration->up(); + $migration->up(); + + $this->assertDatabaseMissing('menues', ['code' => 'adminapp.inicio']); + $this->assertDatabaseHas('menues', ['code' => 'onticket.adminapp.inicio']); + $this->assertDatabaseHas('tenants_menues', [ + 'tenant_code' => 'fiesta_futbol_infantil', + 'menu_code' => 'onticket.adminapp.tickets', + ]); + $this->assertDatabaseHas('tenants_menues', [ + 'tenant_code' => 'fiesta_futbol_infantil', + 'menu_code' => 'onticket.adminapp.inicio', + ]); + + foreach (['sonder', 'mutual_smep'] as $tenantCode) { + $adminMenuCodes = DB::table('tenants_menues') + ->join('menues', 'menues.code', '=', 'tenants_menues.menu_code') + ->where('tenants_menues.tenant_code', $tenantCode) + ->where(fn ($query) => $query + ->where('menues.code', 'main.adminapp') + ->orWhere('menues.parent_menu_code', 'main.adminapp')) + ->orderBy('menues.code') + ->pluck('menues.code') + ->all(); + + $this->assertSame( + collect(['main.adminapp', ...self::SHOPIT_MENU_CODES])->sort()->values()->all(), + $adminMenuCodes, + ); + $this->assertDatabaseHas('tenants_menues', [ + 'tenant_code' => $tenantCode, + 'menu_code' => 'account', + ]); + } + + foreach (self::SHOPIT_MENU_CODES as $menuCode) { + $this->assertDatabaseHas('roles_menues', [ + 'rol_codigo' => 'adminapp', + 'menu_codigo' => $menuCode, + ]); + } + + $migration->down(); + + $this->assertDatabaseHas('menues', ['code' => 'adminapp.inicio']); + $this->assertDatabaseMissing('menues', ['code' => 'onticket.adminapp.inicio']); + $this->assertDatabaseMissing('menues', ['code' => 'shopit.adminapp.marca']); + $this->assertDatabaseHas('tenants_menues', [ + 'tenant_code' => 'sonder', + 'menu_code' => 'adminapp.inicio', + ]); + $this->assertDatabaseHas('tenants_menues', [ + 'tenant_code' => 'fiesta_futbol_infantil', + 'menu_code' => 'adminapp.tickets', + ]); + } +} diff --git a/tests/Feature/Seeders/DesfilePuraTendenciaSeederTest.php b/tests/Feature/Seeders/DesfilePuraTendenciaSeederTest.php index 6dc80cb2..cc804b65 100644 --- a/tests/Feature/Seeders/DesfilePuraTendenciaSeederTest.php +++ b/tests/Feature/Seeders/DesfilePuraTendenciaSeederTest.php @@ -135,7 +135,7 @@ class DesfilePuraTendenciaSeederTest extends TestCase $expectedMenus = DB::table('tenants_menues') ->where('tenant_code', 'fiesta_futbol_infantil') - ->where('menu_code', 'not like', 'adminapp.fiesta-futbol-infantil.%') + ->where('menu_code', 'not like', 'onticket.adminapp.fiesta-futbol-infantil.%') ->orderBy('menu_code') ->pluck('menu_code') ->all(); @@ -147,9 +147,9 @@ class DesfilePuraTendenciaSeederTest extends TestCase $this->assertSame($expectedMenus, $actualMenus); $this->assertContains('main.adminapp', $actualMenus); - $this->assertContains('adminapp.event', $actualMenus); + $this->assertContains('onticket.adminapp.event', $actualMenus); $this->assertContains('scanner.scan', $actualMenus); - $this->assertNotContains('adminapp.fiesta-futbol-infantil.entradas', $actualMenus); + $this->assertNotContains('onticket.adminapp.fiesta-futbol-infantil.entradas', $actualMenus); $catalogItem = DB::table('catalog_items') ->where('tenant_code', 'desfile_pura_tendencia') diff --git a/tests/Feature/Seeders/MenuSeederTest.php b/tests/Feature/Seeders/MenuSeederTest.php index 10d323c6..f7ef95ad 100644 --- a/tests/Feature/Seeders/MenuSeederTest.php +++ b/tests/Feature/Seeders/MenuSeederTest.php @@ -5,6 +5,7 @@ namespace Tests\Feature\Seeders; use App\Domains\Core\Authorization\Enums\RoleCode; use App\Domains\Core\Authorization\Models\Role; use App\Domains\Core\Menu\Models\Menu; +use App\Domains\Core\Tenant\Models\AdminWebsiteType; use App\Domains\Core\Tenant\Models\Tenant; use App\Shared\Attachable\Enums\AttachmentType; use App\Shared\Attachable\Models\Attachment; @@ -25,21 +26,26 @@ class MenuSeederTest extends TestCase $this->seed(MenuSeeder::class); $expectedMenus = [ - 'adminapp.inicio' => ['Inicio', '/admin/inicio'], - 'adminapp.catalog' => ['Catálogo', '/admin/catalog'], - 'adminapp.categories' => ['Categorías', '/admin/categories'], - 'adminapp.combos' => ['Combos', '/admin/combos'], - 'adminapp.event' => ['Eventos', '/admin/event'], - 'adminapp.staff' => ['Staff', '/admin/staff'], - 'adminapp.ventas' => ['Ventas', '/admin/ventas'], + 'onticket.adminapp.inicio' => ['Inicio', '/admin/inicio'], + 'onticket.adminapp.catalog' => ['Catálogo', '/admin/catalog'], + 'onticket.adminapp.categories' => ['Categorías', '/admin/categories'], + 'onticket.adminapp.combos' => ['Combos', '/admin/combos'], + 'onticket.adminapp.event' => ['Eventos', '/admin/event'], + 'onticket.adminapp.staff' => ['Usuarios', '/admin/staff'], + 'onticket.adminapp.ventas' => ['Ventas', '/admin/ventas'], ]; $fiestaCategoryMenus = [ - 'adminapp.tickets' => ['Tickets', '/admin/tickets'], - 'adminapp.fiesta-futbol-infantil.entradas' => ['Entradas', '/admin/entradas'], - 'adminapp.fiesta-futbol-infantil.alojamientos' => ['Alojamientos', '/admin/alojamientos'], - 'adminapp.fiesta-futbol-infantil.merchandising' => ['Merchandising', '/admin/merchandising'], - 'adminapp.fiesta-futbol-infantil.comida' => ['Comida', '/admin/comidas'], + 'onticket.adminapp.tickets' => ['Tickets', '/admin/tickets'], + 'onticket.adminapp.fiesta-futbol-infantil.entradas' => ['Entradas', '/admin/entradas'], + 'onticket.adminapp.fiesta-futbol-infantil.alojamientos' => ['Alojamientos', '/admin/alojamientos'], + 'onticket.adminapp.fiesta-futbol-infantil.merchandising' => ['Merchandising', '/admin/merchandising'], + 'onticket.adminapp.fiesta-futbol-infantil.comida' => ['Comida', '/admin/comidas'], ]; + $desfileMenus = [ + 'onticket.adminapp.desfile.entradas' => ['Entradas', '/admin/desfile/entradas'], + 'onticket.adminapp.desfile.reservas' => ['Reserva de Tickets', '/admin/desfile/reservas'], + ]; + $shopItMenus = $this->shopItAdminMenus(); $adminApp = Menu::query() ->with('children') @@ -53,7 +59,8 @@ class MenuSeederTest extends TestCase collect(array_keys([ ...$expectedMenus, ...$fiestaCategoryMenus, - 'adminapp.desfile.entradas' => ['Entradas', '/admin/desfile/entradas'], + ...$desfileMenus, + ...$shopItMenus, ]))->sort()->values()->all(), $adminApp->children->pluck('code')->sort()->values()->all() ); @@ -88,10 +95,10 @@ class MenuSeederTest extends TestCase } foreach ([ - 'adminapp.inicio', - 'adminapp.catalog', - 'adminapp.categories', - 'adminapp.combos', + 'onticket.adminapp.inicio', + 'onticket.adminapp.catalog', + 'onticket.adminapp.categories', + 'onticket.adminapp.combos', ] as $code) { $this->assertFalse( $fiestaTenant->menues()->where('menues.code', $code)->exists() @@ -116,6 +123,50 @@ class MenuSeederTest extends TestCase ); } + public function test_it_assigns_only_shopit_admin_menus_to_shopit_admin_tenants(): void + { + AdminWebsiteType::query()->create([ + 'codigo' => 'shopit', + 'nombre' => 'ShopIt', + ]); + + $sonder = $this->createTenant('sonder', 'shopit'); + $mutualSmep = $this->createTenant('mutual_smep', 'shopit'); + $onTicket = $this->createTenant('onticket'); + + $this->seed(MenuSeeder::class); + + $shopItMenuCodes = array_keys($this->shopItAdminMenus()); + + foreach ([$sonder, $mutualSmep] as $tenant) { + $adminMenuCodes = $tenant->menues() + ->where(fn ($query) => $query + ->where('menues.code', 'main.adminapp') + ->orWhere('menues.parent_menu_code', 'main.adminapp')) + ->orderBy('menues.code') + ->pluck('menues.code') + ->all(); + + $this->assertSame( + collect(['main.adminapp', ...$shopItMenuCodes])->sort()->values()->all(), + $adminMenuCodes, + ); + } + + foreach ($this->shopItAdminMenus() as $code => [$label, $route]) { + $menu = Menu::query()->where('code', $code)->firstOrFail(); + + $this->assertSame($label, $menu->label); + $this->assertSame($route, $menu->route); + $this->assertSame('main.adminapp', $menu->parent_menu_code); + $this->assertFalse($onTicket->menues()->where('menues.code', $code)->exists()); + } + + $this->assertFalse( + Menu::query()->where('code', 'like', 'adminapp.%')->exists() + ); + } + public function test_it_assigns_menus_to_the_expected_roles(): void { $this->seed(AuthorizationSeeder::class); @@ -162,7 +213,7 @@ class MenuSeederTest extends TestCase $this->assertSame($userMenuCodes, $userRoleMenuCodes); $this->assertNotContains('main.adminapp', $userRoleMenuCodes); - $this->assertNotContains('adminapp.catalog', $userRoleMenuCodes); + $this->assertNotContains('onticket.adminapp.catalog', $userRoleMenuCodes); $scannerRoleMenuCodes = Role::query() ->where('codigo', RoleCode::Scanner->value) @@ -382,7 +433,7 @@ class MenuSeederTest extends TestCase ); } - private function createTenant(string $code): Tenant + private function createTenant(string $code, ?string $adminWebsiteTypeCode = null): Tenant { $headerLogo = $this->createAttachment("{$code}-header.png"); $footerLogo = $this->createAttachment("{$code}-footer.png"); @@ -391,6 +442,7 @@ class MenuSeederTest extends TestCase 'codigo' => $code, 'nombre' => $code, 'dominio' => "{$code}.example.com", + 'admin_website_type_code' => $adminWebsiteTypeCode, 'primary_color' => '#111111', 'secondary_color' => '#222222', 'danger_color' => '#333333', @@ -402,6 +454,20 @@ class MenuSeederTest extends TestCase ]); } + /** @return array */ + private function shopItAdminMenus(): array + { + return [ + 'shopit.adminapp.marca' => ['Marca', '/admin/marca'], + 'shopit.adminapp.contacto' => ['Contacto', '/admin/contacto'], + 'shopit.adminapp.productos' => ['Productos', '/admin/productos'], + 'shopit.adminapp.categorias' => ['Categorías', '/admin/categorias'], + 'shopit.adminapp.transacciones' => ['Transacciones', '/admin/transacciones'], + 'shopit.adminapp.reportes' => ['Reportes', '/admin/reportes'], + 'shopit.adminapp.usuarios_roles' => ['Usuarios y roles', '/admin/usuarios-roles'], + ]; + } + private function createAttachment(string $filename): Attachment { return Attachment::query()->create([ diff --git a/tests/Feature/Ticket/AdminAppTicketControllerTest.php b/tests/Feature/Ticket/AdminAppTicketControllerTest.php index 20f83794..2ab90c87 100644 --- a/tests/Feature/Ticket/AdminAppTicketControllerTest.php +++ b/tests/Feature/Ticket/AdminAppTicketControllerTest.php @@ -1359,7 +1359,7 @@ class AdminAppTicketControllerTest extends TestCase private function grantTicketsMenu(Tenant $tenant): void { $menu = Menu::query()->create([ - 'code' => 'adminapp.tickets', + 'code' => 'onticket.adminapp.tickets', 'label' => 'Tickets', 'route' => '/admin/tickets', ]);