feat: Agrega validaciones de autorización y nuevas clases Request

- Se agregó autorización basada en permisos en múltiples Requests.
- Nuevos Requests para motivos de cancelación y tags con validación y autorización.
- Se añadieron métodos de roles al modelo User (isDeveloper, isAdmin, isPrimary).
- Se actualizó el acceso a Telescope usando validación por roles.
- Mejora en el manejo de excepciones de autorización.
- Actualización de RoleSeeder con nuevas convenciones de permisos.
- Actualización de dependencias (composer.lock).
This commit is contained in:
Juan Felipe Zapata Moreno 2026-02-23 13:05:53 -06:00
parent 69371a0088
commit 31746867b8
38 changed files with 566 additions and 222 deletions

View File

@ -1,4 +1,7 @@
<?php namespace App\Http\Controllers\Admin; <?php
namespace App\Http\Controllers\Admin;
/** /**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved * @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/ */
@ -10,9 +13,9 @@
/** /**
* Eventos del usuarios del sistema * Eventos del usuarios del sistema
* *
* @author Moisés Cortés C. <moises.cortes@notsoweb.com> * @author Moisés Cortés C. <moises.cortes@notsoweb.com>
* *
* @version 1.0.0 * @version 1.0.0
*/ */
class ActivityController extends Controller class ActivityController extends Controller
@ -24,27 +27,23 @@ public function index(UserActivityRequest $request)
{ {
$filters = $request->all(); $filters = $request->all();
$model = UserEvent::with('user:id,name,paternal,maternal,profile_photo_path,deleted_at'); $model = UserEvent::with('user:id,name,paternal,maternal,profile_photo_path,deleted_at')
->when(isset($filters['user']) && !empty($filters['user']), function ($query) use ($filters) {
if(isset($filters['user']) && !empty($filters['user'])){ $query->where('user_id', $filters['user']);
$model->where('user_id', $filters['user']); })
} ->when(isset($filters['search']) && !empty($filters['search']), function ($query) use ($filters) {
$query->where('event', 'like', '%' . $filters['search'] . '%');
if(isset($filters['search']) && !empty($filters['search'])){ })
$model->where('event', 'like', '%'.$filters['search'].'%'); ->when(isset($filters['start_date']) && !empty($filters['start_date']), function ($query) use ($filters) {
} $query->where('created_at', '>=', "{$filters['start_date']} 00:00:00");
})
if(isset($filters['start_date']) && !empty($filters['start_date'])){ ->when(isset($filters['end_date']) && !empty($filters['end_date']), function ($query) use ($filters) {
$model->where('created_at', '>=', "{$filters['start_date']} 00:00:00"); $query->where('created_at', '<=', "{$filters['end_date']} 23:59:59");
} });
if(isset($filters['end_date']) && !empty($filters['end_date'])){
$model->where('created_at', '<=', "{$filters['end_date']} 23:59:59");
}
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'models' => 'models' =>
$model->orderBy('created_at', 'desc') $model->orderBy('created_at', 'desc')
->paginate(config('app.pagination')) ->paginate(config('app.pagination'))
]); ]);
} }

View File

@ -7,6 +7,7 @@
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Roles\RoleStoreRequest; use App\Http\Requests\Roles\RoleStoreRequest;
use App\Http\Requests\Roles\RoleUpdateRequest; use App\Http\Requests\Roles\RoleUpdateRequest;
use Illuminate\Routing\Controllers\HasMiddleware;
use App\Models\Role; use App\Models\Role;
use App\Supports\QuerySupport; use App\Supports\QuerySupport;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -19,8 +20,21 @@
* *
* @version 1.0.0 * @version 1.0.0
*/ */
class RoleController extends Controller class RoleController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('roles.index', ['index']),
self::can('roles.show', ['show']),
self::can('roles.destroy', ['destroy']),
self::can('roles.permissions', ['permissions', 'updatePermissions']),
];
}
/** /**
* Listar * Listar
*/ */
@ -75,7 +89,7 @@ public function update(RoleUpdateRequest $request, Role $role)
*/ */
public function destroy(Role $role) public function destroy(Role $role)
{ {
if (in_array($role->id, ['2'])) { if (in_array($role->id, [1, 2])) {
return ApiResponse::BAD_REQUEST->response([ return ApiResponse::BAD_REQUEST->response([
'message' => 'No se puede eliminar este rol' 'message' => 'No se puede eliminar este rol'
]); ]);

View File

@ -1,16 +1,22 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved use Illuminate\Routing\Controllers\Middleware;
*/
/** /**
* Controlador base * Controlador base
* *
* @author Moisés Cortés C. <moises.cortes@notsoweb.com> * @author Moisés Cortés C. <moises.cortes@notsoweb.com>
* *
* @version 1.0.0 * @version 1.0.0
*/ */
abstract class Controller abstract class Controller
{ {
//
/**
* Evaluar permisos de un usuario
*/
public static function can(string $permission, array $methods): Middleware
{
return new Middleware("permission:{$permission}", only: $methods);
}
} }

View File

@ -16,9 +16,20 @@
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Notsoweb\ApiResponse\Enums\ApiResponse; use Notsoweb\ApiResponse\Enums\ApiResponse;
use Barryvdh\DomPDF\Facade\Pdf; use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Routing\Controllers\HasMiddleware;
class CancellationController extends Controller class CancellationController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('cancellations.cancel_constancia', ['cancelarConstancia']),
self::can('cancellations.cancel_tag_no_asignado', ['cancelarTagNoAsignado']),
];
}
/** /**
* Cancelar la constancia/tag * Cancelar la constancia/tag

View File

@ -7,16 +7,30 @@
*/ */
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Repuve\CancelConstanciaRequest; use App\Http\Requests\Repuve\CatalogCancellationReasonStoreRequest;
use App\Http\Requests\Repuve\CatalogCancellationReasonUpdateRequest;
use App\Models\CatalogCancellationReason; use App\Models\CatalogCancellationReason;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Notsoweb\ApiResponse\Enums\ApiResponse; use Notsoweb\ApiResponse\Enums\ApiResponse;
use Illuminate\Routing\Controllers\HasMiddleware;
/** /**
* Descripción * Descripción
*/ */
class CatalogController extends Controller class CatalogController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('catalogs.cancellation_reasons.index', ['index']),
self::can('catalogs.cancellation_reasons.show', ['show']),
self::can('catalogs.cancellation_reasons.destroy', ['destroy']),
];
}
public function index(Request $request) public function index(Request $request)
{ {
$type = $request->query('type'); $type = $request->query('type');
@ -55,14 +69,9 @@ public function show($id)
]); ]);
} }
public function store(Request $request) public function store(CatalogCancellationReasonStoreRequest $request)
{ {
$validated = $request->validate([ $validated = $request->validated();
'code' => 'required|string|unique:catalog_cancellation_reasons,code',
'name' => 'required|string',
'description' => 'nullable|string',
'applies_to' => 'required|in:cancelacion,sustitucion,ambos',
]);
$reason = CatalogCancellationReason::create($validated); $reason = CatalogCancellationReason::create($validated);
@ -72,7 +81,7 @@ public function store(Request $request)
]); ]);
} }
public function update(Request $request, $id) public function update(CatalogCancellationReasonUpdateRequest $request, $id)
{ {
$reason = CatalogCancellationReason::find($id); $reason = CatalogCancellationReason::find($id);
@ -82,11 +91,7 @@ public function update(Request $request, $id)
]); ]);
} }
$validated = $request->validate([ $validated = $request->validated();
'name' => 'required|string',
'description' => 'nullable|string',
'applies_to' => 'required|in:cancelacion,sustitucion,ambos',
]);
$reason->update($validated); $reason->update($validated);

View File

@ -4,12 +4,24 @@
use App\Http\Requests\Repuve\CatalogNameImgStoreRequest; use App\Http\Requests\Repuve\CatalogNameImgStoreRequest;
use App\Http\Requests\Repuve\CatalogNameImgUpdateRequest; use App\Http\Requests\Repuve\CatalogNameImgUpdateRequest;
use Notsoweb\LaravelCore\Controllers\VueController; use App\Http\Controllers\Controller;
use App\Models\CatalogNameImg; use App\Models\CatalogNameImg;
use Illuminate\Routing\Controllers\HasMiddleware;
use Notsoweb\ApiResponse\Enums\ApiResponse; use Notsoweb\ApiResponse\Enums\ApiResponse;
class CatalogNameImgController extends VueController class CatalogNameImgController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('catalogs.name_img.index', ['index']),
self::can('catalogs.name_img.destroy', ['destroy']),
];
}
/** /**
* Listar * Listar
*/ */

View File

@ -12,9 +12,21 @@
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Routing\Controllers\HasMiddleware;
class DeviceController extends Controller class DeviceController extends Controller implements HasMiddleware
{ {
public static function middleware(): array
{
return [
self::can('devices.index', ['index']),
self::can('devices.show', ['show']),
self::can('devices.destroy', ['destroy']),
self::can('devices.toggle_status', ['toggleStatus']),
];
}
public function index(Request $request) public function index(Request $request)
{ {
try { try {

View File

@ -21,13 +21,28 @@
use PhpOffice\PhpSpreadsheet\Style\Fill; use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Routing\Controllers\HasMiddleware;
/** /**
* Descripción * Descripción
*/ */
class ExcelController extends Controller class ExcelController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('reports.vehicle_updates.index', ['vehicleActualizaciones']),
self::can('reports.substitutions.index', ['constanciasSustituidas']),
self::can('reports.cancellations.index', ['constanciasCanceladas']),
self::can('reports.general.index', ['excelGeneral']),
self::can('reports.search_records.index', ['exportSearchRecords']),
];
}
public function vehicleActualizaciones(Request $request) public function vehicleActualizaciones(Request $request)
{ {

View File

@ -19,9 +19,21 @@
use App\Services\RepuveService; use App\Services\RepuveService;
use App\Services\PadronEstatalService; use App\Services\PadronEstatalService;
use App\Jobs\ProcessRepuveResponse; use App\Jobs\ProcessRepuveResponse;
use Illuminate\Routing\Controllers\HasMiddleware;
class InscriptionController extends Controller class InscriptionController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('repuve.search_records', ['searchRecord']),
self::can('repuve.check_stolen', ['stolen']),
];
}
private RepuveService $repuveService; private RepuveService $repuveService;
private PadronEstatalService $padronEstatalService; private PadronEstatalService $padronEstatalService;

View File

@ -6,15 +6,28 @@
use App\Http\Requests\Repuve\ModuleStoreRequest; use App\Http\Requests\Repuve\ModuleStoreRequest;
use App\Http\Requests\Repuve\ModuleUpdateRequest; use App\Http\Requests\Repuve\ModuleUpdateRequest;
use App\Models\Module; use App\Models\Module;
use App\Models\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Notsoweb\ApiResponse\Enums\ApiResponse; use Notsoweb\ApiResponse\Enums\ApiResponse;
use Illuminate\Routing\Controllers\HasMiddleware;
class ModuleController extends Controller class ModuleController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('modules.index', ['index']),
self::can('modules.show', ['show']),
self::can('modules.destroy', ['destroy']),
self::can('modules.toggle_status', ['toggleStatus']),
];
}
/** /**
* Listar módulos existentes * Listar módulos existentes
*/ */

View File

@ -14,9 +14,23 @@
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use App\Models\Package; use App\Models\Package;
use App\Models\Tag; use App\Models\Tag;
use Illuminate\Routing\Controllers\HasMiddleware;
class PackageController extends Controller class PackageController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('packages.index', ['index']),
self::can('packages.show', ['show']),
self::can('packages.destroy', ['destroy']),
self::can('packages.box_tags', ['getBoxTags']),
];
}
public function index(Request $request) public function index(Request $request)
{ {

View File

@ -11,9 +11,22 @@
use Notsoweb\ApiResponse\Enums\ApiResponse; use Notsoweb\ApiResponse\Enums\ApiResponse;
use Codedge\Fpdf\Fpdf\Fpdf; use Codedge\Fpdf\Fpdf\Fpdf;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Controllers\HasMiddleware;
class RecordController extends Controller class RecordController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('records.index', ['index']),
self::can('records.show', ['show']),
self::can('records.generate_pdf', ['generatePdf', 'generatePdfVerification', 'generatePdfConstancia', 'generatePdfImages', 'generatePdfForm']),
];
}
public function generatePdf($id) public function generatePdf($id)
{ {
$record = Record::with('vehicle.owner', 'user', 'module')->findOrFail($id); $record = Record::with('vehicle.owner', 'user', 'module')->findOrFail($id);

View File

@ -3,6 +3,8 @@
namespace App\Http\Controllers\Repuve; namespace App\Http\Controllers\Repuve;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Repuve\TagStoreRequest;
use App\Http\Requests\Repuve\TagUpdateRequest;
use App\Models\CatalogTagStatus; use App\Models\CatalogTagStatus;
use App\Models\Module; use App\Models\Module;
use App\Models\Package; use App\Models\Package;
@ -15,9 +17,21 @@
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Illuminate\Routing\Controllers\HasMiddleware;
class TagsController extends Controller class TagsController extends Controller implements HasMiddleware
{ {
public static function middleware(): array
{
return [
self::can('tags.index', ['index']),
self::can('tags.create', ['tagStore']),
self::can('tags.assign_to_module', ['assignToModule']),
self::can('tags.show', ['show']),
self::can('tags.destroy', ['destroy']),
];
}
public function index(Request $request) public function index(Request $request)
{ {
try { try {
@ -69,15 +83,10 @@ public function index(Request $request)
} }
} }
public function store(Request $request) public function store(TagStoreRequest $request)
{ {
try { try {
$validated = $request->validate([ $validated = $request->validated();
'folio' => 'required|string|max:8',
'package_id' => 'required|integer|exists:packages,id',
'tag_number' => 'nullable|string|min:32|max:32',
'module_id' => 'nullable|integer|exists:modules,id',
]);
// Verificar si ya existe un tag con el mismo folio // Verificar si ya existe un tag con el mismo folio
$existingTagByFolio = Tag::where('folio', $validated['folio'])->first(); $existingTagByFolio = Tag::where('folio', $validated['folio'])->first();
@ -232,12 +241,6 @@ public function store(Request $request)
} }
return ApiResponse::CREATED->response($response); return ApiResponse::CREATED->response($response);
} catch (ValidationException $e) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'No se pudo crear el tag: Datos de validación incorrectos.',
'error' => 'validation_error',
'errors' => $e->errors(),
]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack(); DB::rollBack();
@ -292,7 +295,7 @@ public function show(Tag $tag)
]); ]);
} }
public function update(Request $request, Tag $tag) public function update(TagUpdateRequest $request, Tag $tag)
{ {
try { try {
// Validar que el tag solo pueda actualizarse si está disponible o cancelado // Validar que el tag solo pueda actualizarse si está disponible o cancelado
@ -304,14 +307,7 @@ public function update(Request $request, Tag $tag)
]); ]);
} }
// Validar los campos de entrada $validated = $request->validated();
$validated = $request->validate([
'folio' => 'sometimes|string|max:8',
'tag_number' => 'nullable|string|min:32|max:32',
'package_id' => 'sometimes|integer|exists:packages,id',
'module_id' => 'nullable|integer|exists:modules,id',
'status_id' => 'sometimes|integer|exists:catalog_tag_status,id',
]);
// Si se va a cambiar el status, validar que solo sea a disponible o cancelado // Si se va a cambiar el status, validar que solo sea a disponible o cancelado
if (isset($validated['status_id'])) { if (isset($validated['status_id'])) {

View File

@ -22,9 +22,22 @@
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use App\Jobs\ProcessRepuveResponse; use App\Jobs\ProcessRepuveResponse;
use App\Models\CatalogTagStatus; use App\Models\CatalogTagStatus;
use Illuminate\Routing\Controllers\HasMiddleware;
class UpdateController extends Controller class UpdateController extends Controller implements HasMiddleware
{ {
/**
* Middleware
*/
public static function middleware(): array
{
return [
self::can('records.update', ['updateData']),
self::can('records.update', ['tagSubstitution']),
];
}
private RepuveService $repuveService; private RepuveService $repuveService;
private PadronEstatalService $padronEstatalService; private PadronEstatalService $padronEstatalService;

View File

@ -11,7 +11,7 @@ class CancelConstanciaRequest extends FormRequest
*/ */
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->hasPermissionTo('cancellations.cancel_constancia');
} }
/** /**

View File

@ -0,0 +1,43 @@
<?php namespace App\Http\Requests\Repuve;
use Illuminate\Foundation\Http\FormRequest;
class CatalogCancellationReasonStoreRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->user()->can('catalogs.cancellation_reasons.create');
}
public function rules(): array
{
return [
'code' => ['required', 'string', 'unique:catalog_cancellation_reasons,code'],
'name' => ['required', 'string'],
'description' => ['nullable', 'string'],
'applies_to' => ['required', 'in:cancelacion,sustitucion,ambos'],
];
}
public function messages(): array
{
return [
'code.required' => 'El código es obligatorio.',
'code.unique' => 'El código ya existe.',
'name.required' => 'El nombre es obligatorio.',
'applies_to.required' => 'El tipo de aplicación es obligatorio.',
'applies_to.in' => 'El tipo de aplicación debe ser: cancelacion, sustitucion o ambos.',
];
}
public function attributes(): array
{
return [
'code' => 'código',
'name' => 'nombre',
'description' => 'descripción',
'applies_to' => 'aplica a',
];
}
}

View File

@ -0,0 +1,39 @@
<?php namespace App\Http\Requests\Repuve;
use Illuminate\Foundation\Http\FormRequest;
class CatalogCancellationReasonUpdateRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->user()->can('catalogs.cancellation_reasons.edit');
}
public function rules(): array
{
return [
'name' => ['required', 'string'],
'description' => ['nullable', 'string'],
'applies_to' => ['required', 'in:cancelacion,sustitucion,ambos'],
];
}
public function messages(): array
{
return [
'name.required' => 'El nombre es obligatorio.',
'applies_to.required' => 'El tipo de aplicación es obligatorio.',
'applies_to.in' => 'El tipo de aplicación debe ser: cancelacion, sustitucion o ambos.',
];
}
public function attributes(): array
{
return [
'name' => 'nombre',
'description' => 'descripción',
'applies_to' => 'aplica a',
];
}
}

View File

@ -7,7 +7,7 @@ class CatalogNameImgStoreRequest extends FormRequest
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('catalogs.name_img.create');
} }
public function rules(): array public function rules(): array

View File

@ -7,7 +7,7 @@ class CatalogNameImgUpdateRequest extends FormRequest
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('catalogs.name_img.edit');
} }
public function rules(): array public function rules(): array

View File

@ -6,7 +6,7 @@ class DeviceStoreRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('devices.create');
} }
public function rules(): array public function rules(): array

View File

@ -8,7 +8,7 @@ class DeviceUpdateRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('devices.edit');
} }
public function rules(): array public function rules(): array

View File

@ -9,7 +9,7 @@ class ModuleStoreRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('modules.create');
} }
public function rules(): array public function rules(): array

View File

@ -9,7 +9,7 @@ class ModuleUpdateRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('modules.edit');
} }
public function rules(): array public function rules(): array

View File

@ -7,7 +7,7 @@ class PackageStoreRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('packages.create');
} }
public function rules(): array public function rules(): array

View File

@ -8,7 +8,7 @@ class PackageUpdateRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('packages.edit');
} }
public function rules(): array public function rules(): array

View File

@ -6,7 +6,7 @@ class RecordSearchRequest extends FormRequest
{ {
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('repuve.records.search');
} }
public function rules(): array public function rules(): array

View File

@ -0,0 +1,44 @@
<?php namespace App\Http\Requests\Repuve;
use Illuminate\Foundation\Http\FormRequest;
class TagStoreRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->user()->can('tags.create');
}
public function rules(): array
{
return [
'folio' => ['required', 'string', 'max:8'],
'package_id' => ['required', 'integer', 'exists:packages,id'],
'tag_number' => ['nullable', 'string', 'min:32', 'max:32'],
'module_id' => ['nullable', 'integer', 'exists:modules,id'],
];
}
public function messages(): array
{
return [
'folio.required' => 'El folio es obligatorio.',
'folio.max' => 'El folio no puede tener más de 8 caracteres.',
'package_id.required' => 'La caja es obligatoria.',
'package_id.exists' => 'La caja seleccionada no existe.',
'tag_number.min' => 'El número de constancia debe tener exactamente 32 caracteres.',
'tag_number.max' => 'El número de constancia debe tener exactamente 32 caracteres.',
'module_id.exists' => 'El módulo seleccionado no existe.',
];
}
public function attributes(): array
{
return [
'folio' => 'folio',
'package_id' => 'caja',
'tag_number' => 'número de constancia',
'module_id' => 'módulo',
];
}
}

View File

@ -0,0 +1,45 @@
<?php namespace App\Http\Requests\Repuve;
use Illuminate\Foundation\Http\FormRequest;
class TagUpdateRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->user()->can('tags.edit');
}
public function rules(): array
{
return [
'folio' => ['sometimes', 'string', 'max:8'],
'tag_number' => ['nullable', 'string', 'min:32', 'max:32'],
'package_id' => ['sometimes', 'integer', 'exists:packages,id'],
'module_id' => ['nullable', 'integer', 'exists:modules,id'],
'status_id' => ['sometimes', 'integer', 'exists:catalog_tag_status,id'],
];
}
public function messages(): array
{
return [
'folio.max' => 'El folio no puede tener más de 8 caracteres.',
'tag_number.min' => 'El número de constancia debe tener exactamente 32 caracteres.',
'tag_number.max' => 'El número de constancia debe tener exactamente 32 caracteres.',
'package_id.exists' => 'La caja seleccionada no existe.',
'module_id.exists' => 'El módulo seleccionado no existe.',
'status_id.exists' => 'El estado seleccionado no existe.',
];
}
public function attributes(): array
{
return [
'folio' => 'folio',
'tag_number' => 'número de constancia',
'package_id' => 'caja',
'module_id' => 'módulo',
'status_id' => 'estado',
];
}
}

View File

@ -7,7 +7,7 @@ class VehicleStoreRequest extends FormRequest
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('vehicles.create');
} }
public function rules(): array public function rules(): array

View File

@ -9,7 +9,7 @@ class VehicleUpdateRequest extends FormRequest
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('vehicles.edit');
} }
public function rules(): array public function rules(): array

View File

@ -21,7 +21,7 @@ class RoleStoreRequest extends FormRequest
*/ */
public function authorize(): bool public function authorize(): bool
{ {
return auth()->user()->hasPermissionTo('roles.create'); return auth()->user()->can('roles.create');
} }
/** /**

View File

@ -9,9 +9,9 @@
/** /**
* Actualizar rol * Actualizar rol
* *
* @author Moisés Cortés C. <moises.cortes@notsoweb.com> * @author Moisés Cortés C. <moises.cortes@notsoweb.com>
* *
* @version 1.0.0 * @version 1.0.0
*/ */
class RoleUpdateRequest extends FormRequest class RoleUpdateRequest extends FormRequest
@ -21,7 +21,7 @@ class RoleUpdateRequest extends FormRequest
*/ */
public function authorize(): bool public function authorize(): bool
{ {
return auth()->user()->hasPermissionTo('roles.edit'); return auth()->user()->can('roles.edit');
} }
/** /**
@ -39,8 +39,10 @@ public function rules(): array
*/ */
protected function passedValidation() protected function passedValidation()
{ {
$this->merge([ if(!in_array($this->route('role')->id, [1, 2])) {
'name' => Str::slug($this->description), $this->merge([
]); 'name' => Str::slug($this->description),
]);
}
} }
} }

View File

@ -7,9 +7,9 @@
/** /**
* Descripción * Descripción
* *
* @author Moisés Cortés C. <moises.cortes@notsoweb.com> * @author Moisés Cortés C. <moises.cortes@notsoweb.com>
* *
* @version 1.0.0 * @version 1.0.0
*/ */
class UserActivityRequest extends FormRequest class UserActivityRequest extends FormRequest
@ -19,7 +19,7 @@ class UserActivityRequest extends FormRequest
*/ */
public function authorize(): bool public function authorize(): bool
{ {
return true; return auth()->user()->can('activities.index');
} }
/** /**

View File

@ -48,7 +48,6 @@ class User extends Authenticatable
'username', 'username',
'phone', 'phone',
'password', 'password',
//'profile_photo_path',
'module_id' 'module_id'
]; ];
@ -58,6 +57,7 @@ class User extends Authenticatable
protected $hidden = [ protected $hidden = [
'password', 'password',
'remember_token', 'remember_token',
'profile_photo_path'
]; ];
/** /**
@ -136,6 +136,30 @@ public function module()
return $this->belongsTo(Module::class); return $this->belongsTo(Module::class);
} }
/**
* Preguntar si el usuario es desarrollador
*/
public function isDeveloper(): bool
{
return $this->hasRole(Role::find(1));
}
/**
* Preguntar si el usuario es administrador
*/
public function isAdmin(): bool
{
return $this->hasRole(Role::find(2));
}
/**
* Preguntar si el usuario es primario (privilegios elevados)
*/
public function isPrimary(): bool
{
return $this->hasRole(Role::find(1), Role::find(2));
}
/** /**
* Módulo del cual el usuario es responsable * Módulo del cual el usuario es responsable
*/ */

View File

@ -11,9 +11,9 @@
/** /**
* Proveedor de servicios de Telescope * Proveedor de servicios de Telescope
* *
* @author Moisés Cortés C. <moises.cortes@notsoweb.com> * @author Moisés Cortés C. <moises.cortes@notsoweb.com>
* *
* @version 1.0.0 * @version 1.0.0
*/ */
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
@ -65,7 +65,7 @@ protected function hideSensitiveRequestDetails(): void
protected function gate(): void protected function gate(): void
{ {
Gate::define('viewTelescope', function (User $user) { Gate::define('viewTelescope', function (User $user) {
return $user->hasRole('developer'); return $user->isDeveloper();
}); });
} }
} }

View File

@ -8,6 +8,8 @@
use Illuminate\Session\Middleware\StartSession; use Illuminate\Session\Middleware\StartSession;
use Notsoweb\ApiResponse\Enums\ApiResponse; use Notsoweb\ApiResponse\Enums\ApiResponse;
use Notsoweb\LaravelCore\Http\APIException; use Notsoweb\LaravelCore\Http\APIException;
use Spatie\Permission\Exceptions\UnauthorizedException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
return Application::configure(basePath: dirname(__DIR__)) return Application::configure(basePath: dirname(__DIR__))
@ -44,6 +46,20 @@
return ApiResponse::SERVICE_UNAVAILABLE->response(); return ApiResponse::SERVICE_UNAVAILABLE->response();
} }
}); });
$exceptions->render(function (UnauthorizedException $e, Request $request) {
if ($request->is('api/*')) {
return ApiResponse::UNPROCESSABLE_CONTENT->response([
'message' => $e->getMessage()
]);
}
});
$exceptions->render(function (AccessDeniedHttpException $e, Request $request) {
if ($request->is('api/*')) {
return ApiResponse::UNPROCESSABLE_CONTENT->response([
'message' => __($e->getMessage())
]);
}
});
$exceptions->render(APIException::notFound(...)); $exceptions->render(APIException::notFound(...));
$exceptions->render(APIException::unauthorized(...)); $exceptions->render(APIException::unauthorized(...));
$exceptions->render(APIException::unprocessableContent(...)); $exceptions->render(APIException::unprocessableContent(...));

184
composer.lock generated
View File

@ -1782,16 +1782,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v12.51.0", "version": "v12.52.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16" "reference": "d5511fa74f4608dbb99864198b1954042aa8d5a7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/ce4de3feb211e47c4f959d309ccf8a2733b1bc16", "url": "https://api.github.com/repos/laravel/framework/zipball/d5511fa74f4608dbb99864198b1954042aa8d5a7",
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16", "reference": "d5511fa74f4608dbb99864198b1954042aa8d5a7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2000,7 +2000,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2026-02-10T18:20:19+00:00" "time": "2026-02-17T17:07:04+00:00"
}, },
{ {
"name": "laravel/passport", "name": "laravel/passport",
@ -3881,16 +3881,16 @@
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
"version": "v1.3.4", "version": "v1.3.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nette/schema.git", "url": "https://github.com/nette/schema.git",
"reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7" "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/086497a2f34b82fede9b5a41cc8e131d087cd8f7", "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002",
"reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7", "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3898,8 +3898,10 @@
"php": "8.1 - 8.5" "php": "8.1 - 8.5"
}, },
"require-dev": { "require-dev": {
"nette/phpstan-rules": "^1.0",
"nette/tester": "^2.6", "nette/tester": "^2.6",
"phpstan/phpstan": "^2.0@stable", "phpstan/extension-installer": "^1.4@stable",
"phpstan/phpstan": "^2.1.39@stable",
"tracy/tracy": "^2.8" "tracy/tracy": "^2.8"
}, },
"type": "library", "type": "library",
@ -3940,9 +3942,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nette/schema/issues", "issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.3.4" "source": "https://github.com/nette/schema/tree/v1.3.5"
}, },
"time": "2026-02-08T02:54:00+00:00" "time": "2026-02-23T03:47:12+00:00"
}, },
{ {
"name": "nette/utils", "name": "nette/utils",
@ -4180,31 +4182,31 @@
}, },
{ {
"name": "nunomaduro/termwind", "name": "nunomaduro/termwind",
"version": "v2.3.3", "version": "v2.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nunomaduro/termwind.git", "url": "https://github.com/nunomaduro/termwind.git",
"reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017" "reference": "712a31b768f5daea284c2169a7d227031001b9a8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017", "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8",
"reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017", "reference": "712a31b768f5daea284c2169a7d227031001b9a8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-mbstring": "*", "ext-mbstring": "*",
"php": "^8.2", "php": "^8.2",
"symfony/console": "^7.3.6" "symfony/console": "^7.4.4 || ^8.0.4"
}, },
"require-dev": { "require-dev": {
"illuminate/console": "^11.46.1", "illuminate/console": "^11.47.0",
"laravel/pint": "^1.25.1", "laravel/pint": "^1.27.1",
"mockery/mockery": "^1.6.12", "mockery/mockery": "^1.6.12",
"pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3", "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2",
"phpstan/phpstan": "^1.12.32", "phpstan/phpstan": "^1.12.32",
"phpstan/phpstan-strict-rules": "^1.6.2", "phpstan/phpstan-strict-rules": "^1.6.2",
"symfony/var-dumper": "^7.3.5", "symfony/var-dumper": "^7.3.5 || ^8.0.4",
"thecodingmachine/phpstan-strict-rules": "^1.0.0" "thecodingmachine/phpstan-strict-rules": "^1.0.0"
}, },
"type": "library", "type": "library",
@ -4236,7 +4238,7 @@
"email": "enunomaduro@gmail.com" "email": "enunomaduro@gmail.com"
} }
], ],
"description": "Its like Tailwind CSS, but for the console.", "description": "It's like Tailwind CSS, but for the console.",
"keywords": [ "keywords": [
"cli", "cli",
"console", "console",
@ -4247,7 +4249,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/nunomaduro/termwind/issues", "issues": "https://github.com/nunomaduro/termwind/issues",
"source": "https://github.com/nunomaduro/termwind/tree/v2.3.3" "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0"
}, },
"funding": [ "funding": [
{ {
@ -4263,7 +4265,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-11-20T02:34:59+00:00" "time": "2026-02-16T23:10:27+00:00"
}, },
{ {
"name": "nyholm/psr7", "name": "nyholm/psr7",
@ -6286,33 +6288,35 @@
}, },
{ {
"name": "sabberworm/php-css-parser", "name": "sabberworm/php-css-parser",
"version": "v9.1.0", "version": "v9.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
"reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb" "reference": "59373045e11ad47b5c18fc615feee0219e42f6d3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb", "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/59373045e11ad47b5c18fc615feee0219e42f6d3",
"reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb", "reference": "59373045e11ad47b5c18fc615feee0219e42f6d3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-iconv": "*", "ext-iconv": "*",
"php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"thecodingmachine/safe": "^1.3 || ^2.5 || ^3.3" "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4"
}, },
"require-dev": { "require-dev": {
"php-parallel-lint/php-parallel-lint": "1.4.0", "php-parallel-lint/php-parallel-lint": "1.4.0",
"phpstan/extension-installer": "1.4.3", "phpstan/extension-installer": "1.4.3",
"phpstan/phpstan": "1.12.28 || 2.1.25", "phpstan/phpstan": "1.12.32 || 2.1.32",
"phpstan/phpstan-phpunit": "1.4.2 || 2.0.7", "phpstan/phpstan-phpunit": "1.4.2 || 2.0.8",
"phpstan/phpstan-strict-rules": "1.6.2 || 2.0.6", "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7",
"phpunit/phpunit": "8.5.46", "phpunit/phpunit": "8.5.52",
"rawr/phpunit-data-provider": "3.3.1", "rawr/phpunit-data-provider": "3.3.1",
"rector/rector": "1.2.10 || 2.1.7", "rector/rector": "1.2.10 || 2.2.8",
"rector/type-perfect": "1.0.0 || 2.1.0" "rector/type-perfect": "1.0.0 || 2.1.0",
"squizlabs/php_codesniffer": "4.0.1",
"thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1"
}, },
"suggest": { "suggest": {
"ext-mbstring": "for parsing UTF-8 CSS" "ext-mbstring": "for parsing UTF-8 CSS"
@ -6320,10 +6324,14 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "9.2.x-dev" "dev-main": "9.3.x-dev"
} }
}, },
"autoload": { "autoload": {
"files": [
"src/Rule/Rule.php",
"src/RuleSet/RuleContainer.php"
],
"psr-4": { "psr-4": {
"Sabberworm\\CSS\\": "src/" "Sabberworm\\CSS\\": "src/"
} }
@ -6354,9 +6362,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.1.0" "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.2.0"
}, },
"time": "2025-09-14T07:37:21+00:00" "time": "2026-02-21T17:12:03+00:00"
}, },
{ {
"name": "setasign/fpdf", "name": "setasign/fpdf",
@ -6489,25 +6497,24 @@
}, },
{ {
"name": "spatie/simple-excel", "name": "spatie/simple-excel",
"version": "3.8.1", "version": "3.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/spatie/simple-excel.git", "url": "https://github.com/spatie/simple-excel.git",
"reference": "80c2fd16090d28e1d0036bfac1afc6bfd8452ea3" "reference": "67095053ff6037284fd213abd84259ea4faca7aa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/spatie/simple-excel/zipball/80c2fd16090d28e1d0036bfac1afc6bfd8452ea3", "url": "https://api.github.com/repos/spatie/simple-excel/zipball/67095053ff6037284fd213abd84259ea4faca7aa",
"reference": "80c2fd16090d28e1d0036bfac1afc6bfd8452ea3", "reference": "67095053ff6037284fd213abd84259ea4faca7aa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/support": "^9.0|^10.0|^11.0|^12.0", "illuminate/support": "^9.0|^10.0|^11.0|^12.0|^13.0",
"openspout/openspout": "^4.30", "openspout/openspout": "^4.30",
"php": "^8.3" "php": "^8.3"
}, },
"require-dev": { "require-dev": {
"pestphp/pest-plugin-laravel": "^1.3|^2.3|^3.0",
"phpunit/phpunit": "^9.4|^10.5|^11.0|^12.0", "phpunit/phpunit": "^9.4|^10.5|^11.0|^12.0",
"spatie/pest-plugin-snapshots": "^1.1|^2.1", "spatie/pest-plugin-snapshots": "^1.1|^2.1",
"spatie/phpunit-snapshot-assertions": "^4.0|^5.1", "spatie/phpunit-snapshot-assertions": "^4.0|^5.1",
@ -6538,7 +6545,7 @@
"spatie" "spatie"
], ],
"support": { "support": {
"source": "https://github.com/spatie/simple-excel/tree/3.8.1" "source": "https://github.com/spatie/simple-excel/tree/3.9.0"
}, },
"funding": [ "funding": [
{ {
@ -6546,7 +6553,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-09-24T06:40:28+00:00" "time": "2026-02-22T08:49:24+00:00"
}, },
{ {
"name": "symfony/clock", "name": "symfony/clock",
@ -9139,16 +9146,16 @@
}, },
{ {
"name": "thecodingmachine/safe", "name": "thecodingmachine/safe",
"version": "v3.3.0", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thecodingmachine/safe.git", "url": "https://github.com/thecodingmachine/safe.git",
"reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236" "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/2cdd579eeaa2e78e51c7509b50cc9fb89a956236", "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19",
"reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236", "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -9258,7 +9265,7 @@
"description": "PHP core functions that throw exceptions instead of returning FALSE on error", "description": "PHP core functions that throw exceptions instead of returning FALSE on error",
"support": { "support": {
"issues": "https://github.com/thecodingmachine/safe/issues", "issues": "https://github.com/thecodingmachine/safe/issues",
"source": "https://github.com/thecodingmachine/safe/tree/v3.3.0" "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@ -9269,25 +9276,29 @@
"url": "https://github.com/shish", "url": "https://github.com/shish",
"type": "github" "type": "github"
}, },
{
"url": "https://github.com/silasjoisten",
"type": "github"
},
{ {
"url": "https://github.com/staabm", "url": "https://github.com/staabm",
"type": "github" "type": "github"
} }
], ],
"time": "2025-05-14T06:15:44+00:00" "time": "2026-02-04T18:08:13+00:00"
}, },
{ {
"name": "tightenco/ziggy", "name": "tightenco/ziggy",
"version": "v2.6.0", "version": "v2.6.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/tighten/ziggy.git", "url": "https://github.com/tighten/ziggy.git",
"reference": "cccc6035c109daab03a33926b3a8499bedbed01f" "reference": "6b9d38415b684b798ba25ae73324f6652ff15314"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/tighten/ziggy/zipball/cccc6035c109daab03a33926b3a8499bedbed01f", "url": "https://api.github.com/repos/tighten/ziggy/zipball/6b9d38415b684b798ba25ae73324f6652ff15314",
"reference": "cccc6035c109daab03a33926b3a8499bedbed01f", "reference": "6b9d38415b684b798ba25ae73324f6652ff15314",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -9297,9 +9308,9 @@
}, },
"require-dev": { "require-dev": {
"laravel/folio": "^1.1", "laravel/folio": "^1.1",
"orchestra/testbench": "^7.0 || ^8.0 || ^9.0 || ^10.0", "orchestra/testbench": "^8.0 || ^9.0 || ^10.0",
"pestphp/pest": "^2.26|^3.0", "pestphp/pest": "^2.0 || ^3.0 || ^4.0",
"pestphp/pest-plugin-laravel": "^2.4|^3.0" "pestphp/pest-plugin-laravel": "^2.0 || ^3.0 || ^4.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -9342,9 +9353,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/tighten/ziggy/issues", "issues": "https://github.com/tighten/ziggy/issues",
"source": "https://github.com/tighten/ziggy/tree/v2.6.0" "source": "https://github.com/tighten/ziggy/tree/v2.6.1"
}, },
"time": "2025-09-15T00:00:26+00:00" "time": "2026-02-16T20:20:46+00:00"
}, },
{ {
"name": "tijsverkoyen/css-to-inline-styles", "name": "tijsverkoyen/css-to-inline-styles",
@ -10169,39 +10180,36 @@
}, },
{ {
"name": "nunomaduro/collision", "name": "nunomaduro/collision",
"version": "v8.8.3", "version": "v8.9.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nunomaduro/collision.git", "url": "https://github.com/nunomaduro/collision.git",
"reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4" "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4", "url": "https://api.github.com/repos/nunomaduro/collision/zipball/a1ed3fa530fd60bc515f9303e8520fcb7d4bd935",
"reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4", "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"filp/whoops": "^2.18.1", "filp/whoops": "^2.18.4",
"nunomaduro/termwind": "^2.3.1", "nunomaduro/termwind": "^2.4.0",
"php": "^8.2.0", "php": "^8.2.0",
"symfony/console": "^7.3.0" "symfony/console": "^7.4.4 || ^8.0.4"
}, },
"conflict": { "conflict": {
"laravel/framework": "<11.44.2 || >=13.0.0", "laravel/framework": "<11.48.0 || >=14.0.0",
"phpunit/phpunit": "<11.5.15 || >=13.0.0" "phpunit/phpunit": "<11.5.50 || >=14.0.0"
}, },
"require-dev": { "require-dev": {
"brianium/paratest": "^7.8.3", "brianium/paratest": "^7.8.5",
"larastan/larastan": "^3.4.2", "larastan/larastan": "^3.9.2",
"laravel/framework": "^11.44.2 || ^12.18", "laravel/framework": "^11.48.0 || ^12.52.0",
"laravel/pint": "^1.22.1", "laravel/pint": "^1.27.1",
"laravel/sail": "^1.43.1", "orchestra/testbench-core": "^9.12.0 || ^10.9.0",
"laravel/sanctum": "^4.1.1", "pestphp/pest": "^3.8.5 || ^4.4.1 || ^5.0.0",
"laravel/tinker": "^2.10.1", "sebastian/environment": "^7.2.1 || ^8.0.3 || ^9.0.0"
"orchestra/testbench-core": "^9.12.0 || ^10.4",
"pestphp/pest": "^3.8.2 || ^4.0.0",
"sebastian/environment": "^7.2.1 || ^8.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -10264,7 +10272,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2025-11-20T02:55:25+00:00" "time": "2026-02-17T17:33:08+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@ -10733,16 +10741,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "11.5.53", "version": "11.5.55",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607" "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a997a653a82845f1240d73ee73a8a4e97e4b0607", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00",
"reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607", "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -10815,7 +10823,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.53" "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55"
}, },
"funding": [ "funding": [
{ {
@ -10839,7 +10847,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-02-10T12:28:25+00:00" "time": "2026-02-18T12:37:06+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",
@ -12017,5 +12025,5 @@
"php": "^8.3" "php": "^8.3"
}, },
"platform-dev": {}, "platform-dev": {},
"plugin-api-version": "2.9.0" "plugin-api-version": "2.6.0"
} }

View File

@ -61,10 +61,10 @@ public function run(): void
$moduleCreate, $moduleCreate,
$moduleEdit, $moduleEdit,
$moduleDestroy $moduleDestroy
] = $this->onCRUD('module', $modules, 'api'); ] = $this->onCRUD('modules', $modules, 'api');
$moduleToggleStatus = $this->onPermission( $moduleToggleStatus = $this->onPermission(
'module.toggle-status', 'modules.toggle_status',
'Cambiar estado del módulo', 'Cambiar estado del módulo',
$modules, $modules,
'api' 'api'
@ -106,20 +106,14 @@ public function run(): void
'api' 'api'
); );
$inscriptionStolen = $this->onPermission(
'inscription.stolen',
'Marcar como robado',
$inscriptions,
'api'
);
$cancellations = PermissionType::firstOrCreate([ $cancellations = PermissionType::firstOrCreate([
'name' => 'Cancelaciones' 'name' => 'Cancelaciones'
]); ]);
$cancellationCancel = $this->onPermission(
'cancellations.cancel', $cancellationTagNoAsignado = $this->onPermission(
'Cancelar constancia', 'cancellations.tag_no_asignado',
'Cancelar constancia no asignada',
$cancellations, $cancellations,
'api' 'api'
); );
@ -147,35 +141,35 @@ public function run(): void
]); ]);
$recordGeneratePdf = $this->onPermission( $recordGeneratePdf = $this->onPermission(
'records.generate-pdf', 'records.generate_pdf',
'Generar PDF de expediente', 'Generar Hoja de recepción',
$records, $records,
'api' 'api'
); );
$recordGeneratePdfVerification = $this->onPermission( $recordGeneratePdfVerification = $this->onPermission(
'records.generate-pdf-verification', 'records.generate_pdf_verification',
'Generar PDF de verificación', 'Generar Hoja de verificación',
$records, $records,
'api' 'api'
); );
$recordGeneratePdfConstancia = $this->onPermission( $recordGeneratePdfConstancia = $this->onPermission(
'records.generate-pdf-constancia', 'records.generate_pdf_constancia',
'Generar PDF de constancia', 'Generar Impresión en la constancia',
$records, $records,
'api' 'api'
); );
$recordGeneratePdfSubtitution = $this->onPermission( $recordGeneratePdfSubtitution = $this->onPermission(
'records.generate-pdf-substitution', 'records.generate_pdf_substitution',
'Generar PDF constancia sustitución', 'Generar Solicitud de sustitución',
$records, $records,
'api' 'api'
); );
$recordGeneratePdfDamaged = $this->onPermission( $recordGeneratePdfDamaged = $this->onPermission(
'records.generate-pdf-damaged', 'records.generate_pdf_damaged',
'Generar PDF constancia dañada', 'Generar PDF constancia dañada',
$records, $records,
'api' 'api'
@ -204,7 +198,7 @@ public function run(): void
] = $this->onCRUD('tags', $tags, 'api'); ] = $this->onCRUD('tags', $tags, 'api');
$tagAssignToModule = $this->onPermission( $tagAssignToModule = $this->onPermission(
'tags.assign-to-module', 'tags.assign_to_module',
'Asignar etiquetas a módulo', 'Asignar etiquetas a módulo',
$tags, $tags,
'api' 'api'
@ -233,7 +227,6 @@ public function run(): void
$roleCreate, $roleCreate,
$roleEdit, $roleEdit,
$roleDestroy, $roleDestroy,
$moduleIndex, //Módulos $moduleIndex, //Módulos
$moduleCreate, $moduleCreate,
$moduleEdit, $moduleEdit,
@ -246,8 +239,7 @@ public function run(): void
$inscriptionVehicle, //Inscripcion de vehículos $inscriptionVehicle, //Inscripcion de vehículos
$inscriptionSearch, $inscriptionSearch,
$inscriptionBusqueda, $inscriptionBusqueda,
$inscriptionStolen, $cancellationTagNoAsignado, //Cancelacion de constancia no asignada
$cancellationCancel, //Cancelacion de constancia
$updateVehicleData, //Actualizaciones de vehículo $updateVehicleData, //Actualizaciones de vehículo
$updateVehicleUpdate, $updateVehicleUpdate,
$recordGeneratePdf, //Expedientes $recordGeneratePdf, //Expedientes
@ -281,8 +273,6 @@ public function run(): void
$deviceDestroy, $deviceDestroy,
$inscriptionVehicle, //Inscripcion de vehículos $inscriptionVehicle, //Inscripcion de vehículos
$inscriptionSearch, $inscriptionSearch,
$inscriptionStolen,
$cancellationCancel, //Cancelacion de constancia
$updateVehicleData, //Actualizaciones de vehículo $updateVehicleData, //Actualizaciones de vehículo
$updateVehicleUpdate, $updateVehicleUpdate,
$recordGeneratePdf, //Expedientes $recordGeneratePdf, //Expedientes
@ -310,7 +300,6 @@ public function run(): void
$userIndex, $userIndex,
$inscriptionVehicle, //Inscripcion de vehículos $inscriptionVehicle, //Inscripcion de vehículos
$inscriptionSearch, $inscriptionSearch,
$inscriptionStolen,
$updateVehicleData, //Actualizaciones de vehículo $updateVehicleData, //Actualizaciones de vehículo
$updateVehicleUpdate, $updateVehicleUpdate,
); );
@ -324,7 +313,6 @@ public function run(): void
$userIndex, $userIndex,
$inscriptionVehicle, //Inscripcion de vehículos $inscriptionVehicle, //Inscripcion de vehículos
$inscriptionSearch, $inscriptionSearch,
$inscriptionStolen,
$updateVehicleData, //Actualizaciones de vehículo $updateVehicleData, //Actualizaciones de vehículo
$updateVehicleUpdate, $updateVehicleUpdate,
); );