еализация PDF отчетов о состоянии истории автомобиля
This commit is contained in:
parent
1cbb64f2f6
commit
1544938c00
260
app.py
260
app.py
@ -13,6 +13,15 @@ import json
|
|||||||
from expiring_dict import ExpiringDict
|
from expiring_dict import ExpiringDict
|
||||||
import uuid
|
import uuid
|
||||||
from flask_swagger_ui import get_swaggerui_blueprint
|
from flask_swagger_ui import get_swaggerui_blueprint
|
||||||
|
import datetime
|
||||||
|
from reportlab.pdfgen import canvas
|
||||||
|
from reportlab.lib.pagesizes import A4
|
||||||
|
from reportlab.lib import colors
|
||||||
|
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, Image
|
||||||
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||||
|
from reportlab.lib.units import inch, mm
|
||||||
|
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -748,9 +757,6 @@ def api_reqimage():
|
|||||||
return 'bad request!', 500
|
return 'bad request!', 500
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/ads.txt")
|
@app.route("/ads.txt")
|
||||||
def ads_txt():
|
def ads_txt():
|
||||||
try:
|
try:
|
||||||
@ -833,6 +839,254 @@ def serve_static(filename):
|
|||||||
app.logger.error(f'Ошибка доступа к файлу {filename}: {str(e)}')
|
app.logger.error(f'Ошибка доступа к файлу {filename}: {str(e)}')
|
||||||
return 'File not found', 404
|
return 'File not found', 404
|
||||||
|
|
||||||
|
@app.route("/salvagereport/<string:vin>")
|
||||||
|
def generate_pdf_report(vin):
|
||||||
|
try:
|
||||||
|
conn = pool.acquire()
|
||||||
|
cur = conn.cursor()
|
||||||
|
user_ip = get_ip(request)
|
||||||
|
|
||||||
|
try:
|
||||||
|
returnVal = cur.callfunc("checkip", int, [user_ip, request.headers.get("CF-IPCountry", 'None'), get_addr(user_ip), 1, 0, 0])
|
||||||
|
except:
|
||||||
|
app.logger.error(traceback.format_exc())
|
||||||
|
|
||||||
|
# Get vehicle details
|
||||||
|
cur.execute("""select 'None', COALESCE((select value from m_JSONS_FROM_NHTSA v3 where v3.svin =s.svin and v3.variableid ='26'),(select val from vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Make'),'UNKNOWN') make,
|
||||||
|
COALESCE((select value from m_JSONS_FROM_NHTSA v3 where v3.svin =s.svin and v3.variableid ='28'),(select val from vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Model'),'UNKNOWN') model,
|
||||||
|
COALESCE((select value from m_JSONS_FROM_NHTSA v3 where v3.svin =s.svin and v3.variableid ='29'),(select val from vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Model Year'),'UNKNOWN') year,
|
||||||
|
COALESCE((select value from m_JSONS_FROM_NHTSA v3 where v3.svin =s.svin and v3.variableid ='5'),(select val from vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Body Class'),'UNKNOWN') body,
|
||||||
|
COALESCE((select value from m_JSONS_FROM_NHTSA v3 where v3.svin =s.svin and v3.variableid ='13'),(select val from vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Engine Model'),'UNKNOWN') engine,
|
||||||
|
COALESCE((select value from m_JSONS_FROM_NHTSA v3 where v3.svin =s.svin and v3.variableid ='9'),(select val from vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Engine Number of Cylinders'),'UNKNOWN') celindr,
|
||||||
|
COALESCE((select value from m_JSONS_FROM_NHTSA v3 where v3.svin =s.svin and v3.variableid ='15'),(select val from vind2 where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) and varb = 'Drive Type'),'-') drive
|
||||||
|
from (select substr(:p1,1,10) svin, :p1 vin from dual) s """, {'p1': vin})
|
||||||
|
det = cur.fetchall()
|
||||||
|
|
||||||
|
# Get salvage history
|
||||||
|
cur.execute("""select rownum, t.vin, t.title, t.odo, t.odos, t.dem1, t.dem2, t.year||'/'||t.month from salvagedb t where vin = :p1 and svin = substr(:p1,1,10) """, {'p1': vin})
|
||||||
|
his = cur.fetchall()
|
||||||
|
|
||||||
|
# Generate current date and report ID
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
report_date = now.strftime("%Y-%m-%d") # Только дата без времени
|
||||||
|
report_id = uuid.uuid4().hex[:8].upper()
|
||||||
|
current_year = now.year
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Создаем буфер для PDF
|
||||||
|
buffer = io.BytesIO()
|
||||||
|
|
||||||
|
# Создаем PDF документ
|
||||||
|
doc = SimpleDocTemplate(
|
||||||
|
buffer,
|
||||||
|
pagesize=A4,
|
||||||
|
rightMargin=20*mm,
|
||||||
|
leftMargin=20*mm,
|
||||||
|
topMargin=15*mm,
|
||||||
|
bottomMargin=20*mm
|
||||||
|
)
|
||||||
|
|
||||||
|
# Создаем стили для текста
|
||||||
|
styles = getSampleStyleSheet()
|
||||||
|
styles.add(ParagraphStyle(
|
||||||
|
name='ReportTitle',
|
||||||
|
parent=styles['Heading1'],
|
||||||
|
fontSize=16,
|
||||||
|
alignment=TA_CENTER
|
||||||
|
))
|
||||||
|
styles.add(ParagraphStyle(
|
||||||
|
name='ReportSubtitle',
|
||||||
|
parent=styles['Normal'],
|
||||||
|
fontSize=12,
|
||||||
|
alignment=TA_CENTER,
|
||||||
|
textColor=colors.HexColor('#0066CC') # Синий цвет для акцента
|
||||||
|
))
|
||||||
|
styles.add(ParagraphStyle(
|
||||||
|
name='Right',
|
||||||
|
parent=styles['Normal'],
|
||||||
|
fontSize=10,
|
||||||
|
alignment=TA_RIGHT
|
||||||
|
))
|
||||||
|
styles.add(ParagraphStyle(
|
||||||
|
name='Disclaimer',
|
||||||
|
parent=styles['Normal'],
|
||||||
|
fontSize=8,
|
||||||
|
textColor=colors.gray
|
||||||
|
))
|
||||||
|
styles.add(ParagraphStyle(
|
||||||
|
name='SalvageDBFooter',
|
||||||
|
parent=styles['Normal'],
|
||||||
|
fontSize=9,
|
||||||
|
alignment=TA_CENTER,
|
||||||
|
textColor=colors.HexColor('#0066CC'), # Синий цвет для акцента
|
||||||
|
fontName='Helvetica-Bold'
|
||||||
|
))
|
||||||
|
|
||||||
|
# Список элементов для PDF
|
||||||
|
elements = []
|
||||||
|
|
||||||
|
# Путь к логотипу
|
||||||
|
# logo_path = os.path.join(app_path, 'static', 'icons', 'icon-144x144.png')
|
||||||
|
|
||||||
|
# Добавляем логотип, если файл существует
|
||||||
|
# if os.path.exists(logo_path):
|
||||||
|
# logo_img = Image(logo_path, width=30*mm, height=30*mm)
|
||||||
|
# logo_img.hAlign = 'CENTER'
|
||||||
|
# elements.append(logo_img)
|
||||||
|
# elements.append(Spacer(1, 5*mm))
|
||||||
|
|
||||||
|
# Заголовок отчета с акцентом на SALVAGEDB.COM
|
||||||
|
elements.append(Paragraph("Vehicle History Report", styles['ReportTitle']))
|
||||||
|
elements.append(Paragraph("SALVAGEDB.COM - Comprehensive Vehicle History Check", styles['ReportSubtitle']))
|
||||||
|
elements.append(Spacer(1, 10*mm))
|
||||||
|
|
||||||
|
# Информация об отчете
|
||||||
|
elements.append(Paragraph(f"Report Date: {report_date}", styles['Right']))
|
||||||
|
elements.append(Paragraph(f"Report ID: {report_id}", styles['Right']))
|
||||||
|
elements.append(Spacer(1, 15*mm))
|
||||||
|
|
||||||
|
# Информация о транспортном средстве
|
||||||
|
elements.append(Paragraph("Vehicle Information", styles['Heading2']))
|
||||||
|
|
||||||
|
# Создаем таблицу с информацией о транспортном средстве
|
||||||
|
vehicle_data = [
|
||||||
|
["VIN", vin],
|
||||||
|
["Make", det[0][1]],
|
||||||
|
["Model", det[0][2]],
|
||||||
|
["Year", det[0][3]],
|
||||||
|
["Body Style", det[0][4]],
|
||||||
|
["Engine", det[0][5]],
|
||||||
|
["Cylinders", det[0][6]],
|
||||||
|
["Drive", det[0][7]]
|
||||||
|
]
|
||||||
|
|
||||||
|
vehicle_table = Table(vehicle_data, colWidths=[100, 350])
|
||||||
|
vehicle_table.setStyle(TableStyle([
|
||||||
|
('BACKGROUND', (0, 0), (0, -1), colors.lightgrey),
|
||||||
|
('TEXTCOLOR', (0, 0), (0, -1), colors.black),
|
||||||
|
('ALIGN', (0, 0), (0, -1), 'LEFT'),
|
||||||
|
('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
|
||||||
|
('FONTSIZE', (0, 0), (0, -1), 10),
|
||||||
|
('BOTTOMPADDING', (0, 0), (-1, -1), 6),
|
||||||
|
('BACKGROUND', (1, 0), (-1, -1), colors.white),
|
||||||
|
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||||
|
]))
|
||||||
|
|
||||||
|
elements.append(vehicle_table)
|
||||||
|
elements.append(Spacer(1, 10*mm))
|
||||||
|
|
||||||
|
# Информация об истории
|
||||||
|
if his:
|
||||||
|
elements.append(Paragraph("Salvage History", styles['Heading2']))
|
||||||
|
|
||||||
|
# Создаем стиль для ячеек с переносом текста
|
||||||
|
table_style = TableStyle([
|
||||||
|
('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey),
|
||||||
|
('TEXTCOLOR', (0, 0), (-1, 0), colors.black),
|
||||||
|
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
|
||||||
|
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
||||||
|
('FONTSIZE', (0, 0), (-1, 0), 9),
|
||||||
|
('BOTTOMPADDING', (0, 0), (-1, 0), 6),
|
||||||
|
('BACKGROUND', (0, 1), (-1, -1), colors.white),
|
||||||
|
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||||
|
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||||
|
('LEFTPADDING', (0, 0), (-1, -1), 3),
|
||||||
|
('RIGHTPADDING', (0, 0), (-1, -1), 3),
|
||||||
|
('FONTSIZE', (0, 1), (-1, -1), 8),
|
||||||
|
('WORDWRAP', (0, 0), (-1, -1), True),
|
||||||
|
])
|
||||||
|
|
||||||
|
# Оптимизированные заголовки без VIN
|
||||||
|
history_headers = ["Title", "Mileage", "Odometer Status", "Primary\nDamage", "Secondary\nDamage"]
|
||||||
|
|
||||||
|
# Формируем данные для таблицы истории
|
||||||
|
history_data = [history_headers]
|
||||||
|
|
||||||
|
for item in his:
|
||||||
|
title_value = item[2]
|
||||||
|
primary_damage = item[5] if item[5] else "N/A"
|
||||||
|
secondary_damage = item[6] if item[6] else "N/A"
|
||||||
|
|
||||||
|
# Добавляем строку с данными, убрав VIN
|
||||||
|
history_data.append([
|
||||||
|
title_value,
|
||||||
|
str(item[3]),
|
||||||
|
item[4],
|
||||||
|
primary_damage,
|
||||||
|
secondary_damage
|
||||||
|
])
|
||||||
|
|
||||||
|
# Устанавливаем ширину колонок оптимально для A4
|
||||||
|
available_width = doc.width # Доступная ширина страницы
|
||||||
|
col_widths = [
|
||||||
|
available_width * 0.20, # 20% для Title
|
||||||
|
available_width * 0.12, # 12% для Mileage
|
||||||
|
available_width * 0.18, # 18% для Odometer Status
|
||||||
|
available_width * 0.25, # 25% для Primary Damage
|
||||||
|
available_width * 0.25 # 25% для Secondary Damage
|
||||||
|
]
|
||||||
|
|
||||||
|
# Создаем таблицу с правильными размерами
|
||||||
|
history_table = Table(history_data, colWidths=col_widths, repeatRows=1)
|
||||||
|
history_table.setStyle(table_style)
|
||||||
|
|
||||||
|
elements.append(history_table)
|
||||||
|
else:
|
||||||
|
elements.append(Paragraph("Salvage History", styles['Heading2']))
|
||||||
|
elements.append(Paragraph("Salvage history not found.", styles['Normal']))
|
||||||
|
|
||||||
|
elements.append(Spacer(1, 15*mm))
|
||||||
|
|
||||||
|
# Дисклеймер
|
||||||
|
disclaimer_text = """
|
||||||
|
Disclaimer: This report provides information about salvage or junk vehicles; damage from hail, flood or fire;
|
||||||
|
mileage discrepancies or odometer rollback; and gray market vehicles. We do not claim that the car got in our
|
||||||
|
databank has salvage title, but the fact that it has been damaged for sure. Our site helps people avoid buying
|
||||||
|
a damaged vehicle in the past.
|
||||||
|
"""
|
||||||
|
elements.append(Paragraph(disclaimer_text, styles['Disclaimer']))
|
||||||
|
|
||||||
|
# Футер с акцентом на SALVAGEDB.COM
|
||||||
|
elements.append(Spacer(1, 15*mm))
|
||||||
|
elements.append(Paragraph(f"© {current_year} SALVAGEDB.COM - All Rights Reserved", styles['SalvageDBFooter']))
|
||||||
|
elements.append(Paragraph("Visit SALVAGEDB.COM for more information about vehicle history", styles['SalvageDBFooter']))
|
||||||
|
elements.append(Paragraph("This report is provided as is without any guarantees or warranty.", styles['Disclaimer']))
|
||||||
|
|
||||||
|
# Строим PDF документ
|
||||||
|
doc.build(elements)
|
||||||
|
|
||||||
|
# Получаем содержимое буфера
|
||||||
|
pdf_data = buffer.getvalue()
|
||||||
|
buffer.close()
|
||||||
|
|
||||||
|
# Создаем HTTP-ответ с PDF
|
||||||
|
response = make_response(pdf_data)
|
||||||
|
response.headers['Content-Type'] = 'application/pdf'
|
||||||
|
response.headers['Content-Disposition'] = f'attachment; filename=vehicle_report_{vin}.pdf'
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except Exception as pdf_error:
|
||||||
|
# Если возникла ошибка при генерации PDF, логируем ее
|
||||||
|
app.logger.error(f"PDF generation error: {str(pdf_error)}")
|
||||||
|
app.logger.error(traceback.format_exc())
|
||||||
|
|
||||||
|
# Показываем печатную версию в браузере
|
||||||
|
return render_template(
|
||||||
|
'report_printable.html',
|
||||||
|
vin=vin,
|
||||||
|
det=det,
|
||||||
|
his=his,
|
||||||
|
report_date=report_date,
|
||||||
|
report_id=report_id,
|
||||||
|
current_year=current_year,
|
||||||
|
error_message=str(pdf_error)
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.error(traceback.format_exc())
|
||||||
|
return 'Report generation failed: ' + str(e), 500
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Start a pool of connections
|
# Start a pool of connections
|
||||||
pool = start_pool()
|
pool = start_pool()
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
flask
|
flask
|
||||||
oracledb
|
oracledb
|
||||||
cacheing
|
cacheing
|
||||||
|
reportlab
|
||||||
274
templates/report_printable.html
Normal file
274
templates/report_printable.html
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Vehicle History Report - {{report_id}}</title>
|
||||||
|
<style>
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
margin: 10mm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
border-bottom: 2px solid #333;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.header p {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.report-date {
|
||||||
|
text-align: right;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.section {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 18px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
margin-top: 50px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
.disclaimer {
|
||||||
|
font-size: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.print-controls {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
user-select: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-right: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #007bff;
|
||||||
|
border-color: #007bff;
|
||||||
|
}
|
||||||
|
.btn-secondary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #6c757d;
|
||||||
|
border-color: #6c757d;
|
||||||
|
}
|
||||||
|
.error-message {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
color: #721c24;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
}
|
||||||
|
.error-details {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function printReport() {
|
||||||
|
window.print();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generatePDF() {
|
||||||
|
// Уведомляем пользователя, что используем встроенную функцию браузера
|
||||||
|
alert("Используйте функцию 'Сохранить как PDF' в диалоговом окне печати вашего браузера.");
|
||||||
|
window.print();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="print-controls no-print">
|
||||||
|
<button class="btn btn-primary" onclick="printReport()">Print Report</button>
|
||||||
|
<button class="btn btn-secondary" onclick="generatePDF()">Save as PDF</button>
|
||||||
|
<a class="btn btn-secondary" href="javascript:history.back()">Back to Vehicle Details</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if error_message %}
|
||||||
|
<div class="error-message no-print">
|
||||||
|
<h3>PDF Generation Error</h3>
|
||||||
|
<p>The system encountered an error while generating the PDF. You can print this page or save it as PDF using your browser's print function.</p>
|
||||||
|
<div class="error-details">
|
||||||
|
{{ error_message }}
|
||||||
|
</div>
|
||||||
|
<p>Note: To install WeasyPrint dependencies on Windows, see the <a href="https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#windows" target="_blank">installation instructions</a>.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
<h1>Vehicle History Report</h1>
|
||||||
|
<p>SALVAGEDB.COM - Comprehensive Vehicle History Check</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="report-date">
|
||||||
|
<p>Report Date: {{report_date}}</p>
|
||||||
|
<p>Report ID: {{report_id}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2 class="section-title">Vehicle Information</h2>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>VIN</strong></td>
|
||||||
|
<td>{{vin}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Make</strong></td>
|
||||||
|
<td>{{det[0][1]}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Model</strong></td>
|
||||||
|
<td>{{det[0][2]}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Year</strong></td>
|
||||||
|
<td>{{det[0][3]}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Body Style</strong></td>
|
||||||
|
<td>{{det[0][4]}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Engine</strong></td>
|
||||||
|
<td>{{det[0][5]}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Cylinders</strong></td>
|
||||||
|
<td>{{det[0][6]}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Drive</strong></td>
|
||||||
|
<td>{{det[0][7]}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if his %}
|
||||||
|
<div class="section">
|
||||||
|
<h2 class="section-title">Salvage History</h2>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>VIN</th>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Odometer</th>
|
||||||
|
<th>Odometer Status</th>
|
||||||
|
<th>Primary Damage</th>
|
||||||
|
<th>Secondary Damage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for it in his %}
|
||||||
|
<tr>
|
||||||
|
<td>{{it[1]}}</td>
|
||||||
|
<td>{{it[2]}}</td>
|
||||||
|
<td>{{it[3]}}</td>
|
||||||
|
<td>{{it[4]}}</td>
|
||||||
|
<td>{{it[5]}}</td>
|
||||||
|
<td>{{it[6]}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="section">
|
||||||
|
<div class="alert-warning" style="padding: 15px; background-color: #fcf8e3; border: 1px solid #faebcc; color: #8a6d3b;">
|
||||||
|
<h2 style="font-size: 16px; margin: 0;">Salvage history not found.</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="disclaimer">
|
||||||
|
<p><strong>Disclaimer:</strong> This report provides information about salvage or junk vehicles; damage from hail, flood or fire; mileage discrepancies or odometer rollback; and gray market vehicles. We do not claim that the car got in our databank has salvage title, but the fact that it has been damaged for sure. Our site helps people avoid buying a damaged vehicle in the past.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>© {{current_year}} SalvageDB.com - All Rights Reserved</p>
|
||||||
|
<p>This report is provided as is without any guarantees or warranty. For additional assistance, please contact us.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -54,6 +54,13 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- PDF Report Download Button -->
|
||||||
|
<div class="mt-3">
|
||||||
|
<a href="/salvagereport/{{vin}}" class="btn btn-primary w-100">
|
||||||
|
<i class="fas fa-file-pdf me-2"></i> Download PDF Report
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user