update formula to follow SPLN

main
MrWaradana 2 months ago
parent 8444ca06ce
commit f095298a15

@ -73,10 +73,10 @@ class Eac:
value / ((1 + inflation_rate) ** (i + 1))
for i, value in enumerate(cumulative_values)
)
# Menghitung PMT
# Menghitung PMT biaya maintenance
# Rumus PMT: PMT = PV * [r(1 + r)^n] / [(1 + r)^n 1]
# dimana PV = final_value, r = inflation_rate, n = row["seq"]
pmt_value = -npf.pmt(inflation_rate, row["seq"], final_value)
pmt_mnt_cost = -npf.pmt(inflation_rate, row["seq"], final_value)
# Menghitung PMT biaya akuisisi
# Rumus PMT: PMT = PV * [r(1 + r)^n] / [(1 + r)^n 1]
@ -85,14 +85,14 @@ class Eac:
# disc_rate adalah discount rate dari database
# row["seq"] adalah periode ke-n
pmt_aq_cost = -npf.pmt(disc_rate, row["seq"], rc_total_cost_0)
eac = pmt_value + pmt_aq_cost
eac = pmt_mnt_cost + pmt_aq_cost
npv_results.append(
{
"seq": row["seq"],
"year": row["tahun"],
"npv": final_value,
"pmt": pmt_value,
"pmt": pmt_mnt_cost,
"pmt_aq_cost": pmt_aq_cost,
"eac": eac,
"is_actual": 1,
@ -110,7 +110,7 @@ class Eac:
update_query,
(
float(final_value),
float(pmt_value),
float(pmt_mnt_cost),
float(pmt_aq_cost),
float(eac),
equipment_id,
@ -173,7 +173,7 @@ class Eac:
# dimana PV = final_value, r = inflation_rate, n = row["seq"]
# periods adalah jumlah periode
# final_value adalah PV pada titik proyeksi periods
pmt_value = -float(npf.pmt(inflation_rate, periods, final_value))
pmt_mnt_cost = -float(npf.pmt(inflation_rate, periods, final_value))
# menghitung PMT biaya akuisisi
# Rumus PMT: PMT = PV * [r(1 + r)^n] / [(1 + r)^n 1]
@ -183,14 +183,14 @@ class Eac:
# row["seq"] adalah periode ke-n
pmt_aq_cost = -float(npf.pmt(disc_rate, row["seq"], rc_total_cost_0))
eac = float(pmt_value) + float(pmt_aq_cost)
eac = float(pmt_mnt_cost) + float(pmt_aq_cost)
npv_results.append(
{
"seq": row["seq"],
"year": row["tahun"],
"npv": final_value,
"pmt": pmt_value,
"pmt": pmt_mnt_cost,
"pmt_aq_cost": pmt_aq_cost,
"eac": eac,
"is_actual": 0,
@ -208,7 +208,7 @@ class Eac:
update_query,
(
float(final_value),
float(pmt_value),
float(pmt_mnt_cost),
float(pmt_aq_cost),
float(eac),
equipment_id,

@ -18,6 +18,8 @@ import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from config import get_connection
from modules.equipment.formula import rc_labor_cost, rc_lost_cost, rc_total_cost
import json
load_dotenv()
@ -332,6 +334,80 @@ class Prediksi:
finally:
if connection:
connection.close()
def __get_asset_criticality_params(self, equipment_id):
try:
connections = get_connection()
connection = (
connections[0] if isinstance(connections, tuple) else connections
)
if connection is None:
print("Database connection failed.")
return None
cursor = connection.cursor(cursor_factory=DictCursor)
# Query untuk mendapatkan asset criticality
query = """
SELECT row_to_json(t) AS asset_criticality
FROM (
SELECT
asset_crit_ens_energy_not_served,
asset_crit_bpp_system,
asset_crit_bpp_pembangkit,
asset_crit_dmn_daya_mampu_netto,
asset_crit_marginal_cost,
asset_crit_efdh_equivalent_force_derated_hours,
asset_crit_foh_force_outage_hours,
asset_crit_extra_fuel_cost
FROM lcc_ms_equipment_data
WHERE assetnum = %s
) t
"""
cursor.execute(query, (equipment_id,))
result = cursor.fetchone()
asset_crit = result.get("asset_criticality") if result else None
if not asset_crit:
return None
# asset_crit may already be a dict (from row_to_json) or a JSON string
try:
ac = asset_crit if isinstance(asset_crit, dict) else json.loads(asset_crit)
except Exception:
ac = {}
def _f(key):
try:
return float(ac.get(key) or 0.0)
except Exception:
return 0.0
ens = _f("asset_crit_ens_energy_not_served") # ENS
bpp_syst = _f("asset_crit_bpp_system") # BPP_SYST
dmn = _f("asset_crit_dmn_daya_mampu_netto") # DMN
extra_fuel = _f("asset_crit_extra_fuel_cost") # Extra Fuel Cost
# Formula from image:
# Asset Criticality = (ENS/1 hour * (7% * BPP_SYST)) + ((DMN - ENS/1 hour) * Extra Fuel Cost)
# ENS/1 hour is ENS (division by 1)
part1 = ens * (0.07 * bpp_syst)
part2 = max(0.0, (dmn - ens)) * extra_fuel
asset_criticality = part1 + part2
efdh = _f("asset_crit_efdh_equivalent_force_derated_hours") # EFDH
foh = _f("asset_crit_foh_force_outage_hours")
return {
"asset_criticality": asset_criticality,
"efdh_oh_sum": efdh + foh,
}
except Exception as e:
print(f"Error saat mendapatkan asset criticality dari database: {e}")
return None
finally:
if connection:
connection.close()
# Fungsi untuk menghapus data proyeksi pada tahun tertentu
def __update_data_lcc(self, equipment_id):
@ -344,46 +420,181 @@ class Prediksi:
print("Database connection failed.")
return None
cursor = connection.cursor()
cursor = connection.cursor(cursor_factory=DictCursor)
# Query untuk menghapus data berdasarkan tahun proyeksi
up_query = """
update lcc_equipment_tr_data
set
rc_cm_material_cost = raw_cm_material_cost
,rc_cm_labor_cost = (raw_cm_interval * raw_cm_labor_time * raw_cm_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) )
,rc_pm_material_cost = raw_pm_material_cost
,rc_pm_labor_cost = (raw_pm_labor_time * raw_pm_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) )
,rc_predictive_labor_cost = COALESCE( (raw_predictive_labor_time * raw_predictive_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) ) , 0)
,rc_oh_material_cost = raw_oh_material_cost
,rc_oh_labor_cost = (raw_oh_labor_time * raw_oh_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) )
,rc_project_material_cost = coalesce(raw_project_task_material_cost, 0)
,rc_lost_cost = coalesce(("raw_loss_output_MW" * raw_loss_output_price * raw_cm_interval), 0) * 1000
,rc_operation_cost = coalesce(raw_operational_cost, 0)
,rc_maintenance_cost = coalesce(raw_maintenance_cost, 0)
,rc_total_cost = (
raw_cm_material_cost
+ (raw_cm_interval * raw_cm_labor_time * raw_cm_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) )
+ raw_pm_material_cost
+ (raw_pm_labor_time * raw_pm_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) )
+ COALESCE( (raw_predictive_labor_time * raw_predictive_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) ) , 0)
+ raw_oh_material_cost
+ (raw_oh_labor_time * raw_oh_labor_human * COALESCE((SELECT man_hour FROM lcc_ms_year_data WHERE year = lcc_equipment_tr_data.tahun), coalesce((select value_num from lcc_ms_master where name='manhours_rate'), 0)) )
+ coalesce(raw_project_task_material_cost, 0)
+ coalesce(("raw_loss_output_MW" * raw_loss_output_price * raw_cm_interval), 0) * 1000
+ coalesce(raw_operational_cost, 0)
+ coalesce(raw_maintenance_cost, 0)
)
, updated_by = 'Sys', updated_at = NOW()
where assetnum = %s;
# Ambil semua baris untuk assetnum
select_q = '''
SELECT id, seq, tahun,
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_predictive_interval, raw_predictive_material_cost, raw_predictive_labor_time, raw_predictive_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_loss_output_MW" as raw_loss_output_mw, raw_loss_output_price,
raw_operational_cost, raw_maintenance_cost, rc_material_cost
FROM lcc_equipment_tr_data
WHERE assetnum = %s;
'''
cursor.execute(select_q, (equipment_id,))
rows = cursor.fetchall()
update lcc_equipment_tr_data set rc_total_cost = (select acquisition_cost from lcc_ms_equipment_data where assetnum=lcc_equipment_tr_data.assetnum) where assetnum = %s and seq=0;
""" # Asumsikan kolom is_actual digunakan untuk membedakan data proyeksi dan data aktual
# Helper to get man_hour for a year (fallback to master 'manhours_rate')
def _get_man_hour_for_year(year):
try:
cur = connection.cursor()
cur.execute("SELECT man_hour FROM lcc_ms_year_data WHERE year = %s", (year,))
r = cur.fetchone()
if r and r[0] is not None:
return float(r[0])
cur.execute("SELECT value_num FROM lcc_ms_master WHERE name='manhours_rate'")
r2 = cur.fetchone()
if r2 and r2[0] is not None:
return float(r2[0])
except Exception:
pass
return 0.0
update_q = '''
UPDATE lcc_equipment_tr_data
SET rc_cm_material_cost = %s,
rc_cm_labor_cost = %s,
rc_pm_material_cost = %s,
rc_pm_labor_cost = %s,
rc_predictive_material_cost = %s,
rc_predictive_labor_cost = %s,
rc_oh_material_cost = %s,
rc_oh_labor_cost = %s,
rc_lost_cost = %s,
rc_operation_cost = %s,
rc_maintenance_cost = %s,
rc_total_cost = %s,
updated_by = 'Sys', updated_at = NOW()
WHERE id = %s;
'''
for r in rows:
try:
yr = r.get("tahun") if isinstance(r, dict) else r[2]
man_hour = _get_man_hour_for_year(yr)
raw_cm_interval = float(r.get("raw_cm_interval") or 0.0)
raw_cm_labor_time = float(r.get("raw_cm_labor_time") or 0.0)
raw_cm_labor_human = float(r.get("raw_cm_labor_human") or 0.0)
raw_pm_interval = float(r.get("raw_pm_interval") or 0.0)
raw_pm_material_cost = float(r.get("raw_pm_material_cost") or 0.0)
raw_pm_labor_time = float(r.get("raw_pm_labor_time") or 0.0)
raw_pm_labor_human = float(r.get("raw_pm_labor_human") or 0.0)
raw_predictive_interval = float(r.get("raw_predictive_interval") or 0.0)
raw_predictive_material_cost = float(r.get("raw_predictive_material_cost") or 0.0)
raw_predictive_labor_time = float(r.get("raw_predictive_labor_time") or 0.0)
raw_predictive_labor_human = float(r.get("raw_predictive_labor_human") or 0.0)
raw_oh_interval = float(r.get("raw_oh_interval") or 0.0)
raw_oh_material_cost = float(r.get("raw_oh_material_cost") or 0.0)
raw_oh_labor_time = float(r.get("raw_oh_labor_time") or 0.0)
raw_oh_labor_human = float(r.get("raw_oh_labor_human") or 0.0)
raw_loss_output_mw = float(r.get("raw_loss_output_mw") or 0.0)
raw_loss_output_price = float(r.get("raw_loss_output_price") or 0.0)
raw_operational_cost = float(r.get("raw_operational_cost") or 0.0)
raw_maintenance_cost = float(r.get("raw_maintenance_cost") or 0.0)
rc_cm_material_cost = float(r.get("rc_cm_material_cost") or 0.0)
# compute per-column costs using helpers
rc_cm_material = rc_cm_material_cost
rc_cm_labor = rc_labor_cost(raw_cm_interval, raw_cm_labor_time, raw_cm_labor_human, man_hour)
try:
if np.isfinite(raw_pm_interval) and raw_pm_interval != 0:
rc_pm_material = raw_pm_material_cost * raw_pm_interval
else:
rc_pm_material = raw_pm_material_cost
except Exception:
rc_pm_material = 0.0
rc_pm_labor = rc_labor_cost(raw_pm_interval, raw_pm_labor_time, raw_pm_labor_human, man_hour)
try:
if np.isfinite(raw_predictive_interval) and raw_predictive_interval != 0:
rc_predictive_material = raw_predictive_material_cost * raw_predictive_interval
else:
rc_predictive_material = raw_predictive_material_cost
except Exception:
rc_predictive_material = 0.0
rc_predictive_labor = raw_predictive_labor_human
try:
rc_predictive_labor = rc_labor_cost(raw_predictive_interval, raw_predictive_labor_time, raw_predictive_labor_human, man_hour)
except Exception:
rc_predictive_labor = 0.0
rc_oh_material = raw_oh_material_cost
rc_oh_labor = rc_labor_cost(raw_oh_interval, raw_oh_labor_time, raw_oh_labor_human, man_hour)
rc_lost = rc_lost_cost(raw_loss_output_mw, raw_loss_output_price, raw_cm_interval)
rc_operation = raw_operational_cost
rc_maintenance = raw_maintenance_cost
asset_criticality_data = self.__get_asset_criticality_params(equipment_id)
asset_criticality_value = 0.0
# Simplify extraction and avoid repeating the multiplication
ac = asset_criticality_data if isinstance(asset_criticality_data, dict) else {}
try:
efdh_oh_sum = float(ac.get("efdh_oh_sum", 0.0))
except Exception:
efdh_oh_sum = 0.0
try:
asset_criticality_value = float(ac.get("asset_criticality", 0.0))
except Exception:
asset_criticality_value = 0.0
# single multiplier used for all RC groups
ac_multiplier = efdh_oh_sum * asset_criticality_value
total = rc_total_cost(
rc_cm=rc_cm_material + rc_cm_labor + ac_multiplier,
rc_pm=rc_pm_material + rc_pm_labor + ac_multiplier,
rc_predictive=rc_predictive_material + rc_predictive_labor + ac_multiplier,
rc_oh=rc_oh_material + rc_oh_labor + ac_multiplier,
rc_lost=rc_lost,
rc_operation=rc_operation,
rc_maintenance=rc_maintenance,
)
id_val = r.get("id") if isinstance(r, dict) else r[0]
cursor.execute(
update_q,
(
rc_cm_material,
rc_cm_labor,
rc_pm_material,
rc_pm_labor,
rc_predictive_material,
rc_predictive_labor,
rc_oh_material,
rc_oh_labor,
rc_lost,
rc_operation,
rc_maintenance,
total,
id_val,
),
)
except Exception:
# ignore row-specific errors and continue
continue
# For seq=0 rows, set rc_total_cost to acquisition_cost
cursor.execute(
"update lcc_equipment_tr_data set rc_total_cost = (select acquisition_cost from lcc_ms_equipment_data where assetnum=lcc_equipment_tr_data.assetnum) where assetnum = %s and seq=0;",
(equipment_id,)
)
# Eksekusi query delete
cursor.execute(up_query, (equipment_id, equipment_id))
connection.commit()
# print(f"Data berhasil diupdate.")
except Exception as e:
print(f"Error saat update data proyeksi dari database: {e}")
@ -440,6 +651,9 @@ class Prediksi:
if connection:
connection.close()
# Authentication: sign-in and refresh helpers
async def sign_in(self, username: str = "user14", password: str = "password") -> dict:
"""Sign in to AUTH_APP_URL/sign-in using provided username/password.

Loading…
Cancel
Save