feature/reliability_stat
Cizz22 4 months ago
parent 3fa022f08f
commit 8c9f573230

10
.env

@ -9,11 +9,9 @@ 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.86 COLLECTOR_HOSTNAME=192.168.1.82
COLLECTOR_PORT=5432 COLLECTOR_PORT=1111
COLLECTOR_CREDENTIAL_USER=postgres COLLECTOR_CREDENTIAL_USER=digital_twin
COLLECTOR_CREDENTIAL_PASSWORD=postgres COLLECTOR_CREDENTIAL_PASSWORD=Pr0jec7@D!g!tTwiN
COLLECTOR_NAME=digital_twin COLLECTOR_NAME=digital_twin
BACKEND_SERVER=

@ -24,7 +24,7 @@ from src.equipment_workscope_group.router import router as equipment_workscope_g
# from src.scope_equipment_job.router import router as scope_equipment_job_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_schedule.router import router as overhaul_schedule_router
from src.overhaul_gantt.router import router as gantt_router from src.overhaul_gantt.router import router as gantt_router
from src.sparepart.router import router as sparepart_router
# from src.overhaul_scope.router import router as scope_router # from src.overhaul_scope.router import router as scope_router
# from src.scope_equipment.router import router as scope_equipment_router # from src.scope_equipment.router import router as scope_equipment_router
@ -90,6 +90,10 @@ authenticated_api_router.include_router(
workscope_group_router, prefix="/workscopes", tags=["workscope_groups"] workscope_group_router, prefix="/workscopes", tags=["workscope_groups"]
) )
authenticated_api_router.include_router(
sparepart_router, prefix="/spareparts", tags=["sparepart"]
)
authenticated_api_router.include_router( authenticated_api_router.include_router(
equipment_workscope_group_router, equipment_workscope_group_router,
prefix="/equipment-workscopes", prefix="/equipment-workscopes",

@ -1,7 +1,7 @@
import random import random
from typing import Optional from typing import Optional
from sqlalchemy import Delete, Select, and_ from sqlalchemy import Delete, Select, and_, text
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
@ -37,39 +37,87 @@ def create_dummy_parts(assetnum: str, count: int = 5):
return parts return parts
async def get_all(db_session: DbSession, assetnum: Optional[str]): async def get_all(db_session: DbSession, assetnum: Optional[str] = None):
# Example usage """
dummy_parts = create_dummy_parts(assetnum, count=10) Get all spare parts with their latest PR and PO information.
# if not assetnum:
# raise ValueError("assetnum parameter is required")
# db_session: DbSession = common.get("db_session")
# # 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(ScopeEquipmentPart)
# .join(ScopeEquipmentPart.master_equipments)
# .join(MasterEquipment.equipment_tree)
# .where(
# and_(
# MasterEquipment.parent_id == equipment.id,
# MasterEquipmentTree.level_no == 4
# )
# ).options(selectinload(ScopeEquipmentPart.master_equipments))
# )
# results = await search_filter_sort_paginate(model=stmt, **common) Args:
db_session: SQLAlchemy database session
assetnum: Optional asset number filter (not used in this query but kept for compatibility)
return dummy_parts Returns:
List of dictionaries containing spare part information
"""
# Define the SQL query
query = text("""
WITH latest_prs AS (
SELECT DISTINCT ON (pl.item_num)
pl.item_num,
h.num as pr_number,
h.issue_date as pr_issue_date,
h.status as pr_status,
pl.qty_ordered as pr_qty_ordered
FROM public.maximo_sparepart_pr_po h
JOIN public.maximo_sparepart_pr_po_line pl ON h.num = pl.num
WHERE h.type = 'PR'
AND h.issue_date IS NOT NULL
AND h.num LIKE 'K%'
ORDER BY pl.item_num, TO_DATE(h.issue_date, 'YYYY-MM-DD') DESC
),
po_details AS (
SELECT
h.num as po_number,
pl.item_num,
h.estimated_arrival_date,
pl.qty_received,
pl.qty_ordered
FROM public.maximo_sparepart_pr_po h
JOIN public.maximo_sparepart_pr_po_line pl ON h.num = pl.num
WHERE h.type = 'PO'
)
SELECT
pr.item_num,
MAX(l.description) as description,
COALESCE(MAX(i.curbaltotal), 0) as current_balance_total,
pr.pr_number,
pr.pr_issue_date,
pr.pr_qty_ordered,
CASE
WHEN po.po_number IS NOT NULL THEN 'YES'
ELSE 'NO'
END as po_exists,
COALESCE(po.qty_received, 0) as po_qty_received,
COALESCE(po.qty_ordered, 0) as po_qty_ordered,
COALESCE(po.estimated_arrival_date, '') as po_estimated_arrival_date
FROM latest_prs pr
LEFT JOIN public.maximo_sparepart_pr_po_line l ON pr.item_num = l.item_num
LEFT JOIN public.maximo_inventory i ON pr.item_num = i.itemnum
LEFT JOIN po_details po ON po.po_number = pr.pr_number AND po.item_num = pr.item_num
GROUP BY pr.item_num, pr.pr_number, pr.pr_issue_date, pr.pr_qty_ordered,
po.po_number, po.qty_received, po.qty_ordered, po.estimated_arrival_date
ORDER BY pr.item_num
""")
# Execute the query
result = await db_session.execute(query)
# Fetch all results and convert to list of dictionaries
spare_parts = []
for row in result:
spare_parts.append({
"item_num": row.item_num,
"description": row.description,
"current_balance_total": float(row.current_balance_total) if row.current_balance_total is not None else 0.0,
"pr_number": row.pr_number,
"pr_issue_date": row.pr_issue_date,
"pr_qty_ordered": float(row.pr_qty_ordered) if row.pr_qty_ordered is not None else 0.0,
"po_exists": row.po_exists,
"po_qty_received": float(row.po_qty_received) if row.po_qty_received is not None else 0.0,
"po_qty_ordered": float(row.po_qty_ordered) if row.po_qty_ordered is not None else 0.0,
"po_estimated_arrival_date": row.po_estimated_arrival_date
})
return spare_parts
# async def create(*, db_session: DbSession, scope_equipment_activty_in: ScopeEquipmentActivityCreate): # async def create(*, db_session: DbSession, scope_equipment_activty_in: ScopeEquipmentActivityCreate):

@ -1,21 +1,20 @@
from fastapi import APIRouter, HTTPException, Query, status from fastapi import APIRouter, HTTPException, Query, status
from src.database.core import CollectorDbSession
from src.database.service import (CommonParameters, DbSession, from src.database.service import (CommonParameters, DbSession,
search_filter_sort_paginate) search_filter_sort_paginate)
from src.models import StandardResponse from src.models import StandardResponse
from .schema import (ActivityMaster, ActivityMasterCreate, from .service import get_all
ActivityMasterPagination)
from .service import create, delete, get, get_all, update
router = APIRouter() router = APIRouter()
@router.get("", response_model=StandardResponse[ActivityMasterPagination]) @router.get("", response_model=StandardResponse[list])
async def get_activities(common: CommonParameters): async def get_sparepart(collector_db_session:CollectorDbSession):
"""Get all scope activity pagination.""" """Get all scope activity pagination."""
# return # return
data = await get_all(common=common) data = await get_all(collector_db_session)
@ -25,62 +24,62 @@ async def get_activities(common: CommonParameters):
) )
@router.post("", response_model=StandardResponse[ActivityMasterCreate]) # @router.post("", response_model=StandardResponse[ActivityMasterCreate])
async def create_activity(db_session: DbSession, activity_in: ActivityMasterCreate): # async def create_activity(db_session: DbSession, activity_in: ActivityMasterCreate):
activity = await create(db_session=db_session, activty_in=activity_in) # activity = await create(db_session=db_session, activty_in=activity_in)
return StandardResponse(data=activity, message="Data created successfully") # return StandardResponse(data=activity, message="Data created successfully")
@router.get( # @router.get(
"/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster] # "/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
) # )
async def get_activity(db_session: DbSession, activity_id: str): # async def get_activity(db_session: DbSession, activity_id: str):
activity = await get(db_session=db_session, activity_id=activity_id) # activity = await get(db_session=db_session, activity_id=activity_id)
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(data=activity, message="Data retrieved successfully") # return StandardResponse(data=activity, message="Data retrieved successfully")
@router.put( # @router.put(
"/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster] # "/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
) # )
async def update_scope( # async def update_scope(
db_session: DbSession, activity_in: ActivityMasterCreate, activity_id # db_session: DbSession, activity_in: ActivityMasterCreate, activity_id
): # ):
activity = await get(db_session=db_session, activity_id=activity_id) # activity = await get(db_session=db_session, activity_id=activity_id)
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, activity=activity, activity_in=activity_in # db_session=db_session, activity=activity, activity_in=activity_in
), # ),
message="Data updated successfully", # message="Data updated successfully",
) # )
@router.delete( # @router.delete(
"/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster] # "/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
) # )
async def delete_scope(db_session: DbSession, activity_id: str): # async def delete_scope(db_session: DbSession, activity_id: str):
activity = await get(db_session=db_session, activity_id=activity_id) # activity = await get(db_session=db_session, activity_id=activity_id)
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=[{"msg": "A data with this id does not exist."}], # detail=[{"msg": "A data with this id does not exist."}],
) # )
await delete(db_session=db_session, activity_id=activity_id) # await delete(db_session=db_session, activity_id=activity_id)
return StandardResponse(message="Data deleted successfully", data=activity) # return StandardResponse(message="Data deleted successfully", data=activity)

@ -1,60 +1,132 @@
from typing import Optional from typing import Optional
from sqlalchemy import Delete, Select from sqlalchemy import Delete, Select, text
from sqlalchemy.orm import joinedload, selectinload from sqlalchemy.orm import joinedload, selectinload
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
from src.database.core import DbSession from src.database.core import DbSession
from src.database.service import CommonParameters, search_filter_sort_paginate 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]:
async def get(*, db_session: DbSession, activity_id: str) -> Optional[ActivityMaster]: # """Returns a document based on the given document id."""
"""Returns a document based on the given document id.""" # result = await db_session.get(MasterActivity, activity_id)
result = await db_session.get(MasterActivity, activity_id) # return result
return result
async def get_all(db_session: DbSession):
async def get_all(common: CommonParameters): """
query = Select(MasterActivity) Get all spare parts with their latest PR and PO information.
results = await search_filter_sort_paginate(model=query, **common) Args:
db_session: SQLAlchemy database session
return results assetnum: Optional asset number filter (not used in this query but kept for compatibility)
Returns:
List of dictionaries containing spare part information
async def create(*, db_session: DbSession, activty_in: ActivityMasterCreate): """
activity = MasterActivity(**activty_in.model_dump()) # Define the SQL query
db_session.add(activity) query = text("""
await db_session.commit() WITH latest_prs AS (
return activity SELECT DISTINCT ON (pl.item_num)
pl.item_num,
h.num as pr_number,
async def update( h.issue_date as pr_issue_date,
*, h.status as pr_status,
db_session: DbSession, pl.qty_ordered as pr_qty_ordered
activity: MasterActivity, FROM public.maximo_sparepart_pr_po h
activity_in: ActivityMasterCreate JOIN public.maximo_sparepart_pr_po_line pl ON h.num = pl.num
): WHERE h.type = 'PR'
"""Updates a document.""" AND h.issue_date IS NOT NULL
data = activity_in.model_dump() AND h.num LIKE 'K%'
ORDER BY pl.item_num, TO_DATE(h.issue_date, 'YYYY-MM-DD') DESC
update_data = activity_in.model_dump(exclude_defaults=True) ),
po_details AS (
for field in data: SELECT
if field in update_data: h.num as po_number,
setattr(activity, field, update_data[field]) pl.item_num,
h.estimated_arrival_date,
await db_session.commit() pl.qty_received,
pl.qty_ordered
return activity FROM public.maximo_sparepart_pr_po h
JOIN public.maximo_sparepart_pr_po_line pl ON h.num = pl.num
WHERE h.type = 'PO'
async def delete(*, db_session: DbSession, activity_id: str): )
"""Deletes a document.""" SELECT
activity = await db_session.get(MasterActivity, activity_id) pr.item_num,
await db_session.delete(activity) MAX(l.description) as description,
await db_session.commit() COALESCE(MAX(i.curbaltotal), 0) as current_balance_total,
pr.pr_number,
pr.pr_issue_date,
pr.pr_qty_ordered,
CASE
WHEN po.po_number IS NOT NULL THEN 'YES'
ELSE 'NO'
END as po_exists,
COALESCE(po.qty_received, 0) as po_qty_received,
COALESCE(po.qty_ordered, 0) as po_qty_ordered,
COALESCE(po.estimated_arrival_date, '') as po_estimated_arrival_date
FROM latest_prs pr
LEFT JOIN public.maximo_sparepart_pr_po_line l ON pr.item_num = l.item_num
LEFT JOIN public.maximo_inventory i ON pr.item_num = i.itemnum
LEFT JOIN po_details po ON po.po_number = pr.pr_number AND po.item_num = pr.item_num
GROUP BY pr.item_num, pr.pr_number, pr.pr_issue_date, pr.pr_qty_ordered,
po.po_number, po.qty_received, po.qty_ordered, po.estimated_arrival_date
ORDER BY pr.item_num
""")
# Execute the query
result = await db_session.execute(query)
# Fetch all results and convert to list of dictionaries
spare_parts = []
for row in result:
spare_parts.append({
"item_num": row.item_num,
"description": row.description,
"current_balance_total": float(row.current_balance_total) if row.current_balance_total is not None else 0.0,
"pr_number": row.pr_number,
"pr_issue_date": row.pr_issue_date,
"pr_qty_ordered": float(row.pr_qty_ordered) if row.pr_qty_ordered is not None else 0.0,
"po_exists": row.po_exists,
"po_qty_received": float(row.po_qty_received) if row.po_qty_received is not None else 0.0,
"po_qty_ordered": float(row.po_qty_ordered) if row.po_qty_ordered is not None else 0.0,
"po_estimated_arrival_date": row.po_estimated_arrival_date
})
return spare_parts
# 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()

Loading…
Cancel
Save