| @@ -9,6 +9,7 @@ from apis.v1 import ( | |||
| route_maintenancejob, | |||
| route_fuelingtask, | |||
| route_auction, | |||
| route_report | |||
| ) | |||
| 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_auction.router, prefix="/auction", tags=["auctions"]) | |||
| api_router.include_router(route_report.router, prefix="/report", tags=["reports"]) | |||
| @@ -12,9 +12,9 @@ from apis.v1.route_auth import get_current_user | |||
| router = APIRouter() | |||
| @router.post("/", status_code=status.HTTP_201_CREATED) | |||
| @router.post("/", response_model=OutputFuelingTask, status_code=status.HTTP_201_CREATED) | |||
| def create_fuelingtask( | |||
| fuelingtask: CreateFuelingTask, | |||
| fuelingtask: CreateFuelingTask = Depends(), | |||
| db: Session = Depends(get_db), | |||
| current_user: User = Depends(get_current_user), | |||
| ): | |||
| @@ -26,7 +26,7 @@ def create_fuelingtask( | |||
| fuelingtask_res = create_fueling_task( | |||
| fueling_task=fuelingtask, current_user=current_user.Id, db=db | |||
| ) | |||
| print("Created FuelTask") | |||
| if fuelingtask_res == "nodriver": | |||
| raise HTTPException( | |||
| status_code=404, detail="Driver ID not found" | |||
| @@ -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 | |||
| @@ -43,6 +43,7 @@ def create_task( | |||
| def changeStatus( | |||
| task_id: int, | |||
| status: str, | |||
| distance: float = 0, | |||
| db: Session = Depends(get_db), | |||
| current_user: User = Depends(get_current_user), | |||
| ): | |||
| @@ -59,7 +60,7 @@ def changeStatus( | |||
| status_code=403, | |||
| 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": | |||
| raise HTTPException( | |||
| status_code=404, detail=f"Task with id {task_id} not found" | |||
| @@ -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 sqlalchemy.orm import relationship | |||
| @@ -11,4 +11,6 @@ class DriveTask(Base): | |||
| Status = Column(String, nullable=False) | |||
| StartLocation = 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) | |||
| @@ -7,9 +7,10 @@ class MaintenanceJob(Base): | |||
| Id = Column(Integer, primary_key=True, index=True) | |||
| # a list of weak entities of class CarPart | |||
| 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) | |||
| Vehicle = relationship("Vehicle", back_populates="maintenanceJobs") | |||
| VehicleDriverId = Column(ForeignKey("user.Id"), nullable=False) | |||
| Description = Column(String, nullable=False) | |||
| Date = Column(DateTime, nullable=False) | |||
| MaintenanceWorker = Column(ForeignKey("user.Id"), nullable=False) | |||
| @@ -25,7 +25,7 @@ class User(Base): | |||
| driveTasks = relationship("DriveTask", back_populates="CreatedBy") | |||
| vehicle = relationship("Vehicle", back_populates="driver") | |||
| #MaintenancePerson-specific relationships | |||
| maintenanceJobs = relationship("MaintenanceJob", back_populates="CreatedBy") | |||
| maintenanceJobs = relationship("MaintenanceJob", back_populates="CreatedBy", foreign_keys="MaintenanceJob.MaintenanceWorker") | |||
| #FuelingPerson-specific relationships | |||
| fuelingTasks = relationship("FuelingTask", back_populates="CreatedBy", foreign_keys="FuelingTask.CreatedById") | |||
| @@ -1,3 +1,4 @@ | |||
| from datetime import datetime | |||
| from sqlalchemy.orm import Session | |||
| from schemas.drivetask import CreateTask | |||
| @@ -24,16 +25,16 @@ def create_new_task(task: CreateTask, db: Session): | |||
| 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() | |||
| if not task: | |||
| return "notaskfound" | |||
| if status == "In Progress": | |||
| # 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 | |||
| db.commit() | |||
| db.refresh(task) | |||
| @@ -1,7 +1,8 @@ | |||
| import base64 | |||
| from sqlalchemy.orm import Session | |||
| from schemas.fuelingtask import CreateFuelingTask | |||
| from schemas.fuelingtask import CreateFuelingTask, OutputFuelingTask | |||
| from db.models.fuelingtask import FuelingTask | |||
| from db.repository.user import get_car_driver, get_user_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, | |||
| FuelRefilled=fueling_task.FuelRefilled, | |||
| 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.commit() | |||
| 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 | |||
| @@ -49,6 +54,12 @@ def get_fueling_task_by_id(fuel_task_id: int, db: Session): | |||
| res = fuel_task.__dict__ | |||
| driver = get_user_by_id(fuel_task.DriverId, role="Driver", db=db) | |||
| 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"]["AssignedVehicle"] = driver.vehicle | |||
| return fuel_task | |||
| return res | |||
| @@ -1,8 +1,10 @@ | |||
| import base64 | |||
| from sqlalchemy.orm import Session | |||
| from schemas.maintenancejob import CreateMaintenanceJob | |||
| from db.models.maintenancejob import MaintenanceJob | |||
| from schemas.carpart import CreateCarPart | |||
| from db.models.carpart import CarPart | |||
| from db.repository.user import get_car_driver | |||
| def create_new_maintenancejob( | |||
| @@ -13,6 +15,7 @@ def create_new_maintenancejob( | |||
| Description=maintenancejob.Description, | |||
| VehicleID=maintenancejob.VehicleID, | |||
| Date=maintenancejob.Date, | |||
| VehicleDriverId=get_car_driver(maintenancejob.VehicleID, db).Id, | |||
| ) | |||
| print("OBJECT CREATED") | |||
| db.add(maintenancejob_object) | |||
| @@ -36,7 +39,9 @@ def create_car_part(car_part: CreateCarPart, db: Session): | |||
| print("OBJECT SAVED") | |||
| db.refresh(car_part_object) | |||
| 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): | |||
| @@ -52,6 +57,8 @@ def get_all_maintenance_jobs(db: Session): | |||
| for job in maintenancejobs: | |||
| job_dict = job.__dict__ | |||
| 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["AssignedTo"] = job.CreatedBy.__dict__ | |||
| job_dict["Vehicle"] = job.Vehicle.__dict__ | |||
| @@ -63,13 +70,16 @@ def get_maintenance_job(maintenancejob_id: int, db: Session): | |||
| maintenancejob = ( | |||
| 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)) | |||
| maintenancejob.TotalCost = calculate_total_cost(maintenancejob.CarParts) | |||
| res["TotalCost"] = calculate_total_cost(maintenancejob.CarParts) | |||
| # 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") | |||
| return maintenancejob | |||
| @@ -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 | |||
| @@ -21,3 +21,4 @@ class ShowCarPart(BaseModel): | |||
| Number: str = Field(...) | |||
| Condition: str = Field(...) | |||
| Cost: int = Field(...) | |||
| image: str = Field(...) | |||
| @@ -19,6 +19,8 @@ class ShowTask(BaseModel): | |||
| StartLocation: tuple[str, str] | |||
| EndLocation: tuple[str, str] | |||
| StartDateTime: Optional[datetime] | |||
| DistanceCovered: Optional[float] | |||
| EndDateTime: Optional[datetime] | |||
| class Config: | |||
| orm_mode = True | |||
| @@ -1,16 +1,17 @@ | |||
| from pydantic import BaseModel, Field | |||
| from fastapi import Form, UploadFile | |||
| from datetime import datetime | |||
| from schemas.user import ShowDriver | |||
| 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={ | |||
| "arbitrary_types_allowed": True | |||
| } | |||
| @@ -22,9 +23,9 @@ class OutputFuelingTask(BaseModel): | |||
| Cost: int = Field(...) | |||
| FuelRefilled: int = Field(...) | |||
| GasStationName: str = Field(...) | |||
| ImageBefore: bytearray = Field(...) | |||
| ImageAfter: bytearray = Field(...) | |||
| Driver: ShowDriver | None | |||
| ImageBefore: str = Field(...) | |||
| ImageAfter: str = Field(...) | |||
| model_config={ | |||
| "arbitrary_types_allowed": True | |||
| } | |||
| @@ -9,6 +9,7 @@ from schemas.vehicle import OutputVehicle | |||
| class CreateMaintenanceJob(BaseModel): | |||
| Description: str = Field(...) | |||
| VehicleID: int = Field(...) | |||
| VehicleDriverId: int = Field(...) | |||
| Date: datetime = Field(...) | |||