@ -670,9 +670,9 @@ async def delete(*, db_session: DbSession, equipment_id: str):
async def check_and_update_acquisition_data ( db_session : DbSession , assetnum : str ) - > bool :
"""
Check if acquisition year/ cost in Maximo differs from local DB .
If changed , archive history , delete transaction data , update master , and return True .
Otherwise return Fal se.
Check if acquisition cost in Maximo differs from local DB .
Updates master acquisition_cost ( initial + replacement ) and sets forecasting_start_year to 2015 .
Returns True if master record was updated , False otherwi se.
"""
conn = get_production_connection ( )
first_year = None
@ -680,7 +680,7 @@ async def check_and_update_acquisition_data(db_session: DbSession, assetnum: str
if conn :
try :
cursor = conn . cursor ( )
# Query the oldest year from wo_maximo to detect the original acquisition
# Query the oldest year from wo_maximo to detect the original replacement cost
query = """
select DATE_PART ( ' year ' , a . reportdate ) AS year , a . asset_replacecost AS cost
from wo_maximo a
@ -697,7 +697,7 @@ async def check_and_update_acquisition_data(db_session: DbSession, assetnum: str
cursor . close ( )
conn . close ( )
except Exception as e :
print ( f " Error fetching acquisition year for { assetnum } : { e } " )
print ( f " Error fetching replacement data for { assetnum } : { e } " )
if conn :
try :
conn . close ( )
@ -706,7 +706,6 @@ async def check_and_update_acquisition_data(db_session: DbSession, assetnum: str
updates_performed = False
if first_year :
# Fetch equipment to update
eq = await get_by_assetnum ( db_session = db_session , assetnum = assetnum )
if eq :
@ -715,111 +714,64 @@ async def check_and_update_acquisition_data(db_session: DbSession, assetnum: str
current_acq = eq . acquisition_year
current_life = eq . design_life
current_target = eq . forecasting_target_year
current_acq_cost = eq . acquisition_cost
# If current_target is logically "default", we update it.
# If user changed it to something else, we might want to preserve it
# if it currently holds the default value (based on old acq year).
is_valid_default = False
if current_acq and current_life and current_target :
is_valid_default = current_target == ( current_acq + current_life )
# Check for changes
change_year = ( eq . acquisition_year != first_year )
change_cost = ( first_cost is not None and eq . acquisition_cost != first_cost )
# We only archive transaction history if the acquisition year itself changed.
# This prevents redundant history entries for cost-only updates.
if change_year :
print ( f " Acquisition year change detected for { assetnum } : { current_acq } -> { first_year } . Archiving history. " )
acq_year_ref = f " { current_acq } _ { current_target } "
# --- ARCHIVE HISTORICAL DATA ---
# Check for existing identical archive to prevent duplicates (after calculation failures/retries)
check_hist_query = text ( " SELECT 1 FROM lcc_ms_equipment_historical_data WHERE assetnum = :assetnum AND acquisition_year_ref = :acq_year_ref LIMIT 1 " )
hist_exists = ( await db_session . execute ( check_hist_query , { " assetnum " : assetnum , " acq_year_ref " : acq_year_ref } ) ) . fetchone ( )
if not hist_exists :
# 1. Copy old equipment master data to history
history_ms_query = text ( """
INSERT INTO lcc_ms_equipment_historical_data (
id , assetnum , acquisition_year , acquisition_cost , capital_cost_record_time , design_life ,
forecasting_start_year , forecasting_target_year , manhours_rate , created_at , created_by ,
updated_at , updated_by , min_eac_info , harga_saat_ini , minimum_eac_seq , minimum_eac_year ,
minimum_eac , minimum_npv , minimum_pmt , minimum_pmt_aq_cost , minimum_is_actual ,
efdh_equivalent_forced_derated_hours , foh_forced_outage_hours , category_no , proportion ,
acquisition_year_ref
)
SELECT
uuid_generate_v4 ( ) , assetnum , acquisition_year , acquisition_cost , capital_cost_record_time , design_life ,
forecasting_start_year , forecasting_target_year , manhours_rate , created_at , created_by ,
updated_at , updated_by , min_eac_info , harga_saat_ini , minimum_eac_seq , minimum_eac_year ,
minimum_eac , minimum_npv , minimum_pmt , minimum_pmt_aq_cost , minimum_is_actual ,
efdh_equivalent_forced_derated_hours , foh_forced_outage_hours , category_no , proportion ,
: acq_year_ref
FROM lcc_ms_equipment_data
WHERE assetnum = : assetnum
""" )
await db_session . execute ( history_ms_query , { " acq_year_ref " : acq_year_ref , " assetnum " : assetnum } )
# 2. Copy old transaction data to lcc_equipment_historical_tr_data
history_tr_query = text ( """
INSERT INTO lcc_equipment_historical_tr_data (
id , assetnum , tahun , seq , is_actual ,
raw_cm_interval , raw_cm_material_cost , raw_cm_labor_time , raw_cm_labor_human ,
raw_pm_interval , raw_pm_material_cost , raw_pm_labor_time , raw_pm_labor_human ,
raw_oh_interval , raw_oh_material_cost , raw_oh_labor_time , raw_oh_labor_human ,
raw_predictive_interval , raw_predictive_material_cost , raw_predictive_labor_time , raw_predictive_labor_human ,
raw_project_task_material_cost , " raw_loss_output_MW " , raw_loss_output_price ,
raw_operational_cost , raw_maintenance_cost ,
rc_cm_material_cost , rc_cm_labor_cost ,
rc_pm_material_cost , rc_pm_labor_cost ,
rc_oh_material_cost , rc_oh_labor_cost ,
rc_predictive_labor_cost ,
rc_project_material_cost , rc_lost_cost , rc_operation_cost , rc_maintenance_cost ,
rc_total_cost ,
eac_npv , eac_annual_mnt_cost , eac_annual_acq_cost , eac_disposal_cost , eac_eac ,
efdh_equivalent_forced_derated_hours , foh_forced_outage_hours ,
created_by , created_at , acquisition_year_ref
)
SELECT
uuid_generate_v4 ( ) , assetnum , tahun , seq , is_actual ,
raw_cm_interval , raw_cm_material_cost , raw_cm_labor_time , raw_cm_labor_human ,
raw_pm_interval , raw_pm_material_cost , raw_pm_labor_time , raw_pm_labor_human ,
raw_oh_interval , raw_oh_material_cost , raw_oh_labor_time , raw_oh_labor_human ,
raw_predictive_interval , raw_predictive_material_cost , raw_predictive_labor_time , raw_predictive_labor_human ,
raw_project_task_material_cost , " raw_loss_output_MW " , raw_loss_output_price ,
raw_operational_cost , raw_maintenance_cost ,
rc_cm_material_cost , rc_cm_labor_cost ,
rc_pm_material_cost , rc_pm_labor_cost ,
rc_oh_material_cost , rc_oh_labor_cost ,
rc_predictive_labor_cost ,
rc_project_material_cost , rc_lost_cost , rc_operation_cost , rc_maintenance_cost ,
rc_total_cost ,
eac_npv , eac_annual_mnt_cost , eac_annual_acq_cost , eac_disposal_cost , eac_eac ,
efdh_equivalent_forced_derated_hours , foh_forced_outage_hours ,
created_by , NOW ( ) , : acq_year_ref
FROM lcc_equipment_tr_data
WHERE assetnum = : assetnum
""" )
await db_session . execute ( history_tr_query , { " acq_year_ref " : acq_year_ref , " assetnum " : assetnum } )
# 3. Delete old data
del_query = text ( " DELETE FROM lcc_equipment_tr_data WHERE assetnum = :assetnum " )
await db_session . execute ( del_query , { " assetnum " : assetnum } )
# Update Equipment Master regardless of if archive was needed/skipped
if change_year or change_cost :
if first_cost is not None and eq . acquisition_cost != first_cost :
eq . acquisition_cost = first_cost
if eq . acquisition_year != first_year :
eq . acquisition_year = first_year
eq . forecasting_start_year = first_year # Align start with acquisition
# Fetch inflation rate from lcc_ms_master for value-of-money adjustment
inflation_rate = 0.05 # Default fallback
try :
rate_query = text ( " SELECT value_num / 100.0 FROM lcc_ms_master WHERE name = ' inflation_rate ' " )
rate_result = ( await db_session . execute ( rate_query ) ) . scalar ( )
if rate_result is not None :
inflation_rate = float ( rate_result )
except Exception as e :
print ( f " Warning: Could not fetch inflation_rate for { assetnum } : { e } " )
# Calculate initial cost from category/proportion (base acquisition cost)
initial_cost = 0.0
if eq . category_no and eq . proportion :
_ , aggregated_cost = await fetch_acquisition_cost_with_rollup (
db_session = db_session , base_category_no = eq . category_no
)
if aggregated_cost :
initial_cost = ( eq . proportion * 0.01 ) * aggregated_cost
# Adjust initial cost to 2015 value (Base Year)
# Formula: Value_2015 = Value_Year / (1 + rate)^(Year - 2015)
adj_initial_cost = initial_cost
if current_acq and current_acq != 2015 :
adj_initial_cost = initial_cost / ( ( 1 + inflation_rate ) * * ( current_acq - 2015 ) )
# Adjust replace cost to 2015 value (Base Year)
adj_replace_cost = ( first_cost or 0.0 )
if first_year and first_year != 2015 :
adj_replace_cost = ( first_cost or 0.0 ) / ( ( 1 + inflation_rate ) * * ( first_year - 2015 ) )
# Total cost is adjusted initial cost plus the adjusted replacement cost
total_cost = adj_initial_cost + adj_replace_cost
change_cost = ( eq . acquisition_cost != total_cost )
# Requirement: forecasting_start_year always starts from 2015
change_start = ( eq . forecasting_start_year != 2015 )
# Note: acquisition_year itself is no longer updated as per requirements.
if change_cost or change_start :
if change_cost :
print (
f " Acquisition cost update for { assetnum } : { eq . acquisition_cost } -> { total_cost } "
f " (Adj. Initial: { adj_initial_cost } + Adj. Replacement: { adj_replace_cost } | Rate: { inflation_rate } ) "
)
eq . acquisition_cost = total_cost
if change_start :
print ( f " Aligning forecasting_start_year to 2015 for { assetnum } " )
eq . forecasting_start_year = 2015
# If target was default, we update it to 2015 + design_life
if is_valid_default and current_life :
eq . forecasting_target_year = first_year + current_life
eq . forecasting_target_year = 2015 + current_life
await db_session . commit ( )
updates_performed = True