diff --git a/app/Domains/Ticketing/Desfile/routes/api.php b/app/Domains/Ticketing/Desfile/routes/api.php index fdf83b81..f588ecdf 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:onticket.adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu: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:onticket.adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu: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:onticket.adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu: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:onticket.adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu: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:onticket.adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu: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:onticket.adminapp.desfile.reservas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:adminapp.desfile.reservas']) ->name('adminapp.desfile.entry-reservations.destroy'); Route::prefix('v1/adminapp/tenant/desfile') - ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu:onticket.adminapp.desfile.entradas']) + ->middleware(['auth:sanctum', 'adminapp.tenant', 'tenant.menu: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 75f1ef9f..ff248d9c 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', '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'); + $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'); Route::get('entries', [EntryController::class, 'index']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.entradas') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas') ->name('adminapp.fiesta-futbol-infantil.entries.index'); Route::post('entries', [EntryController::class, 'store']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.entradas') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas') ->name('adminapp.fiesta-futbol-infantil.entries.store'); Route::delete('entries/{entry}', [EntryController::class, 'destroy']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.entradas') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas') ->name('adminapp.fiesta-futbol-infantil.entries.destroy'); Route::get('foods', [FoodController::class, 'index']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.index'); Route::post('foods', [FoodController::class, 'store']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.store'); Route::patch('foods/history-stock', [FoodController::class, 'updateHistoricalStock']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.history-stock.update'); Route::delete('foods/{food}', [FoodController::class, 'destroy']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.comida') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida') ->name('adminapp.fiesta-futbol-infantil.foods.destroy'); Route::get('accommodations', [AccommodationController::class, 'index']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.alojamientos') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos') ->name('adminapp.fiesta-futbol-infantil.accommodations.index'); Route::post('accommodations', [AccommodationController::class, 'store']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.alojamientos') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos') ->name('adminapp.fiesta-futbol-infantil.accommodations.store'); Route::delete('accommodations/{accommodation}', [AccommodationController::class, 'destroy']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.alojamientos') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos') ->name('adminapp.fiesta-futbol-infantil.accommodations.destroy'); Route::get('merchandise', [MerchandiseController::class, 'index']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.merchandising') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising') ->name('adminapp.fiesta-futbol-infantil.merchandise.index'); Route::post('merchandise', [MerchandiseController::class, 'store']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.merchandising') + ->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising') ->name('adminapp.fiesta-futbol-infantil.merchandise.store'); Route::delete('merchandise/{merchandise}', [MerchandiseController::class, 'destroy']) - ->middleware('tenant.menu:onticket.adminapp.fiesta-futbol-infantil.merchandising') + ->middleware('tenant.menu: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 66b5df4c..1b3bf0eb 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ú -`onticket.adminapp.tickets`: +`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 17e0329a..b785612a 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:onticket.adminapp.tickets') + ->middleware('tenant.menu:adminapp.tickets') ->name('adminapp.tickets.index'); Route::post('tickets/{ticket}/cancel', [TicketController::class, 'cancel']) ->whereNumber('ticket') - ->middleware('tenant.menu:onticket.adminapp.tickets') + ->middleware('tenant.menu:adminapp.tickets') ->name('adminapp.tickets.cancel'); Route::get('tickets/{ticket}/refund', [TicketController::class, 'calculateRefund']) ->whereNumber('ticket') - ->middleware('tenant.menu:onticket.adminapp.tickets') + ->middleware('tenant.menu:adminapp.tickets') ->name('adminapp.tickets.calculate-refund'); Route::post('tickets/{ticket}/refund', [TicketController::class, 'refund']) ->whereNumber('ticket') - ->middleware('tenant.menu:onticket.adminapp.tickets') + ->middleware('tenant.menu:adminapp.tickets') ->name('adminapp.tickets.refund'); Route::get('tickets/pdf', [TicketController::class, 'downloadPdf']) - ->middleware('tenant.menu:onticket.adminapp.tickets') + ->middleware('tenant.menu:adminapp.tickets') ->name('adminapp.tickets.pdf'); Route::get('tickets/excel', [TicketController::class, 'downloadExcel']) - ->middleware('tenant.menu:onticket.adminapp.tickets') + ->middleware('tenant.menu:adminapp.tickets') ->name('adminapp.tickets.excel'); }); diff --git a/app/Shared/Forms/routes/adminapp.php b/app/Shared/Forms/routes/adminapp.php index ed7d070e..6517d639 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:onticket.adminapp.desfile.reservas') + )->middleware('tenant.menu: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:onticket.adminapp.tickets') + ->middleware('tenant.menu:adminapp.tickets') ->name('adminapp.forms.tickets-filter'); Route::get( 'fiesta-futbol-infantil/ticket', diff --git a/database/migrations/2026_10_02_000000_remove_onticket_menu_code_prefix.php b/database/migrations/2026_10_02_000000_remove_onticket_menu_code_prefix.php new file mode 100644 index 00000000..d9f1cfed --- /dev/null +++ b/database/migrations/2026_10_02_000000_remove_onticket_menu_code_prefix.php @@ -0,0 +1,63 @@ +where('code', 'like', 'onticket.%')->get(); + + // Create every destination before updating foreign keys, including parents. + foreach ($menus as $menu) { + $data = (array) $menu; + unset($data['id']); + $data['code'] = substr($menu->code, strlen('onticket.')); + + if (! DB::table('menues')->where('code', $data['code'])->exists()) { + DB::table('menues')->insert($data); + } + } + + foreach ($menus as $menu) { + $code = substr($menu->code, strlen('onticket.')); + + DB::table('menues')->where('parent_menu_code', $menu->code) + ->update(['parent_menu_code' => $code]); + + $this->moveAssignments('tenants_menues', 'menu_code', 'tenant_code', $menu->code, $code); + $this->moveAssignments('roles_menues', 'menu_codigo', 'rol_codigo', $menu->code, $code); + } + + DB::table('menues')->whereIn('code', $menus->pluck('code'))->delete(); + }); + } + + private function moveAssignments( + string $table, + string $menuColumn, + string $ownerColumn, + string $sourceCode, + string $targetCode, + ): void { + foreach (DB::table($table)->where($menuColumn, $sourceCode)->get() as $assignment) { + $data = (array) $assignment; + unset($data['id']); + $data[$menuColumn] = $targetCode; + + DB::table($table)->updateOrInsert([ + $ownerColumn => $data[$ownerColumn], + $menuColumn => $targetCode, + ], $data); + } + + DB::table($table)->where($menuColumn, $sourceCode)->delete(); + } + + public function down(): void + { + // Keep compatible identifiers: merged assignments cannot be split reliably. + } +}; diff --git a/database/seeders/MenuSeeder.php b/database/seeders/MenuSeeder.php index 3932eeac..bb32f000 100644 --- a/database/seeders/MenuSeeder.php +++ b/database/seeders/MenuSeeder.php @@ -53,85 +53,85 @@ class MenuSeeder extends Seeder 'route' => '/scanner/detail/:id', ], [ - 'code' => 'onticket.adminapp.event', + 'code' => 'adminapp.event', 'label' => 'Eventos', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/event', ], [ - 'code' => 'onticket.adminapp.inicio', + 'code' => 'adminapp.inicio', 'label' => 'Inicio', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/inicio', ], [ - 'code' => 'onticket.adminapp.catalog', + 'code' => 'adminapp.catalog', 'label' => 'Catálogo', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/catalog', ], [ - 'code' => 'onticket.adminapp.combos', + 'code' => 'adminapp.combos', 'label' => 'Combos', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/combos', ], [ - 'code' => 'onticket.adminapp.categories', + 'code' => 'adminapp.categories', 'label' => 'Categorías', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/categories', ], [ - 'code' => 'onticket.adminapp.ventas', + 'code' => 'adminapp.ventas', 'label' => 'Ventas', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/ventas', ], [ - 'code' => 'onticket.adminapp.staff', + 'code' => 'adminapp.staff', 'label' => 'Usuarios', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/staff', ], [ - 'code' => 'onticket.adminapp.tickets', + 'code' => 'adminapp.tickets', 'label' => 'Tickets', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/tickets', ], [ - 'code' => 'onticket.adminapp.fiesta-futbol-infantil.entradas', + 'code' => 'adminapp.fiesta-futbol-infantil.entradas', 'label' => 'Entradas', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/entradas', ], [ - 'code' => 'onticket.adminapp.fiesta-futbol-infantil.alojamientos', + 'code' => 'adminapp.fiesta-futbol-infantil.alojamientos', 'label' => 'Alojamientos', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/alojamientos', ], [ - 'code' => 'onticket.adminapp.fiesta-futbol-infantil.merchandising', + 'code' => 'adminapp.fiesta-futbol-infantil.merchandising', 'label' => 'Merchandising', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/merchandising', ], [ - 'code' => 'onticket.adminapp.fiesta-futbol-infantil.comida', + 'code' => 'adminapp.fiesta-futbol-infantil.comida', 'label' => 'Comida', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/comidas', ], [ - 'code' => 'onticket.adminapp.desfile.entradas', + 'code' => 'adminapp.desfile.entradas', 'label' => 'Entradas', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/desfile/entradas', ], [ - 'code' => 'onticket.adminapp.desfile.reservas', + 'code' => 'adminapp.desfile.reservas', 'label' => 'Reserva de Tickets', 'parent_menu_code' => 'main.adminapp', 'route' => '/admin/desfile/reservas', @@ -286,7 +286,7 @@ class MenuSeeder extends Seeder ->delete(); Menu::query() - ->where('code', 'like', 'adminapp.%') + ->where('code', 'like', 'onticket.adminapp.%') ->delete(); $allRoleMenuCodes = Menu::query()->pluck('code'); @@ -333,30 +333,30 @@ class MenuSeeder extends Seeder 'mutual_smep', ]; $ticketAdminMenuCodes = [ - 'onticket.adminapp.tickets', + 'adminapp.tickets', ]; $fiestaCategoryMenuCodes = [ - 'onticket.adminapp.fiesta-futbol-infantil.entradas', - 'onticket.adminapp.fiesta-futbol-infantil.alojamientos', - 'onticket.adminapp.fiesta-futbol-infantil.merchandising', - 'onticket.adminapp.fiesta-futbol-infantil.comida', + 'adminapp.fiesta-futbol-infantil.entradas', + 'adminapp.fiesta-futbol-infantil.alojamientos', + 'adminapp.fiesta-futbol-infantil.merchandising', + 'adminapp.fiesta-futbol-infantil.comida', ]; $fiestaExcludedAdminMenuCodes = [ - 'onticket.adminapp.inicio', - 'onticket.adminapp.catalog', - 'onticket.adminapp.categories', - 'onticket.adminapp.combos', + 'adminapp.inicio', + 'adminapp.catalog', + 'adminapp.categories', + 'adminapp.combos', ]; $desfileMenuCodes = [ - 'onticket.adminapp.desfile.entradas', - 'onticket.adminapp.desfile.reservas', + 'adminapp.desfile.entradas', + 'adminapp.desfile.reservas', ]; $shopItAdminMenuCodes = Menu::query() ->where('code', 'like', 'shopit.adminapp.%') ->pluck('code') ->all(); $onTicketAdminMenuCodes = Menu::query() - ->where('code', 'like', 'onticket.adminapp.%') + ->where('code', 'like', 'adminapp.%') ->pluck('code') ->all(); $onTicketMenuCodes = [ diff --git a/tests/Feature/Auth/ScannerMeControllerTest.php b/tests/Feature/Auth/ScannerMeControllerTest.php index 7f9564f8..576725de 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' => 'onticket.adminapp.inicio', + 'code' => 'adminapp.inicio', 'label' => 'Administración', 'route' => '/admin/inicio', ]); diff --git a/tests/Feature/Desfile/EntryControllerTest.php b/tests/Feature/Desfile/EntryControllerTest.php index 5d98972c..7484a2c4 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' => 'onticket.adminapp.desfile.entradas'], + ['code' => '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 5d28ecce..3050ac09 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' => 'onticket.adminapp.fiesta-futbol-infantil.alojamientos'], + ['code' => '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 8938333d..b6066fe9 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', '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'], + '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'], ]; foreach ($categories as [$label, $menuCode]) { @@ -405,7 +405,7 @@ class EntryControllerTest extends TestCase { $tenant = $this->createTenant('fiesta_futbol_infantil'); $menu = Menu::query()->create([ - 'code' => 'onticket.adminapp.fiesta-futbol-infantil.entradas', + 'code' => '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 f90b70ff..c0339163 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' => 'onticket.adminapp.fiesta-futbol-infantil.comida', + 'code' => '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 39aeaf3c..7f8ddcf8 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' => 'onticket.adminapp.fiesta-futbol-infantil.merchandising', + 'code' => '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 92b63c82..d7a90e93 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' => 'onticket.adminapp.desfile.reservas', + 'code' => '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 64d33a85..b6d873b0 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' => 'onticket.adminapp.tickets', + 'code' => 'adminapp.tickets', 'label' => 'Tickets', 'route' => '/admin/tickets', ]); diff --git a/tests/Feature/Menu/TicketMenuAccessTest.php b/tests/Feature/Menu/TicketMenuAccessTest.php index 48c7549a..926fce47 100644 --- a/tests/Feature/Menu/TicketMenuAccessTest.php +++ b/tests/Feature/Menu/TicketMenuAccessTest.php @@ -18,8 +18,8 @@ class TicketMenuAccessTest extends TestCase public static function menuAssignments(): array { return [ - 'new code' => ['onticket.adminapp.tickets', 'current', false], - 'old code' => ['adminapp.tickets', 'current', true], + 'compatible code' => ['adminapp.tickets', 'current', true], + 'prefixed code' => ['onticket.adminapp.tickets', 'current', false], 'another tenant' => ['adminapp.tickets', 'other', false], 'unrelated menu' => ['adminapp.ventas', 'current', false], ]; @@ -39,6 +39,7 @@ class TicketMenuAccessTest extends TestCase Schema::create('tenants_menues', function (Blueprint $table): void { $table->string('tenant_code'); $table->string('menu_code'); + $table->boolean('is_enabled')->default(true); }); DB::table('tenants')->insert(['codigo' => 'current']); DB::table('menues')->insert(['code' => $menuCode]); diff --git a/tests/Feature/Migrations/RemoveOnticketMenuCodePrefixTest.php b/tests/Feature/Migrations/RemoveOnticketMenuCodePrefixTest.php new file mode 100644 index 00000000..0fe1ce6c --- /dev/null +++ b/tests/Feature/Migrations/RemoveOnticketMenuCodePrefixTest.php @@ -0,0 +1,108 @@ +id(); + $table->string('code')->unique(); + $table->string('label'); + $table->string('parent_menu_code')->nullable(); + $table->foreign('parent_menu_code')->references('code')->on('menues')->nullOnDelete(); + }); + Schema::create('tenants_menues', function (Blueprint $table): void { + $table->id(); + $table->string('tenant_code'); + $table->string('menu_code'); + $table->json('static_content')->nullable(); + $table->boolean('is_enabled')->default(true); + $table->timestamps(); + $table->foreign('menu_code')->references('code')->on('menues')->cascadeOnDelete(); + $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->string('access_level')->default('none'); + $table->foreign('menu_codigo')->references('code')->on('menues')->cascadeOnDelete(); + $table->unique(['rol_codigo', 'menu_codigo']); + }); + } + + public function test_it_preserves_hierarchy_assignments_content_and_access_and_can_run_twice(): void + { + DB::table('menues')->insert(['code' => 'onticket.custom', 'label' => 'Custom']); + DB::table('menues')->insert([ + ['code' => 'onticket.custom.child', 'label' => 'Child', 'parent_menu_code' => 'onticket.custom'], + ['code' => 'unrelated', 'label' => 'Unrelated', 'parent_menu_code' => 'onticket.custom'], + ['code' => 'shopit.adminapp.marca', 'label' => 'Marca', 'parent_menu_code' => null], + ]); + $createdAt = '2026-09-01 12:00:00'; + DB::table('tenants_menues')->insert([ + 'tenant_code' => 'tenant', 'menu_code' => 'onticket.custom.child', + 'static_content' => '{"title":"Content"}', 'is_enabled' => false, + 'created_at' => $createdAt, 'updated_at' => $createdAt, + ]); + DB::table('roles_menues')->insert([ + 'rol_codigo' => 'adminapp', 'menu_codigo' => 'onticket.custom.child', 'access_level' => 'edit', + ]); + + $migration = require database_path('migrations/2026_10_02_000000_remove_onticket_menu_code_prefix.php'); + $migration->up(); + $migration->up(); + + $this->assertFalse(DB::table('menues')->where('code', 'like', 'onticket.%')->exists()); + $this->assertDatabaseHas('menues', ['code' => 'custom.child', 'label' => 'Child', 'parent_menu_code' => 'custom']); + $this->assertDatabaseHas('menues', ['code' => 'unrelated', 'parent_menu_code' => 'custom']); + $this->assertDatabaseHas('menues', ['code' => 'shopit.adminapp.marca']); + $this->assertDatabaseHas('tenants_menues', [ + 'tenant_code' => 'tenant', 'menu_code' => 'custom.child', + 'static_content' => '{"title":"Content"}', 'is_enabled' => false, 'created_at' => $createdAt, + ]); + $this->assertDatabaseHas('roles_menues', [ + 'rol_codigo' => 'adminapp', 'menu_codigo' => 'custom.child', 'access_level' => 'edit', + ]); + $this->assertDatabaseCount('tenants_menues', 1); + $this->assertDatabaseCount('roles_menues', 1); + } + + public function test_it_merges_existing_codes_without_losing_the_active_assignment_settings(): void + { + DB::table('menues')->insert([ + ['code' => 'adminapp.tickets', 'label' => 'Tickets'], + ['code' => 'onticket.adminapp.tickets', 'label' => 'Tickets prefixed'], + ]); + DB::table('tenants_menues')->insert([ + ['tenant_code' => 'tenant', 'menu_code' => 'adminapp.tickets', 'is_enabled' => true], + ['tenant_code' => 'tenant', 'menu_code' => 'onticket.adminapp.tickets', 'is_enabled' => false], + ['tenant_code' => 'other', 'menu_code' => 'adminapp.tickets', 'is_enabled' => true], + ]); + DB::table('roles_menues')->insert([ + ['rol_codigo' => 'adminapp', 'menu_codigo' => 'adminapp.tickets', 'access_level' => 'edit'], + ['rol_codigo' => 'adminapp', 'menu_codigo' => 'onticket.adminapp.tickets', 'access_level' => 'none'], + ['rol_codigo' => 'other', 'menu_codigo' => 'adminapp.tickets', 'access_level' => 'view'], + ]); + + $migration = require database_path('migrations/2026_10_02_000000_remove_onticket_menu_code_prefix.php'); + $migration->up(); + + $this->assertDatabaseCount('menues', 1); + $this->assertDatabaseCount('tenants_menues', 2); + $this->assertDatabaseCount('roles_menues', 2); + $this->assertDatabaseHas('tenants_menues', ['tenant_code' => 'tenant', 'menu_code' => 'adminapp.tickets', 'is_enabled' => false]); + $this->assertDatabaseHas('tenants_menues', ['tenant_code' => 'other', 'menu_code' => 'adminapp.tickets', 'is_enabled' => true]); + $this->assertDatabaseHas('roles_menues', ['rol_codigo' => 'adminapp', 'menu_codigo' => 'adminapp.tickets', 'access_level' => 'none']); + $this->assertDatabaseHas('roles_menues', ['rol_codigo' => 'other', 'menu_codigo' => 'adminapp.tickets', 'access_level' => 'view']); + } +} diff --git a/tests/Feature/Seeders/DesfilePuraTendenciaSeederTest.php b/tests/Feature/Seeders/DesfilePuraTendenciaSeederTest.php index cc804b65..6dc80cb2 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', 'onticket.adminapp.fiesta-futbol-infantil.%') + ->where('menu_code', 'not like', '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('onticket.adminapp.event', $actualMenus); + $this->assertContains('adminapp.event', $actualMenus); $this->assertContains('scanner.scan', $actualMenus); - $this->assertNotContains('onticket.adminapp.fiesta-futbol-infantil.entradas', $actualMenus); + $this->assertNotContains('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 6f1d4bc0..fe46b875 100644 --- a/tests/Feature/Seeders/MenuSeederTest.php +++ b/tests/Feature/Seeders/MenuSeederTest.php @@ -26,24 +26,24 @@ class MenuSeederTest extends TestCase $this->seed(MenuSeeder::class); $expectedMenus = [ - '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'], + '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' => ['Usuarios', '/admin/staff'], + 'adminapp.ventas' => ['Ventas', '/admin/ventas'], ]; $fiestaCategoryMenus = [ - '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'], + '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'], ]; $desfileMenus = [ - 'onticket.adminapp.desfile.entradas' => ['Entradas', '/admin/desfile/entradas'], - 'onticket.adminapp.desfile.reservas' => ['Reserva de Tickets', '/admin/desfile/reservas'], + 'adminapp.desfile.entradas' => ['Entradas', '/admin/desfile/entradas'], + 'adminapp.desfile.reservas' => ['Reserva de Tickets', '/admin/desfile/reservas'], ]; $shopItMenus = $this->shopItAdminMenus(); @@ -95,10 +95,10 @@ class MenuSeederTest extends TestCase } foreach ([ - 'onticket.adminapp.inicio', - 'onticket.adminapp.catalog', - 'onticket.adminapp.categories', - 'onticket.adminapp.combos', + 'adminapp.inicio', + 'adminapp.catalog', + 'adminapp.categories', + 'adminapp.combos', ] as $code) { $this->assertFalse( $fiestaTenant->menues()->where('menues.code', $code)->exists() @@ -163,7 +163,7 @@ class MenuSeederTest extends TestCase } $this->assertFalse( - Menu::query()->where('code', 'like', 'adminapp.%')->exists() + Menu::query()->where('code', 'like', 'onticket.%')->exists() ); } @@ -213,7 +213,7 @@ class MenuSeederTest extends TestCase $this->assertSame($userMenuCodes, $userRoleMenuCodes); $this->assertNotContains('main.adminapp', $userRoleMenuCodes); - $this->assertNotContains('onticket.adminapp.catalog', $userRoleMenuCodes); + $this->assertNotContains('adminapp.catalog', $userRoleMenuCodes); $scannerRoleMenuCodes = Role::query() ->where('codigo', RoleCode::Scanner->value) diff --git a/tests/Feature/Ticket/AdminAppTicketControllerTest.php b/tests/Feature/Ticket/AdminAppTicketControllerTest.php index 2ab90c87..20f83794 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' => 'onticket.adminapp.tickets', + 'code' => 'adminapp.tickets', 'label' => 'Tickets', 'route' => '/admin/tickets', ]);