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_NAME=digital_twin
COLLECTOR_HOSTNAME=192.168.1.86
COLLECTOR_PORT=5432
COLLECTOR_CREDENTIAL_USER=postgres
COLLECTOR_CREDENTIAL_PASSWORD=postgres
COLLECTOR_HOSTNAME=192.168.1.82
COLLECTOR_PORT=1111
COLLECTOR_CREDENTIAL_USER=digital_twin
COLLECTOR_CREDENTIAL_PASSWORD=Pr0jec7@D!g!tTwiN
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.overhaul_schedule.router import router as overhaul_schedule_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.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"]
)
authenticated_api_router.include_router(
sparepart_router, prefix="/spareparts", tags=["sparepart"]
)
authenticated_api_router.include_router(
equipment_workscope_group_router,
prefix="/equipment-workscopes",

@ -1,7 +1,7 @@
import random
from typing import Optional
from sqlalchemy import Delete, Select, and_
from sqlalchemy import Delete, Select, and_, text
from sqlalchemy.orm import selectinload
from src.auth.service import CurrentUser
@ -37,39 +37,87 @@ def create_dummy_parts(assetnum: str, count: int = 5):
return parts
async def get_all(db_session: DbSession, assetnum: Optional[str]):
# Example usage
dummy_parts = create_dummy_parts(assetnum, count=10)
# 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)
return dummy_parts
async def get_all(db_session: DbSession, assetnum: Optional[str] = None):
"""
Get all spare parts with their latest PR and PO information.
Args:
db_session: SQLAlchemy database session
assetnum: Optional asset number filter (not used in this query but kept for compatibility)
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):

@ -1,21 +1,20 @@
from fastapi import APIRouter, HTTPException, Query, status
from src.database.core import CollectorDbSession
from src.database.service import (CommonParameters, DbSession,
search_filter_sort_paginate)
from src.models import StandardResponse
from .schema import (ActivityMaster, ActivityMasterCreate,
ActivityMasterPagination)
from .service import create, delete, get, get_all, update
from .service import get_all
router = APIRouter()
@router.get("", response_model=StandardResponse[ActivityMasterPagination])
async def get_activities(common: CommonParameters):
@router.get("", response_model=StandardResponse[list])
async def get_sparepart(collector_db_session:CollectorDbSession):
"""Get all scope activity pagination."""
# 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])
async def create_activity(db_session: DbSession, activity_in: ActivityMasterCreate):
# @router.post("", response_model=StandardResponse[ActivityMasterCreate])
# async def create_activity(db_session: DbSession, activity_in: ActivityMasterCreate):
activity = await create(db_session=db_session, activty_in=activity_in)
# 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(
"/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
)
async def get_activity(db_session: DbSession, activity_id: str):
activity = await get(db_session=db_session, activity_id=activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
# @router.get(
# "/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
# )
# async def get_activity(db_session: DbSession, activity_id: str):
# activity = await get(db_session=db_session, activity_id=activity_id)
# if not activity:
# raise HTTPException(
# status_code=status.HTTP_404_NOT_FOUND,
# detail="A data with this id does not exist.",
# )
return StandardResponse(data=activity, message="Data retrieved successfully")
# return StandardResponse(data=activity, message="Data retrieved successfully")
@router.put(
"/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
)
async def update_scope(
db_session: DbSession, activity_in: ActivityMasterCreate, activity_id
):
activity = await get(db_session=db_session, activity_id=activity_id)
# @router.put(
# "/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
# )
# async def update_scope(
# db_session: DbSession, activity_in: ActivityMasterCreate, activity_id
# ):
# activity = await get(db_session=db_session, activity_id=activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="A data with this id does not exist.",
)
# if not activity:
# raise HTTPException(
# status_code=status.HTTP_404_NOT_FOUND,
# detail="A data with this id does not exist.",
# )
return StandardResponse(
data=await update(
db_session=db_session, activity=activity, activity_in=activity_in
),
message="Data updated successfully",
)
# return StandardResponse(
# data=await update(
# db_session=db_session, activity=activity, activity_in=activity_in
# ),
# message="Data updated successfully",
# )
@router.delete(
"/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
)
async def delete_scope(db_session: DbSession, activity_id: str):
activity = await get(db_session=db_session, activity_id=activity_id)
# @router.delete(
# "/{scope_equipment_activity_id}", response_model=StandardResponse[ActivityMaster]
# )
# async def delete_scope(db_session: DbSession, activity_id: str):
# activity = await get(db_session=db_session, activity_id=activity_id)
if not activity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=[{"msg": "A data with this id does not exist."}],
)
# if not activity:
# raise HTTPException(
# status_code=status.HTTP_404_NOT_FOUND,
# detail=[{"msg": "A data with this id does not exist."}],
# )
await delete(db_session=db_session, activity_id=activity_id)
# 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 sqlalchemy import Delete, Select
from sqlalchemy import Delete, Select, text
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()
# 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(db_session: DbSession):
"""
Get all spare parts with their latest PR and PO information.
Args:
db_session: SQLAlchemy database session
assetnum: Optional asset number filter (not used in this query but kept for compatibility)
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, 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