From 8f3a74c597c4bdf6ead04a4b6331424f5011ba29 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Wed, 4 Feb 2026 14:41:20 +0700 Subject: [PATCH] feat: Implement historical data archiving for equipment when acquisition year or cost is updated. --- .../__pycache__/service.cpython-311.pyc | Bin 35210 -> 40350 bytes src/equipment/service.py | 106 +++++++++++++++--- 2 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/equipment/__pycache__/service.cpython-311.pyc b/src/equipment/__pycache__/service.cpython-311.pyc index 3e0e7b32e600af19c94f9ece1c223019a3f10b70..0ca7f41726f01d35e1e2dbff7c9cb5a17605c140 100644 GIT binary patch delta 4896 zcmeHK-EZ4e6t|P?qe+vd%}2}HZZ2$HlVycY-6poeD5Hq2AK6EtYbE5lw$pe^?9?9_ z?Ob)R2c}7&N`9F%2D|{3kWi<-Ao0@2zJS~+5>*9K#Xmr*jUn;GxwexyA525=08*{w zew=ge@1Aq+z31F}S95&&ox}H)*XzdMd-CfC-2K}ReUBuM7rM9M|L7N&_W8-+G9f>~ zT?@F#YAxB9P-9p-pN%%Db=Q!j@y&Uex;dZrUbcPS2Xq4wF;wSuC#vTfR2PFQxZt*r zQe76;uQo_d)eq24xe>{mALCZ>`xxU<-B8x6PAI*q*J!(-^gZx=iDTH;@HamkQ{6{^ z(V*7f#~wK68s+u^3&R+Hx$s<*sx@{syVWMOQN@|YPaIk_yRQSs$_6!63<_9-0#6$h zs2CJ92JKaYOi;x+9L;k9balO7=EH(F#67A@ts{%Rt>sTKq&h*S8SS*Vn}0mofW45?UU;;dFRsiGF%o;UrGx1YWzyh3EI2BF0%tBxW5)U!C0(BhCtv zOw0zmiGGnza#@a_B9fdW3*t<-I0O!*-rj{_ZldBlH*$I4(kO9mWHe5sXqrq*Bn$Io z(kw5N=6H^#QY1sk6wzfHuAT02k8@0npd^Wvc_j_4l7{3As8&v)LBAM5QyESMJk%pa zmKH>Yl({q;BN$fVrg$>NCD@o->*)zzNeCc7Nivv1N-`zN7OI^N6HRU})g%C}9}QDGJAsQ!H;NL}q)tB0IaIxDCv``~Tb>^QT~Y7zWhb7H?jP4_5~d z6fvsy%h+23mj;RoV^%f5z=s?M9vCkMQVzg6htegS%M}hsX%-( zkDCFRse}YV4M?C?LKaDtkZ|_PwFE*9NT60i7D+Zp9;u%ZS%#x!F3VOx+ZZ*buyHG= zs$$uu95kmCuCcUC%9M1ymij3{l1K<{8AT?C$4tlDX&I5DtsD|VctQq6B#3ooOO>XO zt9Xj1Su^k&XY;T~qqVNI$RL`A7mbmN61zp0lA{-B~op>8$ehV3Ypp5rE!!8jiiMd6wgC0BGZt03|$Bt5uMW#k>R9_ zAQhdBTT*(K67@SRzwj!2ntbn(+@WoxTwHwoM97`l9D$)bduuXEr6aV z#SV(tVi%xo`mL8Ddj3r-tTfk}hP$@06t4YnGXf2GKmT#F)w6M+BX{7KUf-5?Yt8D5^ZDIa+x}c@_fmAdweQa0 zM(d%)QN6WCZyj5j%$+#5IHUa0@gjUDXDV@;9Z zHr8}7^cWSopU8J&%^g36yVk>9dgSHRAw9wCrv><}g)_NuM)#Nh=8e9E)rqh=5f&5( zYXtvWU?$dXti40;AlKTi=Gv|<)NOzlnN;|@H!G@i#$z50S#KfM%tVO#zQW$$b2 delta 541 zcmbQYo2hFu6W?-PUM>b8aNpIK8K1wA?{hIXJCNH9#GhT5CoeD;*{o3VjghHn`edmx z1E!*e$$n*8EGe9|ypy}iWb1i>EWR3+Mv)rMEMAZ~AW*}S%?zT8IBQsHIOE~sDO^Cc zoLOM|!0MQx>cnf9f$HGmV0FAjJT=@!TtFG_Dv+6+@jM_sAW*|sq)@}KfRBM;@?!y^ z$qI^mle=R1CO@bUWaQrbse+k_IYg6xa({O&8xtb~1CYtyqsgc-*|5i1HM2OrEHNiD zB|arJEwMDGuo7>Xm9HtYB5FfxB& zP?{XyrwOFxC-?M8GkxHhys1w=`+=-dhu;S_1_7xH{HiOIu4vgFkh-MheL>6nhMK_y zrYi!rF?s(4EooOqB~~q{first_year}, Cost {current_acq_cost}->{first_cost}. Archiving history.") - if is_valid_default and current_life: - eq.forecasting_target_year = first_year + current_life + acq_year_ref = f"{current_acq}_{current_target}" + + # --- ARCHIVE HISTORICAL DATA --- + + # 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 + # Format: {acquisition_year}_{forecasting_target_year} + + 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 + 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 + if is_valid_default and current_life: + eq.forecasting_target_year = first_year + current_life - if updates_needed: await db_session.commit() # await db_session.refresh(eq)