|
|
|
|
@ -394,8 +394,8 @@ class Prediksi:
|
|
|
|
|
part2 = max(0.0, (dmn - ens)) * extra_fuel
|
|
|
|
|
asset_criticality = part1 + part2
|
|
|
|
|
|
|
|
|
|
efdh = _f("asset_crit_efdh_equivalent_forced_derated_hours") # EFDH per Year
|
|
|
|
|
foh = _f("asset_crit_foh_forced_outage_hours") # FOH per Year
|
|
|
|
|
# efdh = _f("asset_crit_efdh_equivalent_forced_derated_hours") # EFDH per Year
|
|
|
|
|
# foh = _f("asset_crit_foh_forced_outage_hours") # FOH per Year
|
|
|
|
|
|
|
|
|
|
query_each_equipment = """
|
|
|
|
|
SELECT
|
|
|
|
|
@ -431,6 +431,113 @@ class Prediksi:
|
|
|
|
|
if connection:
|
|
|
|
|
connection.close()
|
|
|
|
|
|
|
|
|
|
# Fungsi untuk mengambil labour cost
|
|
|
|
|
def __get_labour_cost(self, equipment_id, worktype, existing_connection=None):
|
|
|
|
|
"""Return labour cost totals per tahun for the given worktype."""
|
|
|
|
|
labour_costs = {}
|
|
|
|
|
connection = existing_connection
|
|
|
|
|
cursor = None
|
|
|
|
|
close_connection = False
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if connection is None:
|
|
|
|
|
connections = get_production_connection()
|
|
|
|
|
connection = connections[0] if isinstance(connections, tuple) else connections
|
|
|
|
|
close_connection = True
|
|
|
|
|
|
|
|
|
|
if connection is None:
|
|
|
|
|
print("Database connection failed.")
|
|
|
|
|
return labour_costs
|
|
|
|
|
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
|
|
|
|
|
worktype_upper = (worktype or "").upper()
|
|
|
|
|
worktype_condition = "AND a.worktype IN ('CM', 'PROACTIVE', 'WA')"
|
|
|
|
|
params = [equipment_id]
|
|
|
|
|
|
|
|
|
|
if worktype_upper != "CM":
|
|
|
|
|
worktype_condition = "AND a.worktype = %s"
|
|
|
|
|
params.append(worktype_upper)
|
|
|
|
|
|
|
|
|
|
exclude_condition = "AND a.wojp8 != 'S1'" if worktype_upper == "CM" else ""
|
|
|
|
|
|
|
|
|
|
query = f"""
|
|
|
|
|
SELECT
|
|
|
|
|
EXTRACT(YEAR FROM x.reportdate)::int AS tahun,
|
|
|
|
|
SUM(x.upah_per_wonum) AS total_upah_per_tahun
|
|
|
|
|
FROM (
|
|
|
|
|
SELECT
|
|
|
|
|
bw.wonum,
|
|
|
|
|
bw.reportdate,
|
|
|
|
|
bw.jumlah_jam_kerja,
|
|
|
|
|
CASE
|
|
|
|
|
WHEN COUNT(b.laborcode) FILTER (WHERE b.laborcode IS NOT NULL) > 0 THEN
|
|
|
|
|
SUM(
|
|
|
|
|
COALESCE(emp_cost.salary_per_hour_idr,
|
|
|
|
|
(SELECT salary_per_hour_idr FROM lcc_manpower_cost WHERE UPPER(staff_job_level) = UPPER('Junior') LIMIT 1))
|
|
|
|
|
* bw.jumlah_jam_kerja
|
|
|
|
|
)
|
|
|
|
|
ELSE
|
|
|
|
|
3 * (SELECT salary_per_hour_idr FROM lcc_manpower_cost WHERE UPPER(staff_job_level) = UPPER('Junior') LIMIT 1) * bw.jumlah_jam_kerja
|
|
|
|
|
END AS upah_per_wonum
|
|
|
|
|
FROM (
|
|
|
|
|
SELECT
|
|
|
|
|
a.wonum,
|
|
|
|
|
a.reportdate,
|
|
|
|
|
CASE
|
|
|
|
|
WHEN (EXTRACT(EPOCH FROM (a.actfinish - a.actstart)) / 3600.0) = 0
|
|
|
|
|
THEN 1
|
|
|
|
|
ELSE (EXTRACT(EPOCH FROM (a.actfinish - a.actstart)) / 3600.0)
|
|
|
|
|
END AS jumlah_jam_kerja
|
|
|
|
|
FROM public.wo_maximo a
|
|
|
|
|
WHERE
|
|
|
|
|
a.asset_unit = '3'
|
|
|
|
|
AND a.wonum NOT LIKE 'T%'
|
|
|
|
|
AND a.asset_assetnum = %s
|
|
|
|
|
AND (EXTRACT(EPOCH FROM (a.actfinish - a.actstart)) / 3600.0) <= 730
|
|
|
|
|
{worktype_condition}
|
|
|
|
|
{exclude_condition}
|
|
|
|
|
) bw
|
|
|
|
|
LEFT JOIN public.wo_maximo_labtrans b ON b.wonum = bw.wonum
|
|
|
|
|
LEFT JOIN lcc_ms_manpower emp ON UPPER(TRIM(emp."ID Number")) = UPPER(TRIM(b.laborcode))
|
|
|
|
|
LEFT JOIN lcc_manpower_cost emp_cost ON UPPER(TRIM(emp_cost.staff_job_level)) = UPPER(TRIM(emp."Position"))
|
|
|
|
|
GROUP BY bw.wonum, bw.reportdate, bw.jumlah_jam_kerja
|
|
|
|
|
) x
|
|
|
|
|
GROUP BY 1
|
|
|
|
|
ORDER BY 1;
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
cursor.execute(query, tuple(params))
|
|
|
|
|
rows = cursor.fetchall()
|
|
|
|
|
for tahun, total in rows:
|
|
|
|
|
try:
|
|
|
|
|
year_int = int(tahun) if tahun is not None else None
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
year_int = None
|
|
|
|
|
if year_int is None:
|
|
|
|
|
continue
|
|
|
|
|
try:
|
|
|
|
|
labour_costs[year_int] = float(total) if total is not None else 0.0
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
labour_costs[year_int] = 0.0
|
|
|
|
|
|
|
|
|
|
return labour_costs
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"Error saat mendapatkan labour cost dari database: {e}")
|
|
|
|
|
return labour_costs
|
|
|
|
|
finally:
|
|
|
|
|
if cursor:
|
|
|
|
|
try:
|
|
|
|
|
cursor.close()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
if close_connection and connection:
|
|
|
|
|
try:
|
|
|
|
|
connection.close()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Fungsi untuk menghapus data proyeksi pada tahun tertentu
|
|
|
|
|
def __update_data_lcc(self, equipment_id):
|
|
|
|
|
try:
|
|
|
|
|
@ -448,6 +555,17 @@ class Prediksi:
|
|
|
|
|
|
|
|
|
|
cursor = connection.cursor(cursor_factory=DictCursor)
|
|
|
|
|
|
|
|
|
|
labour_cost_maps = {
|
|
|
|
|
"CM": self.__get_labour_cost(equipment_id, "CM", production_connection),
|
|
|
|
|
"PM": self.__get_labour_cost(equipment_id, "PM", production_connection),
|
|
|
|
|
"PDM": self.__get_labour_cost(equipment_id, "PDM", production_connection),
|
|
|
|
|
"OH": self.__get_labour_cost(equipment_id, "OH", production_connection),
|
|
|
|
|
}
|
|
|
|
|
cm_labour_costs = labour_cost_maps.get("CM", {}) or {}
|
|
|
|
|
pm_labour_costs = labour_cost_maps.get("PM", {}) or {}
|
|
|
|
|
pdm_labour_costs = labour_cost_maps.get("PDM", {}) or {}
|
|
|
|
|
oh_labour_costs = labour_cost_maps.get("OH", {}) or {}
|
|
|
|
|
|
|
|
|
|
# Ambil semua baris untuk assetnum
|
|
|
|
|
select_q = '''
|
|
|
|
|
SELECT id, seq, tahun,
|
|
|
|
|
@ -493,9 +611,6 @@ class Prediksi:
|
|
|
|
|
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;
|
|
|
|
|
@ -506,6 +621,8 @@ class Prediksi:
|
|
|
|
|
yr = r.get("tahun") if isinstance(r, dict) else r[2]
|
|
|
|
|
man_hour = _get_man_hour_for_year(yr)
|
|
|
|
|
|
|
|
|
|
seq = int(r.get("seq") or 0) if isinstance(r, dict) else int(r[1] or 0)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
@ -525,11 +642,11 @@ class Prediksi:
|
|
|
|
|
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_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)
|
|
|
|
|
# raw_operational_cost = float(r.get("raw_operational_cost") or 0.0)
|
|
|
|
|
# raw_maintenance_cost = float(r.get("raw_maintenance_cost") or 0.0)
|
|
|
|
|
efdh_equivalent_forced_derated_hours = float(r.get("efdh_equivalent_forced_derated_hours") or 0.0)
|
|
|
|
|
foh_forced_outage_hours = float(r.get("foh_forced_outage_hours") or 0.0)
|
|
|
|
|
|
|
|
|
|
@ -538,6 +655,12 @@ class Prediksi:
|
|
|
|
|
# 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)
|
|
|
|
|
cm_labor_total = cm_labour_costs.get(yr)
|
|
|
|
|
if cm_labor_total is not None:
|
|
|
|
|
try:
|
|
|
|
|
rc_cm_labor = float(cm_labor_total)
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
rc_cm_labor = 0.0
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# if np.isfinite(raw_pm_interval) and raw_pm_interval != 0:
|
|
|
|
|
@ -547,6 +670,12 @@ class Prediksi:
|
|
|
|
|
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)
|
|
|
|
|
pm_labor_total = pm_labour_costs.get(yr)
|
|
|
|
|
if pm_labor_total is not None:
|
|
|
|
|
try:
|
|
|
|
|
rc_pm_labor = float(pm_labor_total)
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
rc_pm_labor = 0.0
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# if np.isfinite(raw_predictive_interval) and raw_predictive_interval != 0:
|
|
|
|
|
@ -561,9 +690,21 @@ class Prediksi:
|
|
|
|
|
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
|
|
|
|
|
predictive_labor_total = pdm_labour_costs.get(yr)
|
|
|
|
|
if predictive_labor_total is not None:
|
|
|
|
|
try:
|
|
|
|
|
rc_predictive_labor = float(predictive_labor_total)
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
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)
|
|
|
|
|
oh_labor_total = oh_labour_costs.get(yr)
|
|
|
|
|
if oh_labor_total is not None:
|
|
|
|
|
try:
|
|
|
|
|
rc_oh_labor = float(oh_labor_total)
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
rc_oh_labor = 0.0
|
|
|
|
|
|
|
|
|
|
# rc_lost = rc_lost_cost(raw_loss_output_mw, raw_loss_output_price, raw_cm_interval)
|
|
|
|
|
|
|
|
|
|
|