| @@ -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"]) | |||||
| @@ -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" | ||||
| @@ -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( | 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" | ||||
| @@ -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) | |||||
| @@ -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) | ||||
| @@ -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") | ||||
| @@ -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) | ||||
| @@ -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 | |||||
| @@ -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 | ||||
| @@ -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(...) | Number: str = Field(...) | ||||
| Condition: str = Field(...) | Condition: str = Field(...) | ||||
| Cost: int = Field(...) | Cost: int = Field(...) | ||||
| image: str = Field(...) | |||||
| @@ -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 | ||||
| @@ -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 | ||||
| } | } | ||||
| @@ -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(...) | ||||