|
|
|
|
@ -1,8 +1,9 @@
|
|
|
|
|
import asyncio
|
|
|
|
|
import datetime
|
|
|
|
|
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.dialects.postgresql import insert
|
|
|
|
|
from sqlalchemy.orm import joinedload, selectinload
|
|
|
|
|
@ -213,8 +214,8 @@ async def add_equipment_to_session(
|
|
|
|
|
) -> Optional[StandardScope]:
|
|
|
|
|
"""
|
|
|
|
|
Add a new equipment to an existing overhaul session.
|
|
|
|
|
Creates a dummy workscope group if needed.
|
|
|
|
|
Silently skips if equipment already exists in the session.
|
|
|
|
|
If equipment's workscope already maps to the overhaul type, skip.
|
|
|
|
|
Otherwise, attach a dummy workscope group for inclusion.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
db_session: Database session
|
|
|
|
|
@ -223,99 +224,97 @@ async def add_equipment_to_session(
|
|
|
|
|
location_tag: The location tag of the equipment to add
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
# 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
|
|
|
|
|
master_eq_query = select(MasterEquipment).filter(
|
|
|
|
|
MasterEquipment.location_tag == location_tag
|
|
|
|
|
)
|
|
|
|
|
master_eq_result = await db_session.execute(master_eq_query)
|
|
|
|
|
master_equipment = master_eq_result.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not master_equipment:
|
|
|
|
|
print("equipment not found in master")
|
|
|
|
|
print("Equipment not found in master")
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Check if equipment already exists in StandardScope
|
|
|
|
|
existing_query = select(StandardScope).filter(
|
|
|
|
|
StandardScope.location_tag == location_tag
|
|
|
|
|
)
|
|
|
|
|
existing_result = await db_session.execute(existing_query)
|
|
|
|
|
existing_equipment = existing_result.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
if existing_equipment:
|
|
|
|
|
# Equipment already in StandardScope, check if it's in current session
|
|
|
|
|
# by verifying if it matches the session's maintenance type criteria
|
|
|
|
|
check_query = (
|
|
|
|
|
Select(StandardScope)
|
|
|
|
|
.outerjoin(StandardScope.oh_history)
|
|
|
|
|
.join(StandardScope.workscope_groups)
|
|
|
|
|
.join(EquipmentWorkscopeGroup.workscope_group)
|
|
|
|
|
.join(MasterActivity.oh_types)
|
|
|
|
|
.join(WorkscopeOHType.oh_type)
|
|
|
|
|
.filter(StandardScope.location_tag == location_tag)
|
|
|
|
|
.filter(MaintenanceType.name == overhaul.maintenance_type.name)
|
|
|
|
|
.filter(
|
|
|
|
|
(StandardScope.is_alternating_oh == False)
|
|
|
|
|
| (StandardScope.oh_history is None)
|
|
|
|
|
| (
|
|
|
|
|
StandardScope.oh_history.has(
|
|
|
|
|
EquipmentOHHistory.last_oh_type != overhaul.maintenance_type.name
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# --- Step 1: Fetch equipment's actual workscope mappings ---
|
|
|
|
|
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)
|
|
|
|
|
)
|
|
|
|
|
eq_workscopes = (await db_session.execute(eq_workscope_query)).scalars().all()
|
|
|
|
|
|
|
|
|
|
# --- Step 2: Check if already included via natural workscope ---
|
|
|
|
|
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)
|
|
|
|
|
in_session = check_result.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
if in_session:
|
|
|
|
|
# Already in current session, skip silently
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Equipment exists but not in this session, need to add workscope
|
|
|
|
|
# Find or create dummy workscope group
|
|
|
|
|
for ws in eq_workscopes
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if is_already_included:
|
|
|
|
|
# Already belongs to this overhaul naturally → skip
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# --- Step 3: Handle existing equipment ---
|
|
|
|
|
if existing_equipment:
|
|
|
|
|
# Add dummy workscope if not already attached
|
|
|
|
|
dummy_workscope = await get_or_create_dummy_workscope(
|
|
|
|
|
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:
|
|
|
|
|
existing_equipment.workscope_groups.append(dummy_workscope)
|
|
|
|
|
dummy_workscope.location_tag = location_tag
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
await db_session.refresh(existing_equipment)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return existing_equipment
|
|
|
|
|
|
|
|
|
|
# Equipment not in StandardScope at all, create new
|
|
|
|
|
# First, get or create dummy workscope group
|
|
|
|
|
|
|
|
|
|
# --- Step 4: Create new StandardScope for fresh equipment ---
|
|
|
|
|
dummy_workscope = await get_or_create_dummy_workscope(
|
|
|
|
|
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(
|
|
|
|
|
location_tag=location_tag,
|
|
|
|
|
is_alternating_oh=False,
|
|
|
|
|
# Add other required fields based on your model
|
|
|
|
|
is_alternating_oh=True,
|
|
|
|
|
assigned_date=datetime.date.today(),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Associate with dummy workscope group
|
|
|
|
|
new_equipment.workscope_groups = [dummy_workscope]
|
|
|
|
|
|
|
|
|
|
dummy_workscope.location_tag = location_tag
|
|
|
|
|
|
|
|
|
|
db_session.add(new_equipment)
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
await db_session.refresh(new_equipment)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new_equipment
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
# Log the error but don't raise it
|
|
|
|
|
print(f"Error adding equipment {location_tag}: {str(e)}")
|
|
|
|
|
await db_session.rollback()
|
|
|
|
|
return None
|
|
|
|
|
@ -324,7 +323,7 @@ async def add_equipment_to_session(
|
|
|
|
|
async def get_or_create_dummy_workscope(
|
|
|
|
|
*,
|
|
|
|
|
db_session: DbSession,
|
|
|
|
|
maintenance_type_name: str
|
|
|
|
|
maintenance_type_name: str,
|
|
|
|
|
) -> EquipmentWorkscopeGroup:
|
|
|
|
|
"""
|
|
|
|
|
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
|
|
|
|
|
"""
|
|
|
|
|
dummy_name = f"Included Equipment Workscope - {maintenance_type_name}"
|
|
|
|
|
|
|
|
|
|
# Check if dummy workscope already exists
|
|
|
|
|
query = (
|
|
|
|
|
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)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- Step 1: Check if dummy MasterActivity exists ---
|
|
|
|
|
query = select(MasterActivity).filter(MasterActivity.workscope == dummy_name)
|
|
|
|
|
result = await db_session.execute(query)
|
|
|
|
|
existing = result.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
if existing:
|
|
|
|
|
return existing
|
|
|
|
|
|
|
|
|
|
# Create dummy workscope group
|
|
|
|
|
# First, get the maintenance type
|
|
|
|
|
master_activity = result.scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
if not master_activity:
|
|
|
|
|
master_activity = MasterActivity(workscope=dummy_name)
|
|
|
|
|
db_session.add(master_activity)
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
await db_session.refresh(master_activity)
|
|
|
|
|
|
|
|
|
|
# --- Step 2: Ensure WorkscopeOHType link exists ---
|
|
|
|
|
mt_query = select(MaintenanceType).filter(MaintenanceType.name == maintenance_type_name)
|
|
|
|
|
mt_result = await db_session.execute(mt_query)
|
|
|
|
|
maintenance_type = mt_result.scalar_one()
|
|
|
|
|
|
|
|
|
|
# Create MasterActivity (workscope_group)
|
|
|
|
|
master_activity = MasterActivity(
|
|
|
|
|
workscope=dummy_name,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Create WorkscopeOHType relationship
|
|
|
|
|
workscope_oh_type = WorkscopeOHType(
|
|
|
|
|
workscope_group=master_activity,
|
|
|
|
|
oh_type=maintenance_type
|
|
|
|
|
|
|
|
|
|
wo_oh_type_query = select(WorkscopeOHType).filter(
|
|
|
|
|
and_(
|
|
|
|
|
WorkscopeOHType.workscope_group_id == master_activity.id,
|
|
|
|
|
WorkscopeOHType.maintenance_type_id == maintenance_type.id,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Create EquipmentWorkscopeGroup
|
|
|
|
|
workscope_oh_type = (await db_session.execute(wo_oh_type_query)).scalar_one_or_none()
|
|
|
|
|
|
|
|
|
|
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(
|
|
|
|
|
workscope_group=master_activity,
|
|
|
|
|
# Add other required fields
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
db_session.add(equipment_workscope_group)
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
await db_session.refresh(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(
|
|
|
|
|
*,
|
|
|
|
|
db_session: DbSession,
|
|
|
|
|
@ -509,8 +451,95 @@ async def update(
|
|
|
|
|
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()
|
|
|
|
|
async def remove_equipment_from_session(
|
|
|
|
|
*,
|
|
|
|
|
db_session: DbSession,
|
|
|
|
|
overhaul_session_id: UUID,
|
|
|
|
|
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
|
|
|
|
|
|