From d84a442d874718419839ae318db001e89a022570 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Tue, 2 Dec 2025 16:46:19 +0700 Subject: [PATCH] update simulate data --- src/auth/__pycache__/service.cpython-311.pyc | Bin 3733 -> 3809 bytes .../__pycache__/model.cpython-311.pyc | Bin 5391 -> 5550 bytes .../__pycache__/router.cpython-311.pyc | Bin 11591 -> 11536 bytes .../__pycache__/schema.cpython-311.pyc | Bin 11856 -> 12098 bytes .../__pycache__/service.cpython-311.pyc | Bin 16805 -> 17516 bytes src/equipment/model.py | 2 +- src/equipment/router.py | 2 +- src/equipment/schema.py | 2 +- src/equipment/service.py | 43 ++++++++++++------ src/modules/equipment/Eac.py | 28 +++++++----- src/modules/equipment/Prediksi.py | 19 ++++---- .../equipment/__pycache__/Eac.cpython-311.pyc | Bin 15809 -> 16136 bytes .../__pycache__/Prediksi.cpython-311.pyc | Bin 50778 -> 50755 bytes .../equipment/__pycache__/run.cpython-311.pyc | Bin 3344 -> 2697 bytes .../__pycache__/service.cpython-311.pyc | Bin 9244 -> 9245 bytes .../__pycache__/model.cpython-311.pyc | Bin 1590 -> 1592 bytes .../__pycache__/schema.cpython-311.pyc | Bin 3633 -> 3639 bytes 17 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/auth/__pycache__/service.cpython-311.pyc b/src/auth/__pycache__/service.cpython-311.pyc index 02e487cc3e3ed3b47d83ed0600ff488333e5117a..daf1c8333770a8e7bec23a46b02343c1f8d32543 100644 GIT binary patch delta 366 zcmbO#`%sp5IWI340}wPzX=Fa%$oqqx@z-WHjz5fyMw^+rk{B6nCZ}=hbFqL_0P*K} zlLfd%CvV}_W)z$JfLlr|g?Skh1H)<{hJav(8ip+9$!oafeOQ(;0%d?0CZoyfSELH$ z6sZA;TMV~&5|fiti;Lq+^0QO(G+Bz&L2}w4IrgH|f}F(U)LZPy`T5zIsl}6RdDOU^ zfl^jLTNDW98X#t5_ti=U6nI)5}dDOTZfP5<;F1DY%nnzCM0XxqJ21Zup8~h^u)m_yy zj4$%bU*VTuz<7mU=>mt+18%+!>U=cQ$)7ioh8Sab7JQge#9 zf$Sn)5Md1>9Du|vZs*dXqSU;S(BjmhB14b}Ye;@}YF?2BNQo$j5CIauIBbAsl;)(` c6?sfv%X?Rvjgfyw_y-0cg-!@fUdm?!09}SstN;K2 diff --git a/src/equipment/__pycache__/model.cpython-311.pyc b/src/equipment/__pycache__/model.cpython-311.pyc index 99402dfeac3c4c99c7f07a2bd7aef982c6f0f344..a8e1524526e71999948e69510cbe9a2f382bbad8 100644 GIT binary patch delta 272 zcmeCzTBpsooR^o20SF|w=w&7fZse0>XI!;egT0hx@ zqDU8LS&<%y&<7EQFhUi`C_cOS3I76SgB#k0E6g^i9#FlY?Qv1t@ z7KCmHy&z|OQO^2`ob?43X$YF!Av}*Ub+Wq1T5DTIn-2__!~&HSJR5R9f@Hp6kp?>m E0OA~1CjbBd delta 127 zcmZ3d-LJ*BoR^o20SK<%Q_j32u#r!aow01Q274*XeH6e<3IWI340}yDf)yuTs$a_bD@!I4AQf7>-lV`|SsnsxNv4CVjpoS@)6~ba* zDB*>%fNcKB3l+QBIEuu8Vv{YEa=EI2jB`L-ymRsfC4I&Rn?EScWMr(K+@+ETB;TlL cFxG7rRc&En11T)3n>=4#mT}_dz3N@80GfFuT>t<8 delta 232 zcmbObbv%l9IWI340}w<%kjjkR$a_bD@!RABQfBt7CCngU2&iGLVO++C?Ob%8_1d>}- dG#KkQ-&1K}VgqR`s-K*pF3UJ+bDMe>D*$VNF}eT% diff --git a/src/equipment/__pycache__/schema.cpython-311.pyc b/src/equipment/__pycache__/schema.cpython-311.pyc index 13617cfa67aad30f12f19af3fafd1b6c10765d6c..2cb302b84241bcad38030e97da0f92f6b981341d 100644 GIT binary patch delta 725 zcmcZ*b105)IWI340}#k<(aSWE*~qt!lX27Ly_|s@lTCOfg-uggQ+Xso@?en4o?cc z5+I$CUs_arOFS(<116JST9TNa3X#w>-<&DR#mE*8G`1*Wa=w@%XqIn?Ed=Q}oA__o+@?=3xVT}?H zvlK*>fe17wWrM^(MAGJCDhnAIvnM+!N^Wjc`^Bi31Cq)G5`G~?JRr6hh(K5*FnNNC zEMw{9T^bg+tye}^k7jcP$TTpq*;ccTk+EX(9<2)QYLF-kSZcDpwggudhzTNECnsu~ zF;-2Up`By_4sdW_CV-^DegK;UR*h=UFAkgB{FKt1RJ)>v$woStjCC2k7(XyzCnrdM S1j~FumQP@uoT#e>#P0#~!mGak delta 536 zcmX>UcOiyvIWI340}!0Jr<^%idL!RDPR5|kdpQF+*ismS88i(xmk0$jGijP`<`Cmz zoUAIxKUrIxkI9{FGC!Nq=3H?>Hns~a?m#s8tZX`01kj)&5aB!7PEM9FVsea}17qZ5 zMLA*V7?2c*2m~>rK!hq(X!1oy@y(CqIG9wDKq9OlLK#FPgNPImkqROdK}6bQK1IpN z8{{|{Ll+w=GBU?8Fo5-YE6FlT<$zS=f(RuLkq08cCgo4=)073do+}e11|kwR?@(RH z$P8qH^%txEV${w8NoE5HzmOsx5L*mHAWRhialxj73>2TdUegr6of2R>%Rt&dM8Rf# ztvW`=vdQbTE4V8`qAXyk$%Z--TooWDh-jW1tYgMlF}X`8$pRdr;IIRF6yk8ONnnLV zDj+d%FscDrzc_4i^HWN5QtgWBCadUPGSX)BVEn*51ac}6P=*1-fDzKDkwim)L=!b$NfYoAqW&=Q!-OXILG+K$du4+mzJ2a_pYQj% z=Y5{*xqbMzgV^ywZZ3~tm3-n4ztMfv;l}HaR(;#QC{h+J9WKX6MB<`I1<;iyjU!dV zRUpHW>fvhG7e{c^H|zslp5zgiNM6w?)rk4hb5gD3D5QbSCDm!QxX|u5t-wO-!!G-Z zc`gQAy~(*jcNn{-SBhBloWiEeD+R7@Vqr zZ%J&i+|S01i5DEdvbZo&?>uP52NRzcwpj3|iQl~z3;rVUSMgF7-%R9|-s7x4KxyPx zv~jzBXA;Fj& z3@PEUm@qm<1Znp~cswe_6u-|xiXk+48&Dt70Q(ptXPii4IHZh3gW(v}*CE3u1w$t9 zBdaU7od)$X$V+|^h4KwTS@=K1dOBL1Xd|i^SOYwCx-RV9CUFp$QEicdnn`62Mori-i z&K-y1Hak*s=UF7$!$`HA#fNd+t}J>iSCML0nM>Sx2E5_PtbIsiUS)>RG3Ee^QLLj3 zDU0WH2$drei1Ui`u|(vos%@6nesBW86<@bJOYT9 zl^{{%$*{7+$B;4zXW(51-Xqfz3W7i?U?-J;raTkoOZeL&W1(O~Zuhs*Mu$ckZ@)~t zwH}OSknSAH!1Ret$NOjTwa%}4ulMTxo02_)sh&a59qBx>d)|svfft;-a4x1w2Bb%Y zG3PEAj!2?8ezYD+Y$7U{vo~dF5l9J*ke!*u_kkvz6rJ4&*kJbriEMCTMT*KKkILzA z8TPe%L(({%X%eHtRzMKKOky<^%u+-L+sGMKtOEXmnm z4E55kG#3b;0eza5gkD-^fYUiBzc}TrnCbl~+ok>3JT;xRqWsMm3UO}J1>c#Gvm>`F zT5eUeBrDod6>T6+I)_rup_$&ajpH`syWSez+X8T5TV~g7?z@iC3p@3$0eyHxcWh5O zwx=B1b=$My;oa=~G_pXXM|j#~ezE21j={^dw*y_b0$tZyl7YTdpbtb81~z7hq-`i= z8`A#+4`HP_8j}(>l;hS}m+Xd@zwRmT>Oj{!`0iHbhP}GGfw|GZ0UZLJxhyE5w&Y=_ z!Ab#xj|N{LwLSA|lED`3vyBL_fE? zJ)QfgGG delta 1413 zcmZWoZD^ZS6u$S(`@T)y<)d9b+oWr^ByE#s{Yukfv|Y9i+D+*cKbQfvrT0cF=?6FI zCS6Jk9d-Jz-a?DhQiSQ4gE?P+2>uWRQ9-mF8IGX%Lx%eynxXy^^xQYwn$DZ#-19u= zoO{ka=jOKy_|h`Ae_*p|2-bIB2PfN7t9BpmS#AAx5od$xAVCCYL+KFgwOKqBPKPlf zb+m!(r+(t3EyP7zX&bfIivx^BBLvUaAe51Ixr~{(&&%nk5m|}yQBRd!B_6Q1SKAk< zZI6Q&9Abup&q(Wg$X*Zj!vvFtcd+5*ryV34c-5Hg%0GBX0xB|qq0`Aji zr9bxJgg$2fRmNU@#Cbu*EBa1-Qo^6;)_^48&veHDw~W8g!-wuD_y^tImRIp#`f|r< z6OQm7yHDeKp6I!ztwaC!V}x>-c-NqdOYv)(0@O16{+#BWU7dVW_40oMUhP$rF)9%J z=zz${$)>Mx=_gpuFRLG(rWu zo1q}(Yj-X0L*@@3WUoGBK`zKoqlh%hByf*dn5c$XL6nrUuTVx=qacQa=td}kO6tVS z)YN32iD$xmAR-F$3w=X~H6aLyk~YgInViT^&P?;my)Ef?feeT~eFe%L_$;BnHDqzz zbVPT|?L~9@&ldZeZa_sx{G+qQ{^1*r;T_9J(K51Y==~Jma6GbONfs^1at%_nvWE7# z`HO?Y@muoYpS=E!;bI_mnchr{?08QUy(hNo9{w(!ERULy)w3ro-Z4NCHvah8jiEB8nUx^fxN z`0Zp{JZA>2`QBn-5u(l+>DUzj7sY7A2rHw3##()R?9qAWZKrp`vU+6g$kG#KE0Ei= zmp|X&*ME6T#dYj$h+s?zcpXp)|7ReoTm|(yZy#L2{rbm)LzpL1r`+Oy!o(wBqO(R$ zc9n0Y8nw>>Lw1xqr+=A>V%>S{I*#Tr_S|v?$|gf;?W-tdB;X#I<-ZRFV@~Wdyu}{r VDVxN8>?va}BLGz*#s`jf{s(gnRsH|~ diff --git a/src/equipment/model.py b/src/equipment/model.py index c39feb8..09c66f1 100644 --- a/src/equipment/model.py +++ b/src/equipment/model.py @@ -94,5 +94,5 @@ class EquipmentTransactionRecords(Base, DefaultMixin, IdentityMixin): eac_annual_acq_cost = Column(Float, nullable=False) eac_disposal_cost = Column(Float, nullable=False) eac_eac = Column(Float, nullable=False) - efdh_equivalent_forced_derating_hours = Column(Float, nullable=False) + efdh_equivalent_forced_derated_hours = Column(Float, nullable=False) foh_forced_outage_hours = Column(Float, nullable=False) diff --git a/src/equipment/router.py b/src/equipment/router.py index 6a86c49..f2969c9 100644 --- a/src/equipment/router.py +++ b/src/equipment/router.py @@ -212,7 +212,7 @@ async def update_equipment( token: Token, ): equipment = await get_by_assetnum(db_session=db_session, assetnum=assetnum) - print(equipment, assetnum) + if not equipment: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, diff --git a/src/equipment/schema.py b/src/equipment/schema.py index a865f92..be238d9 100644 --- a/src/equipment/schema.py +++ b/src/equipment/schema.py @@ -72,7 +72,7 @@ class MasterBase(DefaultBase): eac_annual_acq_cost: Optional[float] = Field(None, nullable=True, le=MAX_PRICE) eac_disposal_cost: Optional[float] = Field(None, nullable=True, le=MAX_PRICE) eac_eac: Optional[float] = Field(None, nullable=True, le=MAX_PRICE) - efdh_equivalent_forced_derating_hours: Optional[float] = Field(None, nullable=True) + efdh_equivalent_forced_derated_hours: Optional[float] = Field(None, nullable=True) foh_forced_outage_hours: Optional[float] = Field(None, nullable=True) diff --git a/src/equipment/service.py b/src/equipment/service.py index cd0e902..5f9556b 100644 --- a/src/equipment/service.py +++ b/src/equipment/service.py @@ -15,6 +15,8 @@ from src.config import RELIABILITY_APP_URL import httpx from src.modules.equipment.run import main +from src.modules.equipment.Prediksi import main as predict_main +from src.modules.equipment.Eac import main as eac_main import datetime import math from sqlalchemy import text @@ -285,15 +287,17 @@ async def generate_transaction( *, db_session: DbSession, data_in: EquipmentCreate, token ): # Delete all existing master records for this asset number and prediction data - query = ( - Delete(EquipmentTransactionRecords) - .where(EquipmentTransactionRecords.assetnum == data_in.assetnum) - .where(EquipmentTransactionRecords.is_actual == 0) - ) - await db_session.execute(query) - await db_session.commit() + # query = ( + # Delete(EquipmentTransactionRecords) + # .where(EquipmentTransactionRecords.assetnum == data_in.assetnum) + # .where(EquipmentTransactionRecords.is_actual == 0) + # ) + # await db_session.execute(query) + # await db_session.commit() """Generate transaction for equipment.""" - prediction = await main(data_in.assetnum, token, RELIABILITY_APP_URL) + # prediction = await main(data_in.assetnum, token, RELIABILITY_APP_URL) + prediction = await predict_main(assetnum=data_in.assetnum, token=token) + eac = eac_main(assetnum=data_in.assetnum) # # Fetch data from external API # async def fetch_api_data(assetnum: str, year: int) -> dict: @@ -396,7 +400,7 @@ async def generate_transaction( # # Return the number of transactions created # return len(transactions) - return prediction + return prediction, eac async def create(*, db_session: DbSession, equipment_in: EquipmentCreate, token): @@ -411,7 +415,10 @@ async def create(*, db_session: DbSession, equipment_in: EquipmentCreate, token) async def update( *, db_session: DbSession, equipment: Equipment, equipment_in: EquipmentUpdate, token ): - """Updates a document.""" + """Updates a document and re-simulates transaction for the asset.""" + + # capture original assetnum (optional use) + old_assetnum = equipment.assetnum data = equipment_in.model_dump() update_data = equipment_in.model_dump(exclude_defaults=True) @@ -421,11 +428,17 @@ async def update( await db_session.commit() - updated_data = vars(equipment) - # equipment_create = EquipmentCreate(**updated_data) - # await generate_transaction( - # db_session=db_session, data_in=equipment_create, token=token - # ) + # prepare a clean dict of attributes for return / recreate input model + updated_data = {k: v for k, v in vars(equipment).items() if not k.startswith("_")} + + # Re-run generate_transaction for this equipment's assetnum. + # Build an EquipmentCreate from the updated SQLAlchemy object and call the generator. + try: + equipment_create = EquipmentCreate(**updated_data) + await generate_transaction(db_session=db_session, data_in=equipment_create, token=token) + except Exception as e: + # don't break the update if resimulation fails — log/print for visibility + print(f"Resimulation failed for assetnum {updated_data.get('assetnum')}: {e}") return updated_data diff --git a/src/modules/equipment/Eac.py b/src/modules/equipment/Eac.py index e9c1055..f79181b 100644 --- a/src/modules/equipment/Eac.py +++ b/src/modules/equipment/Eac.py @@ -308,9 +308,10 @@ class Eac: except Exception as e: print("Terjadi kesalahan saat memproses semua equipment:", str(e)) -def main(): +def main(assetnum=None): """ - Process all equipment EAC calculations. Returns list of processed asset numbers. + Process EAC calculations. If assetnum is provided (string), process only that asset; + otherwise process all equipment. Returns list of processed asset numbers. Raises RuntimeError if database connection cannot be established. """ connections = get_connection() @@ -321,26 +322,31 @@ def main(): cursor = connection.cursor(cursor_factory=DictCursor) processed = [] try: - query_main = "SELECT DISTINCT(assetnum) FROM ms_equipment_master" - cursor.execute(query_main) + if assetnum: + query_main = "SELECT DISTINCT(assetnum) FROM ms_equipment_master WHERE assetnum = %s" + cursor.execute(query_main, (assetnum,)) + else: + query_main = "SELECT DISTINCT(assetnum) FROM ms_equipment_master" + cursor.execute(query_main) + results = cursor.fetchall() eac = Eac() for row in results: try: - assetnum = row["assetnum"] + row_assetnum = row["assetnum"] except Exception: - assetnum = row[0] if len(row) > 0 else None + row_assetnum = row[0] if len(row) > 0 else None - if assetnum is None: + if row_assetnum is None: print("Skipping None assetnum") continue - print(f"Processing asset: {assetnum}") - eac.hitung_eac_equipment(assetnum) - processed.append(assetnum) + print(f"Processing asset: {row_assetnum}") + eac.hitung_eac_equipment(row_assetnum) + processed.append(row_assetnum) - print("EAC calculation finished for all equipment.") + print("EAC calculation finished for processed equipment.") return processed except Exception as e: diff --git a/src/modules/equipment/Prediksi.py b/src/modules/equipment/Prediksi.py index 3249b37..ee169c9 100644 --- a/src/modules/equipment/Prediksi.py +++ b/src/modules/equipment/Prediksi.py @@ -454,7 +454,7 @@ class Prediksi: raw_predictive_interval, raw_predictive_material_cost, raw_predictive_labor_time, raw_predictive_labor_human, "raw_loss_output_MW" as raw_loss_output_mw, raw_loss_output_price, raw_operational_cost, raw_maintenance_cost, - efdh_equivalent_forced_derated_hours, foh_forced_outage_hours, + efdh_equivalent_forced_derated_hours, foh_forced_outage_hours FROM lcc_equipment_tr_data WHERE assetnum = %s; ''' @@ -993,16 +993,20 @@ class Prediksi: RELIABILITY_APP_URL = os.getenv("RELIABILITY_APP_URL", "http://192.168.1.82:8000/reliability") -async def main(RELIABILITY_APP_URL=RELIABILITY_APP_URL, assetnum=None): +async def main(RELIABILITY_APP_URL=RELIABILITY_APP_URL, assetnum=None, token=None): connection = None try: prediksi = Prediksi(RELIABILITY_APP_URL) - # Sign in to obtain access_token/refresh_token before processing - signin_res = await prediksi.sign_in() - if not getattr(prediksi, "access_token", None): - print("Failed to obtain access token; aborting.") - return + # If token not provided, sign in to obtain access_token/refresh_token + if token is None: + signin_res = await prediksi.sign_in() + if not getattr(prediksi, "access_token", None): + print("Failed to obtain access token; aborting.") + return + else: + # Use provided token as access token + prediksi.access_token = token # If an assetnum was provided, run only for that assetnum if assetnum: @@ -1044,7 +1048,6 @@ async def main(RELIABILITY_APP_URL=RELIABILITY_APP_URL, assetnum=None): finally: if connection: connection.close() - if __name__ == "__main__": asyncio.run( diff --git a/src/modules/equipment/__pycache__/Eac.cpython-311.pyc b/src/modules/equipment/__pycache__/Eac.cpython-311.pyc index 026678b141baf5f03a13e8a184ed8c501f2df632..d78681d5008683f4be6f5ee0340953523a4b82e7 100644 GIT binary patch delta 2453 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 diff --git a/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc b/src/modules/equipment/__pycache__/Prediksi.cpython-311.pyc index 909359461859382a592846d2467573cc6881cc72..5cf07adf19844d1d1bb11a01bd6f2c5bebd87c42 100644 GIT binary patch delta 2907 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 Kn<4pf_5T37-2Kr2 delta 3075 zcmZ`*Yj9J?72ds9_v&?J*^;hpAsI{ZL$>9os7-le8wl9uVQ|2txJF~yU}_t z?WPPSFfH+!4v)~O$t2VP+R#yX6hdlDk`5*UiBXFf}`Ih9`P!v6!xz!RvqyU2@ts|!_WHdP}#J_>TSb*;U}7)=of=(A}mA4 zg(go>qeZZ5TXpDPO%DVWnH|gozds8*V8Fjb?d;-+G3bOp`>ogsU;0bnuzwcFr;V_* zHBHE(S~Gm)&r=aOm<!6Yr11LLh(I2XQYbsF5n9?T;d z!F+;-Qs8l&3`^RQ>3HPQI7b(%%NQdqh@-AmMj zE`-qVga#!v6p05QC8V^?aE_xc=rc7i-OXcmn7!SK^Wpp3o!A9in=BkX3%j;2NGS_E zT@6D1EK&w%uUlF4+a(xM}(A+|%1Y)FR8P8&xMIMEH~@`W|~%Qq~qTVCDZ==60pZ{OLYI99A* zyV}vw($d`7-Mp{Wr!@P00iR>j%H`{qI~ea+D8p0VxlbP8=^+UVgY&dn`%z>wluk-dCT-dAg3XX|cLCF!lwv$B~k9NO8Y7m5I zJX%zR85VeI6V+xl6mii)<|$evH7pdO^O&dT0?hEjDm`T$s5zR$1FddTn()BPGn|SU zPAjH(T)>;PXk64a7V_iCrbahEp6U{q$Sp8YAy4rqTI*&PjOf!s@Ah@5R8Q#U!fTdU zu;S2s+!N|QR3?buunqqjuD#kn4VN5UiHAc2M>T5hTLgoH%kfBPeDI4T{0K(Q-oUXC zd1DP%uBEkB)Qmi$9wvBS*FJ^a&5Dl7CNyn3mDUy?J&#pPW}vcswPJ*C-%L$0F#~Pq zPJe4hb6a~ru|V!yecV@EX!tEJS1vG9?UZK?#Y#L7`@zLM$D=8FrjQt6o|Pmp4tHQJ zkl`>EVfEYppi8YjUnRzsdN_LiYNpKWoQz~KvV!?z>;NN}vD+A`h3lbVQ!giE#ZUrW z27%ul!yMqt7H^e^P%Xmf1fo|gN1GF!JUs|{wgCj`JvfBvh3SIQa)VJ7U`6@wAUqto zTrO}*D&bgT2Ykf?gHoDEFyVKI@Rv*%{OC$rnvi&H`c(wKj{E`md*)&A-t7k6dE=+NMdaz4s0Qv` zougILKCU6^Aw#^g+j5K|MwCsWnPt^$1DOe7w0`|X>DeB(3^m2J&?Xbq1@!@Eg00^F zT(?tXqNjf!ScAEF&Fs`CE;T3-Ny&MpolEfeTCG_}3z8DZPw=aSwZAX-e24tm-J$c$ zM0y?lLWI(O3xJd=66tB}@%8_$JvC0O{jtB%BQRC_JUDP&PI-2(EOeJ>Kh{!a;b7cHMAcTl{SLXmUz6BkbRdQp?V3DuQ3XTdy%FDNM8h^f$Mt z3=~4gO>6HKYVjHUZFg6y5c-mS`p|fa+*cFhN`=fxvn^~diI_{H=F$O8OhoqV2R6^g zHc!M>6txwF<>$Wxx=CZ|@x4Q{FIghSim0(7hB&QxQc4M%7Dl8+QE5?FS~M=1V(T!H zQt7P^|9mf-kJaMPlK0->d$l!r=vIM+(Iw6*CmMBNibtKgY8^l7k*fv%HWH}hwjfZ+ zZJmkXxr-_NAh~)TecjPHR~2%1JZ##XLS2n4+^LXjl7%rnn>Lm#P|29grj5CAoq)#j zbhU1N%xkK3@po0Sii+;K1S-1g<|+P2u-46nACH#eN1@Q@DlD>UDRscT@6z>9NWZ9C pA1Z!-Cob(x!o~C|_)hvbF8_O?b{YKX13RsN7iT_Cb^!jc>OZ>oB*p*$ diff --git a/src/modules/equipment/__pycache__/run.cpython-311.pyc b/src/modules/equipment/__pycache__/run.cpython-311.pyc index 6b3e3bbd5693b442b10a248ebf4129ec93f5684f..f5309f3e146167b32b84acbab949c71b4004d138 100644 GIT binary patch delta 695 zcmbOr)hWumoR^o20SG=AX=MJ{$h(q}X&=+%9gJR4wTvaKAPES_VurD57?&|JFsue* z2qyr{NW6-PfdSQ( zwX7Iw*ccd6*s!Q%1De2A1(dC2PhqcNoz0NKQNso#IcwPKQ@Cccq;St=ujR2e s&MeG_q~x9KnGe~s0@=4X;^T7@GxOr(HHC`!CU-%Aux6vywKJ3sEO&1}}1yRPMGV!EhHA=C<$W9^GXFG0TumSty!sddzuE802} zLJ%1R)fFVfDCn2uO9)|5fntxr3O)__7}%Ti2Sj&PYuyy8GiPSby>rgz%=g^!s{1wa zOIh{1%J~8OVJ{bRPC}+yojJMd!gJy2V3a96bmK?O&*n(5v?BZH6>fiEt3X7;^aodaS>vbC3kbk#c5fJ)PoQiT!nW^! zpPyJ#D3{HToN!J9gm)S`on@!ov<~1qL0Z`t}5w_)s?0hi&h^kNGJc}Jk^Vz}_ z(EPT@o)xyF?V92>d0KL?5oc7q*{$IZQjyVCVw6`4tlA^PB>MC~IC%X=#$~jOGvh-qsB(Ym!ttGdQGMI??-$RHok|n~8Lkf7GnFJkk5I zCSuxMUveaq9q{s8VZhW4;v$QfCX)wfL`XECT-Iz7lt}(D$Sv3)U5SfUK^{n%}5Li`08uzEwLj0is(;%1thb=F zGhfE>6&x?%IQ=4qo7QoW5?fYUSCrNQ-r0+st`BHleJ8#b3rZLBWvs4XwSZNR!>tGB z+Qk`oA<3jo23x_bUyY)-b!r4HLuyGi&4L#nR*#*Ifu)!~ mc>pbS)Fs2{Q&?cJi&Lq-v~HwQEqlyL3h`sOd+rJT27dy~dhx^n diff --git a/src/plant_transaction_data/__pycache__/service.cpython-311.pyc b/src/plant_transaction_data/__pycache__/service.cpython-311.pyc index 935bf99c79eb77dfc40c425c11b08bb4d7c3856a..7cf3ef3577b25b32e3c8a8de5a2654b7de186bfd 100644 GIT binary patch delta 64 zcmbQ^G1r54IWI340}$+1(8z4q$lEQ#%3f5OXS8{ah#?buL K1SYct1u_A@e1_!9iI;Orz+$w)V@K!~f1oU@BNK!KDgm-@SlaCn-BEHPi?3J~Utm#P uP_cn^N&N*DAiMY?OYsdO^9`yySPqn22nf6omVLn}=b};0mCcr%|5yO!F;Bz*