fix overhaul equipments

feature/reliability_stat
Cizz22 1 year ago
parent 9204d75de3
commit 93158c0055

@ -7,17 +7,23 @@ from pydantic import BaseModel
from src.auth.service import JWTBearer from src.auth.service import JWTBearer
from src.scope.router import router as scope_router # from src.overhaul_scope.router import router as scope_router
from src.scope_equipment.router import router as scope_equipment_router # from src.scope_equipment.router import router as scope_equipment_router
from src.overhaul.router import router as overhaul_router # from src.overhaul.router import router as overhaul_router
from src.calculation_time_constrains.router import router as calculation_time_constrains_router # from src.calculation_time_constrains.router import router as calculation_time_constrains_router
from src.overhaul_history.router import router as overhaul_history_router # from src.overhaul_history.router import router as overhaul_history_router
from src.scope_equipment_activity.router import router as scope_equipment_activity_router # from src.overhaul_activity.router import router as scope_equipment_activity_router
from src.overhaul_schedule.router import router as ovehaul_schedule_router # # from src.overhaul_schedule.router import router as ovehaul_schedule_router
from src.scope_equipment_part.router import router as scope_equipment_part_router # from src.scope_equipment_part.router import router as scope_equipment_part_router
from src.calculation_target_reliability.router import router as calculation_target_reliability # from src.calculation_target_reliability.router import router as calculation_target_reliability
from src.calculation_budget_constrains.router import router as calculation_budget_constraint # from src.calculation_budget_constrains.router import router as calculation_budget_constraint
# from src.master_activity.router import router as activity_router
from src.overhaul.router import router as overhaul_router
from src.scope_equipment.router import router as scope_equipment_router
from src.overhaul_scope.router import router as scope_router
from src.overhaul_activity.router import router as overhaul_activity_router
class ErrorMessage(BaseModel): class ErrorMessage(BaseModel):
msg: str msg: str
@ -51,49 +57,57 @@ authenticated_api_router.include_router(
overhaul_router, prefix="/overhauls", tags=["overhaul"]) overhaul_router, prefix="/overhauls", tags=["overhaul"])
# Scope data # # Overhaul session data
authenticated_api_router.include_router( authenticated_api_router.include_router(
scope_router, prefix="/scopes", tags=["scope"]) scope_router, prefix="/overhaul-session", tags=["overhaul-session"])
authenticated_api_router.include_router( authenticated_api_router.include_router(
scope_equipment_router, prefix="/scope-equipments", tags=["scope_equipment"] scope_equipment_router, prefix="/scope-equipments", tags=["scope_equipment"]
) )
authenticated_api_router.include_router( authenticated_api_router.include_router(
overhaul_history_router, prefix="/overhaul-history", tags=["overhaul_history"] overhaul_activity_router, prefix="/overhaul-activity", tags=["activity"]
) )
authenticated_api_router.include_router( # authenticated_api_router.include_router(
scope_equipment_activity_router, prefix="/equipment-activities", tags=["scope_equipment_activities"] # overhaul_history_router, prefix="/overhaul-history", tags=["overhaul_history"]
) # )
authenticated_api_router.include_router( # authenticated_api_router.include_router(
scope_equipment_part_router, prefix="/equipment-parts", tags=["scope_equipment_parts"] # scope_equipment_activity_router, prefix="/equipment-activities", tags=["scope_equipment_activities"]
) # )
authenticated_api_router.include_router( # authenticated_api_router.include_router(
ovehaul_schedule_router, prefix="/overhaul-schedules", tags=["overhaul_schedules"] # activity_router, prefix="/activities", tags=["activities"]
) # )
# calculation # authenticated_api_router.include_router(
calculation_router = APIRouter(prefix="/calculation", tags=["calculations"]) # scope_equipment_part_router, prefix="/equipment-parts", tags=["scope_equipment_parts"]
# )
# Time constrains # authenticated_api_router.include_router(
calculation_router.include_router( # ovehaul_schedule_router, prefix="/overhaul-schedules", tags=["overhaul_schedules"]
calculation_time_constrains_router, prefix="/time-constraint", tags=["calculation", "time_constraint"]) # )
# Target reliability # # calculation
calculation_router.include_router( # calculation_router = APIRouter(prefix="/calculation", tags=["calculations"])
calculation_target_reliability, prefix="/target-reliability", tags=["calculation", "target_reliability"]
)
# Budget Constrain # # Time constrains
calculation_router.include_router( # calculation_router.include_router(
calculation_budget_constraint, prefix="/budget-constraint", tags=["calculation", "budget_constraint"] # calculation_time_constrains_router, prefix="/time-constraint", tags=["calculation", "time_constraint"])
)
authenticated_api_router.include_router( # # Target reliability
calculation_router # calculation_router.include_router(
) # calculation_target_reliability, prefix="/target-reliability", tags=["calculation", "target_reliability"]
# )
# # Budget Constrain
# calculation_router.include_router(
# calculation_budget_constraint, prefix="/budget-constraint", tags=["calculation", "budget_constraint"]
# )
# authenticated_api_router.include_router(
# calculation_router
# )
api_router.include_router(authenticated_api_router) api_router.include_router(authenticated_api_router)

@ -1,12 +1,12 @@
import random
from sqlalchemy import Select, Delete from sqlalchemy import Select, Delete
from typing import Optional from typing import Optional
from src.database.core import DbSession from src.database.core import DbSession
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
from src.overhaul_schedule.service import get_all as get_all_schedules from src.overhaul_schedule.service import get_all as get_all_schedules
from src.scope.model import Scope
from src.scope_equipment.model import ScopeEquipment from src.scope_equipment.model import ScopeEquipment
from src.scope_equipment.service import get_by_scope_name from src.scope_equipment.service import get_by_scope_name
@ -25,7 +25,7 @@ async def get_all_budget_constrains(*, db_session: DbSession, scope_name: str, c
'assetnum': equipment.assetnum, 'assetnum': equipment.assetnum,
'location_tag': equipment.master_equipment.location_tag, 'location_tag': equipment.master_equipment.location_tag,
'name': equipment.master_equipment.name, 'name': equipment.master_equipment.name,
'total_cost': equipment.total_cost 'total_cost': 1000000 + random.randint(10000, 5000000)
} }
for equipment in equipments for equipment in equipments
] ]
@ -38,9 +38,10 @@ async def get_all_budget_constrains(*, db_session: DbSession, scope_name: str, c
for equipment in result: for equipment in result:
cumulative_cost += equipment['total_cost'] cumulative_cost += equipment['total_cost']
filtered_result.append(equipment)
if cumulative_cost >= cost_threshold: if cumulative_cost >= cost_threshold:
break break
filtered_result.append(equipment)
return filtered_result return filtered_result

@ -6,7 +6,6 @@ from typing import Optional
from src.database.core import DbSession from src.database.core import DbSession
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
from src.overhaul_schedule.service import get_all as get_all_schedules from src.overhaul_schedule.service import get_all as get_all_schedules
from src.scope.model import Scope
from src.scope_equipment.model import ScopeEquipment from src.scope_equipment.model import ScopeEquipment
from src.scope_equipment.service import get_by_scope_name from src.scope_equipment.service import get_by_scope_name

@ -5,9 +5,8 @@ from sqlalchemy import Select, func, select
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from src.workorder.model import MasterWorkOrder from src.workorder.model import MasterWorkOrder
from src.scope_equipment.model import ScopeEquipment from src.scope_equipment.model import ScopeEquipment
from src.scope.model import Scope
from src.database.core import DbSession from src.database.core import DbSession
from src.scope.service import get_all from src.overhaul_scope.service import get_all
from .schema import CalculationTimeConstrainsParametersRead, CalculationTimeConstrainsParametersRetrive, CalculationTimeConstrainsParametersCreate from .schema import CalculationTimeConstrainsParametersRead, CalculationTimeConstrainsParametersRetrive, CalculationTimeConstrainsParametersCreate
from .service import get_calculation_by_reference_and_parameter, get_calculation_result, get_overhaul_cost_by_time_chart, get_corrective_cost_time_chart, create_param_and_data, get_calculation_data_by_id, create_calculation_result_service, get_avg_cost_by_asset from .service import get_calculation_by_reference_and_parameter, get_calculation_result, get_overhaul_cost_by_time_chart, get_corrective_cost_time_chart, create_param_and_data, get_calculation_data_by_id, create_calculation_result_service, get_avg_cost_by_asset
from src.scope_equipment.service import get_by_assetnum from src.scope_equipment.service import get_by_assetnum

@ -9,7 +9,7 @@ from src.workorder.model import MasterWorkOrder
from .schema import CalculationTimeConstrainsParametersCreate, CalculationTimeConstrainsRead from .schema import CalculationTimeConstrainsParametersCreate, CalculationTimeConstrainsRead
from .model import CalculationParam, OverhaulReferenceType, CalculationData, CalculationResult from .model import CalculationParam, OverhaulReferenceType, CalculationData, CalculationResult
from fastapi import HTTPException, status from fastapi import HTTPException, status
from src.scope.service import get_by_scope_name, get from src.overhaul_scope.service import get_by_scope_name, get
from src.scope_equipment.service import get_by_assetnum from src.scope_equipment.service import get_by_assetnum

@ -27,6 +27,7 @@ def common_parameters(
sort_by: List[str] = Query([], alias="sortBy[]"), sort_by: List[str] = Query([], alias="sortBy[]"),
descending: List[bool] = Query([], alias="descending[]"), descending: List[bool] = Query([], alias="descending[]"),
exclude: List[str] = Query([], alias="exclude[]"), exclude: List[str] = Query([], alias="exclude[]"),
all: int = Query(0)
# role: QueryStr = Depends(get_current_role), # role: QueryStr = Depends(get_current_role),
): ):
return { return {
@ -38,13 +39,14 @@ def common_parameters(
"sort_by": sort_by, "sort_by": sort_by,
"descending": descending, "descending": descending,
"current_user": current_user, "current_user": current_user,
"all": bool(all)
# "role": role, # "role": role,
} }
CommonParameters = Annotated[ CommonParameters = Annotated[
dict[str, int | str | DbSession | QueryStr | dict[str, int | str | DbSession | QueryStr |
Json | List[str] | List[bool]], Json | List[str] | List[bool]] | bool,
Depends(common_parameters), Depends(common_parameters),
] ]
@ -90,10 +92,11 @@ async def search_filter_sort_paginate(
descending: List[bool] = None, descending: List[bool] = None,
current_user: str = None, current_user: str = None,
exclude: List[str] = None, exclude: List[str] = None,
all: bool = False
): ):
"""Common functionality for searching, filtering, sorting, and pagination.""" """Common functionality for searching, filtering, sorting, and pagination."""
# try: # try:
## Check if model is Select # Check if model is Select
if not isinstance(model, Select): if not isinstance(model, Select):
query = Select(model) query = Select(model)
else: else:
@ -103,34 +106,32 @@ async def search_filter_sort_paginate(
sort = False if sort_by else True sort = False if sort_by else True
query = search(query_str=query_str, query=query, query = search(query_str=query_str, query=query,
model=model, sort=sort) model=model, sort=sort)
# Get total count # Get total count
count_query = Select(func.count()).select_from(query.subquery()) count_query = Select(func.count()).select_from(query.subquery())
total = await db_session.scalar(count_query) total = await db_session.scalar(count_query)
if all:
result = await db_session.execute(query)
items = result.scalars().all()
return {
"items": items,
"itemsPerPage": total,
"page": 1,
"total": total,
"totalPages": 1,
}
query = ( query = (
query query
.offset((page - 1) * items_per_page) .offset((page - 1) * items_per_page)
.limit(items_per_page) .limit(items_per_page)
) )
result = await db_session.execute(query) result = await db_session.execute(query)
items = result.scalars().all() items = result.scalars().all()
# try:
# query, pagination = apply_pagination(
# query=query, page_number=page, page_size=items_per_page)
# except ProgrammingError as e:
# log.debug(e)
# return {
# "items": [],
# "itemsPerPage": items_per_page,
# "page": page,
# "total": 0,
# }
return { return {
"items": items, "items": items,
"itemsPerPage": items_per_page, "itemsPerPage": items_per_page,

@ -0,0 +1,28 @@
from sqlalchemy import UUID, Column, Float, Integer, String, ForeignKey
from src.database.core import Base
from src.models import DefaultMixin, IdentityMixin, TimeStampMixin
from sqlalchemy.orm import relationship
from src.workorder.model import MasterWorkOrder
from sqlalchemy.ext.hybrid import hybrid_property
class MasterActivity(Base, DefaultMixin):
__tablename__ = "oh_ms_activity"
name = Column(String, nullable=False)
details = relationship(
"MasterActivityDetail",
lazy="raise",
primaryjoin="and_(MasterActivity.id == foreign(MasterActivityDetail.activity_id))",
)
class MasterActivityDetail(Base, DefaultMixin):
__tablename__ = "oh_ms_activity_detail"
name = Column(String, nullable=False)
activity_id = Column(UUID(as_uuid=True))

@ -0,0 +1,71 @@
from fastapi import APIRouter, HTTPException, Query, status
from .service import get_all, create, get, update, delete
from .schema import ActivityMaster, ActivityMasterCreate, ActivityMasterPagination
from src.models import StandardResponse
from src.database.service import CommonParameters, search_filter_sort_paginate, DbSession
router = APIRouter()
@router.get("", response_model=StandardResponse[ActivityMasterPagination])
async def get_activities(common: CommonParameters):
"""Get all scope activity pagination."""
# return
data = await get_all(common=common)
return StandardResponse(
data=data,
message="Data retrieved successfully",
)
@router.post("", response_model=StandardResponse[ActivityMasterCreate])
async def create_activity(db_session: DbSession, activity_in: ActivityMasterCreate):
activity = await create(db_session=db_session, activty_in=activity_in)
return StandardResponse(data=activity, message="Data created successfully")
@router.get("/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster])
async def get_activity(db_session: DbSession, activity_id: str):
activity = await get(db_session=db_session, activity_id=activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=activity, message="Data retrieved successfully")
@router.put("/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster])
async def update_scope(db_session: DbSession, activity_in: ActivityMasterCreate, activity_id):
activity = await get(db_session=db_session, activity_id=activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=await update(db_session=db_session, activity=activity, activity_in=activity_in), message="Data updated successfully")
@router.delete("/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster])
async def delete_scope(db_session: DbSession, activity_id: str):
activity = await get(db_session=db_session, activity_id=activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=[{"msg": "A data with this id does not exist."}],
)
await delete(db_session=db_session, activity_id=activity_id)
return StandardResponse(message="Data deleted successfully", data=activity)

@ -7,28 +7,25 @@ from pydantic import Field, BaseModel
from src.models import DefultBase, Pagination from src.models import DefultBase, Pagination
class ScopeEquipmentActivityBase(DefultBase): class ActivityMaster(DefultBase):
assetnum: str = Field(..., description="Assetnum is required") name: str
class ScopeEquipmentActivityCreate(ScopeEquipmentActivityBase): class ActivityMasterDetail(DefultBase):
name: str name: str
cost: Optional[float] = Field(0)
class ScopeEquipmentActivityUpdate(ScopeEquipmentActivityBase): class ActivityMasterCreate(ActivityMaster):
name: Optional[str] = Field(None) pass
cost: Optional[float] = Field(0)
class ScopeEquipmentActivityRead(ScopeEquipmentActivityBase): class ActivityMasterRead(ActivityMaster):
id: UUID id: UUID
name: str details: List[ActivityMasterDetail] = []
cost: float
class ScopeEquipmentActivityPagination(Pagination): class ActivityMasterPagination(Pagination):
items: List[ScopeEquipmentActivityRead] = [] items: List[ActivityMasterRead] = []
# { # {

@ -0,0 +1,57 @@
from sqlalchemy import Select, Delete
from sqlalchemy.orm import joinedload, selectinload
from typing import Optional
from .model import MasterActivity, MasterActivityDetail
from .schema import ActivityMaster, ActivityMasterCreate
from src.database.core import DbSession
from src.database.service import CommonParameters, search_filter_sort_paginate
from src.auth.service import CurrentUser
async def get(*, db_session: DbSession, activity_id: str) -> Optional[ActivityMaster]:
"""Returns a document based on the given document id."""
result = await db_session.get(MasterActivity, activity_id)
return result
async def get_all(common: CommonParameters):
query = Select(MasterActivity).options(
selectinload(MasterActivity.details))
results = await search_filter_sort_paginate(model=query, **common)
return results
async def create(*, db_session: DbSession, activty_in: ActivityMasterCreate):
activity = MasterActivity(
**activty_in.model_dump())
db_session.add(activity)
await db_session.commit()
return activity
async def update(*, db_session: DbSession, activity: MasterActivity, activity_in: ActivityMasterCreate):
"""Updates a document."""
data = activity_in.model_dump()
update_data = activity_in.model_dump(exclude_defaults=True)
for field in data:
if field in update_data:
setattr(activity, field, update_data[field])
await db_session.commit()
return activity
async def delete(*, db_session: DbSession, activity_id: str):
"""Deletes a document."""
activity = await db_session.get(MasterActivity, activity_id)
await db_session.delete(activity)
await db_session.commit()

@ -1,7 +1,9 @@
from typing import List
from fastapi import APIRouter, HTTPException, status from fastapi import APIRouter, HTTPException, status
from src.overhaul.service import get_overhaul_critical_parts, get_overhaul_overview, get_overhaul_schedules, get_overhaul_system_components from src.overhaul.service import get_overhaul_critical_parts, get_overhaul_overview, get_overhaul_schedules, get_overhaul_system_components
from src.overhaul_scope.schema import ScopeRead
from .schema import OverhaulRead, OverhaulSchedules, OverhaulCriticalParts, OverhaulSystemComponents from .schema import OverhaulRead, OverhaulSchedules, OverhaulCriticalParts, OverhaulSystemComponents
@ -29,12 +31,12 @@ async def get_overhaul(db_session: DbSession):
) )
@router.get("/schedules", response_model=StandardResponse[OverhaulSchedules]) @router.get("/schedules", response_model=StandardResponse[List[ScopeRead]])
async def get_schedules(): async def get_schedules():
"""Get all overhaul schedules.""" """Get all overhaul schedules."""
schedules = get_overhaul_schedules() schedules = get_overhaul_schedules()
return StandardResponse( return StandardResponse(
data=OverhaulSchedules(schedules=schedules), data=schedules,
message="Data retrieved successfully", message="Data retrieved successfully",
) )

@ -5,7 +5,7 @@ from typing import Optional
from src.database.core import DbSession from src.database.core import DbSession
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
from src.overhaul_schedule.service import get_all as get_all_schedules from src.overhaul_scope.service import get_all as get_all_session
def get_overhaul_overview(): def get_overhaul_overview():
@ -35,7 +35,7 @@ def get_overhaul_critical_parts():
async def get_overhaul_schedules(*, db_session: DbSession): async def get_overhaul_schedules(*, db_session: DbSession):
"""Get all overhaul schedules.""" """Get all overhaul schedules."""
schedules = await get_all_schedules(db_session=db_session) schedules = await get_all_session(db_session=db_session)
return schedules return schedules

@ -0,0 +1,31 @@
from sqlalchemy import UUID, Column, Float, Integer, String, ForeignKey
from src.database.core import Base
from src.models import DefaultMixin, IdentityMixin, TimeStampMixin
from sqlalchemy.orm import relationship
from src.workorder.model import MasterWorkOrder
from sqlalchemy.ext.hybrid import hybrid_property
class OverhaulActivity(Base, DefaultMixin):
__tablename__ = "oh_tr_overhaul_activity"
assetnum = Column(String, nullable=True)
overhaul_scope_id = Column(UUID(as_uuid=True), ForeignKey(
"oh_ms_overhaul_scope.id"), nullable=False)
material_cost = Column(Float, nullable=False, default=0)
service_cost = Column(Float, nullable=False, default=0)
status = Column(String, nullable=False, default="pending")
equipment = relationship(
"MasterEquipment",
lazy="raise",
primaryjoin="and_(OverhaulActivity.assetnum == foreign(MasterEquipment.assetnum))",
uselist=False # Add this if it's a one-to-one relationship
)
overhaul_scope = relationship(
"OverhaulScope",
lazy="raise",
)

@ -0,0 +1,73 @@
from typing import Optional
from uuid import UUID
from fastapi import APIRouter, HTTPException, Query, status
from .service import get_all, create, get, update, delete
from .schema import OverhaulActivityCreate, OverhaulActivityPagination, OverhaulActivityRead, OverhaulActivityUpdate
from src.models import StandardResponse
from src.database.service import CommonParameters, search_filter_sort_paginate, DbSession
router = APIRouter()
@router.get("/{overhaul_session}", response_model=StandardResponse[OverhaulActivityPagination])
async def get_scope_equipments(common: CommonParameters, overhaul_session: str, assetnum: Optional[str] = Query(None), scope_name: Optional[str] = Query(None)):
"""Get all scope activity pagination."""
# return
data = await get_all(common=common, assetnum=assetnum, scope_name=scope_name, overhaul_session_id=overhaul_session)
return StandardResponse(
data=data,
message="Data retrieved successfully",
)
@ router.post("/{overhaul_session}", response_model=StandardResponse[OverhaulActivityRead])
async def create_overhaul_equipment(db_session: DbSession, overhaul_activty_in: OverhaulActivityCreate, overhaul_session: str):
activity = await create(db_session=db_session, overhaul_activty_in=overhaul_activty_in, overhaul_session_id=overhaul_session)
return StandardResponse(data=activity, message="Data created successfully")
@ router.get("/{overhaul_session}/{assetnum}", response_model=StandardResponse[OverhaulActivityRead])
async def get_overhaul_equipment(db_session: DbSession, assetnum: str, overhaul_session):
equipment = await get(db_session=db_session, assetnum=assetnum, overhaul_session_id=overhaul_session)
if not equipment:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=equipment, message="Data retrieved successfully")
@ router.put("/{overhaul_session}/{assetnum}", response_model=StandardResponse[OverhaulActivityRead])
async def update_scope(db_session: DbSession, scope_equipment_activity_in: OverhaulActivityUpdate, assetnum: str):
activity = await get(db_session=db_session, assetnum=assetnum)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=await update(db_session=db_session, activity=activity, scope_equipment_activity_in=scope_equipment_activity_in), message="Data updated successfully")
@ router.delete("/{overhaul_session}/{assetnum}", response_model=StandardResponse[OverhaulActivityRead])
async def delete_scope(db_session: DbSession, assetnum: str):
activity = await get(db_session=db_session, assetnum=assetnum)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=[{"msg": "A data with this id does not exist."}],
)
await delete(db_session=db_session, assetnum=assetnum)
return StandardResponse(message="Data deleted successfully", data=activity)

@ -0,0 +1,35 @@
from datetime import datetime
from typing import Any, Dict, List, Optional
from uuid import UUID
from pydantic import Field, BaseModel
from src.master_activity.schema import ActivityMaster
from src.models import DefultBase, Pagination
from src.scope_equipment.schema import MasterEquipmentRead
class OverhaulActivityBase(DefultBase):
assetnum: str = Field(..., description="Assetnum is required")
class OverhaulActivityCreate(OverhaulActivityBase):
material_cost: Optional[float] = Field(0)
service_cost: Optional[float] = Field(0)
class OverhaulActivityUpdate(OverhaulActivityBase):
material_cost: Optional[float] = Field(0)
service_cost: Optional[float] = Field(0)
class OverhaulActivityRead(OverhaulActivityBase):
id: UUID
material_cost: Optional[float] = Field(0)
service_cost: Optional[float] = Field(0)
status: str
equipment: MasterEquipmentRead
class OverhaulActivityPagination(Pagination):
items: List[OverhaulActivityRead] = []

@ -0,0 +1,101 @@
from uuid import UUID
from sqlalchemy import Select, Delete
from sqlalchemy.orm import joinedload
from typing import List, Optional
from src.scope_equipment.model import ScopeEquipment
from .model import OverhaulActivity
from .schema import OverhaulActivityCreate, OverhaulActivityUpdate, OverhaulActivityRead
from src.database.core import DbSession
from src.database.service import CommonParameters, search_filter_sort_paginate
from src.auth.service import CurrentUser
async def get(*, db_session: DbSession, assetnum: str, overhaul_session_id: Optional[UUID] = None) -> Optional[OverhaulActivityRead]:
"""Returns a document based on the given document id."""
query = Select(OverhaulActivity).where(
OverhaulActivity.assetnum == assetnum).options(joinedload(OverhaulActivity.equipment))
if overhaul_session_id:
query = query.filter(
OverhaulActivity.overhaul_scope_id == overhaul_session_id)
result = await db_session.execute(query)
return result.scalar()
async def get_all(*, common: CommonParameters, overhaul_session_id: UUID, assetnum: Optional[str] = None, scope_name: Optional[str] = None):
query = Select(OverhaulActivity).where(
OverhaulActivity.overhaul_scope_id == overhaul_session_id).options(joinedload(OverhaulActivity.equipment))
if assetnum:
query = query.filter(OverhaulActivity.assetnum == assetnum).options(
joinedload(OverhaulActivity.overhaul_scope))
if scope_name:
query = query.filter(OverhaulActivity.assetnum == assetnum).options(
joinedload(OverhaulActivity.overhaul_scope))
results = await search_filter_sort_paginate(model=query, **common)
return results
async def create(*, db_session: DbSession, overhaul_activty_in: OverhaulActivityCreate, overhaul_session_id: UUID):
# Check if the combination of assetnum and activity_id already exists
existing_equipment_query = (
Select(OverhaulActivity)
.where(
OverhaulActivity.assetnum == overhaul_activty_in.assetnum,
OverhaulActivity.overhaul_scope_id == overhaul_session_id
)
)
result = await db_session.execute(existing_equipment_query)
existing_activity = result.scalar_one_or_none()
# If the combination exists, raise an exception or return the existing activity
if existing_activity:
raise ValueError("This assetnum already exist.")
activity = OverhaulActivity(
**overhaul_activty_in.model_dump(),
overhaul_scope_id=overhaul_session_id)
db_session.add(activity)
await db_session.commit()
# Refresh and load relationships using joinedload
query = (
Select(OverhaulActivity)
.options(joinedload(OverhaulActivity.equipment))
.where(OverhaulActivity.id == activity.id)
)
result = await db_session.execute(query)
activity_with_relationship = result.scalar_one()
return activity_with_relationship
async def update(*, db_session: DbSession, activity: OverhaulActivity, overhaul_activity_in: OverhaulActivityUpdate):
"""Updates a document."""
data = overhaul_activity_in.model_dump()
update_data = overhaul_activity_in.model_dump(exclude_defaults=True)
for field in data:
if field in update_data:
setattr(activity, field, update_data[field])
await db_session.commit()
return activity
async def delete(*, db_session: DbSession, overhaul_activity_id: str):
"""Deletes a document."""
activity = await db_session.get(OverhaulActivity, overhaul_activity_id)
await db_session.delete(activity)
await db_session.commit()

@ -1,9 +0,0 @@
from src.enums import OptimumOHEnum
class OverhaulStatus(OptimumOHEnum):
PLANNED = "PLANNED"
IN_PROGRESS = "IN_PROGRESS"
COMPLETED = "COMPLETED"
DELAYED = "DELAYED"
CANCELLED = "CANCELLED"
ON_HOLD = "ON_HOLD"

@ -1,35 +0,0 @@
from sqlalchemy import UUID, Column, DateTime, Float, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from src.database.core import Base
from src.models import DefaultMixin
from .enums import OverhaulStatus
class OverhaulHistory(Base, DefaultMixin):
__tablename__ = "oh_tr_overhaul_history"
scope_id = Column(UUID(as_uuid=True), ForeignKey(
"oh_scope.id"), nullable=True)
schedule_start_date = Column(DateTime(timezone=True))
schedule_end_date = Column(DateTime(timezone=True))
total_cost = Column(Float, nullable=False, default=0)
status = Column(String, nullable=False, default=OverhaulStatus.PLANNED)
maximo_id = Column(String, nullable=True,
comment="Id From MAXIMO regarding overhaul schedule")
equipments = relationship("OverhaulHistoryEquip",
back_populates="overhaul_history",
cascade="all, delete-orphan")
class OverhaulHistoryEquip(Base, DefaultMixin):
__tablename__ = "oh_tr_overhaul_history_equip"
assetnum = Column(String(10), nullable=False)
overhaul_history_id = Column(
UUID(as_uuid=True), ForeignKey("oh_tr_overhaul_history.id"), nullable=False)
# Relationship to OverhaulHistory
overhaul_history = relationship("OverhaulHistory",
back_populates="equipments")

@ -1,52 +0,0 @@
from fastapi import APIRouter, HTTPException, status
from src.maximo.service import MaximoService
from .model import OverhaulHistory
from .schema import OverhaulHistoryCreate, OverhaulHistoryRead, OverhaulHistoryUpdate, OverhaulHistoryPagination
from .service import get, get_all, start_overhaul
from src.database.service import CommonParameters, search_filter_sort_paginate
from src.database.core import DbSession
from src.auth.service import CurrentUser
from src.models import StandardResponse
router = APIRouter()
@router.get("", response_model=StandardResponse[OverhaulHistoryPagination])
async def get_histories(common: CommonParameters):
"""Get all scope pagination."""
# return
return StandardResponse(
data=await search_filter_sort_paginate(model=OverhaulHistory, **common),
message="Data retrieved successfully",
)
@router.get("/{overhaul_history_id}", response_model=StandardResponse[OverhaulHistoryRead])
async def get_history(db_session: DbSession, overhaul_history_id: str):
overhaul_history = await get(db_session=db_session, overhaul_history_id=overhaul_history_id)
if not overhaul_history:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=overhaul_history, message="Data retrieved successfully")
@router.post("", response_model=StandardResponse[OverhaulHistoryRead])
async def create_history(db_session: DbSession, scope_in: OverhaulHistoryCreate):
try:
maximo_service = MaximoService()
maximo_data = await maximo_service.get_recent_overhaul()
overhaul = await start_overhaul(db_session=db_session, maximo_data=maximo_data)
except HTTPException as he:
raise he
return StandardResponse(data=overhaul, message="Data created successfully")

@ -1,33 +0,0 @@
from datetime import datetime
from typing import List, Optional
from uuid import UUID
from pydantic import Field
from src.models import DefultBase, Pagination
from src.scope.schema import ScopeRead
class OverhaulHistoryBase(DefultBase):
pass
class OverhaulHistoryCreate(OverhaulHistoryBase):
pass
class OverhaulHistoryUpdate(OverhaulHistoryBase):
pass
class OverhaulHistoryRead(OverhaulHistoryBase):
id: UUID
scope_id: UUID
schedule_start_date: datetime
schedule_end_date: Optional[datetime]
total_cost: Optional[float] = Field(0)
maximo_id: Optional[str]
class OverhaulHistoryPagination(Pagination):
items: List[OverhaulHistoryRead] = []

@ -1,81 +0,0 @@
from fastapi import HTTPException
from sqlalchemy import Select, Delete, and_
from src.maximo.service import MaximoDataMapper
from src.overhaul_history.enums import OverhaulStatus
from src.overhaul_history.utils import determine_overhaul_status
from .model import OverhaulHistory, OverhaulHistoryEquip
from .schema import OverhaulHistoryRead, OverhaulHistoryCreate
from typing import Optional
from src.database.core import DbSession
from src.auth.service import CurrentUser
from src.scope.service import get_by_scope_name
from src.scope_equipment.service import get_by_scope_name as scope_equipment_by_scope_name
async def get(*, db_session: DbSession, overhaul_history_id: str) -> Optional[OverhaulHistory]:
"""Returns a document based on the given document id."""
result = await db_session.get(OverhaulHistory, overhaul_history_id)
return result.scalars().one_or_none()
async def get_all(*, db_session: DbSession):
"""Returns all documents."""
query = Select(OverhaulHistory)
result = await db_session.execute(query)
return result.scalars().all()
async def start_overhaul(*, db_session: DbSession, maximo_data: dict):
mapper = MaximoDataMapper(maximo_data)
maximo_id = mapper.get_maximo_id()
# Check for existing overhaul
existing_overhaul = Select(OverhaulHistory).filter(
and_(
OverhaulHistory.maximo_id == maximo_id,
OverhaulHistory.status == OverhaulStatus.IN_PROGRESS
)
)
res = await db_session.execute(existing_overhaul)
if res.first():
raise HTTPException(
status_code=409,
detail=f"Overhaul with MAXIMO ID {maximo_id} already started"
)
status, status_reason = await determine_overhaul_status(maximo_data)
scope = await get_by_scope_name(db_session=db_session, scope_name=mapper.get_scope_name())
overhaul = OverhaulHistory(
scope_id=scope.id,
schedule_start_date=mapper.get_start_date(),
schedule_end_date=mapper.get_end_date(),
total_cost=mapper.get_total_cost(),
maximo_id=maximo_id,
status=status
)
# Get equipment list asynchronously
scope_equipment = await scope_equipment_by_scope_name(
db_session=db_session,
scope_name="A"
)
# Create equipment instances
equipments = [OverhaulHistoryEquip(assetnum=eq.assetnum)
for eq in scope_equipment]
# Assign equipment to overhaul
overhaul.equipments = equipments
# Get All Equipment
db_session.add(overhaul)
await db_session.commit()
await db_session.refresh(overhaul)
return overhaul

@ -1,20 +0,0 @@
from typing import Any, Dict, Optional
from .enums import OverhaulStatus
from src.maximo.service import MaximoDataMapper
async def determine_overhaul_status(maximo_data: Dict[Any, Any]) -> tuple[str, Optional[str]]:
"""Map MAXIMO status to our status enum"""
mapper = MaximoDataMapper(maximo_data)
maximo_status = mapper.get_status()
# TODO: Update these mappings based on actual MAXIMO status values
status_mapping = {
'COMP': OverhaulStatus.COMPLETED,
'INPRG': OverhaulStatus.IN_PROGRESS,
'PLAN': OverhaulStatus.PLANNED,
'HOLD': OverhaulStatus.ON_HOLD,
# Add other status mappings based on actual MAXIMO statuses
}
return status_mapping.get(maximo_status, OverhaulStatus.PLANNED), None

@ -1,16 +0,0 @@
from sqlalchemy import UUID, Column, DateTime, Float, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from src.database.core import Base
from src.models import DefaultMixin
class OverhaulSchedule(Base, DefaultMixin):
__tablename__ = "oh_tr_overhaul_schedule"
scope_id = Column(UUID(as_uuid=True), ForeignKey(
"oh_scope.id"), nullable=True)
start_date = Column(DateTime(timezone=True))
end_date = Column(DateTime(timezone=True))
scope = relationship("Scope", backref="overhaul_schedules", lazy="raise")

@ -1,37 +0,0 @@
from typing import List
from fastapi import APIRouter, HTTPException, status
from src.maximo.service import MaximoService
from .schema import OverhaulScheduleCreate, OverhaulScheduleRead
from .service import get, get_all, create
from src.database.service import CommonParameters, search_filter_sort_paginate
from src.database.core import DbSession
from src.auth.service import CurrentUser
from src.models import StandardResponse
router = APIRouter()
@router.get("", response_model=StandardResponse[List[OverhaulScheduleRead]])
async def get_schedules(db_session: DbSession):
"""Get all scope pagination."""
schedules = await get_all(db_session=db_session)
# return
return StandardResponse(
data=schedules,
message="Data retrieved successfully",
)
@router.post("", response_model=StandardResponse[OverhaulScheduleRead])
async def create_schedule(db_session: DbSession, overhaul_schedule_in: OverhaulScheduleCreate):
schedule = await create(db_session=db_session, overhaul_schedule_in=overhaul_schedule_in)
# raise Exception(schedule.scope)
return StandardResponse(data=schedule, message="Data created successfully")

@ -1,33 +0,0 @@
from datetime import datetime
from typing import List, Optional, Union
from uuid import UUID
from pydantic import Field
from src.models import DefultBase, Pagination
from src.scope.schema import ScopeRead
class OverhaulScheduleBase(DefultBase):
pass
class OverhaulScheduleCreate(OverhaulScheduleBase):
scope_id: Union[UUID, str]
start_date: datetime
end_date: Optional[datetime] = Field(None)
class OverhaulScheduleUpdate(OverhaulScheduleBase):
pass
class OverhaulScheduleRead(OverhaulScheduleBase):
id: UUID
scope: Optional[ScopeRead] = Field(None)
start_date: datetime
end_date: Optional[datetime]
class OverhaulSchedulePagination(Pagination):
items: List[OverhaulScheduleRead] = []

@ -1,68 +0,0 @@
from fastapi import HTTPException
from sqlalchemy import Select, Delete, and_
from sqlalchemy.orm import selectinload
from .model import OverhaulSchedule
from .schema import OverhaulScheduleCreate, OverhaulScheduleUpdate
from typing import Optional
from src.database.core import DbSession
from src.scope.service import get_by_scope_name
async def get(*, db_session: DbSession, overhaul_history_id: str) -> Optional[OverhaulSchedule]:
"""Returns a document based on the given document id."""
result = await db_session.get(OverhaulSchedule, overhaul_history_id)
return result.scalars().one_or_none()
async def get_all(*, db_session: DbSession):
"""Returns all documents."""
query = Select(OverhaulSchedule).options(
selectinload(OverhaulSchedule.scope))
result = await db_session.execute(query)
return result.scalars().all()
async def create(*, db_session: DbSession, overhaul_schedule_in: OverhaulScheduleCreate):
"""Creates a new document."""
scope = await get_by_scope_name(db_session=db_session, scope_name=overhaul_schedule_in.scope_id)
if not scope:
raise HTTPException(
status_code=404,
detail="Not Found"
)
overhaul_schedule_in.scope_id = scope.id
overhaul_schedule = OverhaulSchedule(**overhaul_schedule_in.model_dump())
db_session.add(overhaul_schedule)
await db_session.commit()
results = Select(OverhaulSchedule).options(selectinload(OverhaulSchedule.scope)).filter(OverhaulSchedule.id == overhaul_schedule.id)
return await db_session.scalar(results)
async def update(*, db_session: DbSession, overhaul_schedule: OverhaulSchedule, overhaul_schedule_in: OverhaulScheduleUpdate):
"""Updates a document."""
data = overhaul_schedule_in.model_dump()
update_data = overhaul_schedule_in.model_dump(exclude_defaults=True)
for field in data:
if field in update_data:
setattr(overhaul_schedule, field, update_data[field])
await db_session.commit()
return overhaul_schedule
async def delete(*, db_session: DbSession, overhaul_schedule_id: str):
"""Deletes a document."""
query = Delete(OverhaulSchedule).where(
overhaul_schedule_id == overhaul_schedule_id)
await db_session.execute(query)
await db_session.commit()

@ -0,0 +1,17 @@
from sqlalchemy import Column, DateTime, Float, Integer, String
from src.database.core import Base
from src.models import DefaultMixin, IdentityMixin, TimeStampMixin
class OverhaulScope(Base, DefaultMixin):
__tablename__ = "oh_ms_overhaul_scope"
type = Column(String, nullable=True)
start_date = Column(DateTime(timezone=True))
end_date = Column(DateTime(timezone=True))
duration_oh = Column(Integer, nullable=True)
crew_number = Column(Integer, nullable=True, default=1)
status = Column(String, nullable=False, default="upcoming")

@ -1,7 +1,8 @@
from typing import Optional
from fastapi import APIRouter, HTTPException, status from fastapi import APIRouter, HTTPException, status
from .model import Scope from .model import OverhaulScope
from .schema import ScopeCreate, ScopeRead, ScopeUpdate, ScopePagination from .schema import ScopeCreate, ScopeRead, ScopeUpdate, ScopePagination
from .service import get, get_all, create, update, delete from .service import get, get_all, create, update, delete
@ -14,18 +15,20 @@ router = APIRouter()
@router.get("", response_model=StandardResponse[ScopePagination]) @router.get("", response_model=StandardResponse[ScopePagination])
async def get_scopes(common: CommonParameters): async def get_scopes(common: CommonParameters, scope_name: Optional[str] = None):
"""Get all scope pagination.""" """Get all scope pagination."""
# return # return
results = await get_all(common=common, scope_name=scope_name)
return StandardResponse( return StandardResponse(
data=await search_filter_sort_paginate(model=Scope, **common), data=results,
message="Data retrieved successfully", message="Data retrieved successfully",
) )
@router.get("/{scope_id}", response_model=StandardResponse[ScopeRead]) @router.get("/{overhaul_session_id}", response_model=StandardResponse[ScopeRead])
async def get_scope(db_session: DbSession, scope_id: str): async def get_scope(db_session: DbSession, overhaul_session_id: str):
scope = await get(db_session=db_session, scope_id=scope_id) scope = await get(db_session=db_session, overhaul_session_id=overhaul_session_id)
if not scope: if not scope:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, status_code=status.HTTP_404_NOT_FOUND,

@ -8,13 +8,15 @@ from src.models import DefultBase, Pagination
class ScopeBase(DefultBase): class ScopeBase(DefultBase):
scope_name: Optional[str] = Field(None, title="Scope Name")
duration_oh: Optional[int] = Field(None, title="Duration OH") duration_oh: Optional[int] = Field(None, title="Duration OH")
crew: Optional[int] = Field(None, title="Crew") crew_number: Optional[int] = Field(1, title="Crew")
status: Optional[str] = Field("Upcoming")
type: str
class ScopeCreate(ScopeBase): class ScopeCreate(ScopeBase):
pass start_date: datetime
end_date: Optional[datetime] = Field(None)
class ScopeUpdate(ScopeBase): class ScopeUpdate(ScopeBase):
@ -23,6 +25,8 @@ class ScopeUpdate(ScopeBase):
class ScopeRead(ScopeBase): class ScopeRead(ScopeBase):
id: UUID id: UUID
start_date: datetime
end_date: Optional[datetime]
class ScopePagination(Pagination): class ScopePagination(Pagination):

@ -0,0 +1,93 @@
from sqlalchemy import Select, Delete
from src.database.service import search_filter_sort_paginate
from src.overhaul_activity.model import OverhaulActivity
from src.scope_equipment.service import get_by_scope_name
from .model import OverhaulScope
from .schema import ScopeCreate, ScopeUpdate
from typing import Optional
from src.database.core import DbSession
from src.auth.service import CurrentUser
async def get(*, db_session: DbSession, overhaul_session_id: str) -> Optional[OverhaulScope]:
"""Returns a document based on the given document id."""
query = Select(OverhaulScope).filter(
OverhaulScope.id == overhaul_session_id)
result = await db_session.execute(query)
return result.scalars().one_or_none()
async def get_all(*, common, scope_name: Optional[str] = None):
"""Returns all documents."""
query = Select(OverhaulScope)
if scope_name:
query = query.filter(OverhaulScope.type == scope_name)
results = await search_filter_sort_paginate(model=query, **common)
return results
async def create(*, db_session: DbSession, scope_in: ScopeCreate):
"""Creates a new document."""
overhaul_session = OverhaulScope(**scope_in.model_dump())
db_session.add(overhaul_session)
# Need to flush to get the id
await db_session.flush()
scope_name = scope_in.type
# Fix the function call - parameters were in wrong order
equipments = await get_by_scope_name(
db_session=db_session,
scope_name=scope_name
)
scope_equipments = [
OverhaulActivity(
assetnum=equipment.assetnum,
overhaul_scope_id=overhaul_session.id,
material_cost=100000,
service_cost=100000,
)
for equipment in equipments
]
if scope_equipments: # Only add if there are items
db_session.add_all(scope_equipments)
await db_session.commit()
return overhaul_session
async def update(*, db_session: DbSession, scope: OverhaulScope, scope_in: ScopeUpdate):
"""Updates a document."""
data = scope_in.model_dump()
update_data = scope_in.model_dump(exclude_defaults=True)
for field in data:
if field in update_data:
setattr(scope, field, update_data[field])
await db_session.commit()
return scope
async def delete(*, db_session: DbSession, scope_id: str):
"""Deletes a document."""
query = Delete(OverhaulScope).where(OverhaulScope.id == scope_id)
await db_session.execute(query)
await db_session.commit()
# async def get_by_scope_name(*, db_session: DbSession, scope_name: str) -> Optional[OverhaulScope]:
# """Returns a document based on the given document id."""
# query = Select(OverhaulScope).filter(OverhaulScope.tyoe == scope_name)
# result = await db_session.execute(query)
# return result.scalars().one_or_none()

@ -1,12 +0,0 @@
from sqlalchemy import Column, Float, Integer, String
from src.database.core import Base
from src.models import DefaultMixin, IdentityMixin, TimeStampMixin
class Scope(Base, DefaultMixin):
__tablename__ = "oh_scope"
scope_name = Column(String, nullable=True)
duration_oh = Column(Integer, nullable=True)
crew = Column(Integer, nullable=True)

@ -1,60 +0,0 @@
from sqlalchemy import Select, Delete
from .model import Scope
from .schema import ScopeCreate, ScopeUpdate
from typing import Optional
from src.database.core import DbSession
from src.auth.service import CurrentUser
async def get(*, db_session: DbSession, scope_id: str) -> Optional[Scope]:
"""Returns a document based on the given document id."""
query = Select(Scope).filter(Scope.id == scope_id)
result = await db_session.execute(query)
return result.scalars().one_or_none()
async def get_all(*, db_session: DbSession):
"""Returns all documents."""
query = Select(Scope)
result = await db_session.execute(query)
return result.scalars().all()
async def create(*, db_session: DbSession, scope_in: ScopeCreate):
"""Creates a new document."""
scope = Scope(**scope_in.model_dump())
db_session.add(scope)
await db_session.commit()
return scope
async def update(*, db_session: DbSession, scope: Scope, scope_in: ScopeUpdate):
"""Updates a document."""
data = scope_in.model_dump()
update_data = scope_in.model_dump(exclude_defaults=True)
for field in data:
if field in update_data:
setattr(scope, field, update_data[field])
await db_session.commit()
return scope
async def delete(*, db_session: DbSession, scope_id: str):
"""Deletes a document."""
query = Delete(Scope).where(Scope.id == scope_id)
await db_session.execute(query)
await db_session.commit()
async def get_by_scope_name(*, db_session: DbSession, scope_name: str) -> Optional[Scope]:
"""Returns a document based on the given document id."""
query = Select(Scope).filter(Scope.scope_name == scope_name)
result = await db_session.execute(query)
return result.scalars().one_or_none()

@ -0,0 +1,8 @@
from src.enums import OptimumOHEnum
class ScopeEquipmentType(OptimumOHEnum):
TEMP = "Temporary"
PERM = "Permanent"

@ -1,5 +1,5 @@
from sqlalchemy import UUID, Column, Float, Integer, String, ForeignKey from sqlalchemy import UUID, Column, Date, Float, Integer, String, ForeignKey
from src.database.core import Base from src.database.core import Base
from src.models import DefaultMixin, IdentityMixin, TimeStampMixin from src.models import DefaultMixin, IdentityMixin, TimeStampMixin
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
@ -8,26 +8,13 @@ from sqlalchemy.ext.hybrid import hybrid_property
class ScopeEquipment(Base, DefaultMixin): class ScopeEquipment(Base, DefaultMixin):
__tablename__ = "oh_scope_equip" __tablename__ = "oh_ms_scope_equipment"
assetnum = Column(String, nullable=True) assetnum = Column(String, nullable=True)
scope_id = Column(UUID(as_uuid=True), ForeignKey( scope_overhaul = Column(String, nullable=False)
'oh_scope.id'), nullable=True) type = Column(String, nullable=False, default="Permanent")
current_scope_id = Column(UUID(as_uuid=True), ForeignKey( removal_date = Column(Date, nullable=True)
'oh_scope.id'), nullable=False) assigned_date = Column(Date, nullable=True)
parent_scope = relationship(
"Scope",
foreign_keys=[scope_id],
backref="equipments",
lazy="raise"
)
current_scope = relationship(
"Scope",
foreign_keys=[current_scope_id],
backref="overhaul_equipments",
lazy="raise"
)
master_equipment = relationship( master_equipment = relationship(
"MasterEquipment", "MasterEquipment",
@ -35,12 +22,6 @@ class ScopeEquipment(Base, DefaultMixin):
primaryjoin="and_(ScopeEquipment.assetnum == foreign(MasterEquipment.assetnum))", primaryjoin="and_(ScopeEquipment.assetnum == foreign(MasterEquipment.assetnum))",
uselist=False # Add this if it's a one-to-one relationship uselist=False # Add this if it's a one-to-one relationship
) )
work_orders = relationship("MasterWorkOrder", lazy="selectin",
primaryjoin="and_(ScopeEquipment.assetnum == foreign(MasterWorkOrder.assetnum))")
@ hybrid_property
def total_cost(self):
return sum(wo.total_cost_max for wo in self.work_orders if wo.total_cost_max)
class MasterEquipment(Base, DefaultMixin): class MasterEquipment(Base, DefaultMixin):

@ -5,7 +5,7 @@ from fastapi.params import Query
from .model import ScopeEquipment from .model import ScopeEquipment
from .schema import ScopeEquipmentCreate, ScopeEquipmentPagination, ScopeEquipmentRead, ScopeEquipmentUpdate, MasterEquipmentPagination from .schema import ScopeEquipmentCreate, ScopeEquipmentPagination, ScopeEquipmentRead, ScopeEquipmentUpdate, MasterEquipmentPagination
from .service import get, get_all, create, update, delete, get_by_scope_name, get_exculed_scope_name, get_all_master_equipment from .service import get_all, create, update, delete, get_all_master_equipment, get_by_assetnum
from src.database.service import CommonParameters, search_filter_sort_paginate from src.database.service import CommonParameters, search_filter_sort_paginate
from src.database.core import DbSession from src.database.core import DbSession
@ -16,10 +16,10 @@ router = APIRouter()
@router.get("", response_model=StandardResponse[ScopeEquipmentPagination]) @router.get("", response_model=StandardResponse[ScopeEquipmentPagination])
async def get_scope_equipments(common: CommonParameters, scope_name: str = Query(None), exclude: bool = Query(False)): async def get_scope_equipments(common: CommonParameters, scope_name: str = Query(None)):
"""Get all scope pagination.""" """Get all scope pagination."""
# return # return
data = await get_all(db_session=common["db_session"], common=common, scope_name=scope_name, exclude=exclude) data = await get_all(common=common, scope_name=scope_name)
return StandardResponse( return StandardResponse(
data=data, data=data,
@ -27,33 +27,13 @@ async def get_scope_equipments(common: CommonParameters, scope_name: str = Query
) )
@router.get("/scope/{scope_name}", response_model=StandardResponse[List[ScopeEquipmentRead]])
async def get_scope_name(db_session: DbSession, scope_name: str, exclude: bool = Query(False)):
if exclude:
return StandardResponse(data=await get_exculed_scope_name(db_session=db_session, scope_name=scope_name), message="Data retrieved successfully")
return StandardResponse(data=await get_by_scope_name(db_session=db_session, scope_name=scope_name), message="Data retrieved successfully")
@router.get("/available/{scope_name}", response_model=StandardResponse[MasterEquipmentPagination]) @router.get("/available/{scope_name}", response_model=StandardResponse[MasterEquipmentPagination])
async def get_master_equipment(db_session: DbSession, common: CommonParameters, scope_name: str): async def get_master_equipment(common: CommonParameters, scope_name: str):
results = await get_all_master_equipment(db_session=db_session, common=common, exclude=scope_name) results = await get_all_master_equipment(common=common, scope_name=scope_name)
return StandardResponse(data=results, message="Data retrieved successfully") return StandardResponse(data=results, message="Data retrieved successfully")
@router.get("/{scope_equipment_id}", response_model=StandardResponse[ScopeEquipmentRead])
async def get_scope_equipment(db_session: DbSession, scope_equipment_id: str):
scope = await get(db_session=db_session, scope_equipment_id=scope_equipment_id)
if not scope:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=scope, message="Data retrieved successfully")
@router.post("", response_model=StandardResponse[List[str]]) @router.post("", response_model=StandardResponse[List[str]])
async def create_scope_equipment(db_session: DbSession, scope_equipment_in: ScopeEquipmentCreate): async def create_scope_equipment(db_session: DbSession, scope_equipment_in: ScopeEquipmentCreate):
scope = await create(db_session=db_session, scope_equipment_in=scope_equipment_in) scope = await create(db_session=db_session, scope_equipment_in=scope_equipment_in)
@ -61,9 +41,9 @@ async def create_scope_equipment(db_session: DbSession, scope_equipment_in: Scop
return StandardResponse(data=scope, message="Data created successfully") return StandardResponse(data=scope, message="Data created successfully")
@router.put("/{scope_equipment_id}", response_model=StandardResponse[ScopeEquipmentRead]) @router.put("/{assetnum}", response_model=StandardResponse[ScopeEquipmentRead])
async def update_scope_equipment(db_session: DbSession, scope_equipment_id: str, scope__equipment_in: ScopeEquipmentUpdate): async def update_scope_equipment(db_session: DbSession, assetnum: str, scope__equipment_in: ScopeEquipmentUpdate):
scope_equipment = await get(db_session=db_session, scope_equipment_id=scope_equipment_id) scope_equipment = await get_by_assetnum(db_session=db_session, assetnum=assetnum)
if not scope_equipment: if not scope_equipment:
raise HTTPException( raise HTTPException(
@ -74,9 +54,9 @@ async def update_scope_equipment(db_session: DbSession, scope_equipment_id: str,
return StandardResponse(data=await update(db_session=db_session, scope_equipment=scope_equipment, scope__equipment_in=scope__equipment_in), message="Data updated successfully") return StandardResponse(data=await update(db_session=db_session, scope_equipment=scope_equipment, scope__equipment_in=scope__equipment_in), message="Data updated successfully")
@router.delete("/{scope_equipment_id}", response_model=StandardResponse[None]) @router.delete("/{assetnum}", response_model=StandardResponse[None])
async def delete_scope_equipment(db_session: DbSession, scope_equipment_id: str): async def delete_scope_equipment(db_session: DbSession, assetnum: str):
scope_equipment = await get(db_session=db_session, scope_equipment_id=scope_equipment_id) scope_equipment = await get_by_assetnum(db_session=db_session, assetnum=assetnum)
if not scope_equipment: if not scope_equipment:
raise HTTPException( raise HTTPException(
@ -84,6 +64,6 @@ async def delete_scope_equipment(db_session: DbSession, scope_equipment_id: str)
detail=[{"msg": "A data with this id does not exist."}], detail=[{"msg": "A data with this id does not exist."}],
) )
await delete(db_session=db_session, scope_equipment_id=scope_equipment_id) await delete(db_session=db_session, assetnum=assetnum)
return StandardResponse(message="Data deleted successfully", data=None) return StandardResponse(message="Data deleted successfully", data=None)

@ -5,7 +5,8 @@ from uuid import UUID
from pydantic import Field, computed_field, field_validator, validator from pydantic import Field, computed_field, field_validator, validator
from src.models import DefultBase, Pagination from src.models import DefultBase, Pagination
from src.scope.schema import ScopeRead from src.overhaul_scope.schema import ScopeRead
from .enum import ScopeEquipmentType
class MasterEquipmentBase(DefultBase): class MasterEquipmentBase(DefultBase):
@ -14,12 +15,14 @@ class MasterEquipmentBase(DefultBase):
class ScopeEquipmentBase(DefultBase): class ScopeEquipmentBase(DefultBase):
scope_id: Optional[UUID] = Field(None, title="Scope ID") scope_overhaul: Optional[str] = Field(None, title="Scope ID")
class ScopeEquipmentCreate(DefultBase): class ScopeEquipmentCreate(DefultBase):
assetnums: List[str] assetnums: List[str]
scope_name: str scope_name: str
removal_date: Optional[datetime] = Field(None)
type: Optional[str] = Field(ScopeEquipmentType.PERM)
class ScopeEquipmentUpdate(ScopeEquipmentBase): class ScopeEquipmentUpdate(ScopeEquipmentBase):
@ -29,10 +32,8 @@ class ScopeEquipmentUpdate(ScopeEquipmentBase):
class ScopeEquipmentRead(ScopeEquipmentBase): class ScopeEquipmentRead(ScopeEquipmentBase):
id: UUID id: UUID
assetnum: str assetnum: str
parent_scope: ScopeRead assigned_date: datetime
current_scope: ScopeRead
master_equipment: MasterEquipmentBase master_equipment: MasterEquipmentBase
total_cost: float
class ScopeEquipmentPagination(Pagination): class ScopeEquipmentPagination(Pagination):

@ -1,11 +1,13 @@
from datetime import datetime, timedelta
from fastapi import HTTPException, status from fastapi import HTTPException, status
from sqlalchemy import Select, Delete, desc, func, not_, or_ from sqlalchemy import Select, Delete, and_, desc, func, not_, or_
from sqlalchemy.dialects.postgresql import insert from sqlalchemy.dialects.postgresql import insert
from src.overhaul_scope.model import OverhaulScope
from src.scope_equipment.enum import ScopeEquipmentType
from src.workorder.model import MasterWorkOrder from src.workorder.model import MasterWorkOrder
from .model import MasterEquipmentTree, ScopeEquipment, MasterEquipment from .model import MasterEquipmentTree, ScopeEquipment, MasterEquipment
from src.scope.service import get_by_scope_name as get_scope_by_name_service
from .schema import ScopeEquipmentCreate, ScopeEquipmentUpdate from .schema import ScopeEquipmentCreate, ScopeEquipmentUpdate
from typing import Optional, Union from typing import Optional, Union
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
@ -15,14 +17,6 @@ from src.database.core import DbSession
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
async def get(*, db_session: DbSession, scope_equipment_id: str) -> Optional[ScopeEquipment]:
"""Returns a document based on the given document id."""
query = Select(ScopeEquipment).filter(
ScopeEquipment.id == scope_equipment_id)
result = await db_session.execute(query)
return result.scalars().one_or_none()
async def get_by_assetnum(*, db_session: DbSession, assetnum: str): async def get_by_assetnum(*, db_session: DbSession, assetnum: str):
query = Select(ScopeEquipment).filter(ScopeEquipment.assetnum == assetnum).options( query = Select(ScopeEquipment).filter(ScopeEquipment.assetnum == assetnum).options(
selectinload(ScopeEquipment.master_equipment)) selectinload(ScopeEquipment.master_equipment))
@ -31,17 +25,15 @@ async def get_by_assetnum(*, db_session: DbSession, assetnum: str):
return result.unique().scalars().one_or_none() return result.unique().scalars().one_or_none()
async def get_all(*, db_session: DbSession, common, scope_name: str = None, exclude: bool = False): async def get_all(*, common, scope_name: str = None):
"""Returns all documents.""" """Returns all documents."""
query = Select(ScopeEquipment).options(selectinload( query = Select(ScopeEquipment).options(
ScopeEquipment.parent_scope), selectinload(ScopeEquipment.current_scope), selectinload(ScopeEquipment.master_equipment)) selectinload(ScopeEquipment.master_equipment))
query = query.order_by(desc(ScopeEquipment.created_at)) query = query.order_by(desc(ScopeEquipment.created_at))
if scope_name: if scope_name:
scope = await get_scope_by_name_service(db_session=db_session, scope_name=scope_name) query = query.where(ScopeEquipment.scope_overhaul == scope_name)
query = query.filter(ScopeEquipment.current_scope_id == scope.id) if not exclude else query.filter(
ScopeEquipment.current_scope_id != scope.id)
results = await search_filter_sort_paginate(model=query, **common) results = await search_filter_sort_paginate(model=query, **common)
return results return results
@ -51,28 +43,36 @@ async def create(*, db_session: DbSession, scope_equipment_in: ScopeEquipmentCre
"""Creates a new document.""" """Creates a new document."""
# scope_equipment = ScopeEquipment(**scope_equipment_in.model_dump()) # scope_equipment = ScopeEquipment(**scope_equipment_in.model_dump())
assetnums = scope_equipment_in.assetnums assetnums = scope_equipment_in.assetnums
scope = await get_scope_by_name_service( results = []
db_session=db_session, scope_name=scope_equipment_in.scope_name) removal_date = scope_equipment_in.removal_date
if not scope: if scope_equipment_in.type == ScopeEquipmentType.TEMP:
raise HTTPException( # Search for the next or ongoing overhaul session for the given scope
status_code=status.HTTP_404_NOT_FOUND, stmt = Select(OverhaulScope.end_date).where(
detail="A scope with this name does not exist.", OverhaulScope.type == scope_equipment_in.scope_name,
) (OverhaulScope.start_date <= datetime.now()) & (
OverhaulScope.end_date >= datetime.now()) # Ongoing
| (OverhaulScope.start_date > datetime.now()) # Upcoming
).order_by(OverhaulScope.start_date.asc()).limit(1)
results = [] result = await db_session.execute(stmt)
removal_date = result.scalar_one_or_none()
# If no overhaul found, set a default removal date or handle the error
if removal_date is None:
# Handle if no overhaul session is found, set default or raise an error
removal_date = datetime.now() + timedelta(days=30) # Example: 30 days from now
for assetnum in assetnums: for assetnum in assetnums:
stmt = insert(ScopeEquipment).values( stmt = insert(ScopeEquipment).values(
assetnum=assetnum, assetnum=assetnum,
current_scope_id=scope.id scope_overhaul=scope_equipment_in.scope_name,
type=scope_equipment_in.type,
removal_date=removal_date
) )
stmt = stmt.on_conflict_do_update( stmt = stmt.on_conflict_do_nothing(
index_elements=["assetnum"], index_elements=["assetnum", "scope_overhaul"]
set_={
"current_scope_id": scope.id
}
) )
await db_session.execute(stmt) await db_session.execute(stmt)
@ -97,75 +97,72 @@ async def update(*, db_session: DbSession, scope_equipment: ScopeEquipment, scop
return scope_equipment return scope_equipment
async def delete(*, db_session: DbSession, scope_equipment_id: str): async def delete(*, db_session: DbSession, assetnum: str):
"""Deletes a document.""" """Deletes a document."""
# query = Delete(ScopeEquipment).where( query = Delete(ScopeEquipment).where(
# ScopeEquipment.id == scope_equipment_id) ScopeEquipment.assetnum == assetnum)
# await db_session.execute(query) await db_session.execute(query)
# await db_session.commit() await db_session.commit()
query = Select(ScopeEquipment).filter(
ScopeEquipment.id == scope_equipment_id)
scope_equipment = await db_session.execute(query)
scope_equipment: ScopeEquipment = scope_equipment.scalars().one_or_none()
if not scope_equipment: # query = Select(ScopeEquipment).filter(
raise HTTPException( # ScopeEquipment.id == scope_equipment_id)
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
if not scope_equipment.scope_id: # scope_equipment = await db_session.execute(query)
await db_session.delete(scope_equipment) # scope_equipment: ScopeEquipment = scope_equipment.scalars().one_or_none()
else:
if scope_equipment.current_scope_id == scope_equipment.scope_id: # if not scope_equipment:
await db_session.delete(scope_equipment) # raise HTTPException(
else: # status_code=status.HTTP_404_NOT_FOUND,
scope_equipment.current_scope_id = scope_equipment.scope_id # detail="A data with this id does not exist.",
await db_session.commit() # )
# if not scope_equipment.scope_id:
# await db_session.delete(scope_equipment)
# else:
# if scope_equipment.current_scope_id == scope_equipment.scope_id:
# await db_session.delete(scope_equipment)
# else:
# scope_equipment.current_scope_id = scope_equipment.scope_id
# await db_session.commit()
async def get_by_scope_name(*, db_session: DbSession, scope_name: Union[str, list]) -> Optional[ScopeEquipment]: async def get_by_scope_name(*, db_session: DbSession, scope_name: Optional[str]) -> Optional[ScopeEquipment]:
"""Returns a document based on the given document id.""" """Returns a document based on the given document id."""
scope = await get_scope_by_name_service(db_session=db_session, scope_name=scope_name) query = Select(ScopeEquipment).options(
selectinload(ScopeEquipment.master_equipment))
query = Select(ScopeEquipment).options(selectinload(ScopeEquipment.master_equipment))
if scope: if scope_name:
query = query.filter(ScopeEquipment.current_scope_id == scope.id) query = query.filter(ScopeEquipment.scope_overhaul == scope_name)
result = await db_session.execute(query) result = await db_session.execute(query)
return result.scalars().all() return result.scalars().all()
async def get_exculed_scope_name(*, db_session: DbSession, scope_name: Union[str, list]) -> Optional[ScopeEquipment]: # async def get_exculed_scope_name(*, db_session: DbSession, scope_name: Union[str, list]) -> Optional[ScopeEquipment]:
scope = await get_scope_by_name_service(db_session=db_session, scope_name=scope_name) # scope = await get_scope_by_name_service(db_session=db_session, scope_name=scope_name)
query = Select(ScopeEquipment)
if scope: # query = Select(ScopeEquipment)
query = query.filter(ScopeEquipment.current_scope_id != scope.id)
else: # if scope:
query = query.filter(ScopeEquipment.current_scope_id != None) # query = query.filter(ScopeEquipment.current_scope_id != scope.id)
result = await db_session.execute(query) # else:
return result.scalars().all() # query = query.filter(ScopeEquipment.current_scope_id != None)
# result = await db_session.execute(query)
# return result.scalars().all()
async def get_all_master_equipment(*, db_session: DbSession, exclude: Optional[str] = None, common: CommonParameters):
scope = await get_scope_by_name_service(db_session=db_session, scope_name=exclude)
query = Select(MasterEquipment).filter(MasterEquipment.assetnum != None) async def get_all_master_equipment(*, common: CommonParameters, scope_name):
equipments_scope = [equip.assetnum for equip in await get_by_scope_name(
db_session=common.get("db_session"), scope_name=scope_name)]
query = query.outerjoin( query = Select(MasterEquipment).filter(
ScopeEquipment, MasterEquipment.assetnum == ScopeEquipment.assetnum) MasterEquipment.assetnum.is_not(None))
if scope: # Only add not_in filter if there are items in equipments_scope
query = query.filter( if equipments_scope:
not_(ScopeEquipment.current_scope_id == scope.id) query = query.filter(MasterEquipment.assetnum.not_in(equipments_scope))
)
results = await search_filter_sort_paginate(model=query, **common) results = await search_filter_sort_paginate(model=query, **common)
return results return results

@ -1,18 +0,0 @@
from sqlalchemy import UUID, Column, Float, Integer, String, ForeignKey
from src.database.core import Base
from src.models import DefaultMixin, IdentityMixin, TimeStampMixin
from sqlalchemy.orm import relationship
from src.workorder.model import MasterWorkOrder
from sqlalchemy.ext.hybrid import hybrid_property
class ScopeEquipmentActivity(Base, DefaultMixin):
__tablename__ = "oh_tr_overhaul_activity"
assetnum = Column(String, nullable=True)
name = Column(String, nullable=False)
cost = Column(Float, nullable=False, default=0)
scope_equipments = relationship(
"ScopeEquipment", lazy="raise", primaryjoin="and_(ScopeEquipmentActivity.assetnum == foreign(ScopeEquipment.assetnum))", uselist=False)

@ -1,71 +0,0 @@
from fastapi import APIRouter, HTTPException, Query, status
from .service import get_all, create, get, update, delete
from .schema import ScopeEquipmentActivityCreate, ScopeEquipmentActivityPagination, ScopeEquipmentActivityRead, ScopeEquipmentActivityUpdate
from src.models import StandardResponse
from src.database.service import CommonParameters, search_filter_sort_paginate, DbSession
router = APIRouter()
@router.get("", response_model=StandardResponse[ScopeEquipmentActivityPagination])
async def get_scope_equipment_activities(common: CommonParameters, assetnum: str = Query(None)):
"""Get all scope activity pagination."""
# return
data = await get_all(common=common, assetnum=assetnum)
return StandardResponse(
data=data,
message="Data retrieved successfully",
)
@router.post("", response_model=StandardResponse[ScopeEquipmentActivityRead])
async def create_activity(db_session: DbSession, scope_equipment_activity_in: ScopeEquipmentActivityCreate):
activity = await create(db_session=db_session, scope_equipment_activty_in=scope_equipment_activity_in)
return StandardResponse(data=activity, message="Data created successfully")
@router.get("/{scope_equipment_activity_id}", response_model=StandardResponse[ScopeEquipmentActivityRead])
async def get_activity(db_session: DbSession, scope_equipment_activity_id: str):
activity = await get(db_session=db_session, scope_equipment_activity_id=scope_equipment_activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=activity, message="Data retrieved successfully")
@router.put("/{scope_equipment_activity_id}", response_model=StandardResponse[ScopeEquipmentActivityRead])
async def update_scope(db_session: DbSession, scope_equipment_activity_in: ScopeEquipmentActivityUpdate, scope_equipment_activity_id):
activity = await get(db_session=db_session, scope_equipment_activity_id=scope_equipment_activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
return StandardResponse(data=await update(db_session=db_session, activity=activity, scope_equipment_activity_in=scope_equipment_activity_in), message="Data updated successfully")
@router.delete("/{scope_equipment_activity_id}", response_model=StandardResponse[ScopeEquipmentActivityRead])
async def delete_scope(db_session: DbSession, scope_equipment_activity_id: str):
activity = await get(db_session=db_session, scope_equipment_activity_id=scope_equipment_activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=[{"msg": "A data with this id does not exist."}],
)
await delete(db_session=db_session, scope_equipment_activity_id=scope_equipment_activity_id)
return StandardResponse(message="Data deleted successfully", data=activity)

@ -1,58 +0,0 @@
from sqlalchemy import Select, Delete
from typing import Optional
from .model import ScopeEquipmentActivity
from .schema import ScopeEquipmentActivityCreate, ScopeEquipmentActivityUpdate
from src.database.core import DbSession
from src.database.service import CommonParameters, search_filter_sort_paginate
from src.auth.service import CurrentUser
async def get(*, db_session: DbSession, scope_equipment_activity_id: str) -> Optional[ScopeEquipmentActivity]:
"""Returns a document based on the given document id."""
result = await db_session.get(ScopeEquipmentActivity, scope_equipment_activity_id)
return result
async def get_all(common: CommonParameters, assetnum: Optional[str]):
query = Select(ScopeEquipmentActivity)
if assetnum:
query = query.filter(ScopeEquipmentActivity.assetnum == assetnum)
results = await search_filter_sort_paginate(model=query, **common)
return results
async def create(*, db_session: DbSession, scope_equipment_activty_in: ScopeEquipmentActivityCreate):
activity = ScopeEquipmentActivity(
**scope_equipment_activty_in.model_dump())
db_session.add(activity)
await db_session.commit()
return activity
async def update(*, db_session: DbSession, activity: ScopeEquipmentActivity, scope_equipment_activity_in: ScopeEquipmentActivityUpdate):
"""Updates a document."""
data = scope_equipment_activity_in.model_dump()
update_data = scope_equipment_activity_in.model_dump(exclude_defaults=True)
for field in data:
if field in update_data:
setattr(activity, field, update_data[field])
await db_session.commit()
return activity
async def delete(*, db_session: DbSession, scope_equipment_activity_id: str):
"""Deletes a document."""
activity = await db_session.get(ScopeEquipmentActivity, scope_equipment_activity_id)
await db_session.delete(activity)
await db_session.commit()
Loading…
Cancel
Save