From e6e87b0d9d5fb32db62e68f920be0eae7490eb6e Mon Sep 17 00:00:00 2001 From: Cizz22 Date: Mon, 14 Jul 2025 15:46:33 +0700 Subject: [PATCH] add requests --- src/api.py | 79 ++++--- src/calculation_budget_constrains/service.py | 4 +- src/calculation_target_reliability/service.py | 6 +- src/calculation_time_constrains/service.py | 18 +- src/{job => equipment_sparepart}/__init__.py | 0 .../model.py | 2 +- .../router.py | 0 .../schema.py | 0 .../service.py | 2 - .../__init__.py | 0 src/equipment_workscope_group/model.py | 22 ++ .../router.py | 14 +- .../schema.py | 0 .../service.py | 65 ++++-- src/overhaul_activity/model.py | 46 ++-- src/overhaul_activity/router.py | 6 +- src/overhaul_activity/schema.py | 15 +- src/overhaul_activity/service.py | 59 +++-- src/overhaul_job/model.py | 44 ++-- src/overhaul_job/router.py | 8 +- src/overhaul_job/service.py | 30 ++- src/overhaul_scope/model.py | 16 +- src/overhaul_scope/schema.py | 5 +- src/overhaul_scope/service.py | 186 ++++++++++----- src/scope_equipment/service.py | 202 ----------------- src/scope_equipment_job/model.py | 20 -- .../__init__.py | 0 .../enum.py | 0 .../model.py | 36 ++- .../router.py | 62 +++-- .../schema.py | 5 +- src/standard_scope/service.py | 212 ++++++++++++++++++ src/workorder/model.py | 10 +- .../__init__.py | 0 src/{job => workscope_group}/model.py | 22 +- src/{job => workscope_group}/router.py | 0 src/{job => workscope_group}/schema.py | 1 - src/{job => workscope_group}/service.py | 0 .../__init__.py | 0 src/workscope_group_maintenance_type/model.py | 18 ++ .../service.py | 59 +++++ 41 files changed, 766 insertions(+), 508 deletions(-) rename src/{job => equipment_sparepart}/__init__.py (100%) rename src/{scope_equipment_part => equipment_sparepart}/model.py (93%) rename src/{scope_equipment_part => equipment_sparepart}/router.py (100%) rename src/{scope_equipment_part => equipment_sparepart}/schema.py (100%) rename src/{scope_equipment_part => equipment_sparepart}/service.py (96%) rename src/{scope_equipment => equipment_workscope_group}/__init__.py (100%) create mode 100644 src/equipment_workscope_group/model.py rename src/{scope_equipment_job => equipment_workscope_group}/router.py (78%) rename src/{scope_equipment_job => equipment_workscope_group}/schema.py (100%) rename src/{scope_equipment_job => equipment_workscope_group}/service.py (67%) delete mode 100644 src/scope_equipment/service.py delete mode 100644 src/scope_equipment_job/model.py rename src/{scope_equipment_job => standard_scope}/__init__.py (100%) rename src/{scope_equipment => standard_scope}/enum.py (100%) rename src/{scope_equipment => standard_scope}/model.py (55%) rename src/{scope_equipment => standard_scope}/router.py (53%) rename src/{scope_equipment => standard_scope}/schema.py (98%) create mode 100644 src/standard_scope/service.py rename src/{scope_equipment_part => workscope_group}/__init__.py (100%) rename src/{job => workscope_group}/model.py (71%) rename src/{job => workscope_group}/router.py (100%) rename src/{job => workscope_group}/schema.py (98%) rename src/{job => workscope_group}/service.py (100%) create mode 100644 src/workscope_group_maintenance_type/__init__.py create mode 100644 src/workscope_group_maintenance_type/model.py create mode 100644 src/workscope_group_maintenance_type/service.py diff --git a/src/api.py b/src/api.py index f91bf75..c3a702f 100644 --- a/src/api.py +++ b/src/api.py @@ -9,17 +9,21 @@ from src.calculation_budget_constrains.router import \ router as calculation_budget_constraint from src.calculation_target_reliability.router import \ router as calculation_target_reliability -from src.calculation_time_constrains.router import \ - router as calculation_time_constrains_router -from src.job.router import router as job_router +# from src.calculation_time_constrains.router import \ +# router as calculation_time_constrains_router +# from src.job.router import router as job_router + from src.overhaul.router import router as overhaul_router +from src.standard_scope.router import router as standard_scope_router from src.overhaul_activity.router import router as overhaul_activity_router -from src.overhaul_job.router import router as job_overhaul_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_job.router import router as scope_equipment_job_router -from src.overhaul_schedule.router import router as overhaul_schedule_router -from src.overhaul_gantt.router import router as gantt_router +from src.workscope_group.router import router as workscope_group_router +from src.equipment_workscope_group.router import router as equipment_workscope_group_router +# from src.overhaul_job.router import router as job_overhaul_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_job.router import router as scope_equipment_job_router +# from src.overhaul_schedule.router import router as overhaul_schedule_router +# from src.overhaul_gantt.router import router as gantt_router # from src.overhaul_scope.router import router as scope_router @@ -67,15 +71,15 @@ authenticated_api_router.include_router( overhaul_router, prefix="/overhauls", tags=["overhaul"] ) -authenticated_api_router.include_router(job_router, prefix="/jobs", tags=["job"]) +# authenticated_api_router.include_router(job_router, prefix="/jobs", tags=["job"]) -# # Overhaul session data -authenticated_api_router.include_router( - scope_router, prefix="/overhaul-session", tags=["overhaul-session"] -) +# # # Overhaul session data +# authenticated_api_router.include_router( +# scope_router, prefix="/overhaul-session", tags=["overhaul-session"] +# ) authenticated_api_router.include_router( - scope_equipment_router, prefix="/scope-equipments", tags=["scope_equipment"] + standard_scope_router, prefix="/scope-equipments", tags=["scope_equipment"] ) authenticated_api_router.include_router( @@ -83,24 +87,33 @@ authenticated_api_router.include_router( ) authenticated_api_router.include_router( - scope_equipment_job_router, - prefix="/scope-equipment-jobs", - tags=["scope_equipment", "job"], + workscope_group_router, prefix="/workscopes", tags=["workscope_groups"] ) authenticated_api_router.include_router( - overhaul_schedule_router, - prefix="/overhaul-schedules", - tags=["overhaul_schedule"], + equipment_workscope_group_router, + prefix="/equipment-workscopes", + tags=["equipment_workscope_groups"], ) +# authenticated_api_router.include_router( +# scope_equipment_job_router, +# prefix="/scope-equipment-jobs", +# tags=["scope_equipment", "job"], +# ) -authenticated_api_router.include_router( - job_overhaul_router, prefix="/overhaul-jobs", tags=["job", "overhaul"] -) +# authenticated_api_router.include_router( +# overhaul_schedule_router, +# prefix="/overhaul-schedules", +# tags=["overhaul_schedule"], +# ) -authenticated_api_router.include_router( - gantt_router, prefix="/overhaul-gantt", tags=["gantt"] -) +# authenticated_api_router.include_router( +# job_overhaul_router, prefix="/overhaul-jobs", tags=["job", "overhaul"] +# ) + +# authenticated_api_router.include_router( +# gantt_router, prefix="/overhaul-gantt", tags=["gantt"] +# ) # authenticated_api_router.include_router( # overhaul_history_router, prefix="/overhaul-history", tags=["overhaul_history"] @@ -125,12 +138,12 @@ authenticated_api_router.include_router( # calculation calculation_router = APIRouter(prefix="/calculation", tags=["calculations"]) -# Time constrains -calculation_router.include_router( - calculation_time_constrains_router, - prefix="/time-constraint", - tags=["calculation", "time_constraint"], -) +# # Time constrains +# calculation_router.include_router( +# calculation_time_constrains_router, +# prefix="/time-constraint", +# tags=["calculation", "time_constraint"], +# ) # Target reliability calculation_router.include_router( diff --git a/src/calculation_budget_constrains/service.py b/src/calculation_budget_constrains/service.py index aa0e67d..6f9a14c 100644 --- a/src/calculation_budget_constrains/service.py +++ b/src/calculation_budget_constrains/service.py @@ -5,8 +5,8 @@ from sqlalchemy import Delete, Select from src.auth.service import CurrentUser from src.database.core import DbSession -from src.scope_equipment.model import ScopeEquipment -from src.scope_equipment.service import get_by_scope_name +# from src.scope_equipment.model import ScopeEquipment +# from src.scope_equipment.service import get_by_scope_name from src.overhaul_activity.service import get_all_by_session_id # async def get_all_budget_constrains( diff --git a/src/calculation_target_reliability/service.py b/src/calculation_target_reliability/service.py index 99a2ceb..3ba4194 100644 --- a/src/calculation_target_reliability/service.py +++ b/src/calculation_target_reliability/service.py @@ -4,9 +4,9 @@ from sqlalchemy import Delete, Select from src.auth.service import CurrentUser from src.database.core import DbSession -from src.scope_equipment.model import ScopeEquipment -from src.scope_equipment.service import get_by_scope_name -from src.scope_equipment_job.service import get_equipment_level_by_no +# from src.scope_equipment.model import ScopeEquipment +# from src.scope_equipment.service import get_by_scope_name +# from src.scope_equipment_job.service import get_equipment_level_by_no from datetime import datetime, timedelta import random from typing import List diff --git a/src/calculation_time_constrains/service.py b/src/calculation_time_constrains/service.py index 6ffee7f..0f2540f 100644 --- a/src/calculation_time_constrains/service.py +++ b/src/calculation_time_constrains/service.py @@ -10,7 +10,7 @@ from sqlalchemy import and_, case, func, select, update from sqlalchemy.orm import joinedload from src.database.core import DbSession -from src.overhaul_activity.service import get_all_by_session_id +from src.overhaul_activity.service import get_all as get_all_by_session_id from src.overhaul_scope.service import get as get_scope, get_prev_oh from src.utils import get_latest_numOfFail from src.workorder.model import MasterWorkOrder @@ -264,9 +264,9 @@ class SparePartsService: return projected_stock - async def reduce_stock(self, db_session, assetnum: str): + async def reduce_stock(self, db_session, location_tag: str): requirements_query = select(ScopeEquipmentPart).where( - ScopeEquipmentPart.assetnum == assetnum + ScopeEquipmentPart.location_tag == location_tag ) requirements = await db_session.execute(requirements_query) @@ -293,7 +293,7 @@ class SparePartsService: all_available = True requirements_query = select(ScopeEquipmentPart).where( - ScopeEquipmentPart.assetnum == equipment.assetnum + ScopeEquipmentPart.location_tag == equipment.location_tag ) requirements = await db_session.execute(requirements_query) @@ -504,7 +504,7 @@ class OverhaulCalculator: ) #reduce sparepart stock - await self.spare_parts_service.reduce_stock(db_session, equipment.assetnum) + await self.spare_parts_service.reduce_stock(db_session, equipment.location_tag) # Aggregate costs corrective_costs = [r["corrective_cost"] for r in all_results] @@ -1035,7 +1035,7 @@ async def get_calculation_result(db_session: DbSession, calculation_id: str): for eq in scope_calculation.equipment_results: if eq.procurement_details[i]: - result["procurement_details"][eq.assetnum] = { + result["procurement_details"][eq.location_tag] = { "is_included": eq.is_included, "details": eq.procurement_details[i], } @@ -1280,14 +1280,14 @@ async def create_calculation_result_service( total = [] predicted_num_failures = await get_number_of_failures( - location_tag=eq.equipment.location_tag, + location_tag=eq.location_tag, start_date=start_date, end_date=end_date, token=token ) foh_value = await get_equipment_foh( - location_tag=eq.equipment.location_tag, + location_tag=eq.location_tag, token=token ) @@ -1310,7 +1310,7 @@ async def create_calculation_result_service( service_cost=eq.service_cost, optimum_day=optimal_result['interval'], calculation_data_id=calculation.id, - master_equipment=eq.equipment, + master_equipment=eq.master_equipment, ) ) diff --git a/src/job/__init__.py b/src/equipment_sparepart/__init__.py similarity index 100% rename from src/job/__init__.py rename to src/equipment_sparepart/__init__.py diff --git a/src/scope_equipment_part/model.py b/src/equipment_sparepart/model.py similarity index 93% rename from src/scope_equipment_part/model.py rename to src/equipment_sparepart/model.py index 3f5133e..83331b4 100644 --- a/src/scope_equipment_part/model.py +++ b/src/equipment_sparepart/model.py @@ -12,7 +12,7 @@ class ScopeEquipmentPart(Base, DefaultMixin): required_stock = Column(Float, nullable=False, default=0) sparepart_id = Column(UUID(as_uuid=True), ForeignKey("oh_ms_sparepart.id"), nullable=False) - assetnum = Column(String, nullable=False) + location_tag = Column(String, nullable=False) location_tag = Column(String, nullable=False) part = relationship( diff --git a/src/scope_equipment_part/router.py b/src/equipment_sparepart/router.py similarity index 100% rename from src/scope_equipment_part/router.py rename to src/equipment_sparepart/router.py diff --git a/src/scope_equipment_part/schema.py b/src/equipment_sparepart/schema.py similarity index 100% rename from src/scope_equipment_part/schema.py rename to src/equipment_sparepart/schema.py diff --git a/src/scope_equipment_part/service.py b/src/equipment_sparepart/service.py similarity index 96% rename from src/scope_equipment_part/service.py rename to src/equipment_sparepart/service.py index 45c395e..412f5e7 100644 --- a/src/scope_equipment_part/service.py +++ b/src/equipment_sparepart/service.py @@ -7,8 +7,6 @@ from sqlalchemy.orm import selectinload from src.auth.service import CurrentUser from src.database.core import DbSession from src.database.service import CommonParameters, search_filter_sort_paginate -from src.scope_equipment.model import MasterEquipment, MasterEquipmentTree -from src.scope_equipment.service import get_equipment_level_by_no from .model import ScopeEquipmentPart from .schema import ScopeEquipmentActivityCreate, ScopeEquipmentActivityUpdate diff --git a/src/scope_equipment/__init__.py b/src/equipment_workscope_group/__init__.py similarity index 100% rename from src/scope_equipment/__init__.py rename to src/equipment_workscope_group/__init__.py diff --git a/src/equipment_workscope_group/model.py b/src/equipment_workscope_group/model.py new file mode 100644 index 0000000..0ba3f5c --- /dev/null +++ b/src/equipment_workscope_group/model.py @@ -0,0 +1,22 @@ +from sqlalchemy import UUID, Column, Float, ForeignKey, Integer, String +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship + +from src.database.core import Base +from src.models import DefaultMixin, IdentityMixin, TimeStampMixin +from src.workorder.model import MasterWorkOrder + + +class EquipmentWorkscopeGroup(Base, DefaultMixin): + __tablename__ = "oh_tr_equipment_workscope_group" + + workscope_group_id = Column(UUID(as_uuid=True), ForeignKey('oh_ms_workscope_group.id')) + location_tag = Column(String, nullable=False) + + workscope_group = relationship("MasterActivity", lazy="selectin", back_populates="equipment_workscope_groups") + equipment = relationship( + "StandardScope", + lazy="raise", + primaryjoin="and_(EquipmentWorkscopeGroup.location_tag == foreign(StandardScope.location_tag))", + uselist=False, # Add this if it's a one-to-one relationship + ) diff --git a/src/scope_equipment_job/router.py b/src/equipment_workscope_group/router.py similarity index 78% rename from src/scope_equipment_job/router.py rename to src/equipment_workscope_group/router.py index d07fb25..90e20a2 100644 --- a/src/scope_equipment_job/router.py +++ b/src/equipment_workscope_group/router.py @@ -12,16 +12,16 @@ from .service import create, delete, get_all router = APIRouter() -@router.get("/{assetnum}", response_model=StandardResponse[ScopeEquipmentJobPagination]) -async def get_scope_equipment_jobs( - db_session: DbSession, assetnum, common: CommonParameters -): - """Get all scope activity pagination.""" +@router.get( + "/{location_tag}", response_model=StandardResponse[OverhaulJobPagination] +) +async def get_jobs(common: CommonParameters, location_tag: str, scope: Optional[str] = Query(None)): + """Get all scope pagination.""" # return - data = await get_all(db_session=db_session, assetnum=assetnum, common=common) + results = await get_all(common=common, location_tag=location_tag, scope=scope) return StandardResponse( - data=data, + data=results, message="Data retrieved successfully", ) diff --git a/src/scope_equipment_job/schema.py b/src/equipment_workscope_group/schema.py similarity index 100% rename from src/scope_equipment_job/schema.py rename to src/equipment_workscope_group/schema.py diff --git a/src/scope_equipment_job/service.py b/src/equipment_workscope_group/service.py similarity index 67% rename from src/scope_equipment_job/service.py rename to src/equipment_workscope_group/service.py index 8721668..5e59ae3 100644 --- a/src/scope_equipment_job/service.py +++ b/src/equipment_workscope_group/service.py @@ -22,32 +22,51 @@ from .schema import ScopeEquipmentJobCreate # return result -async def get_all(db_session: DbSession, assetnum: Optional[str], common): - # Example usage - if not assetnum: - raise ValueError("assetnum parameter is required") - - # First get the parent equipment - equipment_stmt = Select(MasterEquipment).where(MasterEquipment.assetnum == assetnum) - equipment: MasterEquipment = await db_session.scalar(equipment_stmt) - - if not equipment: - raise ValueError(f"No equipment found with assetnum: {assetnum}") - - # Build query for parts - stmt = ( - Select(ScopeEquipmentJob) - .where(ScopeEquipmentJob.assetnum == assetnum) - .options( - selectinload(ScopeEquipmentJob.job), - selectinload(ScopeEquipmentJob.overhaul_jobs) - .selectinload(OverhaulJob.overhaul_activity) - .selectinload(OverhaulActivity.overhaul_scope), - ) +# async def get_all(db_session: DbSession, assetnum: Optional[str], common): +# # Example usage +# if not assetnum: +# raise ValueError("assetnum parameter is required") + +# # First get the parent equipment +# equipment_stmt = Select(MasterEquipment).where(MasterEquipment.assetnum == assetnum) +# equipment: MasterEquipment = await db_session.scalar(equipment_stmt) + +# if not equipment: +# raise ValueError(f"No equipment found with assetnum: {assetnum}") + +# # Build query for parts +# stmt = ( +# Select(ScopeEquipmentJob) +# .where(ScopeEquipmentJob.assetnum == assetnum) +# .options( +# selectinload(ScopeEquipmentJob.job), +# selectinload(ScopeEquipmentJob.overhaul_jobs) +# .selectinload(OverhaulJob.overhaul_activity) +# .selectinload(OverhaulActivity.overhaul_scope), +# ) +# ) + +# results = await search_filter_sort_paginate(model=stmt, **common) + +# return results + +async def get_all(*, common, location_tag: str, scope: Optional[str] = None): + """Returns all documents.""" + query = ( + Select(EquipmentWorkscopeGroup) + .where(EquipmentWorkscopeGroup.location_tag == location_tag) ) - results = await search_filter_sort_paginate(model=stmt, **common) + if scope: + query = ( + query + .join(EquipmentWorkscopeGroup.workscope_group) + .join(MasterActivity.oh_types) + .join(WorkscopeOHType.oh_type) + .filter(MaintenanceType.name == scope) + ) + results = await search_filter_sort_paginate(model=query, **common) return results diff --git a/src/overhaul_activity/model.py b/src/overhaul_activity/model.py index d6657ef..2ff860d 100644 --- a/src/overhaul_activity/model.py +++ b/src/overhaul_activity/model.py @@ -18,26 +18,26 @@ class OverhaulActivity(Base, DefaultMixin): 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 - ) - -# sparepart_equipments = relationship( -# "ScopeEquipmentPart", -# lazy="select", # or "joined", "subquery", "dynamic" depending on your needs -# primaryjoin="OverhaulActivity.assetnum == foreign(ScopeEquipmentPart.assetnum)", -# uselist=True -# ) - - - overhaul_scope = relationship( - "OverhaulScope", - lazy="raise", - ) - - overhaul_jobs = relationship( - "OverhaulJob", back_populates="overhaul_activity", lazy="raise" - ) +# equipment = relationship( +# "MasterEquipment", +# lazy="raise", +# primaryjoin="and_(OverhaulActivity.assetnum == foreign(MasterEquipment.assetnum))", +# uselist=False, # Add this if it's a one-to-one relationship +# ) + +# # sparepart_equipments = relationship( +# # "ScopeEquipmentPart", +# # lazy="select", # or "joined", "subquery", "dynamic" depending on your needs +# # primaryjoin="OverhaulActivity.assetnum == foreign(ScopeEquipmentPart.assetnum)", +# # uselist=True +# # ) + + +# overhaul_scope = relationship( +# "OverhaulScope", +# lazy="raise", +# ) + +# overhaul_jobs = relationship( +# "OverhaulJob", back_populates="overhaul_activity", lazy="raise" +# ) diff --git a/src/overhaul_activity/router.py b/src/overhaul_activity/router.py index 4e5e2dd..ea45aae 100644 --- a/src/overhaul_activity/router.py +++ b/src/overhaul_activity/router.py @@ -15,10 +15,10 @@ router = APIRouter() @router.get( - "/{overhaul_session}", response_model=StandardResponse[OverhaulActivityPagination] + "/{overhaul_session}", response_model=StandardResponse[List[OverhaulActivityRead]] ) async def get_scope_equipments( - common: CommonParameters, + db_session: DbSession, overhaul_session: str, assetnum: Optional[str] = Query(None), scope_name: Optional[str] = Query(None), @@ -26,7 +26,7 @@ async def get_scope_equipments( """Get all scope activity pagination.""" # return data = await get_all( - common=common, + db_session=db_session, assetnum=assetnum, scope_name=scope_name, overhaul_session_id=overhaul_session, diff --git a/src/overhaul_activity/schema.py b/src/overhaul_activity/schema.py index 32ca50b..061e563 100644 --- a/src/overhaul_activity/schema.py +++ b/src/overhaul_activity/schema.py @@ -5,8 +5,8 @@ from uuid import UUID from pydantic import Field from src.models import DefultBase, Pagination -from src.scope_equipment.schema import MasterEquipmentTree -from src.job.schema import ActivityMasterRead +from src.standard_scope.schema import MasterEquipmentTree +from src.workscope_group.schema import ActivityMasterRead class OverhaulActivityBase(DefultBase): pass @@ -38,11 +38,12 @@ class OverhaulActivityRead(OverhaulActivityBase): id: UUID material_cost: Optional[float] = Field(0) service_cost: Optional[float] = Field(0) - assetnum: str = Field(..., description="Assetnum is required") - status: str - equipment: MasterEquipmentTree - overhaul_scope: OverhaulScope - overhaul_jobs: Optional[List[OverhaulJob]] = Field([]) + location_tag: str + equipment_name: Optional[str] + oh_scope: str + # equipment: MasterEquipmentTree + # overhaul_scope: OverhaulScope + # overhaul_jobs: Optional[List[OverhaulJob]] = Field([]) class OverhaulActivityPagination(Pagination): diff --git a/src/overhaul_activity/service.py b/src/overhaul_activity/service.py index 0a5669d..b54226b 100644 --- a/src/overhaul_activity/service.py +++ b/src/overhaul_activity/service.py @@ -13,9 +13,10 @@ from src.database.service import CommonParameters, search_filter_sort_paginate from src.overhaul_activity.utils import get_material_cost, get_service_cost from src.overhaul_scope.model import OverhaulScope from src.overhaul_scope.service import get as get_session -from src.scope_equipment.model import MasterEquipment -from src.job.model import MasterActivity -from src.scope_equipment_job.model import ScopeEquipmentJob +from src.standard_scope.model import MasterEquipment +from src.standard_scope.service import get_by_oh_session_id +from src.workscope_group.model import MasterActivity +from src.equipment_workscope_group.model import EquipmentWorkscopeGroup from src.overhaul_job.model import OverhaulJob from .model import OverhaulActivity @@ -43,32 +44,50 @@ async def get( async def get_all( *, - common: CommonParameters, + db_session: DbSession, 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).options(joinedload(MasterEquipment.parent).options(joinedload(MasterEquipment.parent)))) - .options(selectinload(OverhaulActivity.overhaul_scope)) - .options(selectinload(OverhaulActivity.overhaul_jobs).options(joinedload(OverhaulJob.scope_equipment_job).options(joinedload(ScopeEquipmentJob.job)))) + # query = ( + # Select(OverhaulActivity) + # .where(OverhaulActivity.overhaul_scope_id == overhaul_session_id) + # .options(joinedload(OverhaulActivity.equipment).options(joinedload(MasterEquipment.parent).options(joinedload(MasterEquipment.parent)))) + # .options(selectinload(OverhaulActivity.overhaul_scope)) + # .options(selectinload(OverhaulActivity.overhaul_jobs).options(joinedload(OverhaulJob.scope_equipment_job).options(joinedload(ScopeEquipmentJob.job)))) + # ) + + # if assetnum: + # query = query.filter(OverhaulActivity.assetnum == assetnum).options( + # joinedload(OverhaulActivity.overhaul_scope) + # ) + + # if scope_name: + # query = query.filter(OverhaulActivity.scope_name == scope_name).options( + # joinedload(OverhaulActivity.overhaul_scope) + # ) + + # results = await search_filter_sort_paginate(model=query, **common) + + ##raise Exception(results['items'][0].equipment.parent.__dict__) + + equipments, overhaul = await get_by_oh_session_id( + db_session=db_session, oh_session_id=overhaul_session_id ) - if assetnum: - query = query.filter(OverhaulActivity.assetnum == assetnum).options( - joinedload(OverhaulActivity.overhaul_scope) - ) + results = [] - if scope_name: - query = query.filter(OverhaulActivity.scope_name == scope_name).options( - joinedload(OverhaulActivity.overhaul_scope) + for equipment in equipments: + res = OverhaulActivityRead( + id=equipment.id, + material_cost=35000000000, + service_cost=200000000, + location_tag=equipment.location_tag, + equipment_name=equipment.master_equipment.name if equipment.master_equipment else None, + oh_scope=overhaul.maintenance_type.name, ) - results = await search_filter_sort_paginate(model=query, **common) - - ##raise Exception(results['items'][0].equipment.parent.__dict__) + results.append(res) return results diff --git a/src/overhaul_job/model.py b/src/overhaul_job/model.py index d504cd7..b2d60ed 100644 --- a/src/overhaul_job/model.py +++ b/src/overhaul_job/model.py @@ -6,24 +6,38 @@ from src.database.core import Base from src.models import DefaultMixin, IdentityMixin, TimeStampMixin -class OverhaulJob(Base, DefaultMixin): - __tablename__ = "oh_tr_overhaul_job" - - overhaul_activity_id = Column( - UUID(as_uuid=True), ForeignKey("oh_tr_overhaul_activity.id"), nullable=False +class EquipmentWorkscopeGroup(Base, DefaultMixin): + __tablename__ = "oh_tr_equipment_workscope_group" + + # overhaul_activity_id = Column( + # UUID(as_uuid=True), ForeignKey("oh_tr_overhaul_activity.id"), nullable=False + # ) + + # scope_equipment_job_id = Column( + # UUID(as_uuid=True), + # ForeignKey("oh_ms_scope_equipment_job.id", ondelete="cascade"), + # nullable=False, + # ) + + # notes = Column(String, nullable=True) + # status = Column(String, nullable=True, default="pending") + workscope_group_id = Column( + UUID(as_uuid=True), ForeignKey("oh_ms_workscope_group.id"), nullable=False ) - scope_equipment_job_id = Column( - UUID(as_uuid=True), - ForeignKey("oh_ms_scope_equipment_job.id", ondelete="cascade"), - nullable=False, + location_tag = Column(String, nullable=False) + + equipment = relationship( + "StandardScope", + lazy="selectin", + primaryjoin="and_(OverhaulJob.location_tag == foreign(StandardScope.location_tag))", + uselist=False, # Add this if it's a one-to-one relationship ) - notes = Column(String, nullable=True) - status = Column(String, nullable=True, default="pending") + workscope_group = relationship("MasterActivity", lazy="selectin", back_populates="equipment_workscope_groups") - scope_equipment_job = relationship( - "ScopeEquipmentJob", lazy="raise", back_populates="overhaul_jobs" - ) + # scope_equipment_job = relationship( + # "ScopeEquipmentJob", lazy="raise", back_populates="overhaul_jobs" + # ) - overhaul_activity = relationship("OverhaulActivity", lazy="raise", back_populates="overhaul_jobs") + # overhaul_activity = relationship("OverhaulActivity", lazy="raise", back_populates="overhaul_jobs") diff --git a/src/overhaul_job/router.py b/src/overhaul_job/router.py index f0d1615..3501819 100644 --- a/src/overhaul_job/router.py +++ b/src/overhaul_job/router.py @@ -1,6 +1,6 @@ from typing import List, Optional -from fastapi import APIRouter, HTTPException, status +from fastapi import APIRouter, HTTPException, status, Query from src.auth.service import CurrentUser from src.database.core import DbSession @@ -15,12 +15,12 @@ router = APIRouter() @router.get( - "/{overhaul_equipment_id}", response_model=StandardResponse[OverhaulJobPagination] + "/{location_tag}", response_model=StandardResponse[OverhaulJobPagination] ) -async def get_jobs(common: CommonParameters, overhaul_equipment_id: str): +async def get_jobs(common: CommonParameters, location_tag: str, scope: Optional[str] = Query(None)): """Get all scope pagination.""" # return - results = await get_all(common=common, overhaul_equipment_id=overhaul_equipment_id) + results = await get_all(common=common, location_tag=location_tag, scope=scope) return StandardResponse( data=results, diff --git a/src/overhaul_job/service.py b/src/overhaul_job/service.py index f28edbc..c30da08 100644 --- a/src/overhaul_job/service.py +++ b/src/overhaul_job/service.py @@ -7,26 +7,32 @@ from sqlalchemy.orm import selectinload from src.auth.service import CurrentUser from src.database.core import DbSession from src.database.service import search_filter_sort_paginate -from src.scope_equipment_job.model import ScopeEquipmentJob -from src.overhaul_activity.model import OverhaulActivity +# from src.scope_equipment_job.model import ScopeEquipmentJob +# from src.overhaul_activity.model import OverhaulActivity -from .model import OverhaulJob +from src.workscope_group.model import MasterActivity +from src.workscope_group_maintenance_type.model import WorkscopeOHType +from src.overhaul_scope.model import MaintenanceType +from .model import EquipmentWorkscopeGroup from .schema import OverhaulJobCreate -async def get_all(*, common, overhaul_equipment_id: str): +async def get_all(*, common, location_tag: str, scope: Optional[str] = None): """Returns all documents.""" query = ( - Select(OverhaulJob) - .where(OverhaulJob.overhaul_activity_id == overhaul_equipment_id) - .options( - selectinload(OverhaulJob.scope_equipment_job).options( - selectinload(ScopeEquipmentJob.job)), - selectinload(OverhaulJob.overhaul_activity).options( - selectinload(OverhaulActivity.overhaul_scope)), - ) + Select(EquipmentWorkscopeGroup) + .where(EquipmentWorkscopeGroup.location_tag == location_tag) ) + if scope: + query = ( + query + .join(EquipmentWorkscopeGroup.workscope_group) + .join(MasterActivity.oh_types) + .join(WorkscopeOHType.oh_type) + .filter(MaintenanceType.name == scope) + ) + results = await search_filter_sort_paginate(model=query, **common) return results diff --git a/src/overhaul_scope/model.py b/src/overhaul_scope/model.py index b51601c..4daa6de 100644 --- a/src/overhaul_scope/model.py +++ b/src/overhaul_scope/model.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, DateTime, Float, Integer, String +from sqlalchemy import Column, DateTime, Float, Integer, String, ForeignKey, UUID from sqlalchemy.orm import relationship from src.database.core import Base @@ -6,12 +6,20 @@ from src.models import DefaultMixin, IdentityMixin, TimeStampMixin class OverhaulScope(Base, DefaultMixin): - __tablename__ = "oh_ms_overhaul_scope" - type = Column(String, nullable=False) # Changed to non-nullable to match the model + __tablename__ = "oh_ms_overhaul" start_date = Column(DateTime(timezone=True), nullable=False) # Made non-nullable to match model end_date = Column(DateTime(timezone=True), nullable=True) # Already nullable duration_oh = Column(Integer, nullable=True) crew_number = Column(Integer, nullable=True, default=1) status = Column(String, nullable=False, default="Upcoming") + maintenance_type_id = Column( + UUID(as_uuid=True), ForeignKey("oh_ms_maintenance_type.id"), nullable=False) - activity_equipments = relationship("OverhaulActivity", lazy="selectin") + maintenance_type = relationship("MaintenanceType", lazy="selectin", backref="overhaul_scopes") + # activity_equipments = relationship("OverhaulActivity", lazy="selectin") + + +class MaintenanceType(Base, DefaultMixin): + __tablename__ = "oh_ms_maintenance_type" + code = Column(String, nullable=False, default="OH") + name = Column(String, nullable=False) diff --git a/src/overhaul_scope/schema.py b/src/overhaul_scope/schema.py index 3e4c9cd..af37ca3 100644 --- a/src/overhaul_scope/schema.py +++ b/src/overhaul_scope/schema.py @@ -11,9 +11,11 @@ class ScopeBase(DefultBase): duration_oh: Optional[int] = Field(720, title="Duration OH") crew_number: Optional[int] = Field(10, title="Crew") status: Optional[str] = Field("Upcoming") - type: str = Field(..., title="Type") # Added title +class MaintenanceType(DefultBase): + name: str + class ScopeCreate(ScopeBase): start_date: datetime end_date: Optional[datetime] = Field(None) @@ -27,6 +29,7 @@ class ScopeRead(ScopeBase): id: UUID start_date: datetime end_date: Optional[datetime] + maintenance_type: MaintenanceType class ScopePagination(Pagination): diff --git a/src/overhaul_scope/service.py b/src/overhaul_scope/service.py index 632dd75..f60b964 100644 --- a/src/overhaul_scope/service.py +++ b/src/overhaul_scope/service.py @@ -1,15 +1,19 @@ from typing import Optional from sqlalchemy import Delete, Select, func +from sqlalchemy.orm import selectinload from src.auth.service import CurrentUser from src.database.core import DbSession 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 src.utils import time_now +from src.standard_scope.model import StandardScope, EquipmentOHHistory +from src.workscope_group.model import MasterActivity +from src.workscope_group_maintenance_type.model import WorkscopeOHType +from src.equipment_workscope_group.model import EquipmentWorkscopeGroup -from .model import OverhaulScope +from .model import OverhaulScope, MaintenanceType from .schema import ScopeCreate, ScopeUpdate from .utils import get_material_cost, get_service_cost from datetime import datetime @@ -18,7 +22,7 @@ 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) + query = Select(OverhaulScope).filter(OverhaulScope.id == overhaul_session_id).options(selectinload(OverhaulScope.maintenance_type)) result = await db_session.execute(query) return result.scalars().one_or_none() @@ -34,7 +38,7 @@ async def get_all(*, common, scope_name: Optional[str] = None): query = Select(OverhaulScope) if scope_name: - query = query.filter(OverhaulScope.type == scope_name) + query = query.filter(OverhaulScope.maintenance_type.name == scope_name) results = await search_filter_sort_paginate(model=query, **common) return results @@ -66,12 +70,21 @@ async def create(*, db_session: DbSession, scope_in: ScopeCreate): if start_date and end_date: duration_days = (end_date - start_date).days + maintenance_type = Select(MaintenanceType).where(MaintenanceType.name == scope_in.type) + maintenance_type = await db_session.execute(maintenance_type) + maintenance_type = maintenance_type.scalars().one_or_none() + + if maintenance_type is None: + maintenance_type = MaintenanceType(name=scope_in.type) + db_session.add(maintenance_type) + await db_session.flush() + # Create the OverhaulScope object with all hardcoded values overhaul_session = OverhaulScope( start_date=scope_in.start_date, end_date=scope_in.end_date, - type=scope_in.type, # Hardcoded type - duration_oh=duration_days, # Hardcoded duration (30 days) + maintenance_type=maintenance_type, + duration_oh=duration_days, crew_number=scope_in.crew_number, # Hardcoded crew number status=scope_in.status # Hardcoded status ) @@ -138,68 +151,117 @@ async def get_overview_overhaul(*, db_session: DbSession): current_date = time_now().date() - # For ongoing overhaul with count + # 1. Check for ongoing overhaul ongoing_query = ( - Select(OverhaulScope, func.count(OverhaulActivity.id).label("equipment_count")) - .outerjoin(OverhaulScope.activity_equipments) + Select(OverhaulScope) .where( OverhaulScope.start_date <= current_date, OverhaulScope.end_date >= current_date, ) - .group_by(OverhaulScope.id) ) - - ongoing_result = await db_session.execute(ongoing_query) - # Use first() instead of scalar_one_or_none() - ongoing_result = ongoing_result.first() - - - if ongoing_result: - ongoing_overhaul, equipment_count = ongoing_result # Unpack the result tuple - return { - "status": "Ongoing", - "overhaul": { - "id": ongoing_overhaul.id, - "type": ongoing_overhaul.type, - "start_date": ongoing_overhaul.start_date, - "end_date": ongoing_overhaul.end_date, - "duration_oh": ongoing_overhaul.duration_oh, - "crew_number": ongoing_overhaul.crew_number, - "remaining_days": (ongoing_overhaul.end_date - current_date).days, - "equipment_count": equipment_count, - }, - } - - # For upcoming overhaul with count - upcoming_query = ( - Select(OverhaulScope, func.count(OverhaulActivity.id).label("equipment_count")) - .outerjoin(OverhaulScope.activity_equipments) - .where( - OverhaulScope.start_date > current_date, + ongoing_result = await db_session.execute(ongoing_query.options(selectinload(OverhaulScope.maintenance_type))) + ongoing_overhaul = ongoing_result.first() + + # 2. If no ongoing overhaul, get the closest scheduled overhaul + if ongoing_overhaul is None: + # Get the closest future overhaul (next scheduled) + next_overhaul_query = ( + Select(OverhaulScope) + .where(OverhaulScope.start_date > current_date) + .order_by(OverhaulScope.start_date.asc()) + .limit(1) ) - .group_by(OverhaulScope.id) - .order_by(OverhaulScope.start_date) + next_result = await db_session.execute(next_overhaul_query.options(selectinload(OverhaulScope.maintenance_type))) + next_overhaul = next_result.scalar_one_or_none() + + if next_overhaul: + print(f"Next scheduled overhaul starts on: {next_overhaul.start_date}") + selected_overhaul = next_overhaul + else: + print("No upcoming overhauls scheduled") + selected_overhaul = None + else: + print(f"Ongoing overhaul found: {ongoing_overhaul.start_date} to {ongoing_overhaul.end_date}") + selected_overhaul = ongoing_overhaul + + + equipments = ( + Select(StandardScope) + .outerjoin(StandardScope.oh_history) # Use outerjoin to handle None values + .join(StandardScope.workscope_groups) + .join(EquipmentWorkscopeGroup.workscope_group) + .join(MasterActivity.oh_types) + .filter(WorkscopeOHType.maintenance_type_id == selected_overhaul.maintenance_type_id) + .filter( + (StandardScope.is_alternating_oh == False) | + (StandardScope.oh_history == None) | + (StandardScope.oh_history.has(EquipmentOHHistory.last_oh_type != selected_overhaul.maintenance_type.name)) + ).distinct() ) - upcoming_result = await db_session.execute(upcoming_query) - upcoming_result = upcoming_result.first() - - if upcoming_result: - upcoming_overhaul, equipment_count = upcoming_result # Unpack the result tuple - days_until = (upcoming_overhaul.start_date - current_date).days - - return { - "status": "Upcoming", - "overhaul": { - "id": upcoming_overhaul.id, - "type": upcoming_overhaul.type, - "start_date": upcoming_overhaul.start_date, - "end_date": upcoming_overhaul.end_date, - "duration_oh": upcoming_overhaul.duration_oh, - "crew_number": upcoming_overhaul.crew_number, - "remaining_days": days_until, - "equipment_count": equipment_count, - }, - } - - return {"status": "no_overhaul", "overhaul": None} + results = await db_session.execute(equipments) + + return { + "status": selected_overhaul.status, + "overhaul": { + "id": selected_overhaul.id, + "type": selected_overhaul.maintenance_type.name, + "start_date": selected_overhaul.start_date, + "end_date": selected_overhaul.end_date, + "duration_oh": selected_overhaul.duration_oh, + "crew_number": selected_overhaul.crew_number, + "remaining_days": (selected_overhaul.end_date - current_date).days, + "equipment_count": len(results.scalars().all()), + }, + } + + + # if ongoing_result: + # ongoing_overhaul, equipment_count = ongoing_result # Unpack the result tuple + # return { + # "status": "Ongoing", + # "overhaul": { + # "id": ongoing_overhaul.id, + # "type": ongoing_overhaul.maintenance_type.name, + # "start_date": ongoing_overhaul.start_date, + # "end_date": ongoing_overhaul.end_date, + # "duration_oh": ongoing_overhaul.duration_oh, + # "crew_number": ongoing_overhaul.crew_number, + # "remaining_days": (ongoing_overhaul.end_date - current_date).days, + # "equipment_count": equipment_count, + # }, + # } + + # # For upcoming overhaul with count + # upcoming_query = ( + # Select(OverhaulScope, func.count(OverhaulActivity.id).label("equipment_count")) + # .outerjoin(OverhaulScope.activity_equipments) + # .where( + # OverhaulScope.start_date > current_date, + # ) + # .group_by(OverhaulScope.id) + # .order_by(OverhaulScope.start_date) + # ) + + # upcoming_result = await db_session.execute(upcoming_query) + # upcoming_result = upcoming_result.first() + + # if upcoming_result: + # upcoming_overhaul, equipment_count = upcoming_result # Unpack the result tuple + # days_until = (upcoming_overhaul.start_date - current_date).days + + # return { + # "status": "Upcoming", + # "overhaul": { + # "id": upcoming_overhaul.id, + # "type": upcoming_overhaul.type, + # "start_date": upcoming_overhaul.start_date, + # "end_date": upcoming_overhaul.end_date, + # "duration_oh": upcoming_overhaul.duration_oh, + # "crew_number": upcoming_overhaul.crew_number, + # "remaining_days": days_until, + # "equipment_count": equipment_count, + # }, + # } + + # return {"status": "no_overhaul", "overhaul": None} diff --git a/src/scope_equipment/service.py b/src/scope_equipment/service.py deleted file mode 100644 index 5704ac8..0000000 --- a/src/scope_equipment/service.py +++ /dev/null @@ -1,202 +0,0 @@ -from datetime import datetime, timedelta -from typing import Optional, Union - -from fastapi import HTTPException, status -from sqlalchemy import Delete, Select, and_, desc, func, not_, or_ -from sqlalchemy.dialects.postgresql import insert -from sqlalchemy.orm import selectinload - -from src.auth.service import CurrentUser -from src.database.core import DbSession -from src.database.service import CommonParameters, search_filter_sort_paginate -from src.overhaul_scope.model import OverhaulScope -from src.scope_equipment.enum import ScopeEquipmentType -from src.workorder.model import MasterWorkOrder - -from .model import MasterEquipment, MasterEquipmentTree, ScopeEquipment -from .schema import ScopeEquipmentCreate, ScopeEquipmentUpdate - - -async def get_by_assetnum(*, db_session: DbSession, assetnum: str): - query = ( - Select(ScopeEquipment) - .filter(ScopeEquipment.assetnum == assetnum) - .options(selectinload(ScopeEquipment.master_equipment)) - ) - - result = await db_session.execute(query) - return result.unique().scalars().one_or_none() - - -async def get_all(*, common, scope_name: str = None): - """Returns all documents.""" - query = Select(ScopeEquipment).options( - selectinload(ScopeEquipment.master_equipment) - ) - - query = query.order_by(desc(ScopeEquipment.created_at)) - - if scope_name: - query = query.where(ScopeEquipment.scope_overhaul == scope_name) - - results = await search_filter_sort_paginate(model=query, **common) - return results - - -async def create(*, db_session: DbSession, scope_equipment_in: ScopeEquipmentCreate): - """Creates a new document.""" - # scope_equipment = ScopeEquipment(**scope_equipment_in.model_dump()) - assetnums = scope_equipment_in.assetnums - results = [] - removal_date = scope_equipment_in.removal_date - - if scope_equipment_in.type == ScopeEquipmentType.TEMP: - # Search for the next or ongoing overhaul session for the given scope - stmt = ( - Select(OverhaulScope.end_date) - .where( - 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) - ) - - 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: - stmt = insert(ScopeEquipment).values( - assetnum=assetnum, - scope_overhaul=scope_equipment_in.scope_name, - type=scope_equipment_in.type, - removal_date=removal_date, - ) - - stmt = stmt.on_conflict_do_nothing( - index_elements=["assetnum", "scope_overhaul"] - ) - - await db_session.execute(stmt) - results.append(assetnum) - - await db_session.commit() - return results - - -async def update( - *, - db_session: DbSession, - scope_equipment: ScopeEquipment, - scope_equipment_in: ScopeEquipmentUpdate -): - """Updates a document.""" - data = scope_equipment_in.model_dump() - - update_data = scope_equipment_in.model_dump(exclude_defaults=True) - - for field in data: - if field in update_data: - setattr(scope_equipment, field, update_data[field]) - - await db_session.commit() - - return scope_equipment - - -async def delete(*, db_session: DbSession, assetnum: str): - """Deletes a document.""" - query = Delete(ScopeEquipment).where(ScopeEquipment.assetnum == assetnum) - await db_session.execute(query) - await db_session.commit() - - return assetnum - - # 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: - # raise HTTPException( - # status_code=status.HTTP_404_NOT_FOUND, - # detail="A data with this id does not exist.", - # ) - - # 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: Optional[str] -) -> Optional[ScopeEquipment]: - """Returns a document based on the given document id.""" - query = Select(ScopeEquipment).options( - selectinload(ScopeEquipment.master_equipment) - ) - - if scope_name: - query = query.filter(ScopeEquipment.scope_overhaul == scope_name) - - result = await db_session.execute(query) - return result.scalars().all() - - -# 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) - -# query = Select(ScopeEquipment) - -# if scope: -# query = query.filter(ScopeEquipment.current_scope_id != scope.id) - -# else: -# query = query.filter(ScopeEquipment.current_scope_id != None) - -# result = await db_session.execute(query) -# return result.scalars().all() - - -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 = Select(MasterEquipment).filter(MasterEquipment.assetnum.is_not(None)) - - # Only add not_in filter if there are items in equipments_scope - if equipments_scope: - query = query.filter(MasterEquipment.assetnum.not_in(equipments_scope)) - - results = await search_filter_sort_paginate(model=query, **common) - return results - - -async def get_equipment_level_by_no(*, db_session: DbSession, level: int): - query = ( - Select(MasterEquipment) - .join(MasterEquipment.equipment_tree) - .where(MasterEquipmentTree.level_no == level) - ) - - result = await db_session.execute(query) - return result.scalars().all() diff --git a/src/scope_equipment_job/model.py b/src/scope_equipment_job/model.py deleted file mode 100644 index e12324e..0000000 --- a/src/scope_equipment_job/model.py +++ /dev/null @@ -1,20 +0,0 @@ -from sqlalchemy import UUID, Column, Float, ForeignKey, Integer, String -from sqlalchemy.ext.hybrid import hybrid_property -from sqlalchemy.orm import relationship - -from src.database.core import Base -from src.models import DefaultMixin, IdentityMixin, TimeStampMixin -from src.workorder.model import MasterWorkOrder - - -class ScopeEquipmentJob(Base, DefaultMixin): - __tablename__ = "oh_ms_scope_equipment_job" - - assetnum = Column(String, nullable=False) - job_id = Column(UUID(as_uuid=True), ForeignKey("oh_ms_job.id", ondelete="cascade")) - - job = relationship("MasterActivity", lazy="selectin") - - overhaul_jobs = relationship( - "OverhaulJob", back_populates="scope_equipment_job", lazy="selectin" - ) diff --git a/src/scope_equipment_job/__init__.py b/src/standard_scope/__init__.py similarity index 100% rename from src/scope_equipment_job/__init__.py rename to src/standard_scope/__init__.py diff --git a/src/scope_equipment/enum.py b/src/standard_scope/enum.py similarity index 100% rename from src/scope_equipment/enum.py rename to src/standard_scope/enum.py diff --git a/src/scope_equipment/model.py b/src/standard_scope/model.py similarity index 55% rename from src/scope_equipment/model.py rename to src/standard_scope/model.py index 087e4b4..e429a5b 100644 --- a/src/scope_equipment/model.py +++ b/src/standard_scope/model.py @@ -1,4 +1,4 @@ -from sqlalchemy import UUID, Column, Date, Float, ForeignKey, Integer, String +from sqlalchemy import UUID, Column, Date, Float, ForeignKey, Integer, String, Boolean from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship @@ -7,22 +7,40 @@ from src.models import DefaultMixin, IdentityMixin, TimeStampMixin from src.workorder.model import MasterWorkOrder -class ScopeEquipment(Base, DefaultMixin): - __tablename__ = "oh_ms_scope_equipment" +class StandardScope(Base, DefaultMixin): + __tablename__ = "oh_ms_standard_scope" - assetnum = Column(String, nullable=True) - scope_overhaul = Column(String, nullable=False) - type = Column(String, nullable=False, default="Permanent") - removal_date = Column(Date, nullable=True) + location_tag = Column(String, nullable=False) + is_alternating_oh = Column(Boolean, nullable=False, default=False) assigned_date = Column(Date, nullable=True) master_equipment = relationship( "MasterEquipment", - lazy="raise", - primaryjoin="and_(ScopeEquipment.assetnum == foreign(MasterEquipment.assetnum))", + lazy="selectin", + primaryjoin="and_(StandardScope.location_tag == foreign(MasterEquipment.location_tag))", + uselist=False, # Add this if it's a one-to-one relationship + ) + + oh_history = relationship( + "EquipmentOHHistory", + lazy="selectin", + primaryjoin="and_(StandardScope.location_tag == foreign(EquipmentOHHistory.location_tag))", uselist=False, # Add this if it's a one-to-one relationship ) + workscope_groups = relationship( + "EquipmentWorkscopeGroup", + lazy="selectin", + primaryjoin="and_(EquipmentWorkscopeGroup.location_tag == foreign(StandardScope.location_tag))", + uselist=True, # Add this if it's a one-to-one relationship + ) + +class EquipmentOHHistory(Base, DefaultMixin): + __tablename__ = "oh_ms_equipment_oh_history" + location_tag = Column(String, nullable=False) + last_oh_date = Column(Date, nullable=True) + last_oh_type = Column(String, nullable=True) + class MasterEquipment(Base, DefaultMixin): __tablename__ = "ms_equipment_master" diff --git a/src/scope_equipment/router.py b/src/standard_scope/router.py similarity index 53% rename from src/scope_equipment/router.py rename to src/standard_scope/router.py index 851c72a..45b4a4f 100644 --- a/src/scope_equipment/router.py +++ b/src/standard_scope/router.py @@ -8,12 +8,10 @@ from src.database.core import DbSession from src.database.service import CommonParameters, search_filter_sort_paginate from src.models import StandardResponse -from .model import ScopeEquipment from .schema import (MasterEquipmentPagination, ScopeEquipmentCreate, ScopeEquipmentPagination, ScopeEquipmentRead, ScopeEquipmentUpdate) -from .service import (create, delete, get_all, get_all_master_equipment, - get_by_assetnum, update) +from .service import (create, delete, get_all, get_all_master_equipment, update) router = APIRouter() @@ -22,7 +20,7 @@ router = APIRouter() async def get_scope_equipments(common: CommonParameters, scope_name: str = Query(None)): """Get all scope pagination.""" # return - data = await get_all(common=common, scope_name=scope_name) + data = await get_all(common=common, oh_scope=scope_name) return StandardResponse( data=data, @@ -49,38 +47,38 @@ async def create_scope_equipment( return StandardResponse(data=scope, message="Data created successfully") -@router.put("/{assetnum}", response_model=StandardResponse[ScopeEquipmentRead]) -async def update_scope_equipment( - db_session: DbSession, assetnum: str, scope__equipment_in: ScopeEquipmentUpdate -): - scope_equipment = await get_by_assetnum(db_session=db_session, assetnum=assetnum) +# @router.put("/{assetnum}", response_model=StandardResponse[ScopeEquipmentRead]) +# async def update_scope_equipment( +# db_session: DbSession, assetnum: str, scope__equipment_in: ScopeEquipmentUpdate +# ): +# scope_equipment = await get_by_assetnum(db_session=db_session, assetnum=assetnum) - if not scope_equipment: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="A data with this id does not exist.", - ) +# if not scope_equipment: +# 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, - 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("/{assetnum}", response_model=StandardResponse[None]) -async def delete_scope_equipment(db_session: DbSession, assetnum: str): - scope_equipment = await get_by_assetnum(db_session=db_session, assetnum=assetnum) +# @router.delete("/{assetnum}", response_model=StandardResponse[None]) +# async def delete_scope_equipment(db_session: DbSession, assetnum: str): +# scope_equipment = await get_by_assetnum(db_session=db_session, assetnum=assetnum) - if not scope_equipment: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=[{"msg": "A data with this id does not exist."}], - ) +# if not scope_equipment: +# 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) +# await delete(db_session=db_session, assetnum=assetnum) - return StandardResponse(message="Data deleted successfully", data=None) +# return StandardResponse(message="Data deleted successfully", data=None) diff --git a/src/scope_equipment/schema.py b/src/standard_scope/schema.py similarity index 98% rename from src/scope_equipment/schema.py rename to src/standard_scope/schema.py index 634646a..d2621f0 100644 --- a/src/scope_equipment/schema.py +++ b/src/standard_scope/schema.py @@ -32,7 +32,7 @@ class ScopeEquipmentUpdate(ScopeEquipmentBase): class ScopeEquipmentRead(ScopeEquipmentBase): id: UUID - assetnum: str + location_tag: str assigned_date: datetime master_equipment: Optional[MasterEquipmentBase] = Field(None) @@ -40,9 +40,6 @@ class ScopeEquipmentRead(ScopeEquipmentBase): class ScopeEquipmentPagination(Pagination): items: List[ScopeEquipmentRead] = [] - - - class MasterEquipmentRead(DefultBase): assetnum: Optional[str] = Field(None, title="Asset Number") location_tag: Optional[str] = Field(None, title="Location Tag") diff --git a/src/standard_scope/service.py b/src/standard_scope/service.py new file mode 100644 index 0000000..1b0f12c --- /dev/null +++ b/src/standard_scope/service.py @@ -0,0 +1,212 @@ +from datetime import datetime, timedelta +from typing import Optional, Union + +from fastapi import HTTPException, status +from sqlalchemy import Delete, Select, and_, desc, func, not_, or_ +from sqlalchemy.dialects.postgresql import insert +from sqlalchemy.orm import selectinload + +from src.auth.service import CurrentUser +from src.database.core import DbSession +from src.database.service import CommonParameters, search_filter_sort_paginate +from src.overhaul_scope.model import OverhaulScope +from src.standard_scope.enum import ScopeEquipmentType +from src.standard_scope.model import EquipmentOHHistory +from src.workorder.model import MasterWorkOrder +from src.equipment_workscope_group.model import EquipmentWorkscopeGroup +from src.workscope_group.model import MasterActivity +from src.workscope_group_maintenance_type.model import WorkscopeOHType +from src.overhaul_scope.model import MaintenanceType +from src.overhaul_scope.service import get as get_overhaul +from .model import MasterEquipment, MasterEquipmentTree, StandardScope +from .schema import ScopeEquipmentCreate, ScopeEquipmentUpdate +from uuid import UUID + +async def get_by_location_tag(*, db_session: DbSession, location_tag: str): + query = ( + Select(StandardScope) + .filter(StandardScope.location_tag == location_tag) + .options(selectinload(StandardScope.master_equipment)) + ) + + result = await db_session.execute(query) + return result.unique().scalars().one_or_none() + + +async def get_all(*, common, oh_scope: Optional[str] = None): + """Returns all documents.""" + query = Select(StandardScope).options( + selectinload(StandardScope.master_equipment) + ) + + query = query.order_by(desc(StandardScope.created_at)).options(selectinload(StandardScope.master_equipment)) + + if oh_scope: + query = ( + query + .outerjoin(StandardScope.oh_history) # Use outerjoin to handle None values + .join(StandardScope.workscope_groups) + .join(EquipmentWorkscopeGroup.workscope_group) + .join(MasterActivity.oh_types) + .join(WorkscopeOHType.oh_type) + .filter(MaintenanceType.name == oh_scope) + + # .filter( + # (StandardScope.is_alternating_oh == False) | + # (StandardScope.oh_history == None) | + # (StandardScope.oh_history.has(EquipmentOHHistory.last_oh_type != selected_overhaul.maintenance_type.name)) + # ).distinct() + ) + + results = await search_filter_sort_paginate(model=query, **common) + return results + + +async def get_by_oh_session_id(*, db_session: DbSession, oh_session_id: UUID): + overhaul = await get_overhaul(db_session=db_session, overhaul_session_id=oh_session_id) + + query = ( + Select(StandardScope) + .outerjoin(StandardScope.oh_history) # Use outerjoin to handle None values + .join(StandardScope.workscope_groups) + .join(EquipmentWorkscopeGroup.workscope_group) + .join(MasterActivity.oh_types) + .join(WorkscopeOHType.oh_type) + .filter(MaintenanceType.name == overhaul.maintenance_type.name).filter( + (StandardScope.is_alternating_oh == False) | + (StandardScope.oh_history == None) | + (StandardScope.oh_history.has(EquipmentOHHistory.last_oh_type != overhaul.maintenance_type.name)) + ).distinct() + ) + + result = await db_session.execute(query) + return result.scalars().all(), overhaul + +async def create(*, db_session: DbSession, scope_equipment_in: ScopeEquipmentCreate): + """Creates a new document.""" + # scope_equipment = StandardScope(**scope_equipment_in.model_dump()) + assetnums = scope_equipment_in.assetnums + results = [] + removal_date = scope_equipment_in.removal_date + + if scope_equipment_in.type == ScopeEquipmentType.TEMP: + # Search for the next or ongoing overhaul session for the given scope + stmt = ( + Select(OverhaulScope.end_date) + .where( + 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) + ) + + 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: + stmt = insert(StandardScope).values( + assetnum=assetnum, + scope_overhaul=scope_equipment_in.scope_name, + type=scope_equipment_in.type, + removal_date=removal_date, + ) + + stmt = stmt.on_conflict_do_nothing( + index_elements=["assetnum", "scope_overhaul"] + ) + + await db_session.execute(stmt) + results.append(assetnum) + + await db_session.commit() + return results + + +async def update( + *, + db_session: DbSession, + scope_equipment: StandardScope, + scope_equipment_in: ScopeEquipmentUpdate +): + """Updates a document.""" + data = scope_equipment_in.model_dump() + + update_data = scope_equipment_in.model_dump(exclude_defaults=True) + + for field in data: + if field in update_data: + setattr(scope_equipment, field, update_data[field]) + + await db_session.commit() + + return scope_equipment + + +async def delete(*, db_session: DbSession, assetnum: str): + """Deletes a document.""" + query = Delete(StandardScope).where(StandardScope.assetnum == assetnum) + await db_session.execute(query) + await db_session.commit() + + return assetnum + +async def get_by_oh_scope( + *, db_session: DbSession, oh_scope: str +): + pass + + query = (Select(StandardScope) + .outerjoin(StandardScope.oh_history) # Use outerjoin to handle None values + .join(StandardScope.workscope_groups) + .join(EquipmentWorkscopeGroup.workscope_group) + .join(MasterActivity.oh_types) + .join(WorkscopeOHType.oh_type) + .filter(MaintenanceType.name == oh_scope) + # .filter( + # (StandardScope.is_alternating_oh == False) | + # (StandardScope.oh_history == None) | + # (StandardScope.oh_history.has(EquipmentOHHistory.last_oh_type != selected_overhaul.maintenance_type.name)) + # ).distinct() + ) + + results = await db_session.execute(query) + return results.scalars().all() + + +async def get_all_master_equipment(*, common: CommonParameters, scope_name): + equipments_scope = [ + equip.location_tag + for equip in await get_by_oh_scope( + db_session=common.get("db_session"), oh_scope=scope_name + ) + ] + + query = Select(MasterEquipment).filter(MasterEquipment.location_tag.is_not(None)) + + # Only add not_in filter if there are items in equipments_scope + if equipments_scope: + query = query.filter(MasterEquipment.location_tag.not_in(equipments_scope)) + + results = await search_filter_sort_paginate(model=query, **common) + return results + + +async def get_equipment_level_by_no(*, db_session: DbSession, level: int): + query = ( + Select(MasterEquipment) + .join(MasterEquipment.equipment_tree) + .where(MasterEquipmentTree.level_no == level) + ) + + result = await db_session.execute(query) + return result.scalars().all() diff --git a/src/workorder/model.py b/src/workorder/model.py index c346d37..d30a62b 100644 --- a/src/workorder/model.py +++ b/src/workorder/model.py @@ -13,8 +13,8 @@ class MasterWorkOrder(Base, DefaultMixin): workgroup = Column(String, nullable=True) total_cost_max = Column(Float, nullable=True) - scope_equipments = relationship( - "ScopeEquipment", - lazy="raise", - primaryjoin="and_(MasterWorkOrder.assetnum == foreign(ScopeEquipment.assetnum))", - ) + # scope_equipments = relationship( + # "ScopeEquipment", + # lazy="raise", + # primaryjoin="and_(MasterWorkOrder.assetnum == foreign(ScopeEquipment.assetnum))", + # ) diff --git a/src/scope_equipment_part/__init__.py b/src/workscope_group/__init__.py similarity index 100% rename from src/scope_equipment_part/__init__.py rename to src/workscope_group/__init__.py diff --git a/src/job/model.py b/src/workscope_group/model.py similarity index 71% rename from src/job/model.py rename to src/workscope_group/model.py index eba32c7..a726f5b 100644 --- a/src/job/model.py +++ b/src/workscope_group/model.py @@ -8,19 +8,20 @@ from src.workorder.model import MasterWorkOrder class MasterActivitytask(Base, DefaultMixin): - __tablename__ = "oh_ms_job_task" + __tablename__ = "oh_ms_workscope_task" description = Column(String, nullable=False) - oh_type = Column(String, nullable=False) + + job_id = Column( UUID(as_uuid=True), - ForeignKey("oh_ms_job.id", ondelete="cascade"), + ForeignKey("oh_ms_workscope_group.id", ondelete="cascade"), nullable=False, ) class MasterActivity(Base, DefaultMixin): - __tablename__ = "oh_ms_job" + __tablename__ = "oh_ms_workscope_group" workscope = Column(String, nullable=True) system = Column(String, nullable=True) @@ -31,6 +32,19 @@ class MasterActivity(Base, DefaultMixin): lazy="selectin", ) + + equipment_workscope_groups = relationship( + "EquipmentWorkscopeGroup", + lazy="selectin", + back_populates="workscope_group", + ) + + oh_types = relationship( + "WorkscopeOHType", + lazy="selectin", + back_populates="workscope_group", + ) + # details = relationship( # "MasterActivityDetail", # lazy="raise", diff --git a/src/job/router.py b/src/workscope_group/router.py similarity index 100% rename from src/job/router.py rename to src/workscope_group/router.py diff --git a/src/job/schema.py b/src/workscope_group/schema.py similarity index 98% rename from src/job/schema.py rename to src/workscope_group/schema.py index f9bc756..afe9cab 100644 --- a/src/job/schema.py +++ b/src/workscope_group/schema.py @@ -21,7 +21,6 @@ class ActivityMasterCreate(ActivityMaster): class ActivityMasterTasks(DefultBase): description: str - oh_type: str class ActivityMasterRead(ActivityMaster): diff --git a/src/job/service.py b/src/workscope_group/service.py similarity index 100% rename from src/job/service.py rename to src/workscope_group/service.py diff --git a/src/workscope_group_maintenance_type/__init__.py b/src/workscope_group_maintenance_type/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/workscope_group_maintenance_type/model.py b/src/workscope_group_maintenance_type/model.py new file mode 100644 index 0000000..d8f1597 --- /dev/null +++ b/src/workscope_group_maintenance_type/model.py @@ -0,0 +1,18 @@ +from sqlalchemy import UUID, Column, Float, ForeignKey, Integer, String +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import relationship + +from src.database.core import Base +from src.models import DefaultMixin, IdentityMixin, TimeStampMixin +from src.workorder.model import MasterWorkOrder + + +class WorkscopeOHType(Base): + __tablename__ = 'oh_tr_workscope_maintenance_type' + + id = Column(UUID(as_uuid=True), primary_key=True) + workscope_group_id = Column(UUID(as_uuid=True), ForeignKey('oh_ms_workscope_group.id')) + maintenance_type_id = Column(UUID(as_uuid=True), ForeignKey('oh_ms_maintenance_type.id')) + + workscope_group = relationship('MasterActivity', back_populates='oh_types') + oh_type = relationship('MaintenanceType') diff --git a/src/workscope_group_maintenance_type/service.py b/src/workscope_group_maintenance_type/service.py new file mode 100644 index 0000000..9199703 --- /dev/null +++ b/src/workscope_group_maintenance_type/service.py @@ -0,0 +1,59 @@ +from typing import Optional + +from sqlalchemy import Delete, Select +from sqlalchemy.orm import joinedload, selectinload + +from src.auth.service import CurrentUser +from src.database.core import DbSession +from src.database.service import CommonParameters, search_filter_sort_paginate + +from .model import MasterActivity +from .schema import ActivityMaster, ActivityMasterCreate + + +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) + + 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()