Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 

388 righe
14 KiB

  1. from datetime import datetime
  2. from fastapi.responses import StreamingResponse
  3. from sqlalchemy.orm import Session
  4. from db.models.drivetask import DriveTask
  5. from db.models.user import User
  6. from db.models.fuelingtask import FuelingTask
  7. from db.models.maintenancejob import MaintenanceJob
  8. from db.repository.maintenancejob import calculate_total_cost
  9. from reportlab.lib import colors
  10. from reportlab.lib.pagesizes import letter
  11. from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Image, PageBreak
  12. from reportlab.lib.styles import getSampleStyleSheet
  13. from reportlab.lib.units import inch
  14. from reportlab.graphics.shapes import Drawing
  15. from reportlab.graphics.charts.linecharts import HorizontalLineChart
  16. from reportlab.graphics.widgets.markers import makeMarker
  17. from reportlab.platypus import Spacer
  18. from reportlab.graphics.charts.axes import CategoryAxis
  19. from dateutil import parser
  20. def get_repot_jobsdone_by_driver(driver_id: int, db: Session):
  21. driver = db.query(User).filter(User.Id == driver_id).first()
  22. if not driver:
  23. return "notdriver"
  24. if driver.Role != "Driver":
  25. return "notdriver"
  26. tasks = db.query(DriveTask).filter((DriveTask.DriverId == driver_id) & (DriveTask.Status == "Completed")).all()
  27. #order tasks by completion date
  28. tasks.sort(key=lambda x: x.EndDateTime)
  29. #for each task, add TOTAL distance driven at the time of completion
  30. dist = 0
  31. taskslist = []
  32. for task in tasks:
  33. dist += task.DistanceCovered
  34. taskslist.append(task.__dict__)
  35. taskslist[-1]["DistanceAtTime"] = dist
  36. res = {}
  37. res["tasks"] = taskslist
  38. res["Driver"] = driver.__dict__
  39. res["Driver"]["AssignedVehicle"] = driver.vehicle
  40. dist = 0
  41. for task in tasks:
  42. dist += task.DistanceCovered
  43. res["TotalDistance"] = dist
  44. timespent = 0.0
  45. for task in tasks:
  46. edate = task.EndDateTime
  47. sdate = task.StartDateTime
  48. if type(edate) == str:
  49. edate = datetime.strptime(edate, "%Y-%m-%d %H:%M:%S.%f")
  50. timetaken = edate - sdate
  51. timespent += timetaken.total_seconds()
  52. #time spent in hours and minutes
  53. hours = timespent // 3600
  54. minutes = (timespent % 3600) // 60
  55. res["TotalTime"] = str(hours) + " hours " + str(minutes) + " minutes"
  56. #add fuel expenditures
  57. fuel = db.query(FuelingTask).filter(FuelingTask.DriverId == driver_id).all()
  58. fuel.sort(key=lambda x: x.Date)
  59. totalfuelspent = 0
  60. fuelspent = []
  61. for f in fuel:
  62. fuelpoint = {}
  63. totalfuelspent += f.FuelRefilled
  64. fuelpoint["fuelrefilled"] = f.FuelRefilled
  65. fuelpoint["total"] = totalfuelspent
  66. fuelpoint["date"] = f.Date
  67. fuelspent.append(fuelpoint)
  68. res["FuelSpent"] = fuelspent
  69. res["TotalFuelSpent"] = totalfuelspent
  70. #add maintenance costs
  71. mainten = db.query(MaintenanceJob).filter(MaintenanceJob.VehicleDriverId == driver_id).all()
  72. mainten.sort(key=lambda x: x.Date)
  73. totalmaintenspent = 0
  74. maintenspent = []
  75. for m in mainten:
  76. maintenpoint = {}
  77. cost = calculate_total_cost(m.CarParts)
  78. totalmaintenspent += cost
  79. maintenpoint["cost"] = cost
  80. maintenpoint["total"] = totalmaintenspent
  81. maintenpoint["date"] = m.Date
  82. maintenspent.append(maintenpoint)
  83. res["MaintenanceSpent"] = maintenspent
  84. res["TotalMaintenanceSpent"] = totalmaintenspent
  85. return res
  86. def get_pdf(driver_id: int, db: Session):
  87. report_data = get_repot_jobsdone_by_driver(driver_id, db)
  88. if report_data == "notdriver":
  89. return "notdriver"
  90. # Assuming your report data is stored in a variable named 'report_data'
  91. # Create a PDF document
  92. pdf_filename = "report1.pdf"
  93. document = SimpleDocTemplate(pdf_filename, pagesize=letter)
  94. # Create a list to hold the contents of the PDF
  95. content = []
  96. # Add a title to the PDF
  97. title_style = getSampleStyleSheet()['Title']
  98. title = Paragraph("Driver Report", title_style)
  99. content.append(title)
  100. content.append(Paragraph("<br/>", title_style))
  101. print(report_data["Driver"])
  102. # Add detailed information about the driver
  103. driver_info = [
  104. ["Driver Name", report_data["Driver"]["Name"]],
  105. ["Last Name", report_data["Driver"]["LastName"]],
  106. ["Government ID", report_data["Driver"]["GovernmentId"]],
  107. ["Email", report_data["Driver"]["Email"]],
  108. ["Contact Number", report_data["Driver"]["ContactNumber"]],
  109. ["Address", report_data["Driver"]["Address"]],
  110. ["Role", report_data["Driver"]["Role"]],
  111. ]
  112. driver_table_style = TableStyle([
  113. ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
  114. ('BOX', (0, 0), (-1, -1), 1, colors.black),
  115. ])
  116. driver_table = Table(driver_info, style=driver_table_style)
  117. content.append(Paragraph("<br/><br/>", title_style))
  118. vehicle = report_data["Driver"]["AssignedVehicle"].__dict__
  119. print(vehicle)
  120. loc = vehicle["CurrentLocation"][0]
  121. if len(vehicle["CurrentLocation"]) > 1:
  122. loc += ", " + vehicle["CurrentLocation"][1]
  123. # Add vehicle details
  124. vehicle_info = [
  125. ["Vehicle Type", vehicle["Type"]],
  126. ["Vehicle Model", vehicle["Model"]],
  127. ["Year", vehicle["Year"]],
  128. ["License Plate", vehicle["LicensePlate"]],
  129. ["Current Location", loc],
  130. ["Mileage", vehicle["Mileage"]],
  131. ["Capacity", vehicle["Capacity"]],
  132. ]
  133. vehicle_table_style = TableStyle([
  134. ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
  135. ('BOX', (0, 0), (-1, -1), 1, colors.black),
  136. ])
  137. vehicle_table = Table(vehicle_info, style=vehicle_table_style)
  138. content.append(Spacer(1, 12)) # Add space between the tables
  139. content.append(Table([[driver_table, vehicle_table]]))
  140. content.append(Paragraph("<br/><br/>", title_style))
  141. total_info = [
  142. ["Total Tasks Done", report_data["tasks"].__len__()],
  143. ["Total Fuel Spent", report_data["TotalFuelSpent"]],
  144. ["Total Time Spent", report_data["TotalTime"]],
  145. ["Total Distance Driven", report_data["TotalDistance"]],
  146. ["Total Money Spent", report_data["TotalMaintenanceSpent"]],
  147. ]
  148. total_table_style = TableStyle([
  149. ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
  150. ('BOX', (0, 0), (-1, -1), 1, colors.black),
  151. ])
  152. total_table = Table(total_info, style=total_table_style)
  153. content.append(total_table)
  154. content.append(Paragraph("<br/><br/>", title_style))
  155. content.append(PageBreak())
  156. title_style = getSampleStyleSheet()["Heading1"]
  157. content.append(Paragraph("Driving Tasks", title_style))
  158. title_style = getSampleStyleSheet()["Heading2"]
  159. content.append(Paragraph("Distance Driven over Time", title_style))
  160. tasks_data = report_data["tasks"]
  161. if tasks_data.__len__() == 0:
  162. content.append(Paragraph("No tasks done.", title_style))
  163. else:
  164. task_values = [entry["DistanceAtTime"] for entry in tasks_data]
  165. task_dates = [parser.parse(entry['EndDateTime']).strftime("%m/%d/%Y, %H:%M:%S") for entry in tasks_data]
  166. drawing = Drawing(width=400, height=200)
  167. chart = HorizontalLineChart()
  168. chart.x = 0
  169. chart.y = 50
  170. chart.width = 500
  171. chart.height = 125
  172. chart.data = [task_values]
  173. chart.categoryAxis.labels.boxAnchor = 'e'
  174. chart.valueAxis.valueMin = 0
  175. chart.valueAxis.valueMax = max(task_values) + 10
  176. chart.lines[0].strokeColor = colors.blue
  177. chart.lines[0].strokeWidth = 2
  178. chart.categoryAxis.categoryNames = [str(date) for date in task_dates]
  179. chart.categoryAxis.labels.angle = 90
  180. drawing.add(chart)
  181. # Add space between the tables
  182. content.append(drawing)
  183. content.append(Paragraph("<br/><br/>", title_style))
  184. content.append(Paragraph("<br/><br/>", title_style))
  185. content.append(Paragraph("<br/><br/>", title_style))
  186. # Add tasks information
  187. title_style = getSampleStyleSheet()["Heading2"]
  188. content.append(Paragraph("All DriveTasks", title_style))
  189. tasks_header = ["Task ID", "Description", "Start Location", "End Location", "Distance Covered", "Status", "Start DateTime", "End DateTime"]
  190. tasks_info = []
  191. for task in tasks_data:
  192. task_info = [f"{task['Id']}", task["Description"], f"{task['StartLocation'][0]}, {task['StartLocation'][1]}", f"{task['EndLocation'][0]}, {task['EndLocation'][1]}",
  193. "{} 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")]
  194. tasks_info.append(task_info)
  195. # Define the styles
  196. styles = getSampleStyleSheet()
  197. normal_style = styles["Normal"]
  198. # Convert strings to Paragraphs to allow line breaks
  199. for row in tasks_info:
  200. for i, cell in enumerate(row):
  201. row[i] = Paragraph(cell, normal_style)
  202. tasks_table_style = TableStyle([
  203. ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
  204. ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
  205. ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
  206. ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
  207. ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
  208. ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
  209. ('GRID', (0, 0), (-1, -1), 1, colors.black),
  210. ])
  211. tasks_table = Table([tasks_header] + tasks_info, style=tasks_table_style)
  212. content.append(tasks_table)
  213. content.append(PageBreak())
  214. title_style = getSampleStyleSheet()["Heading1"]
  215. content.append(Paragraph("Fuel Spent Over Time", title_style))
  216. # Add chart of fuel spendings
  217. fuel_spent_data = report_data["FuelSpent"]
  218. if fuel_spent_data.__len__() == 0:
  219. content.append(Paragraph("No fuel spent.", title_style))
  220. else:
  221. fuel_values = [entry["total"] for entry in fuel_spent_data]
  222. fuel_dates = [entry["date"] for entry in fuel_spent_data]
  223. drawing = Drawing(width=400, height=200)
  224. chart = HorizontalLineChart()
  225. chart.x = 0
  226. chart.y = 50
  227. chart.width = 500
  228. chart.height = 125
  229. chart.data = [fuel_values]
  230. chart.categoryAxis.labels.boxAnchor = 'e'
  231. chart.valueAxis.valueMin = 0
  232. chart.valueAxis.valueMax = max(fuel_values) + 10
  233. chart.lines[0].strokeColor = colors.blue
  234. chart.lines[0].strokeWidth = 2
  235. chart.categoryAxis.categoryNames = [str(date) for date in fuel_dates]
  236. chart.categoryAxis.labels.angle = 90
  237. drawing.add(chart)
  238. # Add space between the tables
  239. content.append(drawing)
  240. content.append(Paragraph("<br/><br/>", title_style))
  241. fuel_header = ["Date", "Fuel Refilled", "Total Fuel Spent"]
  242. fuel_info = []
  243. for fuel in fuel_spent_data:
  244. fuel_info1 = [fuel["date"].strftime("%m/%d/%Y, %H:%M:%S"), "{} L".format(fuel["fuelrefilled"]), "{} L".format(fuel["total"])]
  245. fuel_info.append(fuel_info1)
  246. # Define the styles
  247. styles = getSampleStyleSheet()
  248. normal_style = styles["Normal"]
  249. # Convert strings to Paragraphs to allow line breaks
  250. for row in fuel_info:
  251. for i, cell in enumerate(row):
  252. row[i] = Paragraph(cell, normal_style)
  253. fuel_table_style = TableStyle([
  254. ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
  255. ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
  256. ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
  257. ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
  258. ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
  259. ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
  260. ('GRID', (0, 0), (-1, -1), 1, colors.black),
  261. ])
  262. fuel_table = Table([fuel_header] + fuel_info, style=fuel_table_style)
  263. content.append(fuel_table)
  264. content.append(PageBreak())
  265. title_style = getSampleStyleSheet()["Heading1"]
  266. content.append(Paragraph("Maintenance Over Time", title_style))
  267. # Add chart of fuel spendings
  268. maintenance_data = report_data["MaintenanceSpent"]
  269. if maintenance_data.__len__() == 0:
  270. content.append(Paragraph("No maintenance done.", title_style))
  271. else:
  272. maintenance_values = [entry["total"] for entry in maintenance_data]
  273. maintenance_dates = [entry["date"] for entry in maintenance_data]
  274. drawing = Drawing(width=400, height=200)
  275. chart = HorizontalLineChart()
  276. chart.x = 0
  277. chart.y = 50
  278. chart.width = 500
  279. chart.height = 125
  280. chart.data = [maintenance_values]
  281. chart.categoryAxis.labels.boxAnchor = 'e'
  282. chart.valueAxis.valueMin = 0
  283. chart.valueAxis.valueMax = max(maintenance_values) + 10
  284. chart.lines[0].strokeColor = colors.blue
  285. chart.lines[0].strokeWidth = 2
  286. chart.categoryAxis.categoryNames = [str(date) for date in maintenance_dates]
  287. chart.categoryAxis.labels.angle = 90
  288. drawing.add(chart)
  289. # Add space between the tables
  290. content.append(drawing)
  291. content.append(Paragraph("<br/><br/>", title_style))
  292. maintenance_header = ["Date", "Maintenance Cost", "Total Maintenance Cost"]
  293. maintenance_info = []
  294. for fuel in maintenance_data:
  295. fuel_info1 = [fuel["date"].strftime("%m/%d/%Y, %H:%M:%S"), "{} L".format(fuel["cost"]), "{} L".format(fuel["total"])]
  296. maintenance_info.append(fuel_info1)
  297. # Define the styles
  298. styles = getSampleStyleSheet()
  299. normal_style = styles["Normal"]
  300. # Convert strings to Paragraphs to allow line breaks
  301. for row in maintenance_info:
  302. for i, cell in enumerate(row):
  303. row[i] = Paragraph(cell, normal_style)
  304. maintenance_table_style = TableStyle([
  305. ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
  306. ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
  307. ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
  308. ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
  309. ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
  310. ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
  311. ('GRID', (0, 0), (-1, -1), 1, colors.black),
  312. ])
  313. maintenance_table = Table([maintenance_header] + maintenance_info, style=maintenance_table_style)
  314. content.append(maintenance_table)
  315. document.build(content)
  316. print(f"PDF generated successfully: {pdf_filename}")
  317. return pdf_filename