add: generar excel del tag history
This commit is contained in:
parent
c0225a69e2
commit
ce7e1f998e
@ -11,6 +11,7 @@
|
|||||||
use App\Models\VehicleTagLog;
|
use App\Models\VehicleTagLog;
|
||||||
use App\Models\Tag;
|
use App\Models\Tag;
|
||||||
use App\Models\Module;
|
use App\Models\Module;
|
||||||
|
use App\Models\Record;
|
||||||
use App\Models\TagCancellationLog;
|
use App\Models\TagCancellationLog;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||||
@ -869,4 +870,279 @@ public function excelGeneral(Request $request)
|
|||||||
|
|
||||||
return response()->download($filePath, $fileName)->deleteFileAfterSend(true);
|
return response()->download($filePath, $fileName)->deleteFileAfterSend(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exportar resultados de búsqueda a Excel
|
||||||
|
*/
|
||||||
|
public function exportSearchRecords(Request $request)
|
||||||
|
{
|
||||||
|
// Reutilizar la misma validación y lógica de búsqueda
|
||||||
|
$request->validate([
|
||||||
|
'folio' => 'nullable|string',
|
||||||
|
'placa' => 'nullable|string',
|
||||||
|
'vin' => 'nullable|string',
|
||||||
|
'tag_number' => 'nullable|string',
|
||||||
|
'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',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Reutilizar la misma query de búsqueda (sin paginación)
|
||||||
|
$records = Record::with([
|
||||||
|
'vehicle',
|
||||||
|
'vehicle.owner',
|
||||||
|
'vehicle.tag:id,vehicle_id,folio,tag_number,status_id,package_id,module_id',
|
||||||
|
'vehicle.tag.status:id,code,name',
|
||||||
|
'vehicle.tag.package:id,lot,box_number',
|
||||||
|
'vehicle.tag.module:id,name',
|
||||||
|
'files:id,record_id,name_id,path,md5',
|
||||||
|
'files.catalogName:id,name',
|
||||||
|
'user:id,name,email,module_id',
|
||||||
|
'module:id,name',
|
||||||
|
'error:id,code,description',
|
||||||
|
'vehicle.vehicleTagLogs' => function ($q) {
|
||||||
|
$q->with([
|
||||||
|
'tag:id,folio,tag_number,status_id,module_id,package_id',
|
||||||
|
'tag.status:id,code,name',
|
||||||
|
'tag.module:id,name',
|
||||||
|
'tag.package:id,lot,box_number'
|
||||||
|
])->orderBy('created_at', 'DESC');
|
||||||
|
},
|
||||||
|
])->orderBy('id', 'ASC');
|
||||||
|
|
||||||
|
// Aplicar los mismos filtros
|
||||||
|
if ($request->filled('folio')) {
|
||||||
|
$records->whereHas('vehicle.tag', function ($q) use ($request) {
|
||||||
|
$q->where('folio', 'LIKE', '%' . $request->input('folio') . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ($request->filled('placa')) {
|
||||||
|
$records->whereHas('vehicle', function ($q) use ($request) {
|
||||||
|
$q->where('placa', 'LIKE', '%' . $request->input('placa') . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ($request->filled('vin')) {
|
||||||
|
$records->whereHas('vehicle', function ($q) use ($request) {
|
||||||
|
$q->where('niv', 'LIKE', '%' . $request->input('vin') . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ($request->filled('tag_number')) {
|
||||||
|
$records->whereHas('vehicle.tag', function ($q) use ($request) {
|
||||||
|
$q->where('tag_number', 'LIKE', '%' . $request->input('tag_number') . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ($request->filled('module_id')) {
|
||||||
|
$records->where('module_id', $request->input('module_id'));
|
||||||
|
}
|
||||||
|
if ($request->filled('action_type')) {
|
||||||
|
$records->whereHas('vehicle.vehicleTagLogs', function ($q) use ($request) {
|
||||||
|
$q->where('action_type', $request->input('action_type'))
|
||||||
|
->whereRaw('id = (
|
||||||
|
SELECT MAX(id)
|
||||||
|
FROM vehicle_tags_logs
|
||||||
|
WHERE vehicle_id = vehicle.id
|
||||||
|
)');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ($request->filled('status')) {
|
||||||
|
$records->whereHas('vehicle.tag.status', function ($q) use ($request) {
|
||||||
|
$q->where('code', $request->input('status'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
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'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$allRecords = $records->get();
|
||||||
|
|
||||||
|
if ($allRecords->isEmpty()) {
|
||||||
|
return ApiResponse::NOT_FOUND->response([
|
||||||
|
'message' => 'No se encontraron registros con los criterios de búsqueda proporcionados.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preparar datos para Excel: una fila por cada entrada del historial
|
||||||
|
$excelRows = [];
|
||||||
|
|
||||||
|
foreach ($allRecords as $record) {
|
||||||
|
$niv = $record->vehicle->niv ?? '';
|
||||||
|
$currentTagId = $record->vehicle->tag?->id;
|
||||||
|
$recordRows = []; // Filas para este registro principal
|
||||||
|
|
||||||
|
// Obtener todos los logs ordenados por fecha ascendente
|
||||||
|
$vehicleLogs = $record->vehicle->vehicleTagLogs->sortBy('created_at');
|
||||||
|
$processedTags = [];
|
||||||
|
|
||||||
|
// Procesar tags del historial (excluyendo el tag actual)
|
||||||
|
foreach ($vehicleLogs as $log) {
|
||||||
|
$tagId = $log->tag_id;
|
||||||
|
|
||||||
|
// Excluir el tag actual y solo procesar cada tag una vez
|
||||||
|
if ($tagId && $tagId !== $currentTagId && !in_array($tagId, $processedTags)) {
|
||||||
|
$processedTags[] = $tagId;
|
||||||
|
$tag = $log->tag;
|
||||||
|
|
||||||
|
// Buscar todos los logs relacionados con este tag
|
||||||
|
$tagLogs = $vehicleLogs->where('tag_id', $tagId);
|
||||||
|
|
||||||
|
// Buscar fecha de cancelación si existe
|
||||||
|
$cancelLog = $tagLogs
|
||||||
|
->whereIn('action_type', ['cancelacion', 'sustitucion'])
|
||||||
|
->whereNotNull('cancellation_at')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// Obtener fecha de asignación (inscripción o sustitución)
|
||||||
|
$assignedLog = $tagLogs
|
||||||
|
->whereIn('action_type', ['inscripcion', 'sustitucion'])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// Determinar fecha: si fue cancelado, usar fecha de cancelación, sino fecha de asignación
|
||||||
|
$fecha = null;
|
||||||
|
$status = 'unknown';
|
||||||
|
|
||||||
|
if ($cancelLog && $cancelLog->cancellation_at) {
|
||||||
|
$fecha = Carbon::parse($cancelLog->cancellation_at);
|
||||||
|
$status = 'Cancelado';
|
||||||
|
} elseif ($assignedLog && $assignedLog->created_at) {
|
||||||
|
$fecha = Carbon::parse($assignedLog->created_at);
|
||||||
|
$status = ucfirst($assignedLog->action_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no hay fecha, usar el status del tag
|
||||||
|
if (!$fecha) {
|
||||||
|
$status = $tag?->status?->name ?? 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
$recordRows[] = [
|
||||||
|
'status' => $status,
|
||||||
|
'folio' => $tag?->folio ?? '',
|
||||||
|
'tag' => $tag?->tag_number ?? '',
|
||||||
|
'niv' => $niv,
|
||||||
|
'fecha' => $fecha ? $fecha->format('d/m/Y H:i') : '',
|
||||||
|
'sort_date' => $fecha ? $fecha->timestamp : 0,
|
||||||
|
'record_id' => $record->id, // Para mantener agrupado
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordenar las filas del historial por fecha ascendente
|
||||||
|
usort($recordRows, function ($a, $b) {
|
||||||
|
return $a['sort_date'] <=> $b['sort_date'];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Agregar el registro principal (tag actual) al final del grupo
|
||||||
|
if ($record->vehicle->tag) {
|
||||||
|
$currentTag = $record->vehicle->tag;
|
||||||
|
$latestLog = $record->vehicle->vehicleTagLogs->first();
|
||||||
|
|
||||||
|
// Determinar fecha y status del tag actual
|
||||||
|
$fechaActual = null;
|
||||||
|
$statusActual = $currentTag->status?->name ?? 'unknown';
|
||||||
|
|
||||||
|
if ($latestLog) {
|
||||||
|
if ($latestLog->cancellation_at) {
|
||||||
|
$fechaActual = Carbon::parse($latestLog->cancellation_at);
|
||||||
|
$statusActual = 'Cancelado';
|
||||||
|
} else {
|
||||||
|
$fechaActual = Carbon::parse($latestLog->created_at);
|
||||||
|
$statusActual = ucfirst($latestLog->action_type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$fechaActual = $record->created_at ? Carbon::parse($record->created_at) : now();
|
||||||
|
}
|
||||||
|
|
||||||
|
$recordRows[] = [
|
||||||
|
'status' => $statusActual,
|
||||||
|
'folio' => $currentTag->folio ?? '',
|
||||||
|
'tag' => $currentTag->tag_number ?? '',
|
||||||
|
'niv' => $niv,
|
||||||
|
'fecha' => $fechaActual->format('d/m/Y H:i'),
|
||||||
|
'sort_date' => $fechaActual->timestamp,
|
||||||
|
'record_id' => $record->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar todas las filas de este registro al array principal
|
||||||
|
$excelRows = array_merge($excelRows, $recordRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear Excel
|
||||||
|
$fileName = 'Busqueda_Registros_' . now()->format('Ymd_His') . '.xlsx';
|
||||||
|
$filePath = storage_path('app/temp/' . $fileName);
|
||||||
|
if (!file_exists(dirname($filePath))) {
|
||||||
|
mkdir(dirname($filePath), 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
$sheet->setTitle('Registros');
|
||||||
|
|
||||||
|
// Estilos
|
||||||
|
$headerStyle = [
|
||||||
|
'font' => ['bold' => true, 'size' => 11, 'color' => ['rgb' => 'FFFFFF']],
|
||||||
|
'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '4472C4']],
|
||||||
|
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true],
|
||||||
|
'borders' => ['allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN]]
|
||||||
|
];
|
||||||
|
|
||||||
|
$cellStyle = [
|
||||||
|
'borders' => ['allBorders' => ['borderStyle' => PhpSpreadsheetBorder::BORDER_THIN]],
|
||||||
|
'alignment' => ['vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Encabezados (solo las 5 columnas solicitadas)
|
||||||
|
$headers = [
|
||||||
|
'A' => 'Status',
|
||||||
|
'B' => 'Folio',
|
||||||
|
'C' => 'Tag',
|
||||||
|
'D' => 'NIV',
|
||||||
|
'E' => 'Fecha de Registro o Cancelación',
|
||||||
|
];
|
||||||
|
|
||||||
|
$row = 1;
|
||||||
|
foreach ($headers as $col => $text) {
|
||||||
|
$sheet->setCellValue("{$col}{$row}", $text);
|
||||||
|
$sheet->getStyle("{$col}{$row}")->applyFromArray($headerStyle);
|
||||||
|
}
|
||||||
|
$sheet->getRowDimension($row)->setRowHeight(30);
|
||||||
|
|
||||||
|
// Datos
|
||||||
|
$row = 2;
|
||||||
|
foreach ($excelRows as $item) {
|
||||||
|
$sheet->setCellValue('A' . $row, $item['status']);
|
||||||
|
$sheet->setCellValue('B' . $row, $item['folio']);
|
||||||
|
$sheet->setCellValue('C' . $row, $item['tag']);
|
||||||
|
$sheet->setCellValue('D' . $row, $item['niv']);
|
||||||
|
$sheet->setCellValue('E' . $row, $item['fecha']);
|
||||||
|
|
||||||
|
// Aplicar estilos
|
||||||
|
foreach (range('A', 'E') as $col) {
|
||||||
|
$sheet->getStyle("{$col}{$row}")->applyFromArray($cellStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Centrar algunas columnas
|
||||||
|
$sheet->getStyle("A{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
||||||
|
$sheet->getStyle("E{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
||||||
|
|
||||||
|
$row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajustar anchos de columna
|
||||||
|
$sheet->getColumnDimension('A')->setWidth(20);
|
||||||
|
$sheet->getColumnDimension('B')->setWidth(18);
|
||||||
|
$sheet->getColumnDimension('C')->setWidth(20);
|
||||||
|
$sheet->getColumnDimension('D')->setWidth(22);
|
||||||
|
$sheet->getColumnDimension('E')->setWidth(25);
|
||||||
|
|
||||||
|
// Guardar archivo
|
||||||
|
$writer = new Xlsx($spreadsheet);
|
||||||
|
$writer->save($filePath);
|
||||||
|
|
||||||
|
return response()->download($filePath, $fileName)->deleteFileAfterSend(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -331,8 +331,10 @@ public function searchRecord(Request $request)
|
|||||||
// Log de acciones
|
// Log de acciones
|
||||||
'vehicle.vehicleTagLogs' => function ($q) {
|
'vehicle.vehicleTagLogs' => function ($q) {
|
||||||
$q->with([
|
$q->with([
|
||||||
'tag:id,folio,tag_number,status_id',
|
'tag:id,folio,tag_number,status_id,module_id,package_id',
|
||||||
'tag.status:id,code,name'
|
'tag.status:id,code,name',
|
||||||
|
'tag.module:id,name',
|
||||||
|
'tag.package:id,lot,box_number'
|
||||||
])->orderBy('created_at', 'DESC');
|
])->orderBy('created_at', 'DESC');
|
||||||
},
|
},
|
||||||
])->orderBy('id', 'ASC');
|
])->orderBy('id', 'ASC');
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
// Rutas de inscripción de vehículos
|
// Rutas de inscripción de vehículos
|
||||||
Route::post('inscripcion', [InscriptionController::class, 'vehicleInscription']);
|
Route::post('inscripcion', [InscriptionController::class, 'vehicleInscription']);
|
||||||
Route::get('consultaV', [InscriptionController::class, 'searchRecord']);
|
Route::get('consultaV', [InscriptionController::class, 'searchRecord']);
|
||||||
|
Route::get('consultaV/export', [InscriptionController::class, 'exportSearchRecords']);
|
||||||
Route::post('reporte-robado', [InscriptionController::class, 'stolen']);
|
Route::post('reporte-robado', [InscriptionController::class, 'stolen']);
|
||||||
|
|
||||||
// Rutas de expedientes y documentos
|
// Rutas de expedientes y documentos
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user