diff --git a/app/Http/Controllers/Repuve/InscriptionController.php b/app/Http/Controllers/Repuve/InscriptionController.php index cbb52e8..5b8274e 100644 --- a/app/Http/Controllers/Repuve/InscriptionController.php +++ b/app/Http/Controllers/Repuve/InscriptionController.php @@ -295,10 +295,15 @@ public function searchRecord(Request $request) 'module_id' => 'nullable|integer|exists:modules,id', 'action_type' => 'nullable|string|in:inscripcion,actualizacion,sustitucion,cancelacion', 'status' => 'nullable|string', + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', ], [ 'folio.required_without_all' => 'Se requiere al menos un criterio de búsqueda.', 'placa.required_without_all' => 'Se requiere al menos un criterio de búsqueda.', 'vin.required_without_all' => 'Se requiere al menos un criterio de búsqueda.', + 'start_date.date' => 'La fecha de inicio debe ser una fecha válida.', + 'end_date.date' => 'La fecha de fin debe ser una fecha válida.', + 'end_date.after_or_equal' => 'La fecha de fin debe ser posterior o igual a la fecha de inicio.', ]); $records = Record::with([ @@ -367,13 +372,21 @@ public function searchRecord(Request $request) }); } + // Filtro por rango de fechas + if ($request->filled('start_date')) { + $records->whereDate('created_at', '>=', $request->input('start_date')); + } + + if ($request->filled('end_date')) { + $records->whereDate('created_at', '<=', $request->input('end_date')); + } + // Paginación $paginatedRecords = $records->paginate(config('app.pagination')); if ($paginatedRecords->isEmpty()) { return ApiResponse::NOT_FOUND->response([ 'message' => 'No se encontraron registros con los criterios de búsqueda proporcionados.', - 'filters_applied' => array_filter($request->only(['folio', 'placa', 'vin', 'module_id', 'action_type', 'status'])) ]); } diff --git a/app/Http/Controllers/Repuve/TagsController.php b/app/Http/Controllers/Repuve/TagsController.php index 72ffe90..b2c4815 100644 --- a/app/Http/Controllers/Repuve/TagsController.php +++ b/app/Http/Controllers/Repuve/TagsController.php @@ -68,17 +68,129 @@ public function index(Request $request) public function store(Request $request) { - $validated = $request->validate([ - 'folio' => 'required|string|max:255', - 'package_id' => 'required|integer|exists:packages,id', - 'tag_number' => 'nullable|string|max:255', - ]); + try { + $validated = $request->validate([ + 'folio' => 'required|string|max:8', + 'package_id' => 'required|integer|exists:packages,id', + 'tag_number' => 'nullable|string|max:32', + 'module_id' => 'nullable|integer|exists:modules,id', + ]); - $tag = Tag::create($validated); + // Verificar si ya existe un tag con el mismo folio + $existingTagByFolio = Tag::where('folio', $validated['folio'])->first(); + if ($existingTagByFolio) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'No se pudo crear el tag: El folio ya existe en el sistema.', + 'error' => 'duplicate_folio', + 'folio' => $validated['folio'], + 'existing_tag_id' => $existingTagByFolio->id, + 'existing_tag' => [ + 'id' => $existingTagByFolio->id, + 'folio' => $existingTagByFolio->folio, + 'tag_number' => $existingTagByFolio->tag_number, + 'status' => $existingTagByFolio->status->name ?? null, + ] + ]); + } - return ApiResponse::CREATED->response([ - 'tag' => $tag, - ]); + // Verificar si ya existe un tag con el mismo tag_number + if (isset($validated['tag_number']) && $validated['tag_number'] !== null) { + $existingTagByNumber = Tag::where('tag_number', $validated['tag_number'])->first(); + if ($existingTagByNumber) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'No se pudo crear el tag: El tag_number ya existe en el sistema.', + 'error' => 'duplicate_tag_number', + 'tag_number' => $validated['tag_number'], + 'existing_tag_id' => $existingTagByNumber->id, + 'existing_tag' => [ + 'id' => $existingTagByNumber->id, + 'folio' => $existingTagByNumber->folio, + 'tag_number' => $existingTagByNumber->tag_number, + 'status' => $existingTagByNumber->status->name ?? null, + ] + ]); + } + } + + // Obtener el status "disponible" por defecto + $statusAvailable = CatalogTagStatus::where('code', Tag::STATUS_AVAILABLE)->first(); + if (!$statusAvailable) { + return ApiResponse::INTERNAL_ERROR->response([ + 'message' => 'No se pudo crear el tag: El status "disponible" no existe en el catálogo de estados.', + 'error' => 'missing_default_status', + ]); + } + + DB::beginTransaction(); + + // Crear el tag con status disponible por defecto + $tag = Tag::create([ + 'folio' => $validated['folio'], + 'tag_number' => $validated['tag_number'] ?? null, + 'package_id' => $validated['package_id'], + 'module_id' => $validated['module_id'] ?? null, + 'status_id' => $statusAvailable->id, + 'vehicle_id' => null, + ]); + + DB::commit(); + + // Cargar relaciones + $tag->load(['package', 'module', 'status']); + + return ApiResponse::CREATED->response([ + 'message' => 'Tag creado correctamente.', + 'tag' => $tag, + ]); + } catch (\Illuminate\Validation\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) { + DB::rollBack(); + + // Capturar errores específicos de base de datos + $errorMessage = $e->getMessage(); + + if (str_contains($errorMessage, 'Duplicate entry') || str_contains($errorMessage, '1062')) { + // Intentar identificar qué campo está duplicado + if (str_contains($errorMessage, 'folio')) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'No se pudo crear el tag: El folio ya existe en el sistema.', + 'error' => 'duplicate_folio', + 'details' => $errorMessage, + ]); + } elseif (str_contains($errorMessage, 'tag_number')) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'No se pudo crear el tag: El tag_number ya existe en el sistema.', + 'error' => 'duplicate_tag_number', + 'details' => $errorMessage, + ]); + } + + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'No se pudo crear el tag: Ya existe un registro duplicado en el sistema.', + 'error' => 'duplicate_entry', + 'details' => $errorMessage, + ]); + } + + if (str_contains($errorMessage, 'Foreign key constraint')) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'No se pudo crear el tag: Referencia a un registro que no existe (package_id o module_id inválido).', + 'error' => 'foreign_key_constraint', + 'details' => $errorMessage, + ]); + } + + return ApiResponse::INTERNAL_ERROR->response([ + 'message' => 'No se pudo crear el tag: Error interno del servidor.', + 'error' => 'internal_error', + 'details' => $errorMessage, + ]); + } } public function show(Tag $tag) @@ -90,6 +202,93 @@ public function show(Tag $tag) ]); } + public function update(Request $request, Tag $tag) + { + try { + // Validar que el tag solo pueda actualizarse si está disponible o cancelado + if (!in_array($tag->status->code, [Tag::STATUS_AVAILABLE, Tag::STATUS_CANCELLED])) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'Solo se pueden actualizar tags con status "disponible" o "cancelado".', + 'current_status' => $tag->status->name, + 'allowed_statuses' => ['Disponible', 'Cancelado'], + ]); + } + + // Validar los campos de entrada + $validated = $request->validate([ + 'folio' => 'sometimes|string|max:8', + 'tag_number' => 'nullable|string|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 + if (isset($validated['status_id'])) { + $newStatus = CatalogTagStatus::find($validated['status_id']); + if (!in_array($newStatus->code, [Tag::STATUS_AVAILABLE, Tag::STATUS_CANCELLED])) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'Solo se puede cambiar el status a disponible o cancelado.', + 'estatus' => $newStatus->name, + 'estatus_permitido' => ['Disponible', 'Cancelado'], + ]); + } + } + + // Verificar unicidad del folio si se está actualizando + if (isset($validated['folio'])) { + $existingTag = Tag::where('folio', $validated['folio']) + ->where('id', '!=', $tag->id) + ->first(); + + if ($existingTag) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'El folio ya está asignado a otro tag.', + 'folio' => $validated['folio'], + 'existing_tag_id' => $existingTag->id, + ]); + } + } + + // Verificar unicidad del tag_number si se está actualizando + if (isset($validated['tag_number']) && $validated['tag_number'] !== null) { + $existingTag = Tag::where('tag_number', $validated['tag_number']) + ->where('id', '!=', $tag->id) + ->first(); + + if ($existingTag) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'El tag_number ya está asignado a otro tag.', + 'tag_number' => $validated['tag_number'], + 'existing_tag_id' => $existingTag->id, + ]); + } + } + + DB::beginTransaction(); + + // Actualizar el tag + $tag->update($validated); + + DB::commit(); + + // Cargar relaciones actualizadas + $tag->load(['package', 'module', 'vehicle', 'status']); + + return ApiResponse::OK->response([ + 'message' => 'Tag actualizado correctamente.', + 'tag' => $tag, + ]); + } catch (\Exception $e) { + DB::rollBack(); + + return ApiResponse::INTERNAL_ERROR->response([ + 'message' => 'Error al actualizar el tag.', + 'error' => $e->getMessage(), + ]); + } + } + public function destroy(Tag $tag) { try {