add rqeuirement sparepart for oh

main
Cizz22 3 months ago
parent b7c2dc6ed2
commit 1aa9e1e9aa

20
.env

@ -9,15 +9,15 @@ DATABASE_CREDENTIAL_USER=postgres
DATABASE_CREDENTIAL_PASSWORD=postgres
DATABASE_NAME=digital_twin
# 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
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
COLLECTOR_HOSTNAME=192.168.1.86
COLLECTOR_PORT=5432
COLLECTOR_CREDENTIAL_USER=postgres
COLLECTOR_CREDENTIAL_PASSWORD=postgres
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

@ -52,6 +52,7 @@ class MaintenanceScenario(OverhaulBase):
class OptimizationResult(OverhaulBase):
current_plant_eaf: float
target_plant_eaf: float
possible_plant_eaf:float
eaf_gap: float
asset_contributions: List[dict]
optimization_success: bool = False

@ -201,11 +201,14 @@ async def identify_worst_eaf_contributors(
else:
# allow overshoot tolerance by skipping large ones, continue with smaller ones
continue
possible_eaf_plant = current_plant_eaf + project_eaf_improvement
# Build output with efficiency included
return OptimizationResult(
current_plant_eaf=current_plant_eaf,
target_plant_eaf=target_eaf,
possible_plant_eaf=possible_eaf_plant,
eaf_gap=eaf_gap,
asset_contributions=[
{

@ -93,12 +93,14 @@ async def create_calculation(
calculation_param_in=calculation_time_constrains_in,
created_by=created_by,
)
rbd_simulation_id = "f9ebaf0a-3c41-4cd6-ba60-552c0b303f3f"
# results = await create_calculation_result_service(
# db_session=db_session, calculation=calculation_data, token=token
# )
results = await run_simulation_with_spareparts(
db_session=db_session, calculation=calculation_data, token=token, collector_db_session=collector_db_session
db_session=db_session, calculation=calculation_data, token=token, collector_db_session=collector_db_session, simulation_id=rbd_simulation_id
)
return results["id"]

@ -5,7 +5,7 @@ from src.database.service import (CommonParameters, DbSession,
search_filter_sort_paginate)
from src.models import StandardResponse
from .service import get_all
from .service import get_spareparts_paginated
router = APIRouter()
@ -14,7 +14,7 @@ router = APIRouter()
async def get_sparepart(collector_db_session:CollectorDbSession):
"""Get all scope activity pagination."""
# return
data = await get_all(collector_db_session)
data = await get_spareparts_paginated(collector_db_session)

@ -23,93 +23,209 @@ from src.overhaul_scope.service import get_prev_oh
log = logging.getLogger(__name__)
setup_logging(logger=log)
async def get_all(db_session: DbSession):
from sqlalchemy import text
import math
async def get_spareparts_paginated(db_session):
"""
Get all spare parts with their latest PR and PO information.
Get paginated spare parts with usage, inventory, and PR/PO information.
Uses two queries: one for data, one for total count.
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
page (int): Page number (1-based)
items_per_page (int): Number of items per page
"""
# 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,
pl.description,
pl.unit_cost,
pl.line_cost
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, h.issue_date DESC
)
SELECT DISTINCT ON (pr.item_num)
pr.item_num,
pr.line_cost,
pr.unit_cost,
pr.description,
COALESCE(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,
po.estimated_arrival_date as po_estimated_arrival_date
FROM latest_prs pr
LEFT JOIN public.maximo_inventory i ON pr.item_num = i.itemnum
LEFT JOIN LATERAL (
# calculate limit/offset
# limit = items_per_page
# offset = (page - 1) * items_per_page
# -----------------------------
# Query #1: Fetch paginated rows
# -----------------------------
data_query = text("""
WITH oh_workorders AS (
SELECT DISTINCT wonum, asset_location, asset_unit
FROM public.wo_staging_maximo_2
WHERE worktype = 'OH'
AND asset_location IS NOT NULL
AND EXTRACT(YEAR FROM reportdate) >= 2019
AND asset_unit IN ('3', '00')
),
sparepart_usage AS (
SELECT oh.asset_location, mwm.itemnum, mwm.itemqty, mwm.wonum
FROM oh_workorders oh
INNER JOIN public.maximo_workorder_materials mwm ON oh.wonum = mwm.wonum
),
location_sparepart_stats AS (
SELECT asset_location, itemnum,
COUNT(DISTINCT wonum) as total_wo_count,
SUM(itemqty) as total_qty_used,
AVG(itemqty) as avg_qty_per_wo,
MIN(itemqty) as min_qty_used,
MAX(itemqty) as max_qty_used
FROM sparepart_usage
GROUP BY asset_location, itemnum
HAVING SUM(itemqty) > 0
),
pr_lines AS (
SELECT
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,
pl.qty_requested as pr_qty_requested
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 EXTRACT(YEAR FROM h.issue_date) >= 2023
),
item_descriptions AS (
SELECT DISTINCT
item_num,
FIRST_VALUE(description) OVER (
PARTITION BY item_num
ORDER BY created_at DESC NULLS LAST
) as description
FROM public.maximo_sparepart_pr_po_line
WHERE description IS NOT NULL
),
po_lines AS (
SELECT
pl.item_num,
h.num as po_number,
pl.qty_received,
pl.qty_ordered,
h.estimated_arrival_date
h.estimated_arrival_date as po_estimated_arrival_date,
h.vendeliverydate as po_vendeliverydate,
h.receipts as po_receipt,
h.status as po_status,
pl.qty_ordered as po_qty_ordered,
pl.qty_received as po_qty_received
FROM public.maximo_sparepart_pr_po h
JOIN public.maximo_sparepart_pr_po_line pl ON h.num = pl.num
WHERE h.type = 'PO'
AND h.num = pr.pr_number
AND pl.item_num = pr.item_num
LIMIT 1
) po ON true
ORDER BY pr.item_num;
AND (h.receipts = 'NONE')
AND (h.status IS NOT NULL)
),
pr_po_unified AS (
SELECT
pr.item_num,
pr.pr_number,
pr.pr_issue_date,
pr.pr_qty_ordered,
pr.pr_status,
po.po_number,
COALESCE(po.po_qty_ordered,0) as po_qty_ordered,
COALESCE(po.po_qty_received,0) as po_qty_received,
po.po_estimated_arrival_date,
po.po_vendeliverydate,
po.po_receipt,
po.po_status,
CASE WHEN po.po_number IS NOT NULL THEN 'YES' ELSE 'NO' END as po_exists
FROM pr_lines pr
LEFT JOIN po_lines po
ON pr.item_num = po.item_num
AND pr.pr_number = po.po_number
),
pr_po_agg AS (
SELECT
item_num,
SUM(COALESCE(pr_qty_ordered,0)) as total_pr_qty,
SUM(COALESCE(po_qty_ordered,0)) as total_po_qty,
SUM(COALESCE(po_qty_received,0)) as total_po_received,
JSON_AGG(
JSON_BUILD_OBJECT(
'pr_number', pr_number,
'pr_issue_date', pr_issue_date,
'pr_qty_requested', pr_qty_ordered,
'pr_status', pr_status,
'po_exists', po_exists,
'po_qty_ordered', po_qty_ordered,
'po_qty_received', po_qty_received,
'po_estimated_arrival_date', po_estimated_arrival_date,
'po_vendeliverydate', po_vendeliverydate,
'po_receipt', po_receipt,
'po_status', po_status
) ORDER BY pr_issue_date DESC
) as pr_po_details
FROM pr_po_unified
GROUP BY item_num
)
SELECT
lss.itemnum,
COALESCE(id.description, 'No description available') as item_description,
lss.total_wo_count,
lss.total_qty_used,
ROUND(CAST(lss.avg_qty_per_wo AS NUMERIC), 2) as avg_qty_per_wo,
lss.min_qty_used,
lss.max_qty_used,
COALESCE(i.curbaltotal,0) as current_balance_total,
COALESCE(ap.total_pr_qty,0) as total_pr_qty,
COALESCE(ap.total_po_qty,0) as total_po_qty,
COALESCE(ap.total_po_received,0) as total_po_received,
ap.pr_po_details
FROM location_sparepart_stats lss
LEFT JOIN item_descriptions id ON lss.itemnum = id.item_num
LEFT JOIN public.maximo_inventory i ON lss.itemnum = i.itemnum
LEFT JOIN pr_po_agg ap ON lss.itemnum = ap.item_num
ORDER BY lss.asset_location, lss.itemnum
""")
# Execute the query
result = await db_session.execute(query)
# Fetch all results and convert to list of dictionaries
rows = await db_session.execute(data_query)
spare_parts = []
for row in result:
for row in rows:
spare_parts.append({
"item_num": row.item_num,
"description": row.description,
"line_cost": row.line_cost,
"unit_cost": row.unit_cost,
"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
"item_num": row.itemnum,
"description": row.item_description,
"current_balance_total": float(row.current_balance_total) if row.current_balance_total else 0.0,
"total_required_for_oh": float(row.avg_qty_per_wo),
"total_pr_qty": row.total_pr_qty,
"total_po_qty": row.total_po_qty,
"total_po_received": row.total_po_received,
"pr_po_details": row.pr_po_details
})
return spare_parts
# # -----------------------------
# # Query #2: Count total rows
# # -----------------------------
# count_query = text("""
# WITH oh_workorders AS (
# SELECT DISTINCT wonum, asset_location, asset_unit
# FROM public.wo_staging_maximo_2
# WHERE worktype = 'OH'
# AND asset_location IS NOT NULL
# AND EXTRACT(YEAR FROM reportdate) >= 2019
# AND asset_unit IN ('3', '00')
# ),
# sparepart_usage AS (
# SELECT oh.asset_location, mwm.itemnum, mwm.itemqty, mwm.wonum
# FROM oh_workorders oh
# INNER JOIN public.maximo_workorder_materials mwm ON oh.wonum = mwm.wonum
# ),
# location_sparepart_stats AS (
# SELECT asset_location, itemnum
# FROM sparepart_usage
# GROUP BY asset_location, itemnum
# )
# SELECT COUNT(*) as total_count
# FROM location_sparepart_stats;
# """)
# total_count_result = await db_session.execute(count_query)
# total_count = total_count_result.scalar() or 0
# # calculate total pages
# total_pages = math.ceil(total_count / items_per_page) if items_per_page > 0 else 1
# return {
# "total": total_count,
# "page": page,
# "items_per_page": items_per_page,
# "total_pages": total_pages,
# "items": spare_parts
# }
class ProcurementStatus(Enum):

Loading…
Cancel
Save