|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- from datetime import datetime
- from fastapi.responses import StreamingResponse
- from sqlalchemy.orm import Session
- from db.models.drivetask import DriveTask
-
- from db.models.user import User
- from db.models.fuelingtask import FuelingTask
- from db.models.maintenancejob import MaintenanceJob
- from db.repository.maintenancejob import calculate_total_cost
-
- from reportlab.lib import colors
- from reportlab.lib.pagesizes import letter
- from reportlab.platypus import (
- SimpleDocTemplate,
- Table,
- TableStyle,
- Paragraph,
- Image,
- PageBreak,
- )
- from reportlab.lib.styles import getSampleStyleSheet
- from reportlab.lib.units import inch
- from reportlab.graphics.shapes import Drawing
- from reportlab.graphics.charts.linecharts import HorizontalLineChart
- from reportlab.graphics.widgets.markers import makeMarker
- from reportlab.platypus import Spacer
- from reportlab.graphics.charts.axes import CategoryAxis
- from dateutil import parser
-
-
- def get_repot_jobsdone_by_driver(driver_id: int, db: Session):
- driver = db.query(User).filter(User.Id == driver_id).first()
- if not driver:
- return "notdriver"
- if driver.Role != "Driver":
- return "notdriver"
- tasks = (
- db.query(DriveTask)
- .filter((DriveTask.DriverId == driver_id) & (DriveTask.Status == "Completed"))
- .all()
- )
- # order tasks by completion date
- tasks.sort(key=lambda x: x.EndDateTime)
- # for each task, add TOTAL distance driven at the time of completion
- dist = 0
- taskslist = []
- for task in tasks:
- dist += task.DistanceCovered
- taskslist.append(task.__dict__)
- taskslist[-1]["DistanceAtTime"] = dist
- res = {}
- res["tasks"] = taskslist
- res["Driver"] = driver.__dict__
- res["Driver"]["AssignedVehicle"] = driver.vehicle
- dist = 0
- for task in tasks:
- dist += task.DistanceCovered
- res["TotalDistance"] = dist
- timespent = 0.0
-
- for task in tasks:
- edate = task.EndDateTime
- sdate = task.StartDateTime
- if edate is None or sdate is None:
- continue
- if type(edate) == str:
- edate = datetime.strptime(edate, "%Y-%m-%d %H:%M:%S.%f")
- timetaken = edate - sdate
- timespent += timetaken.total_seconds()
- # time spent in hours and minutes
- hours = timespent // 3600
- minutes = (timespent % 3600) // 60
- res["TotalTime"] = str(hours) + " hours " + str(minutes) + " minutes"
- # add fuel expenditures
- fuel = db.query(FuelingTask).filter(FuelingTask.DriverId == driver_id).all()
- fuel.sort(key=lambda x: x.Date)
- totalfuelspent = 0
- fuelspent = []
- for f in fuel:
- fuelpoint = {}
- totalfuelspent += f.FuelRefilled
- fuelpoint["fuelrefilled"] = f.FuelRefilled
- fuelpoint["total"] = totalfuelspent
- fuelpoint["date"] = f.Date
- fuelspent.append(fuelpoint)
- res["FuelSpent"] = fuelspent
- res["TotalFuelSpent"] = totalfuelspent
-
- # add maintenance costs
- mainten = (
- db.query(MaintenanceJob)
- .filter(MaintenanceJob.VehicleDriverId == driver_id)
- .all()
- )
- mainten.sort(key=lambda x: x.Date)
- totalmaintenspent = 0
- maintenspent = []
- for m in mainten:
- maintenpoint = {}
- cost = calculate_total_cost(m.CarParts)
- totalmaintenspent += cost
- maintenpoint["cost"] = cost
- maintenpoint["total"] = totalmaintenspent
- maintenpoint["date"] = m.Date
- maintenspent.append(maintenpoint)
- res["MaintenanceSpent"] = maintenspent
- res["TotalMaintenanceSpent"] = totalmaintenspent
- return res
-
-
- def get_pdf(driver_id: int, db: Session):
- report_data = get_repot_jobsdone_by_driver(driver_id, db)
- if report_data == "notdriver":
- return "notdriver"
-
- # Assuming your report data is stored in a variable named 'report_data'
-
- # Create a PDF document
- pdf_filename = "report1.pdf"
- document = SimpleDocTemplate(pdf_filename, pagesize=letter)
-
- # Create a list to hold the contents of the PDF
- content = []
-
- # Add a title to the PDF
- title_style = getSampleStyleSheet()["Title"]
- title = Paragraph("Driver Report", title_style)
- content.append(title)
- content.append(Paragraph("<br/>", title_style))
-
- # Add detailed information about the driver
- driver_info = [
- ["Driver Name", report_data["Driver"]["Name"]],
- ["Last Name", report_data["Driver"]["LastName"]],
- ["Government ID", report_data["Driver"]["GovernmentId"]],
- ["Email", report_data["Driver"]["Email"]],
- ["Contact Number", report_data["Driver"]["ContactNumber"]],
- ["Address", report_data["Driver"]["Address"]],
- ["Role", report_data["Driver"]["Role"]],
- ]
-
- driver_table_style = TableStyle(
- [
- ("ALIGN", (0, 0), (-1, -1), "LEFT"),
- ("BOX", (0, 0), (-1, -1), 1, colors.black),
- ]
- )
-
- driver_table = Table(driver_info, style=driver_table_style)
- content.append(Paragraph("<br/><br/>", title_style))
-
- vehicle = report_data["Driver"]["AssignedVehicle"].__dict__
- if (
- vehicle["CurrentLocation"] is None
- or vehicle["CurrentLocation"] == ""
- or vehicle["CurrentLocation"] == False
- or len(vehicle["CurrentLocation"]) == 0
- ):
- vehicle["CurrentLocation"] = ["Unknown", "Unknown"]
- loc = vehicle["CurrentLocation"][0]
- if len(vehicle["CurrentLocation"]) > 1:
- loc += ", " + vehicle["CurrentLocation"][1]
- # Add vehicle details
- vehicle_info = [
- ["Vehicle Type", vehicle["Type"]],
- ["Vehicle Model", vehicle["Model"]],
- ["Year", vehicle["Year"]],
- ["License Plate", vehicle["LicensePlate"]],
- ["Current Location", loc],
- ["Mileage", vehicle["Mileage"]],
- ["Capacity", vehicle["Capacity"]],
- ]
-
- vehicle_table_style = TableStyle(
- [
- ("ALIGN", (0, 0), (-1, -1), "LEFT"),
- ("BOX", (0, 0), (-1, -1), 1, colors.black),
- ]
- )
-
- vehicle_table = Table(vehicle_info, style=vehicle_table_style)
- content.append(Spacer(1, 12)) # Add space between the tables
- content.append(Table([[driver_table, vehicle_table]]))
- content.append(Paragraph("<br/><br/>", title_style))
-
- total_info = [
- ["Total Tasks Done", report_data["tasks"].__len__()],
- ["Total Fuel Spent", report_data["TotalFuelSpent"]],
- ["Total Time Spent", report_data["TotalTime"]],
- ["Total Distance Driven", report_data["TotalDistance"]],
- ["Total Money Spent", report_data["TotalMaintenanceSpent"]],
- ]
-
- total_table_style = TableStyle(
- [
- ("ALIGN", (0, 0), (-1, -1), "LEFT"),
- ("BOX", (0, 0), (-1, -1), 1, colors.black),
- ]
- )
-
- total_table = Table(total_info, style=total_table_style)
- content.append(total_table)
- content.append(Paragraph("<br/><br/>", title_style))
-
- content.append(PageBreak())
-
- title_style = getSampleStyleSheet()["Heading1"]
- content.append(Paragraph("Driving Tasks", title_style))
-
- title_style = getSampleStyleSheet()["Heading2"]
- content.append(Paragraph("Distance Driven over Time", title_style))
- tasks_data = report_data["tasks"]
- if tasks_data.__len__() == 0:
- content.append(Paragraph("No tasks done.", title_style))
- else:
- task_values = [entry["DistanceAtTime"] for entry in tasks_data]
- task_dates = [
- # if type(entry["EndDateTime"]) == str parse, else just use
- parser.parse(entry["EndDateTime"]).strftime("%m/%d/%Y, %H:%M:%S")
- if type(entry["EndDateTime"]) == str
- else entry["EndDateTime"].strftime("%m/%d/%Y, %H:%M:%S")
- for entry in tasks_data
- ]
-
- drawing = Drawing(width=400, height=200)
- chart = HorizontalLineChart()
- chart.x = 0
- chart.y = 50
- chart.width = 500
- chart.height = 125
- chart.data = [task_values]
- chart.categoryAxis.labels.boxAnchor = "e"
- chart.valueAxis.valueMin = 0
- chart.valueAxis.valueMax = max(task_values) + 10
- chart.lines[0].strokeColor = colors.blue
- chart.lines[0].strokeWidth = 2
- chart.categoryAxis.categoryNames = [str(date) for date in task_dates]
- chart.categoryAxis.labels.angle = 90
- drawing.add(chart)
-
- # Add space between the tables
- content.append(drawing)
- content.append(Paragraph("<br/><br/>", title_style))
- content.append(Paragraph("<br/><br/>", title_style))
- content.append(Paragraph("<br/><br/>", title_style))
-
- # Add tasks information
- title_style = getSampleStyleSheet()["Heading2"]
- content.append(Paragraph("All DriveTasks", title_style))
- tasks_header = [
- "Task ID",
- "Description",
- "Start Location",
- "End Location",
- "Distance Covered",
- "Status",
- "Start DateTime",
- "End DateTime",
- ]
- tasks_info = []
-
- for task in tasks_data:
- task_info = [
- f"{task['Id']}",
- task["Description"],
- f"{task['StartLocation'][0]}, {task['StartLocation'][1]}",
- f"{task['EndLocation'][0]}, {task['EndLocation'][1]}",
- "{} km".format(task["DistanceCovered"]),
- task["Status"],
- task["StartDateTime"].strftime("%m/%d/%Y, %H:%M:%S"),
- parser.parse(task["EndDateTime"]).strftime("%m/%d/%Y, %H:%M:%S")
- if type(task["EndDateTime"]) == str
- else task["EndDateTime"].strftime("%m/%d/%Y, %H:%M:%S"),
- ]
- tasks_info.append(task_info)
-
- # Define the styles
- styles = getSampleStyleSheet()
- normal_style = styles["Normal"]
-
- # Convert strings to Paragraphs to allow line breaks
- for row in tasks_info:
- for i, cell in enumerate(row):
- row[i] = Paragraph(cell, normal_style)
-
- tasks_table_style = TableStyle(
- [
- ("BACKGROUND", (0, 0), (-1, 0), colors.grey),
- ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
- ("ALIGN", (0, 0), (-1, -1), "CENTER"),
- ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
- ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
- ("BACKGROUND", (0, 1), (-1, -1), colors.beige),
- ("GRID", (0, 0), (-1, -1), 1, colors.black),
- ]
- )
-
- tasks_table = Table([tasks_header] + tasks_info, style=tasks_table_style)
- content.append(tasks_table)
-
- content.append(PageBreak())
-
- title_style = getSampleStyleSheet()["Heading1"]
- content.append(Paragraph("Fuel Spent Over Time", title_style))
- # Add chart of fuel spendings
- fuel_spent_data = report_data["FuelSpent"]
- if fuel_spent_data.__len__() == 0:
- content.append(Paragraph("No fuel spent.", title_style))
- else:
- fuel_values = [entry["total"] for entry in fuel_spent_data]
- fuel_dates = [entry["date"] for entry in fuel_spent_data]
-
- drawing = Drawing(width=400, height=200)
- chart = HorizontalLineChart()
- chart.x = 0
- chart.y = 50
- chart.width = 500
- chart.height = 125
- chart.data = [fuel_values]
- chart.categoryAxis.labels.boxAnchor = "e"
- chart.valueAxis.valueMin = 0
- chart.valueAxis.valueMax = max(fuel_values) + 10
- chart.lines[0].strokeColor = colors.blue
- chart.lines[0].strokeWidth = 2
- chart.categoryAxis.categoryNames = [str(date) for date in fuel_dates]
- chart.categoryAxis.labels.angle = 90
- drawing.add(chart)
-
- # Add space between the tables
- content.append(drawing)
- content.append(Paragraph("<br/><br/>", title_style))
-
- fuel_header = ["Date", "Fuel Refilled", "Total Fuel Spent"]
- fuel_info = []
-
- for fuel in fuel_spent_data:
- fuel_info1 = [
- fuel["date"].strftime("%m/%d/%Y, %H:%M:%S"),
- "{} L".format(fuel["fuelrefilled"]),
- "{} L".format(fuel["total"]),
- ]
- fuel_info.append(fuel_info1)
-
- # Define the styles
- styles = getSampleStyleSheet()
- normal_style = styles["Normal"]
-
- # Convert strings to Paragraphs to allow line breaks
- for row in fuel_info:
- for i, cell in enumerate(row):
- row[i] = Paragraph(cell, normal_style)
-
- fuel_table_style = TableStyle(
- [
- ("BACKGROUND", (0, 0), (-1, 0), colors.grey),
- ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
- ("ALIGN", (0, 0), (-1, -1), "CENTER"),
- ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
- ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
- ("BACKGROUND", (0, 1), (-1, -1), colors.beige),
- ("GRID", (0, 0), (-1, -1), 1, colors.black),
- ]
- )
-
- fuel_table = Table([fuel_header] + fuel_info, style=fuel_table_style)
- content.append(fuel_table)
-
- content.append(PageBreak())
-
- title_style = getSampleStyleSheet()["Heading1"]
- content.append(Paragraph("Maintenance Over Time", title_style))
- # Add chart of fuel spendings
- maintenance_data = report_data["MaintenanceSpent"]
- if maintenance_data.__len__() == 0:
- content.append(Paragraph("No maintenance done.", title_style))
- else:
- maintenance_values = [entry["total"] for entry in maintenance_data]
- maintenance_dates = [entry["date"] for entry in maintenance_data]
-
- drawing = Drawing(width=400, height=200)
- chart = HorizontalLineChart()
- chart.x = 0
- chart.y = 50
- chart.width = 500
- chart.height = 125
- chart.data = [maintenance_values]
- chart.categoryAxis.labels.boxAnchor = "e"
- chart.valueAxis.valueMin = 0
- chart.valueAxis.valueMax = max(maintenance_values) + 10
- chart.lines[0].strokeColor = colors.blue
- chart.lines[0].strokeWidth = 2
- chart.categoryAxis.categoryNames = [str(date) for date in maintenance_dates]
- chart.categoryAxis.labels.angle = 90
- drawing.add(chart)
-
- # Add space between the tables
- content.append(drawing)
- content.append(Paragraph("<br/><br/>", title_style))
-
- maintenance_header = ["Date", "Maintenance Cost", "Total Maintenance Cost"]
- maintenance_info = []
-
- for fuel in maintenance_data:
- fuel_info1 = [
- fuel["date"].strftime("%m/%d/%Y, %H:%M:%S"),
- "{} L".format(fuel["cost"]),
- "{} L".format(fuel["total"]),
- ]
- maintenance_info.append(fuel_info1)
-
- # Define the styles
- styles = getSampleStyleSheet()
- normal_style = styles["Normal"]
-
- # Convert strings to Paragraphs to allow line breaks
- for row in maintenance_info:
- for i, cell in enumerate(row):
- row[i] = Paragraph(cell, normal_style)
-
- maintenance_table_style = TableStyle(
- [
- ("BACKGROUND", (0, 0), (-1, 0), colors.grey),
- ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
- ("ALIGN", (0, 0), (-1, -1), "CENTER"),
- ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
- ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
- ("BACKGROUND", (0, 1), (-1, -1), colors.beige),
- ("GRID", (0, 0), (-1, -1), 1, colors.black),
- ]
- )
-
- maintenance_table = Table(
- [maintenance_header] + maintenance_info, style=maintenance_table_style
- )
- content.append(maintenance_table)
-
- document.build(content)
-
- print(f"PDF generated successfully: {pdf_filename}")
-
- return pdf_filename
|