From 89989c6fe4a80364fcaf61459c8425f5a00d0732 Mon Sep 17 00:00:00 2001 From: Juan Felipe Zapata Moreno Date: Wed, 17 Dec 2025 22:53:50 -0600 Subject: [PATCH] =?UTF-8?q?MOD:=20Dise=C3=B1o=20de=20los=20excel=20corregi?= =?UTF-8?q?dos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Repuve/ExcelController.php | 728 ++++++++++-------- .../Controllers/Repuve/UpdateController.php | 8 +- 2 files changed, 429 insertions(+), 307 deletions(-) diff --git a/app/Http/Controllers/Repuve/ExcelController.php b/app/Http/Controllers/Repuve/ExcelController.php index 7e7b5db..65d2ee1 100644 --- a/app/Http/Controllers/Repuve/ExcelController.php +++ b/app/Http/Controllers/Repuve/ExcelController.php @@ -29,26 +29,23 @@ class ExcelController extends Controller { public function constanciasSustituidas(Request $request) { + // VALIDACIÓN Y OBTENCIÓN DE DATOS $request->validate([ 'fecha_inicio' => 'required|date', - 'fecha_fin' => 'required|date|after_or_equal:fecha_inicio', - 'module_id' => 'required|exists:modules,id', + '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; + $fechaFin = Carbon::parse($request->fecha_fin)->endOfDay(); + $moduleId = $request->module_id; - // Obtener información del módulo $module = Module::findOrFail($moduleId); - // Obtener logs de sustitución en el rango de fechas - $logs = VehicleTagLog::with([ - 'vehicle', - 'tag', - 'cancellationReason' - ]) + // Consulta de Logs + $logs = VehicleTagLog::with(['vehicle', 'tag', 'cancellationReason']) ->where('action_type', 'sustitucion') + ->whereNotNull('cancellation_at') ->whereHas('vehicle.records', function ($query) use ($moduleId) { $query->where('module_id', $moduleId); }) @@ -57,195 +54,268 @@ public function constanciasSustituidas(Request $request) ->get(); if ($logs->isEmpty()) { - return ApiResponse::NOT_FOUND->response([ - 'message' => 'No se encontraron constancias sustituidas en el periodo especificado', - 'fecha_inicio' => $fechaInicio->format('Y-m-d'), - 'fecha_fin' => $fechaFin->format('Y-m-d'), - 'module_id' => $moduleId, - ]); + return response()->json(['message' => 'No se encontraron registros.'], 404); } - // Preparar datos para el Excel - $data = $this->prepareExcelData($logs); + // PREPARACIÓN DE DATOS + $data = $logs->map(function ($log) { + $newTagLog = VehicleTagLog::with('tag') + ->where('vehicle_id', $log->vehicle_id) + ->where('action_type', 'sustitucion') + ->whereNull('cancellation_at') + ->where('id', '!=', $log->id) + ->where('created_at', '>=', $log->created_at) + ->orderBy('created_at', 'asc') + ->first(); - // Generar archivo Excel - $fileName = 'Constancias_Sustituidas_' . $fechaInicio->format('Ymd') . '_' . $fechaFin->format('Ymd') . '.xlsx'; - $filePath = storage_path('app/temp/' . $fileName); + return [ + 'niv' => $log->vehicle->niv ?? '', + 'nrpv' => $log->vehicle->nrpv ?? '', + 'marca' => $log->vehicle->marca ?? '', + 'placa' => $log->vehicle->placa ?? '', + 'modelo' => $log->vehicle->modelo ?? '', + 'folio_ant' => $log->tag->folio ?? '', + 'folio_act' => $newTagLog?->tag?->folio ?? '', + 'chip' => $newTagLog?->tag?->rfid ?? $newTagLog?->tag?->tag_number ?? '', + 'fecha' => $log->cancellation_at?->format('d/m/Y') ?? $log->created_at->format('d/m/Y'), + 'observaciones' => $log->cancellationReason?->name ?? $log->cancellation_observations ?? '', + ]; + }); - // Crear directorio temporal si no existe - if (!file_exists(storage_path('app/temp'))) { - mkdir(storage_path('app/temp'), 0755, true); + // 3. CONFIGURACIÓN INICIAL DEL EXCEL + $fileName = 'Constancias_Sustituidas_' . $fechaInicio->format('Ymd') . '.xlsx'; + $tempPath = storage_path('app/temp/'); + $filePath = $tempPath . $fileName; + + if (!file_exists($tempPath)) { + mkdir($tempPath, 0755, true); } - // Crear Excel $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - // Agregar logo - $logoPath = storage_path('app/images/logo-seguridad.png'); + // Fuente Global + $sheet->getParent()->getDefaultStyle()->getFont()->setName('Montserrat'); + $sheet->getParent()->getDefaultStyle()->getFont()->setSize(10); + + // Estilo para cajas de texto + $styleBox = [ + 'borders' => [ + 'allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN, 'color' => ['rgb' => '000000']] + ], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER] + ]; + + // Estilo para etiquetas + $styleLabel = [ + 'font' => ['bold' => true, 'size' => 14], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_RIGHT, 'vertical' => Alignment::VERTICAL_CENTER] + ]; + + // Estilo Encabezado Tabla + $styleTableHeader = [ + 'font' => ['bold' => true, 'size' => 9, 'color' => ['rgb' => '000000']], + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'F2DCDB']], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true], + 'borders' => ['allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN]] + ]; + + // ESTRUCTURA DEL DOCUMENTO + + // Ajuste de altura para filas superiores + $sheet->getRowDimension(1)->setRowHeight(10); + $sheet->getRowDimension(2)->setRowHeight(55); + + $sheet->getRowDimension(5)->setRowHeight(30); + $sheet->getRowDimension(7)->setRowHeight(38); + $sheet->getRowDimension(9)->setRowHeight(30); + + // LOGO + $logoPath = storage_path('app/images/logo_excel.png'); if (file_exists($logoPath)) { $drawing = new Drawing(); - $drawing->setName('Logo Seguridad'); - $drawing->setDescription('Logo Seguridad Pública'); + $drawing->setName('Logo'); $drawing->setPath($logoPath); - $drawing->setHeight(100); // Altura del logo en pixeles - $drawing->setCoordinates('B1'); // Posición del logo + $drawing->setHeight(55); + $drawing->setCoordinates('B2'); $drawing->setWorksheet($sheet); - - // Ajustar altura de las filas del logo - $sheet->getRowDimension(1)->setRowHeight(45); } - // Definir estilo de bordes - $borderStyle = [ - 'borders' => [ - 'allBorders' => [ - 'borderStyle' => PhpSpreadsheetBorder::BORDER_THIN, - 'color' => ['rgb' => '000000'], - ], - ], - ]; - - // Empezar después del logo - $row = 5; - - // Fila 1: ENTIDAD (empieza en B) - $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++; - - // Fila 2: MÓDULO (empieza en B) - $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++; - - // Fila 3: PERIODO A INFORMAR (empieza en B, fecha completa con año) - $sheet->setCellValue('B' . $row, 'PERIODO A INFORMAR:'); - $sheet->mergeCells('C' . $row . ':K' . $row); - $sheet->setCellValue('C' . $row, $fechaInicio->format('d/m/Y') . ' al ' . $fechaFin->format('d/m/Y')); - $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++; - - // Fila vacía - $row++; - - // Título: CONSTANCIAS SUSTITUIDAS (combinada B:K) - $sheet->mergeCells('B' . $row . ':K' . $row); - $sheet->setCellValue('B' . $row, 'CONSTANCIAS SUSTITUIDAS'); - $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++; - - // Fila vacía - $row++; - - // Encabezados de la tabla - $headers = [ - 'No.', - 'NIV DEL VEHÍCULO', - 'NRPV/NCI', - 'MARCA DEL VEHÍCULO', - 'PLACA', - 'AÑO MODELO', - 'FOLIO ANTERIOR', - 'FOLIO ACTUAL', - 'ID DE LA CONSTANCIA (CHIP)', - 'FECHA DE REEMPLAZO', - 'OBSERVACIONES (MOTIVO DEL REEMPLAZO)', - ]; - - $col = 'A'; - foreach ($headers as $header) { - $sheet->setCellValue($col . $row, $header); - $col++; + $logoPath = storage_path('app/images/repuve_excel.png'); + if (file_exists($logoPath)) { + $drawing = new Drawing(); + $drawing->setName('Logo'); + $drawing->setPath($logoPath); + $drawing->setHeight(55); + $drawing->setCoordinates('M2'); + $drawing->setWorksheet($sheet); } - $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'], - ], - ], + // --- BLOQUE DE INFORMACIÓN --- + + // Fila 5: ENTIDAD + $sheet->setCellValue('B5', 'ENTIDAD:'); + $sheet->getStyle('B5')->applyFromArray($styleLabel); + $sheet->getStyle('B5')->getFont()->setBold(false)->setSize(14); + + $sheet->mergeCells('C5:I5'); + $sheet->setCellValue('C5', 'TABASCO'); + $sheet->getStyle('C5:I5')->applyFromArray($styleBox); + $sheet->getStyle('C5')->getFont()->setBold(true)->setSize(14); + + + // Fila 7: MÓDULO + $sheet->setCellValue('B7', 'MÓDULO:'); + $sheet->getStyle('B7')->applyFromArray($styleLabel); + $sheet->getStyle('B7')->getFont()->setBold(false)->setSize(14); + + $sheet->mergeCells('C7:I7'); + $sheet->setCellValue('C7', strtoupper($module->name)); + $sheet->getStyle('C7:I7')->applyFromArray($styleBox); + $sheet->getStyle('C7')->getFont()->setBold(true)->setSize(20); + + + // Fila 9: PERIODO A INFORMAR + $sheet->setCellValue('B9', 'PERIODO A INFORMAR:'); + $sheet->getStyle('B9')->applyFromArray($styleLabel); + $sheet->getStyle('B9')->getFont()->setBold(false)->setSize(14); + + Carbon::setLocale('es'); + $periodoTexto = 'del ' . $fechaInicio->format('d') . ' al ' . $fechaFin->format('d') . ' de ' . $fechaFin->translatedFormat('F'); + + // Fechas + $sheet->mergeCells('C9:F9'); + $sheet->setCellValue('C9', $periodoTexto); + $sheet->getStyle('C9:F9')->applyFromArray($styleBox); + $sheet->getStyle('C9')->getFont()->setSize(14); + + // Conector "de" + $sheet->setCellValue('G9', 'de'); + $sheet->getStyle('G9')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER)->setVertical(Alignment::VERTICAL_CENTER); + $sheet->getStyle('G9')->getFont()->setSize(14); + + // Año + $sheet->mergeCells('H9:I9'); + $sheet->setCellValue('H9', $fechaFin->format('Y')); + $sheet->getStyle('H9:I9')->applyFromArray($styleBox); + $sheet->getStyle('H9')->getFont()->setSize(14); + + + // TÍTULO + $rowTitle = 11; + $sheet->mergeCells("A{$rowTitle}:K{$rowTitle}"); + $sheet->setCellValue("A{$rowTitle}", 'CONSTANCIAS SUSTITUIDAS'); + $sheet->getStyle("A{$rowTitle}")->applyFromArray([ + 'font' => ['bold' => true, 'color' => ['rgb' => '000000'], 'size' => 14], // Texto Negro + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER], ]); - $row++; + $sheet->getRowDimension($rowTitle)->setRowHeight(25); - // 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'], - ], - ], + // BARRA ROJA + $rowRedBar = 13; + $sheet->mergeCells("A{$rowRedBar}:K{$rowRedBar}"); + $sheet->getStyle("A{$rowRedBar}")->applyFromArray([ + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '900000']], // Rojo Oscuro + ]); + $sheet->getRowDimension($rowRedBar)->setRowHeight(20); + + // --- ENCABEZADOS DE TABLA --- + $h1 = 14; + $h2 = 15; + + $headers = [ + 'A' => 'No.', + 'B' => 'NIV DEL VEHÍCULO', + 'C' => 'NRPV/NCI', + 'D' => 'MARCA DEL VEHÍCULO', + 'E' => 'PLACA', + 'F' => "AÑO\nMODELO", + 'I' => 'ID DE LA CONSTANCIA (CHIP)', + 'J' => "FECHA\nREEMPLAZO", + 'K' => "OBSERVACIONES (MOTIVO\nDEL REEMPLAZO)" + ]; + foreach ($headers as $col => $text) { + $sheet->mergeCells("{$col}{$h1}:{$col}{$h2}"); + $sheet->setCellValue("{$col}{$h1}", $text); + } + $sheet->mergeCells("G{$h1}:H{$h1}"); + $sheet->setCellValue("G{$h1}", 'FOLIO'); + $sheet->setCellValue("G{$h2}", 'ANTERIOR'); + $sheet->setCellValue("H{$h2}", 'ACTUAL'); + + $sheet->getStyle("A{$h1}:K{$h2}")->applyFromArray($styleTableHeader); + $sheet->getRowDimension($h1)->setRowHeight(20); + $sheet->getRowDimension($h2)->setRowHeight(25); + + // --- LLENADO DE DATOS --- + $row = 16; + $i = 1; + + foreach ($data as $item) { + $sheet->setCellValue('A' . $row, $i); + $sheet->setCellValue('B' . $row, $item['niv']); + $sheet->setCellValue('C' . $row, $item['nrpv']); + $sheet->setCellValue('D' . $row, $item['marca']); + $sheet->setCellValue('E' . $row, $item['placa']); + $sheet->setCellValue('F' . $row, $item['modelo']); + $sheet->setCellValue('G' . $row, $item['folio_ant']); + $sheet->setCellValue('H' . $row, $item['folio_act']); + $sheet->setCellValue('I' . $row, $item['chip']); + $sheet->setCellValue('J' . $row, $item['fecha']); + $sheet->setCellValue('K' . $row, $item['observaciones']); + + $sheet->getStyle("A{$row}:K{$row}")->applyFromArray([ + 'borders' => ['allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN]], + 'alignment' => ['vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true], + 'font' => ['size' => 9] ]); + + // Centrados específicos + $sheet->getStyle("A{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + $sheet->getStyle("F{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + $sheet->getStyle("G{$row}:H{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + $sheet->getStyle("J{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + $row++; + $i++; } - // Ajustar anchos de columnas - $sheet->getColumnDimension('A')->setWidth(6); - $sheet->getColumnDimension('B')->setWidth(25); - $sheet->getColumnDimension('C')->setWidth(15); + // Anchos de columna + $sheet->getColumnDimension('A')->setWidth(5); + $sheet->getColumnDimension('B')->setWidth(23); + $sheet->getColumnDimension('C')->setWidth(14); $sheet->getColumnDimension('D')->setWidth(20); - $sheet->getColumnDimension('E')->setWidth(12); - $sheet->getColumnDimension('F')->setWidth(15); - $sheet->getColumnDimension('G')->setWidth(18); - $sheet->getColumnDimension('H')->setWidth(18); + $sheet->getColumnDimension('E')->setWidth(13); + $sheet->getColumnDimension('F')->setWidth(9); + $sheet->getColumnDimension('G')->setWidth(13); + $sheet->getColumnDimension('H')->setWidth(13); $sheet->getColumnDimension('I')->setWidth(30); - $sheet->getColumnDimension('J')->setWidth(20); - $sheet->getColumnDimension('K')->setWidth(50); + $sheet->getColumnDimension('J')->setWidth(14); + $sheet->getColumnDimension('K')->setWidth(35); - // Guardar archivo $writer = new Xlsx($spreadsheet); $writer->save($filePath); - // Descargar archivo y eliminarlo después return response()->download($filePath, $fileName)->deleteFileAfterSend(true); } public function constanciasCanceladas(Request $request) { + // 1. VALIDACIÓN Y OBTENCIÓN DE DATOS $request->validate([ 'fecha_inicio' => 'required|date', - 'fecha_fin' => 'required|date|after_or_equal:fecha_inicio', - 'module_id' => 'nullable|exists:modules,id', + 'fecha_fin' => 'required|date|after_or_equal:fecha_inicio', + 'module_id' => 'nullable|exists:modules,id', ]); $fechaInicio = Carbon::parse($request->fecha_inicio)->startOfDay(); - $fechaFin = Carbon::parse($request->fecha_fin)->endOfDay(); - $moduleId = $request->module_id; + $fechaFin = Carbon::parse($request->fecha_fin)->endOfDay(); + $moduleId = $request->module_id; - // Obtener información del módulo + // Información del módulo $module = $moduleId ? Module::find($moduleId) : null; - // Obtener logs de cancelación en el rango de fechas - $logs = VehicleTagLog::with([ - 'vehicle', - 'tag', - 'cancellationReason' - ]) + $logs = VehicleTagLog::with(['vehicle', 'tag', 'cancellationReason']) ->where('action_type', 'cancelacion') ->when($moduleId, function ($query) use ($moduleId) { $query->whereHas('vehicle.records', function ($q) use ($moduleId) { @@ -253,184 +323,236 @@ public function constanciasCanceladas(Request $request) }); }) ->whereBetween('cancellation_at', [$fechaInicio, $fechaFin]) - ->orderBy('cancellation_at', 'asc') ->get(); - $logsT = TagCancellationLog::with([ - 'tag', - 'cancellationReason' - ])->when($moduleId, function ($query) use ($moduleId) { - $query->whereHas('tag', function ($q) use ($moduleId) { - $q->where('module_id', $moduleId); - }); - }) + $logsT = TagCancellationLog::with(['tag.vehicle', 'cancellationReason']) + ->when($moduleId, function ($query) use ($moduleId) { + $query->whereHas('tag', function ($q) use ($moduleId) { + $q->where('module_id', $moduleId); + }); + }) ->whereBetween('cancellation_at', [$fechaInicio, $fechaFin]) - ->orderBy('cancellation_at', 'asc') ->get(); if ($logs->isEmpty() && $logsT->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, - ]); + return response()->json(['message' => 'No se encontraron constancias canceladas.'], 404); } - // Preparar datos para el Excel + // Unir y ordenar $allLogs = $logs->concat($logsT)->sortBy('cancellation_at'); - $data = $this->prepareExcelDataCanceladas($allLogs); - // Generar archivo Excel - $fileName = 'Constancias_Canceladas_' . $fechaInicio->format('Ymd') . '_' . $fechaFin->format('Ymd') . '.xlsx'; + // MAPEO DE DATOS + $data = $allLogs->map(function ($log) { + return [ + 'folio' => $log->tag->folio ?? 'S/F', + 'chip' => $log->tag->rfid ?? '', + 'fecha' => $log->cancellation_at ? Carbon::parse($log->cancellation_at)->format('d/m/Y') : '', + 'motivo' => $log->cancellationReason->name ?? 'DAÑADA', + ]; + }); + + // CONFIGURACIÓN EXCEL Y ESTILOS + $fileName = 'Constancias_Canceladas_' . $fechaInicio->format('Ymd') . '.xlsx'; $filePath = storage_path('app/temp/' . $fileName); + if (!file_exists(dirname($filePath))) mkdir(dirname($filePath), 0755, true); - // 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'); + // Fuente Global + $sheet->getParent()->getDefaultStyle()->getFont()->setName('Montserrat'); + $sheet->getParent()->getDefaultStyle()->getFont()->setSize(10); + + // Estilo para cajas de texto + $styleBox = [ + 'borders' => [ + 'allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN, 'color' => ['rgb' => '000000']] + ], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER] + ]; + + // Estilo para etiquetas + $styleLabel = [ + 'font' => ['bold' => true, 'size' => 14], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_RIGHT, 'vertical' => Alignment::VERTICAL_CENTER] + ]; + + // Estilo Encabezado Tabla + $styleTableHeader = [ + 'font' => ['bold' => true, 'size' => 9, 'color' => ['rgb' => '000000']], + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'F2DCDB']], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true], + 'borders' => ['allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN]] + ]; + + // ESTRUCTURA DEL DOCUMENTO + + // Ajuste de altura para filas superiores + $sheet->getRowDimension(2)->setRowHeight(10); + $sheet->getRowDimension(3)->setRowHeight(55); + + $sheet->getRowDimension(6)->setRowHeight(30); + $sheet->getRowDimension(8)->setRowHeight(38); + $sheet->getRowDimension(10)->setRowHeight(30); + + // LOGO + $logoPath = storage_path('app/images/logo_excel.png'); if (file_exists($logoPath)) { $drawing = new Drawing(); - $drawing->setName('Logo Seguridad'); - $drawing->setDescription('Logo Seguridad Pública'); + $drawing->setName('Logo'); $drawing->setPath($logoPath); - $drawing->setHeight(100); - $drawing->setCoordinates('B1'); + $drawing->setHeight(55); + $drawing->setCoordinates('B2'); $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 ?? 'S/N MODULO'); - $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, $fechaInicio->format('d/m/Y') . ' al ' . $fechaFin->format('d/m/Y')); - $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++; + $logoPath = storage_path('app/images/repuve_excel.png'); + if (file_exists($logoPath)) { + $drawing = new Drawing(); + $drawing->setName('Logo'); + $drawing->setPath($logoPath); + $drawing->setHeight(55); + $drawing->setCoordinates('M2'); + $drawing->setWorksheet($sheet); } - $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'], - ], - ], + // --- BLOQUE DE INFORMACIÓN --- + + // Fila 5: ENTIDAD + $sheet->mergeCells('A5:C5'); // Combinar A-C para la etiqueta + $sheet->setCellValue('A5', 'ENTIDAD:'); + $sheet->getStyle('A5')->applyFromArray($styleLabel); + $sheet->getStyle('A5')->getFont()->setBold(false)->setSize(14); + + $sheet->mergeCells('D5:M5'); // El valor ocupa el resto + $sheet->setCellValue('D5', 'TABASCO'); + $sheet->getStyle('D5:M5')->applyFromArray($styleBox); + $sheet->getStyle('D5')->getFont()->setBold(true)->setSize(14); + + // Fila 7: MÓDULO + $sheet->mergeCells('A7:C7'); + $sheet->setCellValue('A7', 'MÓDULO:'); + $sheet->getStyle('A7')->applyFromArray($styleLabel); + $sheet->getStyle('A7')->getFont()->setBold(false)->setSize(14); + + $sheet->mergeCells('D7:M7'); + $sheet->setCellValue('D7', strtoupper($module->name ?? 'TODOS LOS MÓDULOS')); + $sheet->getStyle('D7:M7')->applyFromArray($styleBox); + $sheet->getStyle('D7')->getFont()->setBold(true)->setSize(20); + + // Fila 9: PERIODO A INFORMAR + $sheet->mergeCells('A9:C9'); + $sheet->setCellValue('A9', 'PERIODO A INFORMAR:'); + $sheet->getStyle('A9')->applyFromArray($styleLabel); + $sheet->getStyle('A9')->getFont()->setBold(false)->setSize(14); + + Carbon::setLocale('es'); + $periodoTexto = 'del ' . $fechaInicio->format('d') . ' al ' . $fechaFin->format('d') . ' de ' . $fechaFin->translatedFormat('F'); + + // Fechas (Movemos a D-G) + $sheet->mergeCells('D9:G9'); + $sheet->setCellValue('D9', $periodoTexto); + $sheet->getStyle('D9:G9')->applyFromArray($styleBox); + $sheet->getStyle('D9')->getFont()->setSize(14); + + // "de" (Movemos a H) + $sheet->setCellValue('H9', 'de'); + $sheet->getStyle('H9')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER)->setVertical(Alignment::VERTICAL_CENTER); + $sheet->getStyle('H9')->getFont()->setSize(14); + + // Año (Movemos a I-J) + $sheet->mergeCells('I9:J9'); + $sheet->setCellValue('I9', $fechaFin->format('Y')); + $sheet->getStyle('I9:J9')->applyFromArray($styleBox); + $sheet->getStyle('I9')->getFont()->setSize(14); + + // --- TÍTULO Y BARRA DECORATIVA --- + $rowTitle = 11; + $sheet->mergeCells("A{$rowTitle}:M{$rowTitle}"); + $sheet->setCellValue("A{$rowTitle}", 'CONSTANCIAS DAÑADAS (NO FUERON SUSTITUIDAS)'); + $sheet->getStyle("A{$rowTitle}")->applyFromArray([ + 'font' => ['bold' => true, 'color' => ['rgb' => '000000'], 'size' => 14], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER], ]); - $row++; + $sheet->getRowDimension($rowTitle)->setRowHeight(25); - // 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'], - ], - ], + // Barra Roja + $rowRedBar = 13; + $sheet->mergeCells("A{$rowRedBar}:M{$rowRedBar}"); + $sheet->getStyle("A{$rowRedBar}")->applyFromArray([ + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '900000']], + ]); + $sheet->getRowDimension($rowRedBar)->setRowHeight(6); + + // --- ENCABEZADOS DE TABLA --- + $h1 = 14; + $h2 = 15; + + // Definir columnas expandidas + $sheet->mergeCells("A{$h1}:B{$h2}"); + $sheet->setCellValue("A{$h1}", 'No.'); + + $sheet->mergeCells("C{$h1}:F{$h2}"); + $sheet->setCellValue("C{$h1}", "FOLIO DE LA\nCONSTANCIA"); + + $sheet->mergeCells("G{$h1}:I{$h2}"); + $sheet->setCellValue("G{$h1}", "FECHA DE\nCANCELACIÓN"); + + $sheet->mergeCells("J{$h1}:M{$h2}"); + $sheet->setCellValue("J{$h1}", "MOTIVO DE\nCANCELACIÓN"); + + // Aplicar estilo beige + $sheet->getStyle("A{$h1}:M{$h2}")->applyFromArray($styleTableHeader); + $sheet->getRowDimension($h1)->setRowHeight(20); + $sheet->getRowDimension($h2)->setRowHeight(25); + + // --- LLENADO DE DATOS --- + $row = 16; + $i = 1; + + foreach ($data as $item) { + $sheet->mergeCells("A{$row}:B{$row}"); + $sheet->setCellValue("A{$row}", $i); + + $sheet->mergeCells("C{$row}:F{$row}"); + $sheet->setCellValue("C{$row}", $item['folio']); + + $sheet->mergeCells("G{$row}:I{$row}"); + $sheet->setCellValue("G{$row}", $item['fecha']); + + $sheet->mergeCells("J{$row}:M{$row}"); + $sheet->setCellValue("J{$row}", $item['motivo']); + + // Estilos de celda + $sheet->getStyle("A{$row}:M{$row}")->applyFromArray([ + 'borders' => ['allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN]], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true], + 'font' => ['size' => 9] ]); + $row++; + $i++; } - // 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); + // --- ANCHOS DE COLUMNA --- + $sheet->getColumnDimension('A')->setWidth(5); + $sheet->getColumnDimension('B')->setWidth(5); + $sheet->getColumnDimension('C')->setWidth(22); + $sheet->getColumnDimension('D')->setWidth(10); + $sheet->getColumnDimension('E')->setWidth(10); + $sheet->getColumnDimension('F')->setWidth(10); + $sheet->getColumnDimension('G')->setWidth(10); + $sheet->getColumnDimension('H')->setWidth(10); + $sheet->getColumnDimension('I')->setWidth(10); + $sheet->getColumnDimension('J')->setWidth(15); + $sheet->getColumnDimension('K')->setWidth(15); + $sheet->getColumnDimension('L')->setWidth(15); + $sheet->getColumnDimension('M')->setWidth(15); - // Guardar archivo + // Guardar $writer = new Xlsx($spreadsheet); $writer->save($filePath); - // Descargar archivo y eliminarlo después return response()->download($filePath, $fileName)->deleteFileAfterSend(true); } diff --git a/app/Http/Controllers/Repuve/UpdateController.php b/app/Http/Controllers/Repuve/UpdateController.php index 629b3af..48536e5 100644 --- a/app/Http/Controllers/Repuve/UpdateController.php +++ b/app/Http/Controllers/Repuve/UpdateController.php @@ -129,14 +129,14 @@ public function tagSubstitution(Request $request) } // Verificar robo del vehículo - $isStolen = $this->checkIfStolen($vehicle->niv); + /* $isStolen = $this->checkIfStolen($vehicle->niv); if ($isStolen) { return ApiResponse::FORBIDDEN->response([ 'message' => 'El vehículo reporta robo. No se puede continuar con la sustitución.', 'niv' => $vehicle->niv, ]); - } + } */ DB::beginTransaction(); @@ -179,9 +179,9 @@ public function tagSubstitution(Request $request) 'performed_by' => Auth::id(), ]); - // 6. Enviar a REPUVE Nacional + /* // 6. Enviar a REPUVE Nacional $datosCompletos = $this->prepararDatosParaInscripcion($vehicle->niv); - ProcessRepuveResponse::dispatch($record->id, $datosCompletos); + ProcessRepuveResponse::dispatch($record->id, $datosCompletos); */ DB::commit();