findOrFail($id); $pdf = Pdf::loadView('pdfs.record', compact('record')) ->setPaper('a4', 'portrait') ->setOptions([ 'defaultFont' => 'sans-serif', 'isHtml5ParserEnabled' => true, 'isRemoteEnabled' => true, ]); return $pdf->stream('constancia-inscripcion-' . $id . '.pdf'); } public function generatePdfVerification($id) { $record = Record::with('vehicle.owner', 'user')->findOrFail($id); $pdf = Pdf::loadView('pdfs.verification', compact('record')) ->setPaper('a4', 'landscape') ->setOptions([ 'defaultFont' => 'sans-serif', 'isHtml5ParserEnabled' => true, 'isRemoteEnabled' => true, ]); return $pdf->stream('hoja-verificacion-' . $id . '.pdf'); } public function generatePdfConstancia($id) { $record = Record::with('vehicle.owner', 'user')->findOrFail($id); $pdf = Pdf::loadView('pdfs.constancia', compact('record')) ->setPaper('a4', 'landscape') ->setOptions([ 'defaultFont' => 'sans-serif', 'isHtml5ParserEnabled' => true, 'isRemoteEnabled' => true, ]); return $pdf->stream('constancia-inscripcion' . $id . '.pdf'); } /** * Generar PDF con las imágenes */ public function generatePdfImages($id) { try { // Obtener el record con sus archivos $record = Record::with(['vehicle.owner', 'files'])->findOrFail($id); // Validar que tenga archivos if ($record->files->isEmpty()) { return ApiResponse::NOT_FOUND->response([ 'message' => 'El expediente no tiene imágenes adjuntas.', 'record_id' => $id, ]); } // Crear instancia de FPDF $pdf = new Fpdf('P', 'mm', 'A4'); $pdf->SetAutoPageBreak(false); $pdf->SetMargins(10, 10, 10); $currentImage = 0; foreach ($record->files as $file) { $currentImage++; // Buscar archivo en disk 'records' $diskRecords = Storage::disk('records'); $fileContent = null; if ($diskRecords->exists($file->path)) { $fileContent = $diskRecords->get($file->path); } // Si no se encontró el archivo, continuar if ($fileContent === null) { continue; } // Agregar nueva página $pdf->AddPage(); // Header con folio $pdf->SetFillColor(44, 62, 80); $pdf->Rect(0, 0, 210, 20, 'F'); $pdf->SetTextColor(255, 255, 255); $pdf->SetFont('Arial', 'B', 14); $pdf->SetXY(10, 7); $pdf->Cell(0, 6, 'FOLIO: ' . $record->folio, 0, 1, 'L'); // Obtener ruta temporal del archivo $tempPath = tempnam(sys_get_temp_dir(), 'pdf_img_'); file_put_contents($tempPath, $fileContent); // Obtener dimensiones de la imagen $imageInfo = getimagesize($tempPath); if ($imageInfo !== false) { list($originalWidth, $originalHeight) = $imageInfo; $imageType = $imageInfo[2]; $availableWidth = 190; // 210mm - 20mm márgenes $availableHeight = 247; // 297mm - 20mm header - 20mm footer - 10mm márgenes // Calcular dimensiones manteniendo proporción $ratio = min($availableWidth / $originalWidth, $availableHeight / $originalHeight); $newWidth = $originalWidth * $ratio; $newHeight = $originalHeight * $ratio; // Centrar imagen $x = (210 - $newWidth) / 2; $y = 25 + (($availableHeight - $newHeight) / 2); // Determinar tipo de imagen $imageExtension = ''; switch ($imageType) { case IMAGETYPE_JPEG: $imageExtension = 'JPEG'; break; case IMAGETYPE_JPEG: $imageExtension = 'JPG'; break; case IMAGETYPE_PNG: $imageExtension = 'PNG'; break; default: // Si no es un formato soportado, continuar unlink($tempPath); continue 2; } // Insertar imagen $pdf->Image($tempPath, $x, $y, $newWidth, $newHeight, $imageExtension); } // Limpiar archivo temporal unlink($tempPath); } // Verificar que se agregaron páginas if ($pdf->PageNo() == 0) { return ApiResponse::NOT_FOUND->response([ 'message' => 'No se pudieron procesar las imágenes del expediente.', 'record_id' => $id, ]); } // Generar PDF $pdfContent = $pdf->Output('S'); return response($pdfContent, 200) ->header('Content-Type', 'application/pdf') ->header('Content-Disposition', 'inline; filename="expediente-imagenes-' . $record->folio . '.pdf"'); } catch (\Exception $e) { return ApiResponse::INTERNAL_ERROR->response([ 'message' => 'Error al generar el PDF de imágenes', 'error' => $e->getMessage(), ]); } } public function errors(Request $request) { $request->validate([ 'folio' => 'nullable|string', 'placa' => 'nullable|string', 'vin' => 'nullable|string', ]); $query = Record::with(['vehicle.owner', 'vehicle.tag', 'files', 'user', 'error']) ->whereNotNull('api_response') ->whereRaw("JSON_EXTRACT(api_response, '$.has_error') = true") ->orderBy('error_occurred_at', 'DESC'); if ($request->filled('folio')) { $query->where('folio', 'LIKE', '%' . $request->input('folio') . '%'); } if ($request->filled('placa')) { $query->whereHas('vehicle', function ($q) use ($request) { $q->where('placa', 'LIKE', '%' . $request->input('placa') . '%'); }); } if ($request->filled('vin')) { $query->whereHas('vehicle', function ($q) use ($request) { $q->where('niv', 'LIKE', '%' . $request->input('vin') . '%'); }); } $perPage = $request->input('per_page', 20); $records = $query->paginate($perPage); if ($records->isEmpty()) { return ApiResponse::NOT_FOUND->response([ 'message' => 'No se encontraron expedientes con errores.', 'records' => [], 'pagination' => [ 'current_page' => 1, 'total_pages' => 0, 'total_records' => 0, 'per_page' => $perPage, ], ]); } return ApiResponse::OK->response([ 'message' => 'Expedientes con errores encontrados exitosamente', 'records' => $records->map(function ($record) { return [ 'id' => $record->id, 'folio' => $record->folio, 'created_at' => $record->created_at->toDateTimeString(), 'error_occurred_at' => $record->error_occurred_at?->toDateTimeString(), // Información del vehículo 'vehicle' => [ 'id' => $record->vehicle->id, 'placa' => $record->vehicle->placa, 'niv' => $record->vehicle->niv, 'marca' => $record->vehicle->marca, 'modelo' => $record->vehicle->modelo, 'color' => $record->vehicle->color, 'clase_veh' => $record->vehicle->clase_veh, ], // Error del catálogo 'error' => $record->error ? [ 'id' => $record->error->id, 'code' => $record->error->code, 'description' => $record->error->description, ] : null, // Respuesta completa de la API con el error 'api_response' => $record->api_response, ]; }), 'pagination' => [ 'current_page' => $records->currentPage(), 'total_pages' => $records->lastPage(), 'total_records' => $records->total(), 'per_page' => $records->perPage(), 'from' => $records->firstItem(), 'to' => $records->lastItem(), ], ]); } }