From 02220407ff833cef63165db32f6f5b9a37cc7dd4 Mon Sep 17 00:00:00 2001 From: Juan Felipe Zapata Moreno Date: Tue, 2 Dec 2025 21:15:37 -0600 Subject: [PATCH] =?UTF-8?q?ADD:=20Se=20agreg=C3=B3=20el=20endpoint=20para?= =?UTF-8?q?=20obtener=20constancias=20canceladas=20y=20se=20implement?= =?UTF-8?q?=C3=B3=20la=20generaci=C3=B3n=20de=20archivos=20Excel=20corresp?= =?UTF-8?q?ondientes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Repuve/ExcelController.php | 223 ++++++++++++++++++ routes/api.php | 1 + 2 files changed, 224 insertions(+) diff --git a/app/Http/Controllers/Repuve/ExcelController.php b/app/Http/Controllers/Repuve/ExcelController.php index 88011c8..6a2e3b3 100644 --- a/app/Http/Controllers/Repuve/ExcelController.php +++ b/app/Http/Controllers/Repuve/ExcelController.php @@ -224,6 +224,200 @@ public function constanciasSustituidas(Request $request) return response()->download($filePath, $fileName)->deleteFileAfterSend(true); } + public function constanciasCanceladas(Request $request) + { + $request->validate([ + 'fecha_inicio' => 'required|date', + 'fecha_fin' => 'required|date|after_or_equal:fecha_inicio', + 'module_id' => 'required|exists:modules,id', + ]); + + $fechaInicio = Carbon::parse($request->fecha_inicio)->startOfDay(); + $fechaFin = Carbon::parse($request->fecha_fin)->endOfDay(); + $moduleId = $request->module_id; + + // Obtener información del módulo + $module = Module::findOrFail($moduleId); + + // Obtener logs de cancelación en el rango de fechas + $logs = VehicleTagLog::with([ + 'vehicle', + 'tag', + 'cancellationReason' + ]) + ->where('action_type', 'cancelacion') + ->whereHas('vehicle.records', function ($query) use ($moduleId) { + $query->where('module_id', $moduleId); + }) + ->whereBetween('cancellation_at', [$fechaInicio, $fechaFin]) + ->orderBy('cancellation_at', 'asc') + ->get(); + + if ($logs->isEmpty()) { + return ApiResponse::NOT_FOUND->response([ + 'message' => 'No se encontraron constancias canceladas en el periodo especificado', + 'fecha_inicio' => $fechaInicio->format('Y-m-d'), + 'fecha_fin' => $fechaFin->format('Y-m-d'), + 'module_id' => $moduleId, + ]); + } + + // Preparar datos para el Excel + $data = $this->prepareExcelDataCanceladas($logs); + + // Generar archivo Excel + $fileName = 'Constancias_Canceladas_' . $fechaInicio->format('Ymd') . '_' . $fechaFin->format('Ymd') . '.xlsx'; + $filePath = storage_path('app/temp/' . $fileName); + + // Crear directorio temporal si no existe + if (!file_exists(storage_path('app/temp'))) { + mkdir(storage_path('app/temp'), 0755, true); + } + + // Crear Excel + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Agregar logo + $logoPath = storage_path('app/images/logo-seguridad.png'); + if (file_exists($logoPath)) { + $drawing = new Drawing(); + $drawing->setName('Logo Seguridad'); + $drawing->setDescription('Logo Seguridad Pública'); + $drawing->setPath($logoPath); + $drawing->setHeight(100); + $drawing->setCoordinates('B1'); + $drawing->setWorksheet($sheet); + + $sheet->getRowDimension(1)->setRowHeight(45); + } + + // Definir estilo de bordes + $borderStyle = [ + 'borders' => [ + 'allBorders' => [ + 'borderStyle' => PhpSpreadsheetBorder::BORDER_THIN, + 'color' => ['rgb' => '000000'], + ], + ], + ]; + + $row = 5; + + // ENTIDAD + $sheet->setCellValue('B' . $row, 'ENTIDAD:'); + $sheet->mergeCells('C' . $row . ':K' . $row); + $sheet->setCellValue('C' . $row, 'TABASCO'); + $sheet->getStyle('B' . $row)->getFont()->setBold(true)->setSize(11); + $sheet->getStyle('B' . $row . ':K' . $row)->applyFromArray($borderStyle); + $sheet->getStyle('B' . $row . ':K' . $row)->getAlignment()->setWrapText(true); + $row++; + + // MÓDULO + $sheet->setCellValue('B' . $row, 'MÓDULO:'); + $sheet->mergeCells('C' . $row . ':K' . $row); + $sheet->setCellValue('C' . $row, $module->name ?? 'MÓDULO 1. BASE 4'); + $sheet->getStyle('B' . $row)->getFont()->setBold(true)->setSize(11); + $sheet->getStyle('B' . $row . ':K' . $row)->applyFromArray($borderStyle); + $sheet->getStyle('B' . $row . ':K' . $row)->getAlignment()->setWrapText(true); + $row++; + + // PERIODO + $sheet->setCellValue('B' . $row, 'PERIODO A INFORMAR:'); + $sheet->mergeCells('C' . $row . ':K' . $row); + $sheet->setCellValue('C' . $row, 'del ' . $fechaInicio->format('d') . ' al ' . $fechaFin->format('d') . ' de ' . $fechaInicio->translatedFormat('F') . ' de ' . $fechaInicio->year); + $sheet->getStyle('B' . $row)->getFont()->setBold(true)->setSize(11); + $sheet->getStyle('B' . $row . ':K' . $row)->applyFromArray($borderStyle); + $sheet->getStyle('B' . $row . ':K' . $row)->getAlignment()->setWrapText(true); + $row++; + + $row++; + + // Título + $sheet->mergeCells('B' . $row . ':K' . $row); + $sheet->setCellValue('B' . $row, 'CONSTANCIAS CANCELADAS'); + $sheet->getStyle('B' . $row)->getFont()->setBold(true)->setSize(12); + $sheet->getStyle('B' . $row)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER)->setWrapText(true); + $sheet->getStyle('B' . $row . ':K' . $row)->applyFromArray($borderStyle); + $row++; + + $row++; + + // Encabezados + $headers = [ + 'No.', + 'NIV DEL VEHÍCULO', + 'NRPV/NCI', + 'MARCA DEL VEHÍCULO', + 'PLACA', + 'AÑO MODELO', + 'FOLIO DE LA CONSTANCIA', + 'ID DE LA CONSTANCIA (CHIP)', + 'FECHA DE CANCELACIÓN', + 'MOTIVO DE CANCELACIÓN', + 'OBSERVACIONES', + ]; + + $col = 'A'; + foreach ($headers as $header) { + $sheet->setCellValue($col . $row, $header); + $col++; + } + + $sheet->getStyle('A' . $row . ':K' . $row)->applyFromArray([ + 'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 10], + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '8B0000']], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'wrapText' => true], + 'borders' => [ + 'allBorders' => [ + 'borderStyle' => PhpSpreadsheetBorder::BORDER_THIN, + 'color' => ['rgb' => '000000'], + ], + ], + ]); + $row++; + + // Agregar datos + foreach ($data as $rowData) { + $col = 'A'; + foreach ($rowData as $value) { + $sheet->setCellValue($col . $row, $value); + $col++; + } + $sheet->getStyle('A' . $row . ':K' . $row)->applyFromArray([ + 'font' => ['size' => 10], + 'alignment' => ['wrapText' => true], + 'borders' => [ + 'allBorders' => [ + 'borderStyle' => PhpSpreadsheetBorder::BORDER_THIN, + 'color' => ['rgb' => '000000'], + ], + ], + ]); + $row++; + } + + // Ajustar anchos de columnas + $sheet->getColumnDimension('A')->setWidth(6); + $sheet->getColumnDimension('B')->setWidth(25); + $sheet->getColumnDimension('C')->setWidth(15); + $sheet->getColumnDimension('D')->setWidth(20); + $sheet->getColumnDimension('E')->setWidth(12); + $sheet->getColumnDimension('F')->setWidth(15); + $sheet->getColumnDimension('G')->setWidth(25); + $sheet->getColumnDimension('H')->setWidth(30); + $sheet->getColumnDimension('I')->setWidth(20); + $sheet->getColumnDimension('J')->setWidth(35); + $sheet->getColumnDimension('K')->setWidth(50); + + // Guardar archivo + $writer = new Xlsx($spreadsheet); + $writer->save($filePath); + + // Descargar archivo y eliminarlo después + return response()->download($filePath, $fileName)->deleteFileAfterSend(true); + } + private function prepareExcelData($logs) { $data = []; @@ -260,4 +454,33 @@ private function prepareExcelData($logs) return $data; } + + private function prepareExcelDataCanceladas($logs) + { + $data = []; + $no = 1; + + foreach ($logs as $log) { + $vehicle = $log->vehicle; + $tag = $log->tag; + + $data[] = [ + $no, + $vehicle->niv ?? 'N/A', + $vehicle->nrpv ?? 'N/A', + strtoupper($vehicle->marca ?? 'N/A'), + strtoupper($vehicle->placa ?? 'N/A'), + $vehicle->modelo ?? 'N/A', + $tag->folio ?? 'N/A', + $tag->tag_number ?? 'N/A', + $log->cancellation_at ? $log->cancellation_at->format('d/m/Y') : 'N/A', + $log->cancellationReason?->name ?? 'N/A', + $log->cancellation_observations ?? 'CONSTANCIA CANCELADA', + ]; + + $no++; + } + + return $data; + } } diff --git a/routes/api.php b/routes/api.php index c4e26f6..29d37d1 100644 --- a/routes/api.php +++ b/routes/api.php @@ -55,6 +55,7 @@ Route::delete('cancelacion', [CancellationController::class, 'cancelarConstancia']); Route::post('tags/cancelar', [CancellationController::class, 'cancelarTagNoAsignado']); Route::get('excel/constancias-sustituidas', [ExcelController::class, 'constanciasSustituidas']); + Route::get('excel/constancias-canceladas', [ExcelController::class, 'constanciasCanceladas']); //Rutas de Modulos Route::patch('module/{id}/toggle-status', [ModuleController::class, 'toggleStatus']);