refactor: equipment transaction data & add search by assetnum equipment master

main
MrWaradana 11 months ago
parent 5c2cf398ca
commit be8a6390a6

@ -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)]

@ -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",
)

@ -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

@ -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))

@ -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()
]
}

Loading…
Cancel
Save