264 lines
9.5 KiB
PHP

<?php
namespace App\Http\Controllers\Repuve;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\VehicleTagLog;
use App\Models\Tag;
use App\Models\Module;
use Carbon\Carbon;
use Notsoweb\ApiResponse\Enums\ApiResponse;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border as PhpSpreadsheetBorder;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
/**
* Descripción
*/
class ExcelController extends Controller
{
public function constanciasSustituidas(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 sustitución en el rango de fechas
$logs = VehicleTagLog::with([
'vehicle',
'tag',
'cancellationReason'
])
->where('action_type', 'sustitucion')
->whereHas('vehicle.records', function ($query) use ($moduleId) {
$query->where('module_id', $moduleId);
})
->whereBetween('created_at', [$fechaInicio, $fechaFin])
->orderBy('created_at', 'asc')
->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,
]);
}
// Preparar datos para el Excel
$data = $this->prepareExcelData($logs);
// Generar archivo Excel
$fileName = 'Constancias_Sustituidas_' . $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); // Altura del logo en pixeles
$drawing->setCoordinates('B1'); // Posición del logo
$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, '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++;
// 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++;
}
$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(18);
$sheet->getColumnDimension('H')->setWidth(18);
$sheet->getColumnDimension('I')->setWidth(30);
$sheet->getColumnDimension('J')->setWidth(20);
$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 = [];
$no = 1;
foreach ($logs as $log) {
$vehicle = $log->vehicle;
$newTag = $log->tag;
// Extraer el folio anterior de las observaciones
$folioAnterior = 'N/A';
if ($log->cancellation_observations) {
if (preg_match('/Folio:\s*([^)]+)/', $log->cancellation_observations, $matches)) {
$folioAnterior = trim($matches[1]);
}
}
$data[] = [
$no,
$vehicle->niv ?? 'N/A',
$vehicle->nrpv ?? 'N/A',
strtoupper($vehicle->marca ?? 'N/A'),
strtoupper($vehicle->placa ?? 'N/A'),
$vehicle->modelo ?? 'N/A',
$folioAnterior,
$newTag->folio ?? 'N/A',
$newTag->tag_number ?? 'N/A',
$log->created_at->format('d/m/Y'),
$log->cancellation_observations ?? 'CONSTANCIA SUSTITUIDA',
];
$no++;
}
return $data;
}
}