From 6ceb2957819b85b757fca18b823373f6a0718843 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Mon, 22 Dec 2025 15:23:05 +0700 Subject: [PATCH 1/8] edit avg proyeksi data equipment --- src/modules/equipment/Prediksi.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/modules/equipment/Prediksi.py b/src/modules/equipment/Prediksi.py index 38ae297..7330433 100644 --- a/src/modules/equipment/Prediksi.py +++ b/src/modules/equipment/Prediksi.py @@ -796,15 +796,8 @@ class Prediksi: if recent_vals.empty: avg = 0.0 else: - # Pastikan numeric; jika gagal, pakai mean dari yang bisa dikonversi - try: - avg = float(np.nanmean(recent_vals.astype(float))) - except Exception: - # jika conversion gagal gunakan mean pandas (objek mungkin numeric-like) - avg = float(recent_vals.mean()) - - if "interval" in col_lower: - avg = max(0.0, avg) + avg = pd.to_numeric(recent_vals, errors="coerce").fillna(0).mean() + avg = 0.0 if pd.isna(avg) else float(avg) preds = np.repeat(float(avg), n_future) print(preds) From 56ec7a1badef4f70ffcbf9ff28d06555ed1b6343 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Mon, 22 Dec 2025 15:41:42 +0700 Subject: [PATCH 2/8] feat: remove `query_data` invocation, add `assetnum` parameter to `predict_run`, and refine fallback imports. --- .../__pycache__/Prediksi.cpython-311.pyc | Bin 41481 -> 41332 bytes .../insert_actual_data.cpython-311.pyc | Bin 51935 -> 51935 bytes .../equipment/__pycache__/run.cpython-311.pyc | Bin 3459 -> 3111 bytes src/modules/equipment/run.py | 24 +++++++++--------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc b/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc index c445d9e896699e7b3889c68e96bee4e90ce65d61..a45bf9bcc798508cc2f71dc6ecf5b7659d893a7a 100644 GIT binary patch delta 1016 zcmaJ+T}V@582-LMl9`6}!ux*D`@YZfp63j`rnX*D ziU)GJ43Jp(S>AqodRmdi%A};dLUQxCaFT6};8l~5C`fJxOWEa41!s!%0Q}7uP;ohbwjJsS z{-1`IkM>SL6~24|32%C9VM@F*^m7Oe4S6l*}R2xPToMPcs=&CCgTZS2NQ)kelR9MVsklI zo5KXd5(mq=*e+ak?Mvw~ayl&ITusjI^A5J%#;%e9+bR~jSi<67!a6QETDUOX(%H$j zh?A)HPM3|%76u1@K*d`IfX{1S4O{~2R5!*$o6>41FWdmt_~vjPEXT9MAFNT@GPsH| z#w=r&_bB~-?$m*~azCnAMin7cv4X4tWcAn9Eu;Dns$W430o1UJ8bhdY%<|5Z<4vAY zJ<@yiespHsIBuLRoKww|yeJXOH*B=$DKT_4v&IaboX#h8A@yub6{HqTaTUeXVi6Q^ zaqPKhW{IH)UXnr)M`wySPgg0Ud@&-&CyTArGCsA)@oAulwOIuF0VGHLFty6a_zzMd zMo`4YQw5|6sEZBN*6K55(*y6{-uVm0WL%Z7-3; z_=7%(jxp}j)l!VXQpTRf?K?TArony{xp0zaaFQ%$)L~>xxGD9aZ}aK(e!j zZy`Cd2w=pJ#j+u4B#(BPaTx%aKow*$talm%4Gxg1vKoL25G&A{X|jQA+*?S>PTPJo z4nQDp3{K+#7(+ukSr-IxgS77d?jfygyvqUHqvut06BbV3+f@~F8zHb-`ar|%bhnnZ+50tdA1I;EY!~Kxqskc zWTAQgT=V`{&SZ0Ms<}7m>Pxx$lER^sa43qSIJ4|6U-Z#Xx^mh-+|{h8~WXNek;!yH_wmioT3ejX6HWOQPBgKkG zAx@!U>9sxRLG-T-%47(KB2)Q?OT?K5t zMibf3a>X5jA1nP=#t(M`!`%a{00daTV$PFC)2NB1oSavt)m`jjSchN=nEX6gKvQ5I zV)+r6RtzszDz!9JsUJRZe}}9@99pRPp{p>$Jw)^^Obuc9l3Qoq7mbMKS^^l{N7um$ zdd!!h4KXSK%SVJgKLD7g@3`=w*s`!rkCeH#7=b7)zs*q*_3PXN4ueU?UuKBj<@&s3 zMD$kJZHX4pz=W@5u@UjNG}6(+x43nVwawn0WkuV{izEmDV+--C083B#z~%h|$n7IT zU?#f(`S(D|e+PQTpVHJj%{taF3DcWGG$@krUWWkK0#@&_Dp;eY5Imzba9PGKTVze@ zw#0U~Eo09rkG*SBSuu~X3~iS&c7UnLfmvj2Q+<=_d}$|Q*U zFF9g5kw_$yap=f1#iBvXQl9=0z6|INPqKN#(F&GsKBrzXEOPjteMHg{Z@bxSRN{C71%+aYa`)4X80wi@^iS9GfrD4nA-RqiYfY2 z>qNbEjz(Q4X_w1SuenAp^wt3ncebzm(OSD~wX4j##rM?yCUu3e&`$k^8cah}1(5B3 E0P{TEIsgCw delta 1299 zcmbtTUuY9a82@Hxc6WA@Y#M8IL0#Hhi4D0d1%b3!QH6{6W~-A<@~ z63w9qf+%4GAEb!*r-Hs5!U=c2G+y6x;6n+BZ^u1Jd=h*RC(#<4`XJoQw;$j4+nwM1 zelzT>dC4+nLm?f+`19SqY_C=}O!RNL@8{9JUT}G>~kI;gIo9tLEvre1x6aWJ`JJd$0B0tVh>;=rnR~P;uBI|2wgxn92HDO zQSp1y4=2B-ElLH+mh#|7mJs2G2;i}JK8=Qvqu(QdEEixc5ipGw?Q6h7{CCL;g%@`L zI7#^-Z1T5Kr`6d)3z)5Jb!-)n;dSA!ZObgm58`!>GP6v#7hd8^ZTIyZhf0@wYCBX! z5>f4x+|cNcFsr4tAln-MjdZS7+R<~0xGr71TRp5d>LRrR1?4u_!GbDss6cJwHnGDq zYEkpzf=B<%zkykNKj|4(8`zhXOV`L^jVk!$CP&8%E^18WmfRDK96r~T^8E?FJL`3y z&O83uj6KH2M!NYC`SoU_Mp)K$d@LN)wA7h#XOd+nyqY}eXFXQKQ_QagCVj`wj_iZPj=%!Vo3|nS+XeSHumi@pknB|C0sFMyArsPkVXAMNp9JbfWH%ZY8cO} zvD5&bACN^|qnV65mi023{uTa;#w7>&8?B5Yyrlm$(kp=Xbh|rY=X1^ue@L{A|7Plf z$aRbmS^%TeoC^>rHD_I+sJ||86d2+0z}}1fbsz$0CIa#SsSf`)FOV(OZ^Z)HRBexN V3#w~E2(JWw)q9cwJf|a(KLY6@9h(3E diff --git a/src/modules/equipment/run.py b/src/modules/equipment/run.py index 5773e38..aa1a9c1 100644 --- a/src/modules/equipment/run.py +++ b/src/modules/equipment/run.py @@ -3,28 +3,28 @@ import time # prefer package-relative imports, but allow running this file directly as a script try: - from src.modules.equipment.insert_actual_data import query_data, insert_lcca_maximo_corrective_data, insert_ms_equipment_data, insert_acquisition_cost_data - from src.modules.equipment.Prediksi import Prediksi, main as predict_run - from src.modules.equipment.Eac import Eac, main as eac_run + from .insert_actual_data import query_data, insert_lcca_maximo_corrective_data, insert_ms_equipment_data, insert_acquisition_cost_data + from .Prediksi import Prediksi, main as predict_run + from .Eac import Eac, main as eac_run except ImportError: # fallback when there's no parent package (e.g., python run.py) - from insert_actual_data import query_data, insert_lcca_maximo_corrective_data, insert_ms_equipment_data, insert_acquisition_cost_data - from Prediksi import Prediksi, main as predict_run - from Eac import Eac, main as eac_run + from insert_actual_data import query_data + from Prediksi import main as predict_run + from Eac import main as eac_run # Panggil fungsi async def main(): start_time = time.time() - try: - await query_data() - except Exception as e: - print(f"Error in query_data: {str(e)}") - return + # try: + # await query_data() + # except Exception as e: + # print(f"Error in query_data: {str(e)}") + # return try: - prediction_result = await predict_run() + prediction_result = await predict_run(assetnum="A22277") if prediction_result is False: print("Prediction step failed or was skipped. Skipping EAC run.") return From fa4ea74d9bcc71a1be59bf3624c7f4719d9cadad Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Mon, 22 Dec 2025 16:03:49 +0700 Subject: [PATCH 3/8] refactor: Standardize module imports to absolute paths and re-enable data querying in run script. --- src/modules/equipment/Eac.py | 3 +-- src/modules/equipment/Prediksi.py | 6 ++--- .../equipment/__pycache__/Eac.cpython-311.pyc | Bin 15560 -> 15261 bytes .../__pycache__/Prediksi.cpython-311.pyc | Bin 41332 -> 41028 bytes .../insert_actual_data.cpython-311.pyc | Bin 51935 -> 51652 bytes .../equipment/__pycache__/run.cpython-311.pyc | Bin 3111 -> 3029 bytes src/modules/equipment/insert_actual_data.py | 6 ++--- src/modules/equipment/run.py | 25 +++++++----------- 8 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/modules/equipment/Eac.py b/src/modules/equipment/Eac.py index c26b432..867a82c 100644 --- a/src/modules/equipment/Eac.py +++ b/src/modules/equipment/Eac.py @@ -5,8 +5,7 @@ import json import sys import os -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) -from config import get_connection +from src.modules.config import get_connection import argparse diff --git a/src/modules/equipment/Prediksi.py b/src/modules/equipment/Prediksi.py index 7330433..14161ec 100644 --- a/src/modules/equipment/Prediksi.py +++ b/src/modules/equipment/Prediksi.py @@ -15,10 +15,8 @@ from dotenv import load_dotenv import sys import os -from equipment.formula import rc_labor_cost, rc_lost_cost, rc_total_cost - -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) -from config import get_connection, get_production_connection +from .formula import rc_labor_cost, rc_lost_cost, rc_total_cost +from src.modules.config import get_connection, get_production_connection import json load_dotenv() diff --git a/src/modules/equipment/__pycache__/Eac.cpython-311.pyc b/src/modules/equipment/__pycache__/Eac.cpython-311.pyc index 12655c98059a27f145e57651208faa688ff95c1d..880816ff5640b88937036df29544b7f292e4c1e0 100644 GIT binary patch delta 494 zcmX?6Ik#M6IWI340}wQEcxFCuWMFs<;=lkql<~QVaiWGnMhZg;a}IkhM-&Gm1CY&> z!x_cN#Nf`5!qUQ!!n%x!fnhZeLqHT)ia-im3u6>_Do+Y~HdwrsHN0r%i2zlIrtqbTOulF!B9+1v%%IGWDyG6vq!1+zmf{DJ0;%GY_bDqHGewC< zi-XjpfLY~?gISCm*BF z<}jhT%#2Gne-RB~VHDi#DRq{MQDU;V>K#U@$zN38Fv?7RsP=*eOBl;)%s>rHmDn!?ouv>y~y t#T}C$SUC&mUSL2$n~SY&86^&y$vcTN91>@BvSB_XBkE+%e8?Qc1^~0FaP$BG delta 688 zcmbPRexg!iIWI340}z}jaLQD1Vqka-;=lkWl=0bvX`+S!Un*-BJ4|W;$K;8IB7CWA zNJ5;LLR^?a+#n&LRGwvw3=FG*7y?q5C(l!pnQWsdn9h*GlEa(J7sbcOkiw9{l*1pz z&&1%)kiy!+kixc%38)K*As|X1MKFcEg)vGnRValc8!TSb&cu+)pCt@alft=%3)QYD zkyMcdq9A9;q;RK-rSPobUB(PF7KkB$kpZYc9H>A^FG_-w0cf6JszjC~OnMC;nt4({ z71AmEsZx_27^Q_}R2YgBqGZ8h0zgtMRd#Y7qq3=Nv}_7fFwjR)Kvp?pIYR|=BttnP zNK8}cCCG41##>x2naL&2rA5X0MSfLGdU}%&F`j4S-#m%wCm*Bl<{rVh%#6!6Yl()i zFbZw1mpseGC^^|zd}cn;dRAg{vQ^7!+m2CnkTjbPix{;b`Y?;-A1Yg?&2zB>n|VOW2q5EaF)a zv?hFg{HpjJ5f^pcuIRd*V7aK^dqu(bqJZBO0l$k3{#O|MFEIGuU{Jh(iZ**#*)mET amXvq4VmNHY>LSm4*k05{ius5Xhz$Vd=A&f* diff --git a/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc b/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc index a45bf9bcc798508cc2f71dc6ecf5b7659d893a7a..2188689e651d02f196c70fdabbff4a63dea614eb 100644 GIT binary patch delta 2089 zcmah~eQZ-z6z_TM+O_-M=(cX%x^ApnH#Zmz7)u!jHdq(34YEj5rsUc8HVbQuw_OG} zHzdF$#K>|InIb|AABlz_c?rR&$XC!9MT}qMA8pp8Ga83B;GzU(UVf zoO^!noO4g_T$C=Km#R->WH?Ox*^wHI1W%hx-_v6Hu}lfKx4?Myv0A(07$}aqL+)rv zs3ck%Dg~2bQql%I(Xvok)En}OH4K!8%JCf3byY|v)wF5u^l3__l671%nO^5V;|W!& zl?o`(XI8RzLCB|8DLI>kmKAYd*i=1j$yYus+v>(gq_LErfN$eXsb0%6Pl7d%ub30> zSp1NOr74d>kv5z%X@*SfwXcIBJY}ziYP@0hLNVU8`@pBob;uU0huq4veVNS?S6stkT^S!vwqGhGPBP%<5sdW07LkSGi)j08vG_LUn|Z} zk-&rA!q*Iboy^Zwx-}e+Mk7fk7}_4lP)}FX0X3;^d~#4_+YD~DnV>x6Vplut&_-P! z*ukT9ROph#9O(1?Y(%RO(O3wwjjaM3ON&OE*ViNfyBMRTXt>`P$%= zX>e+x4N9G!l8kRwW3w}eC#r(bfVZj&cronNt#DZDtd85$jVf^;d8LHonfcme!?zOD z;)TY1Zg{;h0R5VC5ig-ASo&1KC{PV0RuS>?k{39S z4NX34F}arF8%?EntjP~8+Q&_Qr_Ul3HVFOJcF61$9YDnp=@GG5ExsCD%1M3|To329 z#*T9mIJDbqE`T+Y46~@iDrXUHrroCq!UQq_k>&^e)mi7wAdzzFpL_2|82q(hS0ixl zBi##l)YBY~Xg_q%vrlz8xgTi>PD68F6BX*g?_Uvw^Dv`~JNd1)S(^`)@kP0rm5FN4_ zoUkR9jEf-elHYj(k!vSOE`o~$!vr&g1=mY_&u=v{e}(k#5ePPpm^!pk4u{o5!bp>q ztBecJFO@gm1V^<{d|d`F|H@LSe3mJiFYZ!E?K z)#qbfX*2E6f%Bd{l}Sy(1dUQI;dr-)$4K8BfJ<6%?}Qar;CIh21~S#6aM*>On(LwQ8MU^J~E&yq^E9~>LF1^V?0&kt%=rbky%Srj>K34 z_jyNadogZt`B^@>+2q8wSU3{bty|=nA}9F#`{Y{;_fSHPZv%>!$W=_j~c|k+b5T=O4g`?6d#? delta 2285 zcmah~Yitx%6rMY~-ACJ{+jc42cKZUlk3P1Q@F-9kh;19#&C`BXk2oFIMVkSW#DhLS19|U59I)s4w3t}_|qQ;1L&rF+E(0H@^?Y-xo zbI*70dF-Y0{DTX;|Cqy(&arXv(IR>9Lyr3a7bC+yJh?xe-{n72#)5!$O9kejw>LX z$cY)T^0+tTjr&4AeNAHikbl?j)z$#dF{c$!MGC7crAm>ABx(|!{UlT+Rg2jhcs!35 zFfGy^96p?5t177Rcwi^l1|B|W?%{($buoXNSaML^1vTaX$${187l=pw$b8#G9585G zLGt0At&;d4&t66fpw8|kel=_t%$8y_D^V{yX7Ox;IOmdfnD3lIJkaH=w>WTj5-jz) zEjFC`;cI8bv4>$m1L(*~(qQ)ls`{M{>!05TmKK#1V^W>Jo$G;@10p=fEbgdiq$@|r0wyhuf+5pX~Lsy%2t zCf4w1`W{jXduDi9bU&G~lsv7b*FDM{VVbqzjA^`{6@E0-UE{&D0&Xpu$xJ3Rtt1!J zMAN4{X;XtsKO-4>(&393nU^t2d?pk%yGaF1Z>}!OL_M-Dfgi{D3$t|sE zAWPN5Yuc#S9f#{?am|Uj9fT#BV0gu8DW&P&i5jd1uVv!U&j3_2s)c|Md}I* zk%*K`8dYXtTVwOtMWrYszaEt!rufNG^-X1kgGIif?{$)OJgu2N%S`S*VuQ9p|EA?+ z3EbE;F}Hz9lb8s`X?mJxY+g%lfU@~**6QrNH%ZPswoh*{2w3TDoG*c2w|H}OTP#$= z7Aqw9N;|m&Z@qGunKtwd5tbmi{UP!*DE;g-un(Lf<#2wWl+1B zL&d&}z1h;nPPrq_Qacz;(0FG|py}u^0|Dz?Gj|B7^+wyZ3Tu9V2HW!Ig}L(b;wT+0yGa*b>GhO58!Zy(sc|FjuH{WtENEz1A^ diff --git a/src/modules/equipment/__pycache__/insert_actual_data.cpython-311.pyc b/src/modules/equipment/__pycache__/insert_actual_data.cpython-311.pyc index 77f83169f0ac741bfcd6ab4491fda88c1c708c23..0c990aba1d5407c1f652593c04c6b94c31499878 100644 GIT binary patch delta 1808 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 diff --git a/src/modules/equipment/insert_actual_data.py b/src/modules/equipment/insert_actual_data.py index 226dd8a..66cecac 100644 --- a/src/modules/equipment/insert_actual_data.py +++ b/src/modules/equipment/insert_actual_data.py @@ -8,10 +8,8 @@ from datetime import datetime import sys import os import httpx -from where_query_sql import get_where_query_sql -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) -from config import get_connection, get_production_connection - +from src.modules.config import get_connection, get_production_connection +from .where_query_sql import get_where_query_sql async def fetch_api_data( assetnum: str, year: int, RELIABILITY_APP_URL: str, token: str diff --git a/src/modules/equipment/run.py b/src/modules/equipment/run.py index aa1a9c1..400a047 100644 --- a/src/modules/equipment/run.py +++ b/src/modules/equipment/run.py @@ -1,27 +1,20 @@ import asyncio import time -# prefer package-relative imports, but allow running this file directly as a script -try: - from .insert_actual_data import query_data, insert_lcca_maximo_corrective_data, insert_ms_equipment_data, insert_acquisition_cost_data - from .Prediksi import Prediksi, main as predict_run - from .Eac import Eac, main as eac_run -except ImportError: - # fallback when there's no parent package (e.g., python run.py) - from insert_actual_data import query_data - from Prediksi import main as predict_run - from Eac import main as eac_run - +# clean absolute imports +from src.modules.equipment.insert_actual_data import query_data +from src.modules.equipment.Prediksi import Prediksi, main as predict_run +from src.modules.equipment.Eac import Eac, main as eac_run # Panggil fungsi async def main(): start_time = time.time() - # try: - # await query_data() - # except Exception as e: - # print(f"Error in query_data: {str(e)}") - # return + try: + await query_data() + except Exception as e: + print(f"Error in query_data: {str(e)}") + return try: prediction_result = await predict_run(assetnum="A22277") From 0dd0ce1fe28bee4432111e61b7daf6546c9e419c Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Mon, 22 Dec 2025 16:23:30 +0700 Subject: [PATCH 4/8] refactor: Exclude `seq=0` from historical data, simplify CM prediction logic, and remove hardcoded assetnum from run script. --- src/modules/equipment/Prediksi.py | 19 +++++++----------- .../__pycache__/Prediksi.cpython-311.pyc | Bin 41028 -> 40721 bytes .../equipment/__pycache__/run.cpython-311.pyc | Bin 3029 -> 2686 bytes src/modules/equipment/run.py | 12 +++++------ 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/modules/equipment/Prediksi.py b/src/modules/equipment/Prediksi.py index 14161ec..bd69dae 100644 --- a/src/modules/equipment/Prediksi.py +++ b/src/modules/equipment/Prediksi.py @@ -95,6 +95,7 @@ class Prediksi: FROM lcc_equipment_tr_data WHERE assetnum = %s and is_actual=1 + and seq != 0 ; """ cursor.execute(query, (equipment_id,)) @@ -711,7 +712,6 @@ class Prediksi: if df is None: print("Data tidak tersedia untuk prediksi.") return - # Mendapatkan tahun proyeksi dari DB par_tahun_target = self.__get_param(assetnum) @@ -769,19 +769,14 @@ class Prediksi: try: # Case untuk kolom yang terkait dengan corrective maintenance (cm) if "cm" in col_lower: - # Tentukan jumlah baris recent yang dianggap actual jika kolom is_actual ada - if "is_actual" in df.columns: - recent_df = df[df["is_actual"] == 1] - recent_n = recent_df.shape[0] - avg_recent = recent_df[column].mean() - print(f"avg_recent: {avg_recent}") - else: - recent_df = df - recent_n = df.shape[0] + + recent_df = df + recent_n = df.shape[0] recent_n = max(1, recent_n) recent_vals = ( - recent_df.sort_values("year", ascending=True) + recent_df + .sort_values("year", ascending=True) .head(recent_n)[column] .dropna() ) @@ -798,7 +793,7 @@ class Prediksi: avg = 0.0 if pd.isna(avg) else float(avg) preds = np.repeat(float(avg), n_future) - print(preds) + # print(preds) else: # Untuk kolom non-cm, gunakan nilai dari last actual year bila ada, # jika tidak ada gunakan last available non-NA value, jika tidak ada pakai 0.0 diff --git a/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc b/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc index 2188689e651d02f196c70fdabbff4a63dea614eb..511bc59a95a97b74a9e136b1e88199ddb0a2b49e 100644 GIT binary patch delta 1538 zcmZuxTTB#Z6#oAiW?^r$v)9?nEDJ6-8x)p{XcZBQrB<+lwq7VI>1Zmot1N@CIHQ=T z?6wcAIaSeEg~U>t(ik%jwRfAEKD2@?^`Z5}ZE6$Kr!_Hc-`aoJu2ADi{xjb>=bJO< z|4uTuZc=Byrq~b7W&qmm5{Kg_<-8P zZNj($64qwi0(ez9)r=vfcjt0WF18`P1pd*x)YZ24DLkP5;z-f>g!;LAhQ(uQy!3k$ zepB62^BIjBRKrTqioaD4ZM>$#<7!~bNh98*UhViJ4Rp`#uZlzfhO3WM4q2o6BO^Dw?LunJ+@pz1STVqld%XT8pEu#G#eu%KgCdNuqqnFHt387{PqM6Pl{}Okqk#ruJ7hLIy?+95mO%8~8Z0kcg-P%p5swBItXc%>HE6lb_p3N1`R1ocJc zOV2CL`CgRgNmX{fHLvSJMsbNq;bqsN30{_6fCqSsWf9Ar5dyoRejos^M=d!DAGU!t z>hu^DekTg&^rHcKC+f#CKh*aBedrXA?CECV&VYyYbU$e-T0F3~-;H^&M0tCri!R%R ztc;&mkk=H%c2J_r>_+*&MP=`!*x{?_DvMnz%VrRo;$Yk_=oGtbAM?ZY@+Giw&`575 z^KTz4#$HecHyFJ#mZ=Gvtdxc`XLxup=&<@E5@$`c%0BqD&|~x+^M&(>LgWd{j&6F2 zWy`QUq$;AVD8uW=*-I?7t6v=5rHAFGijDX52YUB(y&?5=9fYl?lJMN=I^DgTxA%30 zq3iS%_5(XS0v`Ab-{SZAwLnuuhf^)G7Iu!`Q53z4@ zTd}$J5o(1*ykh?g*jk(7eWTG?zAVX?rHV>M^*;xTudbYIyt;Zc@AqKISkGixGFW{# zSUsAT5{mEp%Pw|Ix^C2rb|n4l?)ul=_ZME=Hdc0F_odyFFFs}{f6ZSylwWl5wF^5g z?MUm9rzp+AiFeNDTwu}$we;Oa`gl8sK3N|k{=2|S#hd-qZN}2#q;5N~hMlICBIb4> zrQsmfa8U`t(?)M=2{m1;ai&X5t+mW_mByK_!5XeDC3r@_r0I-5u(^SmSwm@fE!J>D zV-*QztNd*oN?NKlR+2Nct)P=$TU&@umNQx=#AulnZi44HLwg-P=e4z0(Q{QydmVU3 z&f$ExKC;bH$pq8riQ5m3gz7m=Gt1NH8D32#ZtBR3P=Lme9Zl+kH05`g;4 fOK_9A_wrgC>R>VH@NEBRKL2=eRTkjRmA-!gmcg3w delta 1907 zcmah}ZA?>F7{2FTZog=ITl!t@<*N#kva1&$`2RP>kWYcYa5HC8>HK7z*@K*T2 zgqlp<-b9N*M;79m4ISnt+l(J0(d?H(3tcp3PE59FmTak;KlWqUb}qHFer+e`zJ1Pn zp7WgdzVCbc(IxWA1gZT@qfrrf^eGy4H=I4Iy`Uj)Ay`sphVyd0_=o0m1Ya?y(0k$* z-5P|Jz+UBRs1fe#pNHyq?Q+JX8>~wdz&}c}*qn2MM1Jvi<1B^x#2M?P7JVXqTJoJ5 z?GksFpQBK<=&0oNXhIxp_)>;O#LD&k*{D&x_|7j16ci&otwN*X8P89o>}4F%00-fA zH^qfGxZ1u8ad5C}De&G36SoubS^bKjY*0cpM)E-p&Ujboxi-1w9O?(^7HbH9i6}k>hv0PADcnv)9HMa zL`@D}CFmh$HYz+!hzsHe_>Py58e%I=*(9Gmrap!5`+|hu{CV(W2Zyv!Xf$FKCO=2W zX=73{UVDhkylZ5h_u`{Giq`}Up6$NE)JcM9)2FbI!)wQwhc{mG<-xBjbPuCu))*c+ zW0*fADK$ zCwjud6G5wB$%vv+uw>S!ZT>i~n}(O~UkFG0V|3R0tt}qd`9UR&elUjeV8emK z*{U=XZXei}m51L9?yTdWXQ0M#8GoQ1-_r!~=RM*c(MKf6PPjTyN+)DQ!2k?UomUR4R=Q^&X~nHn_C6tr)jsgJ+Dbjri7fZEl6l#bLbdz%gTjYht$LBuzE2sg zwN!6YIdS?GH@27a8P$~97$MFEa6i7Iu$vklsHo= z^*S3pWtKQoRwQ9t3C2+ZVbLhcU+&FW+-8Ui7_y!FcfLkGNI^WF5yJT*Dy^EU{dF0s$&A_PGP78vL^3g zl$dPA$R|+CT*8Y`n#Dd@k6B{!B_?5ML4;@xbBPdwS0XZrS(YE!l`JLVlXaM7Q(5OS zqq{ecAH`j481jVu!cNdHkC<)iIkLenDzYk(L^!pEHHD*!iGcyt)><|UHNenJ;l!en z9cTh)6;QU8BZaGmZ8k#+cMUs`e*Xya2)m zhP#5IQzR!!Pmyl$`XIp0%70f$ccJbQ-3v1MXlV0Kb_phT17HwOS9fG&ILOH5Xv%z$ zTi(%t`Je$Sh;8X;=4`-l*nrDLh54|Ryo)^Z5qVZ1`xZxhd~RZ9UVOYJZxKJxfFjPx zxm>Yqpxkgva`HkhF)r7{Z9w~!`au%5FyozDa8uVNQy1~zp4UxDkOg7Ci; zD6|KL)B+;Dije=-6=WjP5x%9X_R@4Ph4DC!m{#O=-oSS>Jx$UB5yzG6?d|RFZ-+$u8KXxF=`Vl=T4O>9OJ#isrH{jw{>T~D#; zo&`>VC3iA{J~Su8XeBJLbfv9*Pz9^1`#g_U8=D8?Xf-add`(K89*Tocad+wzT9=zs z-DtgAV7Vh{S~hK3n%1shfBA3n&^q}B^id+Wb*g0(8Ny0u4NY?p^Xm=x!HNJ!S@L457P diff --git a/src/modules/equipment/run.py b/src/modules/equipment/run.py index 400a047..ebadb24 100644 --- a/src/modules/equipment/run.py +++ b/src/modules/equipment/run.py @@ -10,14 +10,14 @@ from src.modules.equipment.Eac import Eac, main as eac_run async def main(): start_time = time.time() - try: - await query_data() - except Exception as e: - print(f"Error in query_data: {str(e)}") - return + # try: + # await query_data() + # except Exception as e: + # print(f"Error in query_data: {str(e)}") + # return try: - prediction_result = await predict_run(assetnum="A22277") + prediction_result = await predict_run() if prediction_result is False: print("Prediction step failed or was skipped. Skipping EAC run.") return From baf05b10de36fda7a0b78cc06b8596715a03e586 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Tue, 23 Dec 2025 10:07:07 +0700 Subject: [PATCH 5/8] fix: correctly calculate remaining life and apply ordering using aliased column in EAC queries. --- .../__pycache__/service.cpython-311.pyc | Bin 27991 -> 28138 bytes src/equipment/service.py | 24 ++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/equipment/__pycache__/service.cpython-311.pyc b/src/equipment/__pycache__/service.cpython-311.pyc index 0ce524a131bf2f3d2df4774cee6460e0fa476b21..52128380ec84374df9c93915f1f9499edcc97374 100644 GIT binary patch delta 4254 zcmcgudu&_P8Taw4w&TQ!>o{rJByO5Cxk=+RZCIK%ZE5;|qo-J zt(e9i)2{5_{m%C~=X~F}-}&CO$oqdHB|k1M_SxY1!rhk`PMj>MBDyvc66&Zd?hv#DX~R4bmWJnOXC&cQ$b$lcjfWReVTrd#M%+C6Sx zHZQT!Yt`M|FjA|igKk~qtNk$ERxlo*Jy&X=oZsxIp5Cqw2){cD?F;7^x2r?Pobpb) zjqW@PbDdk5UET#ea`?J=2EG0)0Xh8hkKC)?K*Q=V-3oK`iCJ8Qo^gHrb4PLQZgmfB zR&Nq|xX#Gp%IDU(Ya#bKzEx;rk2=jg>#I1)O}z%0G9Js4%)P6 zGwxRRgM3hU&ac!#tFMqB0Qu0gP>{tEuU0q+3OA@kz4=ihv~Hop>aBB|E_CHlW5?X` zjY0B1_BiF6Pzc!=1I4{UF-}*HJ5?3NBVtU&cpS$2#CU>MtCTjv z9uEO;zu>_Zz$O9X1N;$}M11@?S7(vsP>i_cRH+fq{sWTaZiL*hMt;!KS=BB`fL#)? zTxQBtv?)h>bRBETKIvIch?ITD`zhJpglZCixbn&a)*i z+l|ip`J3ev;B0HSj>NKK;r;HtUC0+Rxsj?sL-%+>Gr_9z*Yj16YyBz2Nnu=FA36w^YZ(9;?t|9HAcpH^mYFR#7TRV<{F( z!kd*NJIv3t)O41j(34^+WwEhI_5eys5HJF)5&^?#ErAoEm?jhXXB+t^EfbY76gZRg z4pVB%N5@3{er~S$pdOdajv`DV+=*}(!rch>AWZWITKmYo{PouFk+1W^(RPUIqtO-Q z>Fo2-Z7zsb^qOTn)NwDlkDu;{RF0yJ*cSSp3j&7rwT>0!8UB99c1T6^n&V_d?C(pW zz`hBFk~6~vk@<7+^u=Q_r)sUC6KkE9eef*c>Ix+d+;eS3G#CJ@Cil^3hZLr-5>Q&uDx0Upoc}|JBxT$z6^q zXdP5?#D(g}3g%f*4at-Cvv7dVIe5{vpWDp_UVE){YNVW>zit!%!L~EgzX6N7_}!{`KVn)8K%zi$1{x4q$$3_d?Im!b5Y~}>}e$5;yZgM_=)YU)1UZk;o4kz z+xa!K_#=I5{~rnd z-Sn#%%hvz~*uCN51W{RLkXlGBo5i8{>=zR&Y8fV$T>@C1Pc&wiy#Zhp zrZ3dn;ywetkbyb;&W&Fwe-)LOzY@$}3FfZ^@)ro5pfjQR*^-7_Ndx8&G7Ioo75Daa zmz`cU6J9+VY|I54XT421Z_`zIfC}?c->*poKlCSvsCSZ`iJRa-T=Bw%@>u_7@+yD3 zzkUmTnv$m=hzn&uU&ZS|o-drMP%~c)urWA7p#t!212tvBbzuqM>47@(GUo$NK{4tX zys%DGmp_C3AhXbm!}6yYRTFVDrYni0@NaqWio&4;-wy8>lAxmBI#fem=XVe72SaIZV71!?!Jv=2Y+n-9I)%Xa=VPdnzC<<R zkQX0pb7Nz}B;Io{O^)#F!CL}&o8^6?-w(Et5#=Sf6#pfHg+N=@OSCL=o4bFcG?Hw68&%GK0mVkXU6*F=#ZNf^gKL zFoGZ&&{EV;GUlPELD}sI=!NUh(1+}JDmk8*V5|7M@ztcB`_%Mw0~(4l^)OPREAK!9 zXyN0g=%ZN_C2a_Y5JdVh)vONzGjCx>(4U%^fKIg;nR}4w)Dnitu7pWt`=ejQ2;59S6cV;A(8y*#-tKoY7kap3Dd-ylH CdM951 delta 3976 zcmbtW3v3j}8NRuf@BBJA8)N*&__bi4A3Tg5oA|-gU>idKvp|mZ?VNpN_s-1j0VWR@ zg%%P;70IAfZBmI!DGg2423^#WC?Qdh3aMyogDa$Mqo%6Vst`p)Nuf zhE}SV$z>pCs#)4%y<9E_Ia>{AOY{o4La&s^EA=Y5N;uEcs`VPVMwetsUn(yZy7}5N zy;iOja!{+&Lvl#SM5~wUA@LloL2r~Bg)T>H0(tqgyaMEvLeAAz>CJNUbidW|YUoF_ z7P-ag*x=w#kwVg%`W_i00}s(Q+D==e&PB+Rc<35+a~nu%0d>*#S-rXi+7HiZ_tK90 zJLfqHvVF2Z|pd$y?-BZx@X9?KhZ$I(| zbt}zP2WUIQ+KAEkC$7@cP3m@9qdp?Em_f;GPSY6_kM{_lom86c-2wfJ=J-9VlA~!3 z$J}{Ged;dAdo%RB*ULq#X8T0F>LA#+h{$$ME?Rh>eK**9(LS!qBE1J4_JBj5O4PkC z6A@+~?N=Y2p5EM0J~e#YD{mD(IQ6+Ux4Ivq4Ezt90=8{xKjaW~szcD&E*vAYBI;IE zXg?y_RJ5be-XYq-D6Z?lGAdA8Z0tqI6+%h#u|8+qySg1NI$4lF!p@K0CK_+7BgcoX3QL8xM9yZ z@6GMN(#O4rK*L7)t)&GpqIX$x9G6roXJR_}XjBn;5HNo>3}9s>;xwFK;W)fm4ytoe z?LLr*#VtQQn2e3;G;UgH3Bj_#veE2IFqN|K&=@<0O_yRs1Pd$=BOsMlTJ|tC71Ly5 zOR&}4S38`)4=wIEJz`2VHbo3O^zak4w<<w3sj{7-c+ zk*E2Sp+=bM&q77yeCleb(*u-su3W^cSA2tv^H*1t<%>lS6UNwv3!qH!`_YOb@&^C+ zif&ks&Xp(0PBHT@;fH+_`bcg&SBzwN4kjrZV}lsbZ3l!ELrVZA43vb$V#Sj>dy|(o zpM()!Z7w5`pMy)Elx8o-%y5=7rp~U$eWSev9oPkgFB!`}Jr?wS2V4{=wnmIM4(0LA zmR-QZcUwxx#ngqC%g&y6!ESle30mSYQJe|a*SmJpzYaiAX15bg< zKWMA#3WA5^wF$w{>>_~WjU;qE5ucMUZaW|w9-Eys%vjMhb|tmCJwys|cShhZ9^Cj) z#~n|@|Fcu6V{14`SIJMDXTk8Alke~N2RGIi@oSw;{68B8`1Q^+X80-49|b zZ2BRCAsgpBHXE1G4HwMHj3gO@QxnGHZ7-h(^wVtcW!=>z$$z|Qn7`Fs*KphCSeSo1 z!<&`;sRQ71gu9uJK<=}2BDZ2PyK*YK^3#CNpZ>W6;BJtg>S-%F)%HVas=RG7r|m|t z>sqjDGPrgsxOURNZpy!of7ny)Ep~X)|6ak))a@!!et{rZ{vn46|oZhXk{00EKK4MP!*>2QcQ+IJRk-_hsDp$mQv;&tvDc zVCQ78dn(vH>0dkLU;6-$aF8F`{5~neBXo|4Ix0DtsJbUGHQ1`K!ce@6d)vt+zNfch zji|uBIc&|;UAtPALl?UsF9vD)RN?LW7=@$6-{~!xFG9~fOZ?;Ba`HA0^!*fX)4ume z4II&w`U&Bui9Pr|F*@={U+jWn(8s#ef;jUKF z#q$Txc>}>+DwISTzd)%2;UK~Y!Vm)1A93efUL(OwsVc?1*rZD!gc`3munyU6a1My^H$F9-)k~x6wgt2pkFs5Dd*!{rgC;yimO#C=cm-s@g?Xds>^dI zi4WN(>;PZ75tHHfD62)NLx>`DAgn~#h=6Nv;WfG?F+2>nTMa4)Q0dlUhRN_##ojOH zQF;U6O$5Ae2UrV=R}g-Oa0B6w2x5canXnfh7fftWCQb+LiZ6U^KwMIzYgj2*;Rkh% zPtdm3EfbFa^OxEdeZt#cOoFdVw;k}h;=Z!`YCwn&!kQ8iywGyn0k4UH9TPjlQv>@& O>p|$?CHfUNru|<9QRiR) diff --git a/src/equipment/service.py b/src/equipment/service.py index c18b2f1..91bc657 100644 --- a/src/equipment/service.py +++ b/src/equipment/service.py @@ -2,7 +2,7 @@ import os import logging from typing import Optional, TypedDict, Any -from sqlalchemy import Select, Delete, Float, func, cast, String, text, case +from sqlalchemy import Select, Delete, Float, func, cast, String, text, case, asc, desc from sqlalchemy.orm import selectinload from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.ext.asyncio import AsyncSession @@ -395,13 +395,17 @@ async def get_top_10_economic_life(*, db_session: DbSession, common) -> list[Equ (current_year - Equipment.minimum_eac_year) >= 0, (current_year - Equipment.minimum_eac_year), ), - else_=0, - ).label("remaining_life") - ) - .filter(Equipment.minimum_eac_year != None) - .filter((Equipment.minimum_eac != None) & (Equipment.minimum_eac != 0)) + ( + (Equipment.minimum_eac_year - current_year) >= 0, + (Equipment.minimum_eac_year - current_year), + ), + else_=0, + ).label("remaining_life") + ) + .filter(Equipment.minimum_eac_year != None) + .filter((Equipment.minimum_eac != None) & (Equipment.minimum_eac != 0)) # .filter((current_year - Equipment.minimum_eac_year) >= 0) - .order_by((current_year - Equipment.minimum_eac_year).desc()) + .order_by(desc("remaining_life")) .order_by(func.abs(Equipment.minimum_eac).desc()) ) @@ -427,13 +431,17 @@ async def get_top_10_replacement_priorities(*, db_session: DbSession, common) -> (current_year - Equipment.minimum_eac_year) >= 0, (current_year - Equipment.minimum_eac_year), ), + ( + (Equipment.minimum_eac_year - current_year) >= 0, + (Equipment.minimum_eac_year - current_year), + ), else_=0, ).label("remaining_life") ) .filter(Equipment.minimum_eac_year != None) .filter((Equipment.minimum_eac != None) & (Equipment.minimum_eac != 0)) # .filter((current_year - Equipment.minimum_eac_year) >= 0) - .order_by((current_year - Equipment.minimum_eac_year).asc()) + .order_by(asc("remaining_life")) .order_by(func.abs(Equipment.minimum_eac).desc()) ) From d1aa0ced704f4c66dfcd632b7dea119f8c944947 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Tue, 23 Dec 2025 10:33:07 +0700 Subject: [PATCH 6/8] refactor: refine EAC year difference calculation logic and add an explanatory comment for EM. --- .../__pycache__/service.cpython-311.pyc | Bin 28138 -> 27937 bytes src/equipment/service.py | 8 -------- src/modules/equipment/where_query_sql.py | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/equipment/__pycache__/service.cpython-311.pyc b/src/equipment/__pycache__/service.cpython-311.pyc index 52128380ec84374df9c93915f1f9499edcc97374..c619640b67417f4fa759935de47760f5b27bcb5f 100644 GIT binary patch delta 412 zcmaELn{nYSM!w~|yj%=G5X$A1`7?bZU#1-wJCNH9#Gi9EH`)aBQJ~9A_FCgMO4+FPA zm+A!pg^OH@SGW{E@^f&qePI9+--RYyx|FcVGO%)eRhi7??MSq>#f+N+JVF@R<}fla z6oVX40<~O0S6t!)(0)FU{d^$%`GEHGi*%)45K+0vr+S4?6=XlqWk3RG{{%0X{hPVG z1DF^OPmcE8%(!PWzu!wn#$%g*`p;rywA(x-@HYqJq|FnexR@B-H_wilz{L)XZXQPbi$2MiBV{W list[Equ query = ( query.add_columns( case( - ( - (current_year - Equipment.minimum_eac_year) >= 0, - (current_year - Equipment.minimum_eac_year), - ), ( (Equipment.minimum_eac_year - current_year) >= 0, (Equipment.minimum_eac_year - current_year), @@ -427,10 +423,6 @@ async def get_top_10_replacement_priorities(*, db_session: DbSession, common) -> query = ( query.add_columns( case( - ( - (current_year - Equipment.minimum_eac_year) >= 0, - (current_year - Equipment.minimum_eac_year), - ), ( (Equipment.minimum_eac_year - current_year) >= 0, (Equipment.minimum_eac_year - current_year), diff --git a/src/modules/equipment/where_query_sql.py b/src/modules/equipment/where_query_sql.py index f8bb101..e33d325 100644 --- a/src/modules/equipment/where_query_sql.py +++ b/src/modules/equipment/where_query_sql.py @@ -14,7 +14,7 @@ def get_where_query_sql(assetnum, worktype): ) ) """ - + # EM = Emergency Maintainance return where_query def get_where_query_sql_all_worktype(assetnum): From d2861e1a35c2ce5594e0176d3ed81259a4797b43 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Tue, 23 Dec 2025 14:53:04 +0700 Subject: [PATCH 7/8] refactor: Streamline actual data queries by removing labor details, add optional asset filtering, and update EAC disposal cost calculation. --- src/modules/equipment/Eac.py | 3 +- .../equipment/__pycache__/Eac.cpython-311.pyc | Bin 15261 -> 15388 bytes .../insert_actual_data.cpython-311.pyc | Bin 51652 -> 51445 bytes .../equipment/__pycache__/run.cpython-311.pyc | Bin 2686 -> 2998 bytes src/modules/equipment/insert_actual_data.py | 36 ++++++++---------- src/modules/equipment/run.py | 10 ++--- 6 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/modules/equipment/Eac.py b/src/modules/equipment/Eac.py index 867a82c..e91a793 100644 --- a/src/modules/equipment/Eac.py +++ b/src/modules/equipment/Eac.py @@ -186,7 +186,8 @@ class Eac: # final_value adalah PV pada titik proyeksi periods pmt_mnt_cost = -float(npf.pmt(disc_rate, periods, final_value)) - eac_disposal_cost_proyeksi = 0.07 * pmt_mnt_cost + eac_disposal_cost_proyeksi = -npf.pmt(disc_rate, row["seq"], 0, 0.05 * rc_total_cost_0) if row["seq"] > 0 else 0.0 + # menghitung PMT biaya akuisisi # Rumus PMT: PMT = PV * [r(1 + r)^n] / [(1 + r)^n – 1] # dimana PV = rc_total_cost_0, r = disc_rate, n = row["seq"] diff --git a/src/modules/equipment/__pycache__/Eac.cpython-311.pyc b/src/modules/equipment/__pycache__/Eac.cpython-311.pyc index 880816ff5640b88937036df29544b7f292e4c1e0..08b9fa69e2549a7194b95f8f4fcb114f24fa2fa8 100644 GIT binary patch delta 372 zcmbPRKBt0jIWI340}xnxd1V?qZRA_W#Kgh1c^^|fE90fjb{vx!Cof@*oqUt?8Kd~* z16*eruT1Xap35jPS%=4yOVY2138?j#w9Dj=M#7sX@%-grN>rWfC^T=gg_t)p&skOm zh95tEG%$Q%O5fZsY0b>;!^kW2k-=y3MVadk*?AZ8ORi*>UZ|+NlwEltyK-&vn)D5s z2ZRrV9+5f`cp)IgC1XE?~} zC<&wvDFo;NsmuIaA&ktIC1rzcm@nI~hA?jSlxJpTl$`9Va)(iRvX<%_M%l^YYCjki zCJU(FV^rGwUi}~w(5vpQkV3@4K z^_*3rR;-3)a)G}1WPR>UtgC967w}JBs30=Az(`;+7f&gpfYc>bu3&NIOZu|GLd=(i zScAnkpO9x}Wt5nFM&%Bp)Z~?_Zy04JPgDEBC_lMh{T`#@<~)sqOpJdv8)$!E5>97k zHTb}QM24|XcGMG|?5oGV*;h}5ozY=)l4${}MG*_5KjQ}m+|);i+!s_O8JoGRg%|;& Cn`s&V diff --git a/src/modules/equipment/__pycache__/insert_actual_data.cpython-311.pyc b/src/modules/equipment/__pycache__/insert_actual_data.cpython-311.pyc index 0c990aba1d5407c1f652593c04c6b94c31499878..1dee995c90eacecc3a27a82b9c30c6cde72989a0 100644 GIT binary patch delta 4420 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 diff --git a/src/modules/equipment/__pycache__/run.cpython-311.pyc b/src/modules/equipment/__pycache__/run.cpython-311.pyc index e53b8ce9b711f692d89b1c392157b2cc0d6db792..ef5c1fd1b2fdb1f17012b63118f815c1bac17ab2 100644 GIT binary patch delta 948 zcmah`O=uHA6rP`*>`%J+p{Y$=q=^;_QcWvCrI15w7fTO<2!fY}lHI^++@{kBtzlQ| zQ53OE!9&PF&?@LH(0i-BNAMH~-bB1uZ=Q-16A5XHzMYwUZ{FMQ``+7w*!HmgM%OhU z?0aV3xw4`EKyhi~;8q3#_wpIQq;{%fqkx|CA(Q{c09cTzy~u++g2#0D09xQCuz)W- z{uQ3(b5I{f9Qx9B6{f8;L9SbwX?or1-(EO zSOcCcPTf7Z> z+j8ayJS1TCX2Z)4wM@!Kgp$o6`Z&NP|uL{By>ywiHtfU)Cnnz@#UJYc>oGFyQ zh>e5y+H?|ck4zhQ#~{Mp86BGmf!&aH72)0Z$V?XRW{L1W1g0;|X2Hj-W=`TgdBhyY Rd*j5Mp2oN?$c*?G zLJND4T=n4I1WzIa{S^c1)teqYh}cng$LPUox~YCuuj*ADW$!!8ebY2R+K;v=cdTY! z<1JFVpI-=3fEcQRpW(C_elmvl5Ws=FPlkZOPw+;1fvf*8fFk&VA#ULjuE+5Jiy7Q+ z;w{`{GYF+8j!|DaB;1VCmNjvNhw_;i2?+lX|9FSE!(FMD@)VvG1EkBLb@E!MmueBD zzKOp-g!b+b7v%eRV&zehU*fq~Yd~3I69cq%4b?X}a*a$E3rcoa-;{osU`C+s0!s#( zeA|KqGj|o%Ue`k1`zWjG&)s@>PV_0=!&(#j&uryT$=!?h;@0t6oGazU%QwpZLAxRJgnDMP!5f!dB-xGtYSvT=bod>MD Date: Tue, 23 Dec 2025 15:27:37 +0700 Subject: [PATCH 8/8] feat: Implement upsert functionality for prediction data, updating existing records or inserting new ones, and remove the previous deletion of all predictions. --- src/modules/equipment/Prediksi.py | 116 +++++++++--------- .../__pycache__/Prediksi.cpython-311.pyc | Bin 40721 -> 43567 bytes 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/src/modules/equipment/Prediksi.py b/src/modules/equipment/Prediksi.py index bd69dae..206cdab 100644 --- a/src/modules/equipment/Prediksi.py +++ b/src/modules/equipment/Prediksi.py @@ -239,57 +239,39 @@ class Prediksi: # print(f"HTTP error occurred: {e}") # return {} - # Menyiapkan data untuk batch insert - # print(f"Data to be inserted: {data}") + # Menyiapkan data untuk batch insert atau update records_to_insert = [] + + check_existence_query = """ + SELECT id FROM lcc_equipment_tr_data + WHERE assetnum = %s AND tahun = %s AND is_actual = 0 + """ + + update_query = """ + 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_oh_material_cost = %s, + rc_oh_labor_cost = %s, + rc_predictive_material_cost = %s, + rc_predictive_labor_cost = %s, + updated_by = 'Sys', + updated_at = NOW() + WHERE id = %s + """ + for _, row in data.iterrows(): - max_seq = max_seq + 1 - # (token already stored before defining fetch_api_data) - # maintain previous cm_interval between iterations using attribute on fetch_api_data - # if not hasattr(fetch_api_data, "prev_cm"): - # fetch_api_data.prev_cm = None - - # Update values from API (current year) - # api_data = await fetch_api_data(equipment_id, row["year"]) - # if api_data and "data" in api_data and isinstance(api_data["data"], list) and len(api_data["data"]) > 0: - # try: - # cur_cm = float(api_data["data"][0].get("num_fail", row.get("cm_interval", 1))) - # except Exception: - # cur_cm = float(row.get("cm_interval", 1)) if not pd.isna(row.get("cm_interval", None)) else 1.0 - # else: - # try: - # val = float(row.get("cm_interval", 1)) - # cur_cm = val if val >= 1 else 1.0 - # except Exception: - # cur_cm = 1.0 - - # Determine previous cm_interval: prefer stored prev_cm, otherwise try API for previous year, else fallback to cur_cm - # if fetch_api_data.prev_cm is not None: - # prev_cm = float(fetch_api_data.prev_cm) - # else: - # try: - # api_prev = await fetch_api_data(equipment_id, int(row["year"]) - 1) - # if api_prev and "data" in api_prev and isinstance(api_prev["data"], list) and len(api_prev["data"]) > 0: - # prev_cm = float(api_prev["data"][0].get("num_fail", cur_cm)) - # else: - # # attempt to use any available previous value from the row if present, otherwise fallback to current - # prev_cm = float(row.get("cm_interval", cur_cm)) if not pd.isna(row.get("cm_interval", None)) else cur_cm - # except Exception: - # prev_cm = cur_cm - - # compute difference: current year interval minus previous year interval - # try: - # cm_interval_diff = float(cur_cm) - float(prev_cm) - # except Exception: - # cm_interval_diff = 0.0 - - # append record using the difference for raw_cm_interval - records_to_insert.append( - ( - str(uuid4()), # id - int(max_seq), # seq - int(row["year"]), - equipment_id, + # Check if data exists + cursor.execute(check_existence_query, (equipment_id, int(row["year"]))) + existing_record = cursor.fetchone() + + if existing_record: + # Update existing record + record_id = existing_record[0] + cursor.execute(update_query, ( float(row.get("rc_cm_material_cost", 0)) if not pd.isna(row.get("rc_cm_material_cost", 0)) else 0.0, float(row.get("rc_cm_labor_cost", 0)) if not pd.isna(row.get("rc_cm_labor_cost", 0)) else 0.0, float(row.get("rc_pm_material_cost", 0)) if not pd.isna(row.get("rc_pm_material_cost", 0)) else 0.0, @@ -298,16 +280,36 @@ class Prediksi: float(row.get("rc_oh_labor_cost", 0)) if not pd.isna(row.get("rc_oh_labor_cost", 0)) else 0.0, float(row.get("rc_predictive_material_cost", 0)) if not pd.isna(row.get("rc_predictive_material_cost", 0)) else 0.0, float(row.get("rc_predictive_labor_cost", 0)) if not pd.isna(row.get("rc_predictive_labor_cost", 0)) else 0.0, + record_id + )) + else: + max_seq = max_seq + 1 + # Prepare for insert + records_to_insert.append( + ( + str(uuid4()), # id + int(max_seq), # seq + int(row["year"]), + equipment_id, + float(row.get("rc_cm_material_cost", 0)) if not pd.isna(row.get("rc_cm_material_cost", 0)) else 0.0, + float(row.get("rc_cm_labor_cost", 0)) if not pd.isna(row.get("rc_cm_labor_cost", 0)) else 0.0, + float(row.get("rc_pm_material_cost", 0)) if not pd.isna(row.get("rc_pm_material_cost", 0)) else 0.0, + float(row.get("rc_pm_labor_cost", 0)) if not pd.isna(row.get("rc_pm_labor_cost", 0)) else 0.0, + float(row.get("rc_oh_material_cost", 0)) if not pd.isna(row.get("rc_oh_material_cost", 0)) else 0.0, + float(row.get("rc_oh_labor_cost", 0)) if not pd.isna(row.get("rc_oh_labor_cost", 0)) else 0.0, + float(row.get("rc_predictive_material_cost", 0)) if not pd.isna(row.get("rc_predictive_material_cost", 0)) else 0.0, + float(row.get("rc_predictive_labor_cost", 0)) if not pd.isna(row.get("rc_predictive_labor_cost", 0)) else 0.0, + ) ) - ) - - # store current cm for next iteration - # fetch_api_data.prev_cm = cur_cm - # Eksekusi batch insert - cursor.executemany(insert_query, records_to_insert) + # Eksekusi batch insert jika ada data baru + if records_to_insert: + cursor.executemany(insert_query, records_to_insert) + connection.commit() - # print("Data proyeksi berhasil dimasukkan ke database.") + + # Recalculate total costs and update asset criticality + self.__update_data_lcc(equipment_id) except Exception as e: print(f"Error saat menyimpan data ke database: {e}") @@ -930,7 +932,7 @@ class Prediksi: predictions_df = pd.DataFrame(predictions) # print(predictions_df) # Hapus data prediksi yang ada sebelumnya - self.__delete_predictions_from_db(assetnum) + # self.__delete_predictions_from_db(assetnum) # Insert hasil prediksi ke database try: diff --git a/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc b/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc index 511bc59a95a97b74a9e136b1e88199ddb0a2b49e..c2dfa406cf957954f5a880dedabf86428f6b3555 100644 GIT binary patch delta 3726 zcmeHKTX0jy89sYt$+9fT$2Uo~C3Nu(85?Y%K*4|wHonOhfiW1H2w6Hd3bG6<2{4h7 zxrFjSh{Mj9lGwyeNnj?^LaUcfGl3)|l(dwboC70<`o-l1X)7!2Tz;WVE zUow5^O6S}E^6kH?|KHg?dhRlPQJ_`lRVoFAo4KXlllL=Ke>Qzhh4}57$l2_2pm0kE zlHIZaWeA`hC3)&9YDl_$u#={!0o8yS?as+cPY%(6bP^!mLTYy+ve)Y9ZW^7;S*9CE z38f6t@K7kl4YD4Rr~!tI1xhrk)JoK2O2k)W0y#1n=B4>_138a)RA{Et43cIJK+W@v zbI`HNGK+kFZu0$aki*6~BZrN%BWq1_lC`GUIcSCY_>H%yRkcSjwYGlsHPzQ_;DHIhjBd1b_ynEFNq}Hf( zp^o|1qKD|21^RzQzw3(TBy}ra0l1#{i8owN>50Q31=OHHb1NO9P&BAn5u#_aeAZkl zF#q8wipry)ejqiF_}Jo33#B4nla-u$Fx4k_Qv$ z6cm9>G*6d{juoWr5G5X80G4BinBejIoT8+M4T#ciZ=W*&YlvCm4?sv#ASSc>SywQ? z_Bwt2&`vDbjuyzeJ-hrKhaVl)gZn1AJ>xXbtkV zy@G8orw@--kL8BX7rs=;6|H?EmA9-HEbDoFm7uTU@HZ5`UDt3!%h_8e>|4j}TexFjYlY)6*2S9c-W<#5=5Q1~o(@9i|#u=*Nk!xsFTK zAXplBy-m>DIK2%s8tE4LwtbU8%G5d0zGJ+72j_f>8#u_fhlTbqj<^w2l8B@u5$nH- z7$()PdIQ(4R}g3#rse^KAxdC6Cgo9#IZ6Rl6_{i+ z6O3h?v5b{-W$Somy}+#JnDtXi&4ki0t~BsUqo6c$N@G+;sZuADmT@Jf^2$;{S;{Hp z_$mGJ;}jigUNE|3TLSf_VQT^IL<#6f#3zwrTaiRmr)|rZh$bnq?zQN_+@4-@mh5-n~;hLln@A`q~(QR zKPp?k7_;5Wo0IlovtNe+-D%dM-z{$jm66;Pzh!_6P1g>CtC8b%Pf9=_@`bGiFoPsU z7l9oFT&TXOXXR-uit>jinh2ms_d`*R&q~M6z959p6Y2{DMhJ`&I7{F~^m)@|8Cd{c z*Tv?-q+u-j^DyAGm`}AV2S1LiXt5-#j}l5Pf!Bz$F*O?RqC2Fn^$7Kxn z@q^o%3M+oYLI=Vdp_$l%X4uYx3XM;=V?|ndqCdFs^kc^K_EF}_|DK%?8cJS5KE~jcl!Noz!&U=J*ewgnej91 zgMT6LC4ooV2-Xwz9{TyQ3h*iV;@CCWH5zZfw#bzqxDxPxk?)`QyWGBt`pLR7`zo~h znN4A=+%y=Q)=F=d(?nhah`hGafECVQXu-G=5P6ltZkF)UG`n8HYo*x2>!rkE))9G? zVxvVeE=}8Lkc=CoScdEHLhzP-overKV{57?cQ|~`Ue@6d6%GfkOwh}sl#?161u*Ad zXu-)mbpPqXBA7z-m&rhq0!S0pO{75rWMjkk37FBrlZVqCv@|zL&A@fiNcyvXmC3pY zhe6Enc3dgnaDCk1Mwf@RGKR$LLAQp>K_AkcE|o6DhF?Y+Poo6z5xVojTi|VUZo~!- qq3Mxy8F4}jQjA(aZKPy$4Jg~L1`DIqx8roo{$QrJ!hlB32LBCn=~zPm delta 2381 zcmah~4Qvx-7{2dry>{E()(+UZ!Zx5mm)@8~(5fmYs7|j+n#=q$IUNbZb?wWh<`JVTC zzW2Vn_r1P0%J-b+<(FhRg=5EhX=PyGb-CTar&zS798H9e5;(gpv$r^HRxQ`fZ$7n& z=eW+)PAO{fn>v`I(-KYTPlo*I)6>)$xJ2Smv%o9a;ln*?yqXR3raP=^_GFCXqLN>P zclX#GQC^+-x4bQFl1C+YcugknH}^X8<@`w%jW_h%Ss~)L{J%Z<7IvmjZHM8U+17|t z{ZD!paAyB+X1L_Mh4qqi3TtoP&7Hk@Qy4*-dvhlXOl2*feG6;(?5V6(g}1O)6*^~H znx*4}<6dEB;vlSs_MVA~{WexHGhklPlERS7$*F~t6F6=TM`v})s`+olZ;i?j&&*Dh zyX26?&vmjZ=tYkZo7Pl(l{Zl=T{v0t4(u$wjZBAJyAv*yrq|Lsrt3mPr4(1wg+NH9 zRmhS8k&ssxS`<|`H3!39RZmrRD!w*VY4wKMX(O9M=P_`l!NM}1jd*l{h9997Op0KQ z!uMtC)0QN0+&Ap^C^yb;;^7N>9oY)YH_aysd|2MFWf{-qJBOv5F-Pu^l0zl2vc9r$ zZn2y(fzTs%lkNp$j{N@Rv3cF*@g~CA3NBiUN36xy?K2PG8LR87i%EUb=k}QgZ;%!J zVqbmSUOZ|q9<$GZBksqc-~E`@?=B(>$Ft=bnG-^~E#pUy!8pQ%!EWQ^X&0s35h?dz zbhu<`T&fH4TJ9>534k)()@u$V&XM{l5L=tj6EJO(0>dbzL2? z?n0jr!HeLBf%Pq<7v^usb3Bj2euM)E2N7Zjhd|kITBJxjz_qc6^g!drE##>7#>Rrw z)ZM7xjqoO1X?}pzYn3e(=FGQId5gi<>}1E%WiFmZp(|8NPQ&@oK5LYTbPht|p5UQy zm6&kB3*nZm0T$}8-a{3CV0$D`8VR(7Jb_S`R(*YcajaIH@ebOySBy&>T6Qyf~F z!&LEkS$ox@_BjKWnO;G@8sn*cuj=(g6dF(>^eQUJtzo|s^fU)ldJW!s_EBd2l58-UA!Nev+s_al$!wcSE(5NH!F$jizM!P3g#zeZPhJyjNwL91V>SIMv z*)z9HcX%e>smIf{gY8f87@G|Ge6Aeh`Rf*MB%-LHwpQ81k*pRJ4 zxB>$`%g8k_^CTqMLD8I2V}e7*^l z3KJ@e?2M0CQ<^G;5l2RoTNrVh7^gMt_E^=Q#Jj{+aM^T=#}o3lDjtuX;_yARSDT2$hIID-Ga?Q;|RIX7khl#X5Qo+=l+3RNm|9B zpGDCqe;G=TZYH^~_vk98A>cx~iM^V@4x{i~GM$Et$(X7cemPo2g0SdVxv889C$;Uz zAc^Sk=kaso44ivuwZmv28#=NO3@=Wlc~E?!fYfUBCzg_mjcKHGoVz(r82XR@j7Dd{ I+b_5M1#5C(8~^|S