From be8a6390a6f2d54b0ef2cfc6eef2466e83bce764 Mon Sep 17 00:00:00 2001 From: MrWaradana Date: Tue, 11 Feb 2025 12:56:10 +0700 Subject: [PATCH] refactor: equipment transaction data & add search by assetnum equipment master --- src/__pycache__/exceptions.cpython-311.pyc | Bin 7117 -> 7518 bytes src/auth/__pycache__/service.cpython-311.pyc | Bin 3329 -> 3744 bytes src/auth/service.py | 25 ++++-- .../__pycache__/router.cpython-311.pyc | Bin 5341 -> 5455 bytes .../__pycache__/service.cpython-311.pyc | Bin 10866 -> 14243 bytes src/equipment/router.py | 17 +++- src/equipment/service.py | 77 ++++++++++++++++-- .../__pycache__/service.cpython-311.pyc | Bin 2653 -> 2774 bytes src/equipment_master/service.py | 5 +- src/exceptions.py | 19 ++++- 10 files changed, 121 insertions(+), 22 deletions(-) diff --git a/src/__pycache__/exceptions.cpython-311.pyc b/src/__pycache__/exceptions.cpython-311.pyc index c896da4ecb7c1bf5716e5ba8ca0f18f79e5c02f5..f76a8b355ec62dbc33e81b98eba4bd9065cd59b0 100644 GIT binary patch delta 717 zcmaJ-O=#0#82*wpY0@qIOPZvA8gWc3+d)0dcA_96h;$Qn6c^hj9gF>eEQ*YT?ckvY zFY*-`3}Gi7da$E<^5Bjl3@Y>x0+V@|f~TB4`DL+FFTT9L&-1?D`||D0d?`g=vTOt( zX?}dQ^i$Z0zKP=xL;Vl&Z+Ona^n_3Oq9=n0z$Q>xGX=jgnYB&uoUjS=%!mTO!qli5 zen9~68d)GVX^}?JB5lf|bbf>y(Z8#Ixt`CZMxDBFoQb2%4x^5f(s4;!1iC9`g^`b2 zG&+p53AmRO6Nw{+uyBNh)R3BlF;2!+4xZ;syud@q|2U18WS3PG)2P(6YNd8xQC6wQ zjpc?WuZE}O#&S!Op_Q7(3u*W%)h-!V&|WueR+X0a$aHCx)Qw70bE&#gYpa?&R%Mdz+xWB2#m%bA_yfw(1nsvgtq08&1}&12z=n{IETZBb zvX%FJC~RYE-U%ROyY^6=9`LhB-*LT#9qFwURO{t^A-_@Ey4t(`Stt&L;`+Qt0b29` zMb2Rko9p0CH2y^Q0LJ8;1lP@Uu6YEAC4NH(ywJTh7`6z%r}LQJCo@m6nRyJOHkLf#$L*Uz{J%F&pioTlcE~cYcCF_`{P@0!o zQIMKklA5BBT2z!@q>!JSTv}9=nxdyEJh@aXpGlK-vYfaMYcVU(q{+47vRolRMgkBQ zTW?+>zJgKVs~iI>PmAvj4$q~*D})zDEQz?l;R!@LY#{XHkCL)-JPbS%H$=oAh)CQJ zmzq+0MO^o;n93C~t)~LgH)O0gt4jqiGKNg9kd|dk*gQ>oBBQwrBO}|4^bZUmdW9#1 L#!nV00v!baV3Suv diff --git a/src/auth/__pycache__/service.cpython-311.pyc b/src/auth/__pycache__/service.cpython-311.pyc index fd2da1d894b92cf4f41e9ee53801db733a16f18c..e6d8d51d53d82de4a22344fa401f1cb31aa3a2d3 100644 GIT binary patch delta 866 zcmah{%}*0i5Pxsm#bx)kn{I&?3bb~EbP*E>@gry~2{B+4Js>6F;=x@S6+vH1(0~Es zM=Bw)WDgQAHZjpgy(l+~|HCfX#0?3^g~)LmIT%jPmLMQ8&Sriy?>BE|Co}I+U7^AM z&gbJ1$cFhoJ29qF^PGX1L1=cjYeHLHOCe+`dD(ZYqc3$8$Y%eHLki1cTIXNYP@qac01fQl^x$ zq?AEYi}xye87wa@ac^*|#17&@+Ci@U4<_{I{8xNR?-3e@Zu}V~49o-i81(0TfJ+FY zmuL#z0)Iye`|s|ONW}+N@(@p98kxfSQKn{EWex^a&)&ZJVM?$s?-kkv#kO&bx=%sz z&|_d|3&0ASxjS+*t1z^te9Dg9)=+K%_40x7uJsu2VqvW#i|#Rvy%%QrWm!vXaQSd+~DHtfa?HcEJ>uU&JLkO!evBU(K;#!N`GJ8^(2wzfgv@;YS^O)w zGp=aZUzBjTBH_^Cc|%wRq}?B`-4~?YAFSOUtlggxq#a1IF(_$wxcB&8;gJLCy1*mz zR7n1YjQj-+SD+SQcaRn!3A7PN0=4kEGj5*G=E20Mu=xeYVn!W)R(Hk)=^q$CGyzg+ z@^-GhipIcDDi#D1kdV5;E!1OsgV8A3MaD4=cenChDOjhGlR%YOrn8C3?eS!J~Evt)4 U)>o9QFGyHl;j?Mr20^gZ06#{NWB>pF diff --git a/src/auth/service.py b/src/auth/service.py index 75f582b..975ca23 100644 --- a/src/auth/service.py +++ b/src/auth/service.py @@ -13,21 +13,24 @@ class JWTBearer(HTTPBearer): super(JWTBearer, self).__init__(auto_error=auto_error) async def __call__(self, request: Request): - credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request) + credentials: HTTPAuthorizationCredentials = await super( + JWTBearer, self + ).__call__(request) if credentials: if not credentials.scheme == "Bearer": raise HTTPException( - status_code=403, detail="Invalid authentication scheme.") + status_code=403, detail="Invalid authentication scheme." + ) user_info = self.verify_jwt(credentials.credentials) if not user_info: raise HTTPException( - status_code=403, detail="Invalid token or expired token.") + status_code=403, detail="Invalid token or expired token." + ) request.state.user = user_info return user_info else: - raise HTTPException( - status_code=403, detail="Invalid authorization code.") + raise HTTPException(status_code=403, detail="Invalid authorization code.") def verify_jwt(self, jwtoken: str) -> Optional[UserBase]: try: @@ -40,7 +43,7 @@ class JWTBearer(HTTPBearer): return None user_data = response.json() - return UserBase(**user_data['data']) + return UserBase(**user_data["data"]) except Exception as e: print(f"Token verification error: {str(e)}") @@ -52,4 +55,14 @@ async def get_current_user(request: Request) -> UserBase: return request.state.user +async def get_token(request: Request): + token = request.headers.get("Authorization") + + if token: + return token.split(" ")[1] + + return " " + + CurrentUser = Annotated[UserBase, Depends(get_current_user)] +Token = Annotated[str, Depends(get_token)] diff --git a/src/equipment/__pycache__/router.cpython-311.pyc b/src/equipment/__pycache__/router.cpython-311.pyc index d70c62c440ce019e538b59d6b221ef7727871740..b34a8c74ae94bc7e29487598622e25f9fcf233a4 100644 GIT binary patch delta 1727 zcmaJ>OK%%h6ux&J_IPZMA4!}zevF+qPMjF0p*$p-q@-yPpgE}L_uTXR z=8UiBzwgmL3kFpJ>*t$aOurFc)!Jx!wd+dHtUjSrVh}@}$;@UavXltKl-9xUOSE>@ zM2Fe2c7PX!RxxV^FNy6uLm!PCjPKqPBWem}Cx4CVsT`W_T{H+rvzg^KP4%^0BzJ}H zy01^n@i~y_JR=!x7w;~s8~pP1vO75K3Cjwb_pc8H%)KJj#-nB%`G`6wo08bDrg zvmN3EU$UDW0hOfyWa^9cz@ZkLHp`Rdn~Se6%t9+{ke~H^OA9=w>b{y>#-2_~d{}Fy z3;ZRu|KyUmLDxl?F4*q60MmC~JVh>x?@4b-Q^i*98@ zpkt5opH!XZ_@8R3zmX*8@~C40Q1k88XvuJPdH|w^{juc}a2|tgO##%2(um$$P4}&g zR;9%CSaPc=_4(*`vMma&o^1lKgJ2UOa(`HP>b61x$+dXpp|Og;bj@F?`b!n5FcA>_%yrj;F!m6+$#(eFKt9_3beKC^$8~71Ouk zom;@(40)US0ML`Vjol&aKnbWb;B2F!|Sntm;XUwwM(BCs~eU5(>y5hn2Fkj@S!ap{# z1jsejVyBC<^Wb8!BtH^KjN-e=@Fit~Xdo@jTV;l`SQ8f(%M7_<7?3r**l_$y8Gta0 zGv*L`8IBaTRoeVCLTRk8LhkY1+>Aa7%Q6rR~X+q?E=<2X)YJ6=0+el~6r6{vucl+skFlqhvoKy9fMwb@C8NZNGP zMnZ}p2#!4v&7FozC~CzeoVc_XZb-P2CBRapUMg`xtZ5Na55Rl7Hcbg)cIVso^UZtn z-p+hKanCWoNF;OuBlq2xEBCv$%zm2O8oNG9iA!94)m|%{FHj;8rtAReCNhI@zQ~H( zLtCw$2yqQoUV;Xzh%2bkq%SbjO`=Jzcs zv!d{&J{4EQafJ;lU>o*6<^k6{L!83yN%>`J(xx$2b4U;^)uj{SE$y~3iPkcLBMOoJ+!TnYdI^A^;n^g0TxbvOfYMB?u<9baT6<@G z4Qk*s;)B>Xv@BlK?Y<=$2%VvT@G;DXm&JSfL2=t0oR+JRj+c-P*_Cd|I})4{nBjmf zDGQDiZevzF)@?c>GREMCK{J%L9k~1mKr{BwHayIR+YI+;Epc|S%Jyt?4*aKJdanbt zdlMygxsjjVoNp-Ed+FQ_{Z6i)UbvfHXrveF*4{UV%I0eijO_M6{kcl4J zsX%LgHHOoezcaANpz?<3Qv1cxcwSaE6mc>BuBvQEw-j+x&xl{*nPTuijsu$?M0f_k zk;5X7pn;@QE?#<{W1o00KxjPqpSxV_G0`LgICzAO;ppotaeoT#P zEduZe!6&M!L7T3b53E-qLsMS!R@xPdkGhJBV_@W?0FL&bRi@D&oPc(7f}(;_@W2Iy zz_)3+Y?VFr*YRgx71X+};k|Gs#g6rZ+0;G0G_`gG*dEV{PrI}86X4}|efSJOQ(3>_ zRXHA+ro3LOa%>RCSbWcw1NCuq2Ex=<*%AIWs1&C6?Cu}klv?9;^3=O)_8g)!8a+*a zv<7@R5S$mC$9=`XJy}k-xxZ*uSegvf` b>B;*slt>3K%xMTy@g+1(iHE7P3O3_!(ppI5 diff --git a/src/equipment/__pycache__/service.cpython-311.pyc b/src/equipment/__pycache__/service.cpython-311.pyc index 778a0a25714e753e8ef97df2d74b4dde2ac6fe09..eb27d58228839c464f5760b590f89356f2b9874e 100644 GIT binary patch delta 4372 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 diff --git a/src/equipment/router.py b/src/equipment/router.py index 07a7340..83100ba 100644 --- a/src/equipment/router.py +++ b/src/equipment/router.py @@ -13,7 +13,7 @@ from .service import get_master_by_assetnum, get_by_id, get_all, create, update, from src.database.service import CommonParameters, search_filter_sort_paginate from src.database.core import DbSession -from src.auth.service import CurrentUser +from src.auth.service import CurrentUser, Token from src.models import StandardResponse router = APIRouter() @@ -78,10 +78,15 @@ async def get_equipment(db_session: DbSession, assetnum: str): @router.post("", response_model=StandardResponse[EquipmentCreate]) async def create_equipment( - db_session: DbSession, equipment_in: EquipmentCreate, current_user: CurrentUser + db_session: DbSession, + equipment_in: EquipmentCreate, + current_user: CurrentUser, + token: Token, ): equipment_in.created_by = current_user.name - equipment = await create(db_session=db_session, equipment_in=equipment_in) + equipment = await create( + db_session=db_session, equipment_in=equipment_in, token=token + ) return StandardResponse(data=equipment, message="Data created successfully") @@ -92,6 +97,7 @@ async def update_equipment( equipment_id: str, equipment_in: EquipmentUpdate, current_user: CurrentUser, + token: Token, ): equipment = await get_by_id(db_session=db_session, equipment_id=equipment_id) @@ -104,7 +110,10 @@ async def update_equipment( return StandardResponse( data=await update( - db_session=db_session, equipment=equipment, equipment_in=equipment_in + db_session=db_session, + equipment=equipment, + equipment_in=equipment_in, + token=token, ), message="Data updated successfully", ) diff --git a/src/equipment/service.py b/src/equipment/service.py index 5fac574..8b07e35 100644 --- a/src/equipment/service.py +++ b/src/equipment/service.py @@ -9,6 +9,7 @@ from typing import Optional from src.database.core import DbSession from src.auth.service import CurrentUser +import httpx async def get_master_by_assetnum( @@ -63,7 +64,14 @@ async def get_master_by_assetnum( ) min_seq = min_record[1] if min_record else None - return equipment_master_record, equipment_record, records, min_eac_value, min_seq, last_actual_year + return ( + equipment_master_record, + equipment_record, + records, + min_eac_value, + min_seq, + last_actual_year, + ) # return result.scalars().all() @@ -91,7 +99,9 @@ async def get_all( return result -async def generate_transaction(*, db_session: DbSession, data_in: EquipmentCreate): +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(MasterRecords) @@ -101,6 +111,23 @@ async def generate_transaction(*, db_session: DbSession, data_in: EquipmentCreat await db_session.execute(query) await db_session.commit() """Generate transaction for equipment.""" + + # Fetch data from external API + async def fetch_api_data(assetnum: str, year: int) -> dict: + async with httpx.AsyncClient() as client: + try: + response = await client.get( + f"http://192.168.1.82:8000/reliability/main/number-of-failures/{assetnum}/{year}/{year}", + timeout=30.0, + headers={"Authorization": f"Bearer {token}"}, + ) + response.raise_for_status() + return response.json() + except httpx.HTTPError as e: + print(f"HTTP error occurred: {e}") + return {} + + # Initialize base transaction with default values base_transaction = { "assetnum": data_in.assetnum, "is_actual": 0, @@ -142,10 +169,41 @@ async def generate_transaction(*, db_session: DbSession, data_in: EquipmentCreat transactions = [] + # Query existing records with is_actual=1 + actual_years_query = ( + Select(MasterRecords.tahun) + .filter(MasterRecords.assetnum == data_in.assetnum) + .filter(MasterRecords.is_actual == 1) + ) + result = await db_session.execute(actual_years_query) + actual_years = {row[0] for row in result.all()} + for sequence, year in enumerate( range(data_in.acquisition_year - 1, data_in.forecasting_target_year + 1), 0 ): + # Skip if year already has actual data + if year in actual_years: + continue + transaction = base_transaction.copy() + # Update values from API + api_data = await fetch_api_data(data_in.assetnum, year) + + if api_data: + # Get current num_fail + current_num_fail = api_data["data"][0]["num_fail"] + + # Calculate sum of previous failures for this asset + previous_failures_query = ( + Select(func.sum(MasterRecords.raw_cm_interval)) + .filter(MasterRecords.assetnum == data_in.assetnum) + .filter(MasterRecords.tahun < year) + ) + previous_failures_result = await db_session.execute(previous_failures_query) + previous_failures_sum = previous_failures_result.scalar() or 0 + + # Update with current minus sum of previous + transaction.update({"raw_cm_interval": current_num_fail - previous_failures_sum}) transaction.update({"tahun": int(year), "seq": int(sequence)}) transactions.append(MasterRecords(**transaction)) @@ -156,29 +214,34 @@ async def generate_transaction(*, db_session: DbSession, data_in: EquipmentCreat return len(transactions) -async def create(*, db_session: DbSession, equipment_in: EquipmentCreate): +async def create(*, db_session: DbSession, equipment_in: EquipmentCreate, token): """Creates a new document.""" equipment = Equipment(**equipment_in.model_dump()) db_session.add(equipment) await db_session.commit() - await generate_transaction(db_session=db_session, data_in=equipment_in) + await generate_transaction(db_session=db_session, data_in=equipment_in, token=token) return equipment async def update( - *, db_session: DbSession, equipment: Equipment, equipment_in: EquipmentUpdate + *, db_session: DbSession, equipment: Equipment, equipment_in: EquipmentUpdate, token ): """Updates a document.""" - data = equipment_in.model_dump() + data = equipment_in.model_dump() update_data = equipment_in.model_dump(exclude_defaults=True) - for field in data: if field in update_data: setattr(equipment, field, update_data[field]) 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 + ) + return equipment diff --git a/src/equipment_master/__pycache__/service.cpython-311.pyc b/src/equipment_master/__pycache__/service.cpython-311.pyc index d84d61678f9bab66e89e87ad9ef1b6943e20375e..cba13a1de9009ae83f9da58b5318f6b1b1c0aed3 100644 GIT binary patch delta 361 zcmcaBa!r(PIWI340}wbrTb0hmwvo?*nTrF+Z3g1ct0o69*D*#-KF=I8c_te#CmTp1 z2u%LZCN^1^MM9#Aoq=H)BLl-~AclZi)*99Y?2{SUMVLwiCx^0_G73-bW^rNUntXvp zm6Ic}xHz>WuQYe^7nWo$b)XhOATEA3Ig!;qf`ygqhJfgFo=H4+d1bEfDqiPRzr?G) zf_H@*5Ch>wUb8E_W?(th>%7{Rc(qsfZeUyC3xXGUt*-D|ePm|jwfV@*EXehR0Z4SP ze&Ax@7214}^(7;l2GF7+)yW6g)mROHO#RKT*(Dj-Ku#z!n9Ri~%V;rKgL7MeG^6kb z1{m=`K=K1Ch{MJpATfivr}hIoh{wUeD>@;#$M*v#h{wesDmx>1ith(*m^Op~A8aP; Hap?m9h%;T- delta 312 zcmca6dRK&RIWI340}zO?ccpJ+-N$McMph5T8v>%!c_#79 zjlUvmcwN@~lC1d--W_g041^bD-LA;GT@-M?BH-S^`hZ7pvlrV-MmBYz2}LTCEjiR! z^?^*C%_$s`j4B|ri$MG$IS?TRB1C}1FAkgB{FKt1RJ$Vc$qPBR1xPRoe_((S4+JDX zu!1;j3<44}n0snJu!DFU47{Qff_r>FaDsST45G3#f~WX?;D%{K81TVt@^UVH07o-S AUH||9 diff --git a/src/equipment_master/service.py b/src/equipment_master/service.py index 8c50001..69a6864 100644 --- a/src/equipment_master/service.py +++ b/src/equipment_master/service.py @@ -29,7 +29,10 @@ async def get_all_master( query = query.filter(EquipmentMaster.parent_id == parent_id) if search: - query = query.filter(EquipmentMaster.name.ilike(f"%{search}%")) + query = query.filter( + (EquipmentMaster.name.ilike(f"%{search}%")) | + (EquipmentMaster.assetnum.ilike(f"%{search}%")) + ) query = query.options(recursive_load(5)) diff --git a/src/exceptions.py b/src/exceptions.py index 1694d00..769acc0 100644 --- a/src/exceptions.py +++ b/src/exceptions.py @@ -143,21 +143,32 @@ def handle_exception(request: Request, exc: Exception): ) # Log unexpected errors + error_message = f"{exc.__class__.__name__}: {str(exc)}" + error_traceback = getattr(exc, '__traceback__', None) + + # Get file and line info if available + if error_traceback: + tb = error_traceback + while tb.tb_next: + tb = tb.tb_next + file_name = tb.tb_frame.f_code.co_filename + line_num = tb.tb_lineno + error_message = f"{error_message}\nFile {file_name}, line {line_num}" + logging.error( - f"Unexpected Error | Error: {str(exc)} | Request: {request_info}", + f"Unexpected Error | Error: {error_message} | Request: {request_info}", extra={"error_category": "unexpected"}, ) - return JSONResponse( status_code=500, content={ "data": None, - "message": exc.__class__.__name__, + "message": error_message, "status": ResponseStatus.ERROR, "errors": [ ErrorDetail( - message="An unexpected error occurred." + message=error_message ).model_dump() ] }