update plant simulation
parent
78ef25d708
commit
effe624bd4
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,529 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
# Tambah path ke config.py (seperti di kode-kode kamu sebelumnya)
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||||
|
from config import get_connection # harus mengembalikan koneksi psycopg2
|
||||||
|
from math import pow
|
||||||
|
import numpy_financial as npf
|
||||||
|
|
||||||
|
|
||||||
|
def validate_number(n):
|
||||||
|
return n if n is not None else 0
|
||||||
|
def cumulative_npv(values, rate, initial_cf0=0.0):
|
||||||
|
"""
|
||||||
|
Penggunaan:
|
||||||
|
discount_rate = 0.12 # setara Params!C2
|
||||||
|
cashflows = [10000, 15000, 20000, 18000]
|
||||||
|
result = cumulative_npv(cashflows, discount_rate, initial_cf0=0)
|
||||||
|
"""
|
||||||
|
cumulative_results = []
|
||||||
|
running_npv = 0.0
|
||||||
|
|
||||||
|
for i, cf in enumerate(values, start=1):
|
||||||
|
running_npv += cf / pow(1 + rate, i)
|
||||||
|
cumulative_results.append(initial_cf0 + running_npv)
|
||||||
|
|
||||||
|
return cumulative_results
|
||||||
|
def pmt_excel_style(rate, periods, pv):
|
||||||
|
"""
|
||||||
|
Fungsi ini menghasilkan nilai setara Excel:
|
||||||
|
=-PMT(rate, periods, pv)
|
||||||
|
rate : discount_rate (contoh: 0.12)
|
||||||
|
periods : jumlah periode (contoh: 1,2,3,... seperti E2)
|
||||||
|
pv : present value (contoh: E17 hasil NPV cumulative)
|
||||||
|
Output : nilai positif seperti yang muncul di Excel
|
||||||
|
"""
|
||||||
|
if periods <= 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Jika rate == 0, maka PMT hanya pembagian sederhana
|
||||||
|
if rate == 0:
|
||||||
|
return pv / periods
|
||||||
|
|
||||||
|
# Rumus Excel PMT:
|
||||||
|
# PMT = pv * (rate / (1 - (1 + rate)^(-periods)))
|
||||||
|
payment = pv * (rate / (1 - pow(1 + rate, -periods)))
|
||||||
|
|
||||||
|
# Excel memberi hasil negatif, tapi rumusmu pakai -PMT, maka hasilnya positif
|
||||||
|
return abs(payment)
|
||||||
|
def hitung_pv(rate, nper, fv):
|
||||||
|
pv = npf.pv(rate, nper, pmt=0, fv=fv)
|
||||||
|
return -pv
|
||||||
|
def hitung_irr(cashflows: list):
|
||||||
|
return npf.irr(cashflows)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
conn = get_connection()
|
||||||
|
if conn is None:
|
||||||
|
print("Koneksi ke database gagal.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# 1. Ambil data awal
|
||||||
|
select_sql = """
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM lcc_plant_tr_data
|
||||||
|
ORDER BY seq
|
||||||
|
"""
|
||||||
|
cur.execute(select_sql)
|
||||||
|
|
||||||
|
col_names = [desc[0] for desc in cur.description]
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
print(f"Jumlah baris yang akan di-update: {len(rows)}")
|
||||||
|
|
||||||
|
# 2. Siapkan data untuk bulk UPDATE
|
||||||
|
update_sql = """
|
||||||
|
UPDATE lcc_plant_tr_data
|
||||||
|
SET
|
||||||
|
net_capacity_factor = %s,
|
||||||
|
eaf = %s,
|
||||||
|
production_bruto = %s,
|
||||||
|
production_netto = %s,
|
||||||
|
energy_sales = %s,
|
||||||
|
fuel_consumption = %s,
|
||||||
|
revenue_a = %s,
|
||||||
|
revenue_b = %s,
|
||||||
|
revenue_c = %s,
|
||||||
|
revenue_d = %s,
|
||||||
|
revenue_total = %s,
|
||||||
|
revenue_pv = %s,
|
||||||
|
revenue_annualized = %s,
|
||||||
|
cost_a_replacement = %s,
|
||||||
|
cost_a_pm = %s,
|
||||||
|
cost_a_acquisition = %s,
|
||||||
|
cost_a_pinjaman = %s,
|
||||||
|
cost_a_depreciation = %s,
|
||||||
|
cost_a_total = %s,
|
||||||
|
cost_a_pv = %s,
|
||||||
|
cost_a_annualized = %s,
|
||||||
|
cost_c_fuel = %s,
|
||||||
|
cost_c_pv = %s,
|
||||||
|
cost_c_annualized = %s,
|
||||||
|
cost_bd_om = %s,
|
||||||
|
cost_bd_pm_nonmi = %s,
|
||||||
|
cost_bd_bd = %s,
|
||||||
|
cost_bd_total = %s,
|
||||||
|
cost_bd_pv = %s,
|
||||||
|
cost_bd_annualized = %s,
|
||||||
|
total_expense = %s,
|
||||||
|
total_cost_eac = %s,
|
||||||
|
total_profit_loss = %s,
|
||||||
|
total_residual_value = %s,
|
||||||
|
calc_depreciation = %s,
|
||||||
|
calc_interest_payment = %s,
|
||||||
|
calc_principal_payment = %s,
|
||||||
|
calc_dept_amount = %s,
|
||||||
|
calc2_ebitda = %s,
|
||||||
|
calc2_earning_before_tax = %s,
|
||||||
|
calc2_tax = %s,
|
||||||
|
calc2_earning_after_tax = %s,
|
||||||
|
calc2_nopat = %s,
|
||||||
|
calc3_interest_after_tax = %s,
|
||||||
|
calc3_free_cash_flow_on_project = %s,
|
||||||
|
calc3_discounted_fcf_on_project = %s,
|
||||||
|
calc4_principal_repayment = %s,
|
||||||
|
calc4_free_cash_flow_on_equity = %s,
|
||||||
|
calc4_discounted_fcf_on_equity = %s,
|
||||||
|
chart_total_revenue = %s,
|
||||||
|
chart_revenue_a = %s,
|
||||||
|
chart_revenue_b = %s,
|
||||||
|
chart_revenue_c = %s,
|
||||||
|
chart_revenue_d = %s,
|
||||||
|
chart_revenue_annualized = %s,
|
||||||
|
chart_fuel_cost_component_c = %s,
|
||||||
|
chart_fuel_cost = %s,
|
||||||
|
chart_fuel_cost_annualized = %s,
|
||||||
|
chart_oem_component_bd = %s,
|
||||||
|
chart_oem_bd_cost = %s,
|
||||||
|
chart_oem_periodic_maintenance_cost = %s,
|
||||||
|
chart_oem_annualized = %s,
|
||||||
|
chart_capex_component_a = %s,
|
||||||
|
chart_capex_biaya_investasi_tambahan = %s,
|
||||||
|
chart_capex_acquisition_cost = %s,
|
||||||
|
chart_capex_annualized = %s
|
||||||
|
WHERE seq = %s
|
||||||
|
"""
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT name,
|
||||||
|
value_num AS value
|
||||||
|
FROM lcc_ms_master
|
||||||
|
""")
|
||||||
|
param_rows = cur.fetchall()
|
||||||
|
param_map = {name: val for (name, val) in param_rows}
|
||||||
|
|
||||||
|
# helper biar aman
|
||||||
|
def get_param(name, default=0.0):
|
||||||
|
v = param_map.get(name, default)
|
||||||
|
return float(v) if v is not None else float(default)
|
||||||
|
|
||||||
|
# Ambil parameter dari tabel (fungsi get_param sudah kamu buat sebelumnya)
|
||||||
|
discount_rate = get_param("discount_rate") / 100
|
||||||
|
total_project_cost = get_param("total_project_cost")
|
||||||
|
daya_mampu_netto = get_param("daya_mampu_netto")
|
||||||
|
auxiliary = get_param("auxiliary")
|
||||||
|
susut_trafo = get_param("susut_trafo")
|
||||||
|
sfc = get_param("sfc")
|
||||||
|
|
||||||
|
# Harga listrik berdasarkan tipe
|
||||||
|
price_a = get_param("electricity_price_a")
|
||||||
|
price_b = get_param("electricity_price_b")
|
||||||
|
price_c = get_param("electricity_price_c")
|
||||||
|
price_d = get_param("electricity_price_d")
|
||||||
|
|
||||||
|
# Parameter lain
|
||||||
|
harga_bahan_bakar = get_param("harga_bahan_bakar")
|
||||||
|
inflation_rate = get_param("inflation_rate") / 100
|
||||||
|
loan_portion = get_param("loan_portion") / 100
|
||||||
|
equity_portion = get_param("equity_portion") / 100
|
||||||
|
interest_rate = get_param("interest_rate") / 100
|
||||||
|
loan_tenor = get_param("loan_tenor")
|
||||||
|
loan = get_param("loan")
|
||||||
|
corporate_tax_rate = get_param("corporate_tax_rate") / 100
|
||||||
|
wacc_on_equity = get_param("wacc_on_equity") / 100
|
||||||
|
wacc_on_project = get_param("wacc_on_project") / 100
|
||||||
|
manhours_rate = get_param("manhours_rate")
|
||||||
|
principal_interest_payment = get_param("principal_interest_payment")
|
||||||
|
umur_teknis = get_param("umur_teknis")
|
||||||
|
tahun_cod = get_param("tahun_cod")
|
||||||
|
daya_terpasang = get_param("daya_terpasang")
|
||||||
|
equity = get_param("equity")
|
||||||
|
|
||||||
|
params = []
|
||||||
|
revenue_total_array = []
|
||||||
|
cost_a_acquisition_array = []
|
||||||
|
cost_c_fuel_array = []
|
||||||
|
cost_bd_total_array = []
|
||||||
|
total_residual_value = 0 # nilai awal dari total_residual_value
|
||||||
|
calc_dept_amount = 0 # nilai awal dari calc_dept_amount
|
||||||
|
revenue_total_start = 0 # nilai awal dari revenue_total_start
|
||||||
|
calc4_free_cash_flow_on_equity = 0 # nilai awal dari calc4_free_cash_flow_on_equity
|
||||||
|
calc3_free_cash_flow_on_project_array = []
|
||||||
|
calc4_free_cash_flow_on_equity_array = []
|
||||||
|
total_residual_value_array = []
|
||||||
|
calc2_earning_after_tax_array = []
|
||||||
|
total_residual_value_array_sampai_sekarang = []
|
||||||
|
calc2_earning_after_tax_array_sampai_sekarang = []
|
||||||
|
net_capacity_factor = 0
|
||||||
|
eaf = 0
|
||||||
|
cost_bd_om = 0
|
||||||
|
cost_bd_pm_nonmi = 0
|
||||||
|
cost_bd_bd = 0
|
||||||
|
cost_a_replacement = 0
|
||||||
|
cost_a_pm = 0
|
||||||
|
cost_a_pinjaman = 0
|
||||||
|
cost_a_depreciation = 0
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
# row adalah tuple sesuai urutan select_sql
|
||||||
|
data = dict(zip(col_names, row))
|
||||||
|
|
||||||
|
seq = data["seq"] # primary key / unique key untuk WHERE
|
||||||
|
|
||||||
|
if data["is_actual"] == 1:
|
||||||
|
net_capacity_factor = validate_number(data["net_capacity_factor"])
|
||||||
|
eaf = validate_number(data["eaf"])
|
||||||
|
production_bruto = validate_number(data["production_bruto"])
|
||||||
|
production_netto = validate_number(data["production_netto"])
|
||||||
|
energy_sales = production_netto
|
||||||
|
fuel_consumption = validate_number(data["fuel_consumption"])
|
||||||
|
revenue_a = validate_number(data["revenue_a"])
|
||||||
|
revenue_b = validate_number(data["revenue_b"])
|
||||||
|
revenue_c = validate_number(data["revenue_c"])
|
||||||
|
revenue_d = validate_number(data["revenue_d"])
|
||||||
|
cost_c_fuel = validate_number(data["cost_c_fuel"])
|
||||||
|
cost_bd_om = validate_number(data["cost_bd_om"])
|
||||||
|
cost_bd_pm_nonmi = validate_number(data["cost_bd_pm_nonmi"])
|
||||||
|
cost_bd_bd = validate_number(data["cost_bd_bd"])
|
||||||
|
else:
|
||||||
|
net_capacity_factor = net_capacity_factor #last value
|
||||||
|
eaf = eaf #last value
|
||||||
|
production_netto = net_capacity_factor * 8760 * daya_mampu_netto / 100
|
||||||
|
production_bruto = production_netto/(100-(auxiliary+susut_trafo))*100
|
||||||
|
energy_sales = production_netto
|
||||||
|
fuel_consumption = production_bruto * sfc
|
||||||
|
revenue_a = (price_a * eaf * daya_mampu_netto * 1000 * 12 / 100) / 1000000
|
||||||
|
revenue_b = (price_b * eaf * daya_mampu_netto * 1000 * 12 / 100) / 1000000
|
||||||
|
revenue_c = price_c * production_netto * 1000 / 1000000
|
||||||
|
revenue_d = price_d * production_netto * 1000 / 1000000
|
||||||
|
cost_c_fuel = fuel_consumption * harga_bahan_bakar / 1000000
|
||||||
|
cost_bd_om = cost_bd_om #last value
|
||||||
|
cost_bd_pm_nonmi = cost_bd_pm_nonmi #last value
|
||||||
|
cost_bd_bd = cost_bd_bd #last value
|
||||||
|
|
||||||
|
|
||||||
|
# ++++++ REVENUE +++++++
|
||||||
|
revenue_total = revenue_a + revenue_b + revenue_c + revenue_d
|
||||||
|
if seq > 0:
|
||||||
|
revenue_total_array.append(revenue_total)
|
||||||
|
revenue_pv = cumulative_npv(revenue_total_array, discount_rate)[-1] + revenue_total_start
|
||||||
|
revenue_annualized = pmt_excel_style(discount_rate, seq, revenue_pv)
|
||||||
|
else:
|
||||||
|
revenue_annualized = 0
|
||||||
|
revenue_pv = 0
|
||||||
|
revenue_total_start = revenue_total
|
||||||
|
|
||||||
|
# print(revenue_total_array)
|
||||||
|
# print(discount_rate)
|
||||||
|
# print(revenue_pv)
|
||||||
|
|
||||||
|
chart_total_revenue = revenue_total
|
||||||
|
chart_revenue_a = revenue_a
|
||||||
|
chart_revenue_b = revenue_b
|
||||||
|
chart_revenue_c = revenue_c
|
||||||
|
chart_revenue_d = revenue_d
|
||||||
|
chart_revenue_annualized = revenue_annualized
|
||||||
|
|
||||||
|
# ===== COST A =====
|
||||||
|
if seq > 0:
|
||||||
|
if data["is_actual"] == 1:
|
||||||
|
cost_a_replacement = validate_number(data["cost_a_replacement"])
|
||||||
|
cost_a_pm = validate_number(data["cost_a_pm"])
|
||||||
|
cost_a_pinjaman = 0 # validate_number(data["cost_a_pinjaman"])
|
||||||
|
cost_a_depreciation = 0 # validate_number(data["cost_a_depreciation"])
|
||||||
|
else:
|
||||||
|
cost_a_replacement = cost_a_replacement
|
||||||
|
cost_a_pm = cost_a_pm
|
||||||
|
cost_a_pinjaman = 0 #cost_a_pinjaman
|
||||||
|
cost_a_depreciation = 0 # cost_a_depreciation
|
||||||
|
cost_a_total = validate_number(data["cost_a_total"])
|
||||||
|
cost_a_acquisition = (
|
||||||
|
cost_a_replacement
|
||||||
|
+ cost_a_pm
|
||||||
|
# + cost_a_pinjaman
|
||||||
|
# + cost_a_depreciation
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cost_a_replacement = 0
|
||||||
|
cost_a_pm = 0
|
||||||
|
cost_a_pinjaman = 0
|
||||||
|
cost_a_depreciation = 0
|
||||||
|
cost_a_total = 0
|
||||||
|
cost_a_acquisition = total_project_cost
|
||||||
|
|
||||||
|
if seq > 0:
|
||||||
|
cost_a_acquisition_array.append(cost_a_acquisition)
|
||||||
|
cost_a_pv = cumulative_npv(cost_a_acquisition_array, discount_rate)[-1] + total_project_cost
|
||||||
|
cost_a_annualized = pmt_excel_style(discount_rate, seq, cost_a_pv)
|
||||||
|
|
||||||
|
chart_capex_component_a = cost_a_acquisition
|
||||||
|
chart_capex_annualized = cost_a_annualized
|
||||||
|
else:
|
||||||
|
chart_capex_component_a = total_project_cost
|
||||||
|
chart_capex_annualized = 0
|
||||||
|
cost_a_pv = 0
|
||||||
|
cost_a_annualized = 0
|
||||||
|
|
||||||
|
chart_capex_biaya_investasi_tambahan = 0
|
||||||
|
chart_capex_acquisition_cost = 0
|
||||||
|
|
||||||
|
# ===== COST C =====
|
||||||
|
cost_c_fuel_start = 0
|
||||||
|
|
||||||
|
if seq > 0:
|
||||||
|
cost_c_fuel_array.append(cost_c_fuel)
|
||||||
|
cost_c_pv = cumulative_npv(cost_c_fuel_array, discount_rate)[-1] + cost_c_fuel_start
|
||||||
|
cost_c_annualized = pmt_excel_style(discount_rate, seq, cost_c_pv)
|
||||||
|
else:
|
||||||
|
cost_c_fuel_start = cost_c_fuel
|
||||||
|
cost_c_pv = 0
|
||||||
|
cost_c_annualized = 0
|
||||||
|
|
||||||
|
chart_fuel_cost_component_c = cost_c_fuel
|
||||||
|
chart_fuel_cost = cost_c_fuel
|
||||||
|
chart_fuel_cost_annualized = cost_c_annualized
|
||||||
|
|
||||||
|
# ===== COST BD =====
|
||||||
|
cost_bd_total_start = 0
|
||||||
|
|
||||||
|
if seq > 0:
|
||||||
|
cost_bd_total = cost_bd_om + cost_bd_pm_nonmi + cost_bd_bd
|
||||||
|
cost_bd_total_array.append(cost_bd_total)
|
||||||
|
cost_bd_pv = cumulative_npv(cost_bd_total_array, discount_rate)[-1] + cost_bd_total_start
|
||||||
|
cost_bd_annualized = pmt_excel_style(discount_rate, seq, cost_bd_pv)
|
||||||
|
else:
|
||||||
|
cost_bd_total = 0
|
||||||
|
cost_bd_total_start = cost_bd_om + cost_bd_pm_nonmi
|
||||||
|
cost_bd_pv = 0
|
||||||
|
cost_bd_annualized = 0
|
||||||
|
|
||||||
|
chart_oem_component_bd = cost_bd_total
|
||||||
|
chart_oem_bd_cost = cost_bd_om
|
||||||
|
chart_oem_periodic_maintenance_cost = cost_bd_pm_nonmi
|
||||||
|
chart_oem_annualized = cost_bd_annualized
|
||||||
|
|
||||||
|
# ===== TOTAL EXPENSE & PROFIT/LOSS =====
|
||||||
|
if seq > 0:
|
||||||
|
calc_depreciation = total_residual_value / (umur_teknis - seq + 1)
|
||||||
|
total_residual_value = total_residual_value + cost_a_replacement - calc_depreciation
|
||||||
|
calc_interest_payment = interest_rate * calc_dept_amount
|
||||||
|
calc_principal_payment = principal_interest_payment - calc_interest_payment
|
||||||
|
calc_dept_amount = calc_dept_amount - calc_principal_payment
|
||||||
|
else:
|
||||||
|
calc_depreciation = 0
|
||||||
|
total_residual_value = total_project_cost
|
||||||
|
calc_interest_payment = 0
|
||||||
|
calc_principal_payment = 0
|
||||||
|
calc_dept_amount = loan
|
||||||
|
total_residual_value_array.append(total_residual_value)
|
||||||
|
if data["is_actual"] == 1:
|
||||||
|
total_residual_value_array_sampai_sekarang.append(total_residual_value)
|
||||||
|
|
||||||
|
total_expense = cost_c_fuel + cost_bd_total
|
||||||
|
total_cost_eac = cost_a_annualized + cost_c_annualized + cost_bd_annualized
|
||||||
|
total_profit_loss = revenue_annualized - total_cost_eac
|
||||||
|
|
||||||
|
calc2_ebitda = revenue_total - total_expense
|
||||||
|
calc2_earning_before_tax = calc2_ebitda - cost_a_depreciation - calc_interest_payment
|
||||||
|
calc2_tax = calc2_earning_before_tax * corporate_tax_rate if calc2_earning_before_tax > 0 else 0
|
||||||
|
calc2_earning_after_tax = calc2_earning_before_tax - calc2_tax
|
||||||
|
calc2_earning_after_tax_array.append(calc2_earning_after_tax)
|
||||||
|
if data["is_actual"] == 1: calc2_earning_after_tax_array_sampai_sekarang.append(calc2_earning_after_tax)
|
||||||
|
calc3_interest_after_tax = calc_interest_payment * (1 - corporate_tax_rate)
|
||||||
|
calc2_nopat = calc2_earning_before_tax - calc3_interest_after_tax
|
||||||
|
|
||||||
|
if seq > 0:
|
||||||
|
calc3_free_cash_flow_on_project = calc2_earning_after_tax + calc3_interest_after_tax + calc_depreciation - cost_a_replacement
|
||||||
|
else:
|
||||||
|
calc3_free_cash_flow_on_project = -total_project_cost
|
||||||
|
calc3_free_cash_flow_on_project_array.append(calc3_free_cash_flow_on_project)
|
||||||
|
calc3_discounted_fcf_on_project = hitung_pv(wacc_on_project, seq, calc3_free_cash_flow_on_project)
|
||||||
|
|
||||||
|
calc4_principal_repayment = -calc_principal_payment
|
||||||
|
if seq > 0:
|
||||||
|
calc4_free_cash_flow_on_equity = calc4_principal_repayment+calc2_earning_after_tax+calc_depreciation - cost_a_replacement
|
||||||
|
else:
|
||||||
|
calc4_free_cash_flow_on_equity = -equity
|
||||||
|
calc4_free_cash_flow_on_equity_array.append(calc4_free_cash_flow_on_equity)
|
||||||
|
calc4_discounted_fcf_on_equity = hitung_pv(wacc_on_equity, seq, calc4_free_cash_flow_on_equity)
|
||||||
|
|
||||||
|
params.append((
|
||||||
|
net_capacity_factor,
|
||||||
|
eaf,
|
||||||
|
production_bruto,
|
||||||
|
production_netto,
|
||||||
|
energy_sales,
|
||||||
|
fuel_consumption,
|
||||||
|
revenue_a,
|
||||||
|
revenue_b,
|
||||||
|
revenue_c,
|
||||||
|
revenue_d,
|
||||||
|
revenue_total,
|
||||||
|
revenue_pv,
|
||||||
|
revenue_annualized,
|
||||||
|
cost_a_replacement,
|
||||||
|
cost_a_pm,
|
||||||
|
cost_a_acquisition,
|
||||||
|
cost_a_pinjaman,
|
||||||
|
cost_a_depreciation,
|
||||||
|
cost_a_total,
|
||||||
|
cost_a_pv,
|
||||||
|
cost_a_annualized,
|
||||||
|
cost_c_fuel,
|
||||||
|
cost_c_pv,
|
||||||
|
cost_c_annualized,
|
||||||
|
cost_bd_om,
|
||||||
|
cost_bd_pm_nonmi,
|
||||||
|
cost_bd_bd,
|
||||||
|
cost_bd_total,
|
||||||
|
cost_bd_pv,
|
||||||
|
cost_bd_annualized,
|
||||||
|
total_expense,
|
||||||
|
total_cost_eac,
|
||||||
|
total_profit_loss,
|
||||||
|
total_residual_value,
|
||||||
|
calc_depreciation,
|
||||||
|
calc_interest_payment,
|
||||||
|
calc_principal_payment,
|
||||||
|
calc_dept_amount,
|
||||||
|
calc2_ebitda,
|
||||||
|
calc2_earning_before_tax,
|
||||||
|
calc2_tax,
|
||||||
|
calc2_earning_after_tax,
|
||||||
|
calc2_nopat,
|
||||||
|
calc3_interest_after_tax,
|
||||||
|
calc3_free_cash_flow_on_project,
|
||||||
|
calc3_discounted_fcf_on_project,
|
||||||
|
calc4_principal_repayment,
|
||||||
|
calc4_free_cash_flow_on_equity,
|
||||||
|
calc4_discounted_fcf_on_equity,
|
||||||
|
chart_total_revenue,
|
||||||
|
chart_revenue_a,
|
||||||
|
chart_revenue_b,
|
||||||
|
chart_revenue_c,
|
||||||
|
chart_revenue_d,
|
||||||
|
chart_revenue_annualized,
|
||||||
|
chart_fuel_cost_component_c,
|
||||||
|
chart_fuel_cost,
|
||||||
|
chart_fuel_cost_annualized,
|
||||||
|
chart_oem_component_bd,
|
||||||
|
chart_oem_bd_cost,
|
||||||
|
chart_oem_periodic_maintenance_cost,
|
||||||
|
chart_oem_annualized,
|
||||||
|
chart_capex_component_a,
|
||||||
|
chart_capex_biaya_investasi_tambahan,
|
||||||
|
chart_capex_acquisition_cost,
|
||||||
|
chart_capex_annualized,
|
||||||
|
seq # <-- penting: ini untuk WHERE
|
||||||
|
))
|
||||||
|
|
||||||
|
# 3. Bulk update dengan executemany
|
||||||
|
if params:
|
||||||
|
cur.executemany(update_sql, params)
|
||||||
|
conn.commit()
|
||||||
|
print("Bulk update selesai dan sudah di-commit.")
|
||||||
|
else:
|
||||||
|
print("Tidak ada data untuk di-update.")
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# ----- ==== HITUNGAN TERAKHIR LCC PLANT ==== -----
|
||||||
|
# ===========================================================================
|
||||||
|
IRR_ON_PROJECT = hitung_irr(calc3_free_cash_flow_on_project_array) # dalam %
|
||||||
|
NPV_ON_PROJECT = cumulative_npv(calc3_free_cash_flow_on_project_array[1:], wacc_on_project)[-1] + \
|
||||||
|
calc3_free_cash_flow_on_project_array[0]
|
||||||
|
|
||||||
|
IRR_ON_EQUITY = hitung_irr(calc4_free_cash_flow_on_equity_array) # dalam %
|
||||||
|
NPV_ON_EQUITY = cumulative_npv(calc4_free_cash_flow_on_equity_array[1:], wacc_on_equity)[-1] + \
|
||||||
|
calc4_free_cash_flow_on_equity_array[0]
|
||||||
|
|
||||||
|
ROA_ALL = sum(calc2_earning_after_tax_array) / sum(total_residual_value_array) * 100 # dalam %
|
||||||
|
ROA_TO_L = sum(calc2_earning_after_tax_array_sampai_sekarang) / sum(total_residual_value_array_sampai_sekarang) * 100 # dalam %
|
||||||
|
|
||||||
|
update_kpi_sql = """
|
||||||
|
UPDATE lcc_ms_master
|
||||||
|
SET value_num = %s
|
||||||
|
WHERE name = %s \
|
||||||
|
"""
|
||||||
|
|
||||||
|
kpi_params = [
|
||||||
|
(IRR_ON_EQUITY * 100, "calc_on_equity_irr"),
|
||||||
|
(NPV_ON_EQUITY, "calc_on_equity_npv"),
|
||||||
|
(IRR_ON_PROJECT * 100, "calc_on_project_irr"),
|
||||||
|
(NPV_ON_PROJECT, "calc_on_project_npv"),
|
||||||
|
(ROA_ALL, "calc_roa_all"),
|
||||||
|
(ROA_TO_L, "calc_roa_current"),
|
||||||
|
]
|
||||||
|
|
||||||
|
cur.executemany(update_kpi_sql, kpi_params)
|
||||||
|
conn.commit()
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
conn.rollback()
|
||||||
|
print(f"Terjadi error, transaksi di-rollback. Error: {e}")
|
||||||
|
try:
|
||||||
|
cur.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -0,0 +1,130 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Tambah path ke config.py (seperti di kode-kode kamu sebelumnya)
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||||
|
|
||||||
|
from config import get_connection, get_connection_db_collect # pastikan fungsi ini ada di config.py
|
||||||
|
import psycopg2
|
||||||
|
|
||||||
|
|
||||||
|
def get_cost_a_pm(conn2):
|
||||||
|
"""
|
||||||
|
Ambil cost_a_pm per tahun dari conn2 (wo_maximo, worktype = 'OH', MI).
|
||||||
|
"""
|
||||||
|
query = """
|
||||||
|
SELECT DATE_PART('year', a.reportdate) AS tahun, SUM(a.actmatcost) AS total_cost
|
||||||
|
FROM public.wo_maximo AS a
|
||||||
|
WHERE
|
||||||
|
a.asset_unit = '3'
|
||||||
|
AND a.worktype IN ('OH')
|
||||||
|
AND a.status IN ('CLOSE', 'COMP')
|
||||||
|
AND a.wonum NOT LIKE 'T%%'
|
||||||
|
AND a.wojp8 NOT IN ('S1')
|
||||||
|
GROUP BY DATE_PART('year', a.reportdate)
|
||||||
|
ORDER BY DATE_PART('year', a.reportdate) ASC;
|
||||||
|
"""
|
||||||
|
data = {}
|
||||||
|
with conn2.cursor() as cur:
|
||||||
|
cur.execute(query)
|
||||||
|
for tahun, total_cost in cur.fetchall():
|
||||||
|
# tahun akan float dari DATE_PART, ubah ke int
|
||||||
|
tahun_int = int(tahun)
|
||||||
|
data[tahun_int] = float(total_cost or 0.0)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_cost_bd_pm_nonmi(conn2):
|
||||||
|
"""
|
||||||
|
Ambil cost_bd_pm_nonmi per tahun dari conn2 (wo_maximo, worktype != 'OH', Non-MI).
|
||||||
|
"""
|
||||||
|
query = """
|
||||||
|
SELECT DATE_PART('year', a.reportdate) AS tahun, SUM(a.actmatcost) AS total_cost
|
||||||
|
FROM public.wo_maximo AS a
|
||||||
|
WHERE
|
||||||
|
a.asset_unit = '3'
|
||||||
|
AND a.worktype NOT IN ('OH')
|
||||||
|
AND a.status IN ('CLOSE', 'COMP')
|
||||||
|
AND a.wonum NOT LIKE 'T%%'
|
||||||
|
GROUP BY DATE_PART('year', a.reportdate)
|
||||||
|
ORDER BY DATE_PART('year', a.reportdate) ASC;
|
||||||
|
"""
|
||||||
|
data = {}
|
||||||
|
with conn2.cursor() as cur:
|
||||||
|
cur.execute(query)
|
||||||
|
for tahun, total_cost in cur.fetchall():
|
||||||
|
tahun_int = int(tahun)
|
||||||
|
data[tahun_int] = float(total_cost or 0.0)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def upsert_lcc_plant_tr_data(conn, tahun, cost_a_pm, cost_bd_pm_nonmi):
|
||||||
|
"""
|
||||||
|
Update kalau tahun sudah ada, kalau tidak ada -> insert.
|
||||||
|
Table: lcc_plant_tr_data (tahun, cost_a_pm, cost_bd_pm_nonmi)
|
||||||
|
"""
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# Coba update dulu
|
||||||
|
update_sql = """
|
||||||
|
UPDATE lcc_plant_tr_data
|
||||||
|
SET cost_a_pm = %s,
|
||||||
|
cost_bd_pm_nonmi = %s
|
||||||
|
WHERE tahun = %s;
|
||||||
|
"""
|
||||||
|
cur.execute(update_sql, (cost_a_pm, cost_bd_pm_nonmi, tahun))
|
||||||
|
|
||||||
|
# if cur.rowcount == 0:
|
||||||
|
# insert_sql = """
|
||||||
|
# INSERT INTO lcc_plant_tr_data (tahun, cost_a_pm, cost_bd_pm_nonmi)
|
||||||
|
# VALUES (%s, %s, %s);
|
||||||
|
# """
|
||||||
|
# cur.execute(insert_sql, (tahun, cost_a_pm, cost_bd_pm_nonmi))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Koneksi ke DB1 (utama) untuk table lcc_plant_tr_data
|
||||||
|
conn = get_connection()
|
||||||
|
if conn is None:
|
||||||
|
print("Koneksi ke database (conn) gagal.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Koneksi ke DB2 (collect) untuk table wo_maximo
|
||||||
|
conn2 = get_connection_db_collect()
|
||||||
|
if conn2 is None:
|
||||||
|
print("Koneksi ke database 2 (conn2) gagal.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cost_a_pm_data = get_cost_a_pm(conn2)
|
||||||
|
cost_bd_pm_nonmi_data = get_cost_bd_pm_nonmi(conn2)
|
||||||
|
|
||||||
|
# Gabungkan semua tahun yang muncul di salah satu / keduanya
|
||||||
|
semua_tahun = sorted(set(cost_a_pm_data.keys()) | set(cost_bd_pm_nonmi_data.keys()))
|
||||||
|
|
||||||
|
for tahun in semua_tahun:
|
||||||
|
cost_a_pm = cost_a_pm_data.get(tahun, 0.0)/1000000
|
||||||
|
cost_bd_pm_nonmi = cost_bd_pm_nonmi_data.get(tahun, 0.0)/1000000
|
||||||
|
|
||||||
|
upsert_lcc_plant_tr_data(conn, tahun, cost_a_pm, cost_bd_pm_nonmi)
|
||||||
|
print(f"Tahun {tahun}: cost_a_pm={cost_a_pm}, cost_bd_pm_nonmi={cost_bd_pm_nonmi} -> disimpan")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
print("Update lcc_plant_tr_data selesai dan sudah di-commit.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
conn.rollback()
|
||||||
|
print("Terjadi error, transaksi di-rollback:", e)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
conn.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
conn2.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue