Browse Source

added reports

main
Madiwka 1 year ago
parent
commit
f9b3fe31a2
15 changed files with 166 additions and 33 deletions
  1. +2
    -0
      app/apis/base.py
  2. +3
    -3
      app/apis/v1/route_fuelingtask.py
  3. +22
    -0
      app/apis/v1/route_report.py
  4. +2
    -1
      app/apis/v1/route_task.py
  5. +4
    -2
      app/db/models/drivetask.py
  6. +2
    -1
      app/db/models/maintenancejob.py
  7. +1
    -1
      app/db/models/user.py
  8. +6
    -5
      app/db/repository/drivetask.py
  9. +15
    -4
      app/db/repository/fuelingtask.py
  10. +16
    -6
      app/db/repository/maintenancejob.py
  11. +78
    -0
      app/db/repository/report.py
  12. +1
    -0
      app/schemas/carpart.py
  13. +2
    -0
      app/schemas/drivetask.py
  14. +11
    -10
      app/schemas/fuelingtask.py
  15. +1
    -0
      app/schemas/maintenancejob.py

+ 2
- 0
app/apis/base.py View File

@@ -9,6 +9,7 @@ from apis.v1 import (
route_maintenancejob, route_maintenancejob,
route_fuelingtask, route_fuelingtask,
route_auction, route_auction,
route_report
) )


api_router = APIRouter() api_router = APIRouter()
@@ -21,3 +22,4 @@ api_router.include_router(
) )
api_router.include_router(route_fuelingtask.router, prefix="/fuel", tags=["fueltasks"]) api_router.include_router(route_fuelingtask.router, prefix="/fuel", tags=["fueltasks"])
api_router.include_router(route_auction.router, prefix="/auction", tags=["auctions"]) api_router.include_router(route_auction.router, prefix="/auction", tags=["auctions"])
api_router.include_router(route_report.router, prefix="/report", tags=["reports"])

+ 3
- 3
app/apis/v1/route_fuelingtask.py View File

@@ -12,9 +12,9 @@ from apis.v1.route_auth import get_current_user


router = APIRouter() router = APIRouter()


@router.post("/", status_code=status.HTTP_201_CREATED)
@router.post("/", response_model=OutputFuelingTask, status_code=status.HTTP_201_CREATED)
def create_fuelingtask( def create_fuelingtask(
fuelingtask: CreateFuelingTask,
fuelingtask: CreateFuelingTask = Depends(),
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
): ):
@@ -26,7 +26,7 @@ def create_fuelingtask(
fuelingtask_res = create_fueling_task( fuelingtask_res = create_fueling_task(
fueling_task=fuelingtask, current_user=current_user.Id, db=db fueling_task=fuelingtask, current_user=current_user.Id, db=db
) )
print("Created FuelTask")
if fuelingtask_res == "nodriver": if fuelingtask_res == "nodriver":
raise HTTPException( raise HTTPException(
status_code=404, detail="Driver ID not found" status_code=404, detail="Driver ID not found"


+ 22
- 0
app/apis/v1/route_report.py View File

@@ -0,0 +1,22 @@
from fastapi import Depends, APIRouter, HTTPException, status
from requests import Session
from apis.v1.route_auth import get_current_user
from db.models.user import User
from db.repository.report import get_repot_jobsdone_by_driver

from db.session import get_db

router = APIRouter()

@router.get("/jobsdone/{driver_id}", status_code=status.HTTP_200_OK)
def get_report_jobsdone(driver_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
if current_user.Role != "Admin":
raise HTTPException(
status_code=403, detail="You are not authorized to perform this action"
)
report = get_repot_jobsdone_by_driver(driver_id, db)
if report == "notdriver":
raise HTTPException(
status_code=404, detail=f"Driver with id {driver_id} not found"
)
return report

+ 2
- 1
app/apis/v1/route_task.py View File

@@ -43,6 +43,7 @@ def create_task(
def changeStatus( def changeStatus(
task_id: int, task_id: int,
status: str, status: str,
distance: float = 0,
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
): ):
@@ -59,7 +60,7 @@ def changeStatus(
status_code=403, status_code=403,
detail="You are not authorized to perform this action", detail="You are not authorized to perform this action",
) )
task = change_task_status(task_id, status, db)
task = change_task_status(task_id, status, distance, db)
if task == "notaskfound": if task == "notaskfound":
raise HTTPException( raise HTTPException(
status_code=404, detail=f"Task with id {task_id} not found" status_code=404, detail=f"Task with id {task_id} not found"


+ 4
- 2
app/db/models/drivetask.py View File

@@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String, ForeignKey, ARRAY, DateTime
from sqlalchemy import Column, Double, Integer, String, ForeignKey, ARRAY, DateTime
from db.base import Base from db.base import Base
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship


@@ -11,4 +11,6 @@ class DriveTask(Base):
Status = Column(String, nullable=False) Status = Column(String, nullable=False)
StartLocation = Column(ARRAY(String), nullable=False) StartLocation = Column(ARRAY(String), nullable=False)
EndLocation = Column(ARRAY(String), nullable=False) EndLocation = Column(ARRAY(String), nullable=False)
StartDateTime = Column(DateTime, nullable=False)
StartDateTime = Column(DateTime, nullable=True)
DistanceCovered = Column(Double, nullable=True)
EndDateTime = Column(DateTime, nullable=True)

+ 2
- 1
app/db/models/maintenancejob.py View File

@@ -7,9 +7,10 @@ class MaintenanceJob(Base):
Id = Column(Integer, primary_key=True, index=True) Id = Column(Integer, primary_key=True, index=True)
# a list of weak entities of class CarPart # a list of weak entities of class CarPart
CarParts = relationship("CarPart", back_populates="parent") CarParts = relationship("CarPart", back_populates="parent")
CreatedBy = relationship("User", back_populates="maintenanceJobs")
CreatedBy = relationship("User", back_populates="maintenanceJobs", foreign_keys="MaintenanceJob.MaintenanceWorker")
VehicleID = Column(ForeignKey("vehicle.Id"), nullable=False) VehicleID = Column(ForeignKey("vehicle.Id"), nullable=False)
Vehicle = relationship("Vehicle", back_populates="maintenanceJobs") Vehicle = relationship("Vehicle", back_populates="maintenanceJobs")
VehicleDriverId = Column(ForeignKey("user.Id"), nullable=False)
Description = Column(String, nullable=False) Description = Column(String, nullable=False)
Date = Column(DateTime, nullable=False) Date = Column(DateTime, nullable=False)
MaintenanceWorker = Column(ForeignKey("user.Id"), nullable=False) MaintenanceWorker = Column(ForeignKey("user.Id"), nullable=False)

+ 1
- 1
app/db/models/user.py View File

@@ -25,7 +25,7 @@ class User(Base):
driveTasks = relationship("DriveTask", back_populates="CreatedBy") driveTasks = relationship("DriveTask", back_populates="CreatedBy")
vehicle = relationship("Vehicle", back_populates="driver") vehicle = relationship("Vehicle", back_populates="driver")
#MaintenancePerson-specific relationships #MaintenancePerson-specific relationships
maintenanceJobs = relationship("MaintenanceJob", back_populates="CreatedBy")
maintenanceJobs = relationship("MaintenanceJob", back_populates="CreatedBy", foreign_keys="MaintenanceJob.MaintenanceWorker")
#FuelingPerson-specific relationships #FuelingPerson-specific relationships
fuelingTasks = relationship("FuelingTask", back_populates="CreatedBy", foreign_keys="FuelingTask.CreatedById") fuelingTasks = relationship("FuelingTask", back_populates="CreatedBy", foreign_keys="FuelingTask.CreatedById")



+ 6
- 5
app/db/repository/drivetask.py View File

@@ -1,3 +1,4 @@
from datetime import datetime
from sqlalchemy.orm import Session from sqlalchemy.orm import Session


from schemas.drivetask import CreateTask from schemas.drivetask import CreateTask
@@ -24,16 +25,16 @@ def create_new_task(task: CreateTask, db: Session):
return task_object return task_object




def change_task_status(task_id: int, status: str, db: Session):
def change_task_status(task_id: int, status: str, distance: int, db: Session):
task = db.query(DriveTask).filter(DriveTask.Id == task_id).first() task = db.query(DriveTask).filter(DriveTask.Id == task_id).first()
if not task: if not task:
return "notaskfound" return "notaskfound"
if status == "In Progress": if status == "In Progress":
# see if there are any other tasks in progress by this driver, if yes, cancel # see if there are any other tasks in progress by this driver, if yes, cancel
tasks = db.query(DriveTask).filter(DriveTask.DriverId == task.DriverId).all()
for task in tasks:
if task.Status == "In Progress":
return "driverhasothertask"
task.StartDateTime = datetime.now()
if status == "Completed":
task.DistanceCovered = distance
task.EndDateTime = datetime.now()
task.Status = status task.Status = status
db.commit() db.commit()
db.refresh(task) db.refresh(task)


+ 15
- 4
app/db/repository/fuelingtask.py View File

@@ -1,7 +1,8 @@
import base64
from sqlalchemy.orm import Session from sqlalchemy.orm import Session




from schemas.fuelingtask import CreateFuelingTask
from schemas.fuelingtask import CreateFuelingTask, OutputFuelingTask
from db.models.fuelingtask import FuelingTask from db.models.fuelingtask import FuelingTask
from db.repository.user import get_car_driver, get_user_by_id from db.repository.user import get_car_driver, get_user_by_id
from db.repository.vehicle import get_vehicle_by_id from db.repository.vehicle import get_vehicle_by_id
@@ -25,12 +26,16 @@ def create_fueling_task(fueling_task: CreateFuelingTask, current_user: int, db:
Cost=fueling_task.Cost, Cost=fueling_task.Cost,
FuelRefilled=fueling_task.FuelRefilled, FuelRefilled=fueling_task.FuelRefilled,
GasStationName=fueling_task.GasStationName, GasStationName=fueling_task.GasStationName,
ImageBefore=fueling_task.ImageBefore,
ImageAfter=fueling_task.ImageAfter,
ImageBefore=fueling_task.ImageBefore.file.read(),
ImageAfter=fueling_task.ImageAfter.file.read(),
) )
db.add(fueling_task_object) db.add(fueling_task_object)
db.commit() db.commit()
db.refresh(fueling_task_object) db.refresh(fueling_task_object)
print(driver.__dict__)
driverobj = driver.__dict__
driverobj["AssignedVehicle"] = driver.vehicle.__dict__
fueling_task_object.Driver = driverobj
return fueling_task_object return fueling_task_object




@@ -49,6 +54,12 @@ def get_fueling_task_by_id(fuel_task_id: int, db: Session):
res = fuel_task.__dict__ res = fuel_task.__dict__
driver = get_user_by_id(fuel_task.DriverId, role="Driver", db=db) driver = get_user_by_id(fuel_task.DriverId, role="Driver", db=db)
driver_obj = driver.__dict__ driver_obj = driver.__dict__
imagebefore = fuel_task.ImageBefore
imageafter = fuel_task.ImageAfter
imagebeforeBase64 = base64.b64encode(imagebefore).decode('ascii')
imageafterBase64 = base64.b64encode(imageafter).decode('ascii')
res["ImageBefore"] = imagebeforeBase64
res["ImageAfter"] = imageafterBase64
res["Driver"] = driver_obj res["Driver"] = driver_obj
res["Driver"]["AssignedVehicle"] = driver.vehicle res["Driver"]["AssignedVehicle"] = driver.vehicle
return fuel_task
return res

+ 16
- 6
app/db/repository/maintenancejob.py View File

@@ -1,8 +1,10 @@
import base64
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from schemas.maintenancejob import CreateMaintenanceJob from schemas.maintenancejob import CreateMaintenanceJob
from db.models.maintenancejob import MaintenanceJob from db.models.maintenancejob import MaintenanceJob
from schemas.carpart import CreateCarPart from schemas.carpart import CreateCarPart
from db.models.carpart import CarPart from db.models.carpart import CarPart
from db.repository.user import get_car_driver




def create_new_maintenancejob( def create_new_maintenancejob(
@@ -13,6 +15,7 @@ def create_new_maintenancejob(
Description=maintenancejob.Description, Description=maintenancejob.Description,
VehicleID=maintenancejob.VehicleID, VehicleID=maintenancejob.VehicleID,
Date=maintenancejob.Date, Date=maintenancejob.Date,
VehicleDriverId=get_car_driver(maintenancejob.VehicleID, db).Id,
) )
print("OBJECT CREATED") print("OBJECT CREATED")
db.add(maintenancejob_object) db.add(maintenancejob_object)
@@ -36,7 +39,9 @@ def create_car_part(car_part: CreateCarPart, db: Session):
print("OBJECT SAVED") print("OBJECT SAVED")
db.refresh(car_part_object) db.refresh(car_part_object)
print("OBJECT REFRESHED") print("OBJECT REFRESHED")
return car_part_object
res_obj = car_part_object.__dict__
res_obj["image"] = base64.b64encode(car_part_object.ImageURL).decode("ascii")
return res_obj




def calculate_total_cost(car_parts: CarPart): def calculate_total_cost(car_parts: CarPart):
@@ -52,6 +57,8 @@ def get_all_maintenance_jobs(db: Session):
for job in maintenancejobs: for job in maintenancejobs:
job_dict = job.__dict__ job_dict = job.__dict__
job_dict["CarPartsList"] = [part.__dict__ for part in job.CarParts] job_dict["CarPartsList"] = [part.__dict__ for part in job.CarParts]
for part in job_dict["CarPartsList"]:
part["image"] = base64.b64encode(part["ImageURL"]).decode("ascii")
job_dict["TotalCost"] = calculate_total_cost(job.CarParts) job_dict["TotalCost"] = calculate_total_cost(job.CarParts)
job_dict["AssignedTo"] = job.CreatedBy.__dict__ job_dict["AssignedTo"] = job.CreatedBy.__dict__
job_dict["Vehicle"] = job.Vehicle.__dict__ job_dict["Vehicle"] = job.Vehicle.__dict__
@@ -63,13 +70,16 @@ def get_maintenance_job(maintenancejob_id: int, db: Session):
maintenancejob = ( maintenancejob = (
db.query(MaintenanceJob).filter(MaintenanceJob.Id == maintenancejob_id).first() db.query(MaintenanceJob).filter(MaintenanceJob.Id == maintenancejob_id).first()
) )
maintenancejob.CarPartsList = [part.__dict__ for part in maintenancejob.CarParts]
res = maintenancejob.__dict__
res["CarPartsList"] = [part.__dict__ for part in maintenancejob.CarParts]
for part in maintenancejob.CarPartsList:
part["image"] = base64.b64encode(part["ImageURL"]).decode("ascii")
# print(type(result.CarPartsList)) # print(type(result.CarPartsList))
maintenancejob.TotalCost = calculate_total_cost(maintenancejob.CarParts)
res["TotalCost"] = calculate_total_cost(maintenancejob.CarParts)
# print(result.TotalCost) # print(result.TotalCost)
maintenancejob.AssignedTo = maintenancejob.CreatedBy.__dict__
maintenancejob.Vehicle = maintenancejob.Vehicle.__dict__
print(maintenancejob.AssignedTo)
res["AssignedTo"] = maintenancejob.CreatedBy.__dict__
res["Vehicle"] = maintenancejob.Vehicle.__dict__
print("DB Access complete") print("DB Access complete")
return maintenancejob return maintenancejob




+ 78
- 0
app/db/repository/report.py View File

@@ -0,0 +1,78 @@
from datetime import datetime
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


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 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

+ 1
- 0
app/schemas/carpart.py View File

@@ -21,3 +21,4 @@ class ShowCarPart(BaseModel):
Number: str = Field(...) Number: str = Field(...)
Condition: str = Field(...) Condition: str = Field(...)
Cost: int = Field(...) Cost: int = Field(...)
image: str = Field(...)

+ 2
- 0
app/schemas/drivetask.py View File

@@ -19,6 +19,8 @@ class ShowTask(BaseModel):
StartLocation: tuple[str, str] StartLocation: tuple[str, str]
EndLocation: tuple[str, str] EndLocation: tuple[str, str]
StartDateTime: Optional[datetime] StartDateTime: Optional[datetime]
DistanceCovered: Optional[float]
EndDateTime: Optional[datetime]


class Config: class Config:
orm_mode = True orm_mode = True

+ 11
- 10
app/schemas/fuelingtask.py View File

@@ -1,16 +1,17 @@
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from fastapi import Form, UploadFile
from datetime import datetime from datetime import datetime
from schemas.user import ShowDriver from schemas.user import ShowDriver


class CreateFuelingTask(BaseModel): class CreateFuelingTask(BaseModel):
VehicleId: int = Field(...)
Description: str = Field(...)
Date: datetime = Field(...)
Cost: int = Field(...)
FuelRefilled: int = Field(...)
GasStationName: str = Field(...)
ImageBefore: bytearray = Field(...)
ImageAfter: bytearray = Field(...)
VehicleId: int = Form(...)
Description: str = Form(...)
Date: datetime = Form(...)
Cost: int = Form(...)
FuelRefilled: int = Form(...)
GasStationName: str = Form(...)
ImageBefore: UploadFile = Form(...)
ImageAfter: UploadFile = Form(...)
model_config={ model_config={
"arbitrary_types_allowed": True "arbitrary_types_allowed": True
} }
@@ -22,9 +23,9 @@ class OutputFuelingTask(BaseModel):
Cost: int = Field(...) Cost: int = Field(...)
FuelRefilled: int = Field(...) FuelRefilled: int = Field(...)
GasStationName: str = Field(...) GasStationName: str = Field(...)
ImageBefore: bytearray = Field(...)
ImageAfter: bytearray = Field(...)
Driver: ShowDriver | None Driver: ShowDriver | None
ImageBefore: str = Field(...)
ImageAfter: str = Field(...)
model_config={ model_config={
"arbitrary_types_allowed": True "arbitrary_types_allowed": True
} }

+ 1
- 0
app/schemas/maintenancejob.py View File

@@ -9,6 +9,7 @@ from schemas.vehicle import OutputVehicle
class CreateMaintenanceJob(BaseModel): class CreateMaintenanceJob(BaseModel):
Description: str = Field(...) Description: str = Field(...)
VehicleID: int = Field(...) VehicleID: int = Field(...)
VehicleDriverId: int = Field(...)
Date: datetime = Field(...) Date: datetime = Field(...)






Loading…
Cancel
Save