update run2 & export plant

main
ariwahyunahar 1 month ago
parent cb229086e8
commit bb70d7b445

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EditMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/be-lcca.iml" filepath="$PROJECT_DIR$/.idea/be-lcca.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

@ -110,7 +110,7 @@ def fetch_param_map(cur) -> Dict[str, Param]:
'wacc_on_equity','wacc_on_project','calc_on_equity_irr','calc_on_equity_npv',
'calc_on_project_irr','calc_on_project_npv','calc_roa_all','calc_roa_current'
)
ORDER BY name
ORDER BY seq ASC
"""
)
rows = cur.fetchall()

@ -1,14 +1,19 @@
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
import math
import uuid
def validate_number(n):
return n if n is not None else 0
def cumulative_npv(values, rate, initial_cf0=0.0):
"""
Penggunaan:
@ -24,6 +29,8 @@ def cumulative_npv(values, rate, initial_cf0=0.0):
cumulative_results.append(initial_cf0 + running_npv)
return cumulative_results
def pmt_excel_style(rate, periods, pv):
"""
Fungsi ini menghasilkan nilai setara Excel:
@ -46,12 +53,17 @@ def pmt_excel_style(rate, periods, pv):
# 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:
@ -59,95 +71,22 @@ def main():
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()
# ### LOCKING: pastikan transaksi manual (non-autocommit)
try:
conn.autocommit = False
except Exception:
# Kalau driver tidak punya autocommit, abaikan
pass
print(f"Jumlah baris yang akan di-update: {len(rows)}")
cur = conn.cursor()
# 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
"""
# ### LOCKING: kunci tabel lcc_plant_tr_data
# Mode SHARE ROW EXCLUSIVE:
# - Menghalangi INSERT/UPDATE/DELETE di tabel ini
# - Menghalangi lock SHARE ROW EXCLUSIVE lain → script ngantri satu per satu
cur.execute("LOCK TABLE lcc_plant_tr_data IN SHARE ROW EXCLUSIVE MODE")
# 0 Mendapatkan master parameter dari tabel lcc_ms_master
cur.execute("""
SELECT name,
value_num AS value
@ -161,6 +100,141 @@ def main():
v = param_map.get(name, default)
return float(v) if v is not None else float(default)
# 0-1 Generate New data Projection (is_actual=0) if not exist
# Hapus data projection lama (is_actual = 0)
cur.execute("""
DELETE
FROM lcc_plant_tr_data
WHERE is_actual = 0
""")
# Hitung kebutuhan jumlah baris projection baru agar total (actual + projection)
# sama dengan parameter umur_teknis
cur.execute("""
SELECT COALESCE(COUNT(*), 0)
FROM lcc_plant_tr_data
WHERE is_actual = 1
""")
count_actual = cur.fetchone()[0] if cur.rowcount != -1 else 0
umur_teknis = int(get_param("umur_teknis"))
proj_needed = max(0, umur_teknis - int(count_actual))
# Ambil seq dan tahun terakhir sebagai titik awal penomoran berikutnya
cur.execute("SELECT COALESCE(MAX(seq), 0) FROM lcc_plant_tr_data")
last_seq = int(cur.fetchone()[0])
cur.execute("SELECT COALESCE(MAX(tahun), 0) FROM lcc_plant_tr_data")
last_year = int(cur.fetchone()[0])
# Jika belum ada tahun sama sekali, gunakan tahun_cod-1 sebagai dasar
if last_year == 0:
try:
last_year = int(get_param("tahun_cod")) - 1
except Exception:
last_year = 0
if proj_needed > 0:
# Siapkan rows untuk INSERT projection baru
values = []
next_seq = last_seq + 1
next_year = last_year + 1
for _ in range(proj_needed):
values.append((str(uuid.uuid4()), next_seq, next_year))
next_seq += 1
next_year += 1
insert_sql = (
"INSERT INTO lcc_plant_tr_data (id, seq, tahun, is_actual, created_at, created_by) "
"VALUES (%s, %s, %s, 0, CURRENT_TIMESTAMP, 'SYS')"
)
cur.executemany(insert_sql, values)
# 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 \
"""
# 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")
@ -198,10 +272,10 @@ def main():
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
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 = []
@ -240,10 +314,10 @@ def main():
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
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
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
@ -251,10 +325,9 @@ def main():
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
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
@ -283,19 +356,19 @@ def main():
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"])
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_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
# + cost_a_pinjaman
# + cost_a_depreciation
)
else:
cost_a_replacement = 0
@ -395,7 +468,7 @@ def main():
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
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)
@ -482,16 +555,17 @@ def main():
# ===========================================================================
# ----- ==== HITUNGAN TERAKHIR LCC PLANT ==== -----
# ===========================================================================
IRR_ON_PROJECT = hitung_irr(calc3_free_cash_flow_on_project_array) # dalam %
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 %
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]
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 %
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
@ -499,7 +573,7 @@ def main():
WHERE name = %s \
"""
kpi_params = [
kpi_params_raw = [
(IRR_ON_EQUITY * 100, "calc_on_equity_irr"),
(NPV_ON_EQUITY, "calc_on_equity_npv"),
(IRR_ON_PROJECT * 100, "calc_on_project_irr"),
@ -508,6 +582,11 @@ def main():
(ROA_TO_L, "calc_roa_current"),
]
kpi_params = [
(None if (value is None or isinstance(value, float) and math.isnan(value)) else value, key)
for value, key in kpi_params_raw
]
cur.executemany(update_kpi_sql, kpi_params)
conn.commit()
# ===========================================================================

Loading…
Cancel
Save