add and delete scope q

feature/reliability_stat
Cizz22 3 months ago
parent 69bb64cf48
commit 94e362eecd

16
.env

@ -9,9 +9,15 @@ DATABASE_CREDENTIAL_USER=postgres
DATABASE_CREDENTIAL_PASSWORD=postgres DATABASE_CREDENTIAL_PASSWORD=postgres
DATABASE_NAME=digital_twin DATABASE_NAME=digital_twin
COLLECTOR_HOSTNAME=192.168.1.82 # COLLECTOR_HOSTNAME=192.168.1.82
COLLECTOR_PORT=1111 # COLLECTOR_PORT=1111
COLLECTOR_CREDENTIAL_USER=digital_twin # COLLECTOR_CREDENTIAL_USER=digital_twin
COLLECTOR_CREDENTIAL_PASSWORD=Pr0jec7@D!g!tTwiN # COLLECTOR_CREDENTIAL_PASSWORD=Pr0jec7@D!g!tTwiN
COLLECTOR_NAME=digital_twin # COLLECTOR_NAME=digital_twin
COLLECTOR_HOSTNAME=192.168.1.86
COLLECTOR_PORT=5432
COLLECTOR_CREDENTIAL_USER=postgres
COLLECTOR_CREDENTIAL_PASSWORD=postgres
COLLECTOR_NAME=digital_twin

@ -10,7 +10,7 @@ from src.models import StandardResponse
from .schema import (OverhaulActivityCreate, OverhaulActivityPagination, from .schema import (OverhaulActivityCreate, OverhaulActivityPagination,
OverhaulActivityRead, OverhaulActivityUpdate) OverhaulActivityRead, OverhaulActivityUpdate)
from .service import add_multiple_equipment_to_session, create, delete, get, get_all, update from .service import add_multiple_equipment_to_session, get, get_all, remove_equipment_from_session, update
router = APIRouter() router = APIRouter()
@ -79,46 +79,38 @@ async def get_overhaul_equipment(
return StandardResponse(data=equipment, message="Data retrieved successfully") return StandardResponse(data=equipment, message="Data retrieved successfully")
@router.put( # @router.put(
"/{overhaul_session}/{assetnum}", # "/{overhaul_session}/{assetnum}",
response_model=StandardResponse[OverhaulActivityRead], # response_model=StandardResponse[OverhaulActivityRead],
) # )
async def update_scope( # async def update_scope(
db_session: DbSession, # db_session: DbSession,
scope_equipment_activity_in: OverhaulActivityUpdate, # scope_equipment_activity_in: OverhaulActivityUpdate,
assetnum: str, # assetnum: str,
): # ):
activity = await get(db_session=db_session, assetnum=assetnum) # activity = await get(db_session=db_session, assetnum=assetnum)
if not activity: # if not activity:
raise HTTPException( # raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, # status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.", # detail="A data with this id does not exist.",
) # )
return StandardResponse( # return StandardResponse(
data=await update( # data=await update(
db_session=db_session, # db_session=db_session,
activity=activity, # activity=activity,
scope_equipment_activity_in=scope_equipment_activity_in, # scope_equipment_activity_in=scope_equipment_activity_in,
), # ),
message="Data updated successfully", # message="Data updated successfully",
) # )
@router.delete( @router.delete(
"/{overhaul_session}/{assetnum}", "/{overhaul_session}/{location_tag}",
response_model=StandardResponse[OverhaulActivityRead], response_model=StandardResponse[None],
) )
async def delete_scope(db_session: DbSession, assetnum: str): async def delete_scope(db_session: DbSession, location_tag: str, overhaul_session:UUID):
activity = await get(db_session=db_session, assetnum=assetnum) await remove_equipment_from_session(db_session=db_session, overhaul_session_id=overhaul_session, location_tag=location_tag)
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) return StandardResponse(message="Data deleted successfully", data=None)

@ -1,8 +1,9 @@
import asyncio import asyncio
import datetime
from typing import List, Optional from typing import List, Optional
from uuid import UUID from uuid import UUID, uuid4
from sqlalchemy import Delete, Select, func, select from sqlalchemy import Delete, Select, and_, func, select
from sqlalchemy import update as sqlUpdate from sqlalchemy import update as sqlUpdate
from sqlalchemy.dialects.postgresql import insert from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.orm import joinedload, selectinload from sqlalchemy.orm import joinedload, selectinload
@ -213,8 +214,8 @@ async def add_equipment_to_session(
) -> Optional[StandardScope]: ) -> Optional[StandardScope]:
""" """
Add a new equipment to an existing overhaul session. Add a new equipment to an existing overhaul session.
Creates a dummy workscope group if needed. If equipment's workscope already maps to the overhaul type, skip.
Silently skips if equipment already exists in the session. Otherwise, attach a dummy workscope group for inclusion.
Args: Args:
db_session: Database session db_session: Database session
@ -223,99 +224,97 @@ async def add_equipment_to_session(
location_tag: The location tag of the equipment to add location_tag: The location tag of the equipment to add
Returns: Returns:
StandardScope: The newly created StandardScope record, or None if already exists StandardScope: The newly created or updated StandardScope record, or None if skipped
""" """
try: try:
# Get the overhaul session # Get the overhaul session
overhaul = await get_session(db_session=db_session, overhaul_session_id=overhaul_session_id) overhaul = await get_session(
db_session=db_session, overhaul_session_id=overhaul_session_id
)
# Check if MasterEquipment exists # Check if MasterEquipment exists
master_eq_query = select(MasterEquipment).filter( master_eq_query = select(MasterEquipment).filter(
MasterEquipment.location_tag == location_tag MasterEquipment.location_tag == location_tag
) )
master_eq_result = await db_session.execute(master_eq_query) master_eq_result = await db_session.execute(master_eq_query)
master_equipment = master_eq_result.scalar_one_or_none() master_equipment = master_eq_result.scalar_one_or_none()
if not master_equipment: if not master_equipment:
print("equipment not found in master") print("Equipment not found in master")
return None return None
# Check if equipment already exists in StandardScope # Check if equipment already exists in StandardScope
existing_query = select(StandardScope).filter( existing_query = select(StandardScope).filter(
StandardScope.location_tag == location_tag StandardScope.location_tag == location_tag
) )
existing_result = await db_session.execute(existing_query) existing_result = await db_session.execute(existing_query)
existing_equipment = existing_result.scalar_one_or_none() existing_equipment = existing_result.scalar_one_or_none()
if existing_equipment: # --- Step 1: Fetch equipment's actual workscope mappings ---
# Equipment already in StandardScope, check if it's in current session eq_workscope_query = (
# by verifying if it matches the session's maintenance type criteria select(EquipmentWorkscopeGroup)
check_query = ( .join(EquipmentWorkscopeGroup.workscope_group)
Select(StandardScope) .join(
.outerjoin(StandardScope.oh_history) WorkscopeOHType,
.join(StandardScope.workscope_groups) WorkscopeOHType.workscope_group_id == MasterActivity.id,
.join(EquipmentWorkscopeGroup.workscope_group) )
.join(MasterActivity.oh_types) .join(
.join(WorkscopeOHType.oh_type) MaintenanceType,
.filter(StandardScope.location_tag == location_tag) MaintenanceType.id == WorkscopeOHType.maintenance_type_id,
.filter(MaintenanceType.name == overhaul.maintenance_type.name) )
.filter( .filter(EquipmentWorkscopeGroup.location_tag == location_tag)
(StandardScope.is_alternating_oh == False) )
| (StandardScope.oh_history is None) eq_workscopes = (await db_session.execute(eq_workscope_query)).scalars().all()
| (
StandardScope.oh_history.has( # --- Step 2: Check if already included via natural workscope ---
EquipmentOHHistory.last_oh_type != overhaul.maintenance_type.name is_already_included = any(
) ws.workscope_group
) and any(
) wot.oh_type.name == overhaul.maintenance_type.name
for wot in ws.workscope_group.oh_types
) )
check_result = await db_session.execute(check_query) for ws in eq_workscopes
in_session = check_result.scalar_one_or_none() )
if in_session: if is_already_included:
# Already in current session, skip silently # Already belongs to this overhaul naturally → skip
return None return None
# Equipment exists but not in this session, need to add workscope # --- Step 3: Handle existing equipment ---
# Find or create dummy workscope group if existing_equipment:
# Add dummy workscope if not already attached
dummy_workscope = await get_or_create_dummy_workscope( dummy_workscope = await get_or_create_dummy_workscope(
db_session=db_session, db_session=db_session,
maintenance_type_name=overhaul.maintenance_type.name maintenance_type_name=overhaul.maintenance_type.name,
) )
# Add the dummy workscope to existing equipment if not already there
if dummy_workscope not in existing_equipment.workscope_groups: if dummy_workscope not in existing_equipment.workscope_groups:
existing_equipment.workscope_groups.append(dummy_workscope) dummy_workscope.location_tag = location_tag
await db_session.commit() await db_session.commit()
await db_session.refresh(existing_equipment) await db_session.refresh(existing_equipment)
return existing_equipment return existing_equipment
# Equipment not in StandardScope at all, create new # --- Step 4: Create new StandardScope for fresh equipment ---
# First, get or create dummy workscope group
dummy_workscope = await get_or_create_dummy_workscope( dummy_workscope = await get_or_create_dummy_workscope(
db_session=db_session, db_session=db_session,
maintenance_type_name=overhaul.maintenance_type.name maintenance_type_name=overhaul.maintenance_type.name,
) )
# Create new StandardScope record
new_equipment = StandardScope( new_equipment = StandardScope(
location_tag=location_tag, location_tag=location_tag,
is_alternating_oh=False, is_alternating_oh=True,
# Add other required fields based on your model assigned_date=datetime.date.today(),
) )
dummy_workscope.location_tag = location_tag
# Associate with dummy workscope group
new_equipment.workscope_groups = [dummy_workscope]
db_session.add(new_equipment) db_session.add(new_equipment)
await db_session.commit() await db_session.commit()
await db_session.refresh(new_equipment) await db_session.refresh(new_equipment)
return new_equipment return new_equipment
except Exception as e: except Exception as e:
# Log the error but don't raise it
print(f"Error adding equipment {location_tag}: {str(e)}") print(f"Error adding equipment {location_tag}: {str(e)}")
await db_session.rollback() await db_session.rollback()
return None return None
@ -324,7 +323,7 @@ async def add_equipment_to_session(
async def get_or_create_dummy_workscope( async def get_or_create_dummy_workscope(
*, *,
db_session: DbSession, db_session: DbSession,
maintenance_type_name: str maintenance_type_name: str,
) -> EquipmentWorkscopeGroup: ) -> EquipmentWorkscopeGroup:
""" """
Get or create a dummy workscope group for included equipment. Get or create a dummy workscope group for included equipment.
@ -337,50 +336,49 @@ async def get_or_create_dummy_workscope(
EquipmentWorkscopeGroup: The dummy workscope group EquipmentWorkscopeGroup: The dummy workscope group
""" """
dummy_name = f"Included Equipment Workscope - {maintenance_type_name}" dummy_name = f"Included Equipment Workscope - {maintenance_type_name}"
# Check if dummy workscope already exists # --- Step 1: Check if dummy MasterActivity exists ---
query = ( query = select(MasterActivity).filter(MasterActivity.workscope == dummy_name)
select(EquipmentWorkscopeGroup)
.join(EquipmentWorkscopeGroup.workscope_group)
.join(MasterActivity.oh_types)
.join(WorkscopeOHType.oh_type)
.filter(MasterActivity.name == dummy_name)
.filter(MaintenanceType.name == maintenance_type_name)
)
result = await db_session.execute(query) result = await db_session.execute(query)
existing = result.scalar_one_or_none() master_activity = result.scalar_one_or_none()
if existing: if not master_activity:
return existing master_activity = MasterActivity(workscope=dummy_name)
db_session.add(master_activity)
# Create dummy workscope group await db_session.commit()
# First, get the maintenance type await db_session.refresh(master_activity)
# --- Step 2: Ensure WorkscopeOHType link exists ---
mt_query = select(MaintenanceType).filter(MaintenanceType.name == maintenance_type_name) mt_query = select(MaintenanceType).filter(MaintenanceType.name == maintenance_type_name)
mt_result = await db_session.execute(mt_query) mt_result = await db_session.execute(mt_query)
maintenance_type = mt_result.scalar_one() maintenance_type = mt_result.scalar_one()
# Create MasterActivity (workscope_group) wo_oh_type_query = select(WorkscopeOHType).filter(
master_activity = MasterActivity( and_(
workscope=dummy_name, WorkscopeOHType.workscope_group_id == master_activity.id,
) WorkscopeOHType.maintenance_type_id == maintenance_type.id,
)
# Create WorkscopeOHType relationship
workscope_oh_type = WorkscopeOHType(
workscope_group=master_activity,
oh_type=maintenance_type
) )
workscope_oh_type = (await db_session.execute(wo_oh_type_query)).scalar_one_or_none()
# Create EquipmentWorkscopeGroup
if not workscope_oh_type:
workscope_oh_type = WorkscopeOHType(
id=uuid4(),
workscope_group=master_activity,
oh_type=maintenance_type,
)
db_session.add(workscope_oh_type)
await db_session.commit()
await db_session.refresh(workscope_oh_type)
# --- Step 3: Create new EquipmentWorkscopeGroup ---
equipment_workscope_group = EquipmentWorkscopeGroup( equipment_workscope_group = EquipmentWorkscopeGroup(
workscope_group=master_activity, workscope_group=master_activity,
# Add other required fields
) )
db_session.add(equipment_workscope_group) db_session.add(equipment_workscope_group)
await db_session.commit() await db_session.commit()
await db_session.refresh(equipment_workscope_group) await db_session.refresh(equipment_workscope_group)
return equipment_workscope_group return equipment_workscope_group
@ -433,62 +431,6 @@ async def get_all_by_session_id(*, db_session: DbSession, overhaul_session_id):
async def create(
*,
db_session: DbSession,
overhaul_activty_in: OverhaulActivityCreate,
overhaul_session_id: UUID
):
"""Creates a new document."""
assetnums = overhaul_activty_in.assetnums
if not assetnums:
return []
# Get session and count in parallel
session = await get_session(
db_session=db_session, overhaul_session_id=overhaul_session_id
)
equipment_count = await db_session.scalar(
select(func.count())
.select_from(OverhaulActivity)
.where(OverhaulActivity.overhaul_scope_id == overhaul_session_id)
)
# Calculate costs for all records
total_equipment = equipment_count + len(assetnums)
material_cost = get_material_cost(
scope=session.type, total_equipment=total_equipment
)
service_cost = get_service_cost(scope=session.type, total_equipment=total_equipment)
# Create the insert statement
stmt = insert(OverhaulActivity).values(
[
{
"assetnum": assetnum,
"overhaul_scope_id": overhaul_session_id,
"material_cost": material_cost,
"service_cost": service_cost,
}
for assetnum in assetnums
]
)
# Add the ON CONFLICT DO NOTHING clause
stmt = stmt.on_conflict_do_nothing(index_elements=["assetnum", "overhaul_scope_id"])
# Execute the statement
await db_session.execute(stmt)
await db_session.execute(
sqlUpdate(OverhaulActivity)
.where(OverhaulActivity.overhaul_scope_id == overhaul_session_id)
.values(material_cost=material_cost, service_cost=service_cost)
)
await db_session.commit()
return assetnums
async def update( async def update(
*, *,
db_session: DbSession, db_session: DbSession,
@ -509,8 +451,95 @@ async def update(
return activity return activity
async def delete(*, db_session: DbSession, overhaul_activity_id: str): async def remove_equipment_from_session(
"""Deletes a document.""" *,
activity = await db_session.get(OverhaulActivity, overhaul_activity_id) db_session: DbSession,
await db_session.delete(activity) overhaul_session_id: UUID,
await db_session.commit() location_tag: str
) -> bool:
"""
Remove equipment from a given overhaul session.
Only removes dummy workscope group links; natural workscope mappings are preserved.
Args:
db_session: Database session
overhaul_session_id: The UUID of the overhaul session
location_tag: The location tag of the equipment to remove
Returns:
bool: True if removed, False if skipped (not found or naturally included)
"""
try:
# Get the overhaul session
overhaul = await get_session(
db_session=db_session, overhaul_session_id=overhaul_session_id
)
# Find the equipment in StandardScope
existing_query = select(StandardScope).filter(
StandardScope.location_tag == location_tag
)
existing_result = await db_session.execute(existing_query)
equipment = existing_result.scalar_one_or_none()
if not equipment:
print(f"Equipment {location_tag} not found in StandardScope")
return False
# --- Step 1: Check if equipment belongs naturally (exclude dummy groups) ---
eq_workscope_query = (
select(EquipmentWorkscopeGroup)
.join(EquipmentWorkscopeGroup.workscope_group)
.join(
WorkscopeOHType,
WorkscopeOHType.workscope_group_id == MasterActivity.id,
)
.join(
MaintenanceType,
MaintenanceType.id == WorkscopeOHType.maintenance_type_id,
)
.filter(EquipmentWorkscopeGroup.location_tag == location_tag)
.filter(~MasterActivity.workscope.like("Included Equipment Workscope%")) # 🚨 exclude dummy
)
eq_workscopes = (await db_session.execute(eq_workscope_query)).scalars().all()
is_natural_inclusion = any(
ws.workscope_group
and any(
wot.oh_type.name == overhaul.maintenance_type.name
for wot in ws.workscope_group.oh_types
)
for ws in eq_workscopes
)
if is_natural_inclusion:
print(f"Equipment {location_tag} is naturally part of OH {overhaul.maintenance_type.name}, skip removal")
return False
# --- Step 2: Remove dummy workscope group for this overhaul ---
dummy_name = f"Included Equipment Workscope - {overhaul.maintenance_type.name}"
dummy_group = next(
(wg for wg in equipment.workscope_groups if wg.workscope_group.workscope == dummy_name),
None,
)
if dummy_group:
equipment.workscope_groups.remove(dummy_group)
await db_session.commit()
await db_session.refresh(equipment)
# --- Step 3 (optional): Delete StandardScope if no groups left ---
if not equipment.workscope_groups:
await db_session.delete(equipment)
await db_session.commit()
print(f"Equipment {location_tag} completely removed from StandardScope")
return True
print(f"No dummy workscope group found for {location_tag} in OH {overhaul.maintenance_type.name}")
return False
except Exception as e:
print(f"Error removing equipment {location_tag}: {str(e)}")
await db_session.rollback()
return False

Loading…
Cancel
Save