Commit 0b8c92d9 authored by harshavardhan.c's avatar harshavardhan.c

service modification fixes for displaying the oee.

parent f85e10e2
import pandas as pd
from scripts.schemas.batch_oee import ChartResponse, ChartDBResponse
from scripts.utils.common_utils import CommonUtils
def processor(data):
db_response = ChartDBResponse(**data)
db_response.total_time = (
db_response.batch_end_time - db_response.batch_start_time
) / 60000
db_response.actual_cycle = round(
db_response.total_units / db_response.total_time, 2
)
db_response.ideal_cycle = round(db_response.cycle_time, 2)
db_response.good_units = round(
db_response.total_units - db_response.reject_units, 2
)
class OEEAggregator:
def __init__(self):
self.common_util = CommonUtils()
chart_response = ChartResponse(**db_response.dict())
return chart_response.dict()
def processor(self, data):
db_response = ChartDBResponse(**data)
duration = self.common_util.get_duration(meta=data, difference=True, tz=data["tz"])
cal_type = self.common_util.get_uom_type(uom_type=data["uom"])
db_response.total_time = self.common_util.get_diff_duration_in_int(input_time=duration, return_type=cal_type)
db_response.actual_cycle = round(
db_response.total_units / db_response.total_time, 2
)
db_response.ideal_cycle = round(db_response.cycle_time, 2)
db_response.good_units = round(
db_response.total_units - db_response.reject_units, 2
)
chart_response = ChartResponse(**db_response.dict())
return chart_response.dict()
def aggregator(data, activity_length=1):
df = pd.DataFrame(data)
df["total_time"] = (df["batch_end_time"] - df["batch_start_time"]) / 60000
df["actual_cycle"] = df["total_units"] / df["total_time"]
df["ideal_cycle"] = df["cycle_time"]
df["good_units"] = df["total_units"] - df["reject_units"]
df["reject_time"] = df["reject_units"] * (1 / df["ideal_cycle"])
agg_oee = df.sum().round(2)
availability = (agg_oee["total_time"] - agg_oee["downtime"]) / agg_oee["total_time"]
performance = agg_oee["productive_time"] / (
agg_oee["total_time"] - agg_oee["downtime"]
)
quality = (agg_oee["total_units"] - agg_oee["reject_units"]) / agg_oee[
"total_units"
]
oee_overall = round(availability * performance * quality, 2) * 100
availability_loss = agg_oee["downtime"] / agg_oee["total_time"] * 100
quality_loss = agg_oee["reject_time"] / agg_oee["total_time"] * 100
chart_response = ChartResponse(
total_units=round(agg_oee["total_units"] - (len(df) * activity_length)),
reject_units=agg_oee["reject_units"],
oee=oee_overall,
availability=round(availability * 100, 2),
downtime=agg_oee["downtime"],
performance=round(performance * 100, 2),
quality=round(quality * 100, 2),
actual_cycle=agg_oee["actual_cycle"],
ideal_cycle=agg_oee["ideal_cycle"],
good_units=round(agg_oee["good_units"] - (len(df) * activity_length)),
availability_loss=availability_loss,
quality_loss=quality_loss,
performance_loss=round(100 - availability_loss - quality_loss - oee_overall, 2),
total_time=agg_oee["total_time"],
productive_time=agg_oee["productive_time"],
)
filtered = chart_response.dict()
remove_keys = ["productive_time", "downtime", "reject_units"]
[filtered.pop(each, None) for each in remove_keys]
return filtered
@staticmethod
def aggregator(data, activity_length=1):
df = pd.DataFrame(data)
df["total_time"] = (df["batch_end_time"] - df["batch_start_time"]) / 60000
df["actual_cycle"] = df["total_units"] / df["total_time"]
df["ideal_cycle"] = df["cycle_time"]
df["good_units"] = df["total_units"] - df["reject_units"]
df["reject_time"] = df["reject_units"] * (1 / df["ideal_cycle"])
agg_oee = df.sum().round(2)
availability = (agg_oee["total_time"] - agg_oee["downtime"]) / agg_oee["total_time"]
performance = agg_oee["productive_time"] / (
agg_oee["total_time"] - agg_oee["downtime"]
)
quality = (agg_oee["total_units"] - agg_oee["reject_units"]) / agg_oee[
"total_units"
]
oee_overall = round(availability * performance * quality, 2) * 100
availability_loss = agg_oee["downtime"] / agg_oee["total_time"] * 100
quality_loss = agg_oee["reject_time"] / agg_oee["total_time"] * 100
chart_response = ChartResponse(
total_units=round(agg_oee["total_units"] - (len(df) * activity_length)),
reject_units=agg_oee["reject_units"],
oee=oee_overall,
availability=round(availability * 100, 2),
downtime=agg_oee["downtime"],
performance=round(performance * 100, 2),
quality=round(quality * 100, 2),
actual_cycle=agg_oee["actual_cycle"],
ideal_cycle=agg_oee["ideal_cycle"],
good_units=round(agg_oee["good_units"] - (len(df) * activity_length)),
availability_loss=availability_loss,
quality_loss=quality_loss,
performance_loss=round(100 - availability_loss - quality_loss - oee_overall, 2),
total_time=agg_oee["total_time"],
productive_time=agg_oee["productive_time"],
)
filtered = chart_response.dict()
remove_keys = ["productive_time", "downtime", "reject_units"]
[filtered.pop(each, None) for each in remove_keys]
return filtered
from datetime import datetime
import pendulum
import pytz
from scripts.constants import UOM, TagCategoryConstants
from scripts.constants import TagCategoryConstants
from scripts.errors import ErrorCodes
from scripts.logging import logger
from scripts.schemas.batch_oee import OEEDataSaveRequest, BatchOEEData
......@@ -120,25 +119,11 @@ class OEEEngine:
logger.debug(f"Calculating OEE for {request_data.reference_id}")
# Start and End time should be in milliseconds since epoch.
if request_data.uom == UOM.minutes:
divisor = UOM.time_divs.minutes
cal_type = "minutes"
elif request_data.uom == UOM.seconds:
divisor = UOM.time_divs.seconds
cal_type = "seconds"
elif request_data.uom == UOM.hours:
divisor = UOM.time_divs.hours
cal_type = "hours"
elif request_data.uom == UOM.millis:
divisor = UOM.time_divs.millis
cal_type = "microseconds"
else:
divisor = UOM.time_divs.minutes
cal_type = "minutes"
cal_type = self.common_util.get_uom_type(uom_type=request_data.uom)
duration = self.common_util.get_duration(tz=request_data.tz, meta=request_data.dict(),
difference=True)
planned_production_time = self.get_updated_planned_production_time(
planned_production_time = self.common_util.get_diff_duration_in_int(
input_time=duration, return_type=cal_type)
# operating time is production time
production_time = planned_production_time - request_data.downtime
......@@ -219,16 +204,3 @@ class OEEEngine:
except Exception as e:
logger.exception(f"Exception occurred while calculating batch oee {e.args}")
raise
@staticmethod
def get_updated_planned_production_time(input_time: pendulum.Duration, return_type):
if return_type == "minutes":
return input_time.in_minutes()
elif return_type == "seconds":
return input_time.in_seconds()
elif return_type == "hours":
return input_time.in_hours()
elif return_type == "microseconds":
return input_time.total_seconds()
else:
return input_time.in_minutes()
import time
from datetime import datetime
import pytz
from sqlalchemy.orm import Session
from scripts.core.engine.chart_creators import ChartMaker
from scripts.core.engine.oee_aggregator import processor, aggregator
from scripts.core.engine.oee_aggregator import OEEAggregator
from scripts.db.psql.oee_discrete import DiscreteOEE
from scripts.logging import logger
from scripts.schemas.batch_oee import (
GetOEERequest,
GetOEERequestOneBatch,
GetBatches,
GetProducts,
BatchesGet,
ChartRequest,
)
from scripts.schemas.meta import LabelValue
class APIHandler:
def __init__(self):
self.oee_agg = OEEAggregator()
@staticmethod
def get_oee_all(db: Session, get_oee_request: GetOEERequest):
table_obj = DiscreteOEE(db=db)
......@@ -58,21 +64,23 @@ class APIHandler:
raise
@staticmethod
async def get_products(db: Session, request_data: GetProducts):
async def get_batches_info(db: Session, request_data: BatchesGet):
table_obj = DiscreteOEE(db=db)
try:
data = table_obj.get_products(
data = table_obj.get_batches_info(
hierarchy=request_data.hierarchy,
prod_start_time=request_data.queryDate[0],
prod_end_time=request_data.queryDate[1],
prod_start_time=datetime.fromtimestamp(request_data.queryDate[0] / 1000).astimezone(
tz=pytz.timezone(request_data.tz)).isoformat(),
prod_end_time=datetime.fromtimestamp(request_data.queryDate[-1] / 1000).astimezone(
tz=pytz.timezone(request_data.tz)).isoformat(), tz=request_data.tz
)
return [
LabelValue(
label=each[0], value=each[0], start_time=each[1], end_time=each[2]
) if isinstance(each, list) else LabelValue(
label=each['batch_id'], value=each['batch_id'],
start_time=each['batch_start_time'], end_time=each['batch_end_time']
label=each['reference_id'], value=each['reference_id'],
start_time=each['prod_start_time'], end_time=each['prod_end_time']
)
for each in data
......@@ -81,8 +89,7 @@ class APIHandler:
logger.exception(e, exc_info=True)
raise
@staticmethod
async def get_chart_data(db: Session, request_data: ChartRequest):
async def get_chart_data(self, db: Session, request_data: ChartRequest):
table_obj = DiscreteOEE(db=db)
try:
if not request_data.hierarchy:
......@@ -92,18 +99,19 @@ class APIHandler:
hierarchy=request_data.hierarchy,
prod_start_time=request_data.queryDate[0],
prod_end_time=request_data.queryDate[1],
reference_id=request_data.productId,
reference_id=request_data.reference_id,
aggregation=request_data.aggregation,
tz=request_data.tz
)
if not request_data.aggregation or len(data) == 1:
if isinstance(data, list):
data = data[0]
raw_data = processor(data)
raw_data = self.oee_agg.processor(data)
return chart_maker.main_creator(raw_data, overall=False)
elif len(data) == 0:
return dict()
else:
agg_data = aggregator(data)
agg_data = self.oee_agg.aggregator(data)
return chart_maker.main_creator(agg_data)
except Exception as e:
......
......@@ -56,15 +56,16 @@ class CalculateBatchOEEHandler:
hierarchy=request_data.hierarchy, project_id=request_data.project_id)
oee_calculation = oee_engine.start_batch_oee_calc(request_data=request_data)
self.save_oee_data(oee_calculation, db)
oee_production_db.set(name=redis_key,
value=json.dumps(BatchOEEData(**request_data.dict(exclude_none=True))))
if not request_data.prod_end_time:
oee_production_db.set(name=redis_key,
value=json.dumps(BatchOEEData(**request_data.dict(exclude_none=True))))
response = DefaultResponse(
status=ResponseCodes.SUCCESS,
data=oee_calculation,
message="OEE saved Successfully",
)
return response
status = self.update_oee_data(oee_data=BatchOEEData(**request_data.dict(exclude_none=True)),
status = self.update_oee_data(oee_data=OEEDataSaveRequest(**request_data.dict(exclude_none=True)),
old_record=record_presence, db=db)
if status:
if request_data.prod_end_time:
......@@ -92,7 +93,7 @@ class CalculateBatchOEEHandler:
raise e
@staticmethod
def update_oee_data(oee_data: BatchOEEData, old_record: dict, db: Session):
def update_oee_data(oee_data: OEEDataSaveRequest, old_record: dict, db: Session):
table_obj = DiscreteOEE(db=db)
try:
old_record.update(**oee_data.dict(exclude_none=True))
......
from fastapi.encoders import jsonable_encoder
from sqlalchemy import func
from sqlalchemy.orm import Session, defer
from scripts.db.db_models import OEEDiscreteTable
......@@ -70,19 +71,21 @@ class DiscreteOEE(SQLDBUtils):
logger.exception(e)
raise
def get_products(self, hierarchy, prod_start_time, prod_end_time):
def get_batches_info(self, hierarchy, prod_start_time, prod_end_time, tz):
try:
data = (
self.session.query(
self.table.batch_id,
self.table.batch_start_time,
self.table.batch_end_time,
self.table.reference_id,
# func.to_char(func.timezone(tz, self.table.prod_start_time), "DD-MM-YYYY HH24:MI").label(
# self.table.prod_start_time.key),
func.timezone(tz, self.table.prod_end_time).label(self.table.prod_end_time.key),
func.timezone(tz, self.table.prod_start_time).label(self.table.prod_start_time.key),
)
.order_by(self.table.calculated_on)
.filter(
self.table.hierarchy == hierarchy,
self.table.batch_start_time >= prod_start_time,
self.table.batch_end_time <= prod_end_time,
self.table.prod_start_time >= prod_start_time,
self.table.prod_end_time <= prod_end_time,
)
)
if data:
......@@ -94,7 +97,7 @@ class DiscreteOEE(SQLDBUtils):
raise
def get_chart_data(
self, prod_start_time, prod_end_time, hierarchy, reference_id, aggregation=False
self, prod_start_time, prod_end_time, hierarchy, reference_id, tz, aggregation=False
):
try:
if not aggregation:
......
......@@ -7,10 +7,26 @@ from scripts.utils.common_utils import CommonUtils
common_utils = CommonUtils()
class GetProducts(BaseModel):
class BatchesGet(BaseModel):
queryDate: List[int]
hierarchy: str
project_id: Optional[str]
tz: Optional[str] = "Asia/Kolkata"
class Config:
schema_extra = {
"example": {
"site_id": "site_100",
"hierarchy": "site_100$dept_100$line_100$equipment_100",
"queryDate": [
1653503456000,
1653935456000
],
"project_id": "project_099",
"tz": "Asia/Kolkata",
"language": "en"
}
}
class WaterFallChart(BaseModel):
......@@ -26,10 +42,27 @@ class WaterFallChart(BaseModel):
class ChartRequest(BaseModel):
project_id: str
queryDate: List[int]
queryDate: List[str]
hierarchy: Optional[str]
productId: Optional[str]
reference_id: Optional[str]
aggregation: Optional[bool] = False
tz: Optional[str] = "Asia/kolkata"
class Config:
schema_extra = {
"example": {
"site_id": "site_100",
"hierarchy": "site_100$dept_100$line_100$equipment_100",
"queryDate": [
"2022-05-26T19:49:00",
"2022-05-30T19:49:00"
],
"project_id": "project_099",
"tz": "Asia/Kolkata",
"language": "en",
"reference_id": "reference_123"
}
}
class ChartDBResponse(BaseModel):
......@@ -44,18 +77,21 @@ class ChartDBResponse(BaseModel):
availability_loss: float
quality_loss: float
cycle_time: float
batch_start_time: int
batch_end_time: int
prod_start_time: str
prod_end_time: str
good_units: Optional[float]
actual_cycle: Optional[float]
ideal_cycle: Optional[float]
total_time: Optional[float]
productive_time: int
downtime: int
tz: Optional[str] = "Asia/Kolkata"
@validator("*")
def round_float(cls, v):
return round(v, 2)
if isinstance(v, float) or isinstance(v, int):
return round(v, 2)
return v
class ChartResponse(BaseModel):
......
......@@ -14,5 +14,5 @@ class GetHierarchyRequest(BaseModel):
class LabelValue(BaseModel):
label: str
value: str
start_time: int
end_time: int
start_time: Union[int, str]
end_time: Union[int, str]
from fastapi import APIRouter
from scripts.services.calculate_oee import calc_oee_router
# from scripts.services.ui_services import ui_service_router
from scripts.services.ui_services import ui_service_router
route = APIRouter()
route.include_router(calc_oee_router)
# route.include_router(ui_service_router)
route.include_router(ui_service_router)
......@@ -5,24 +5,24 @@ from sqlalchemy.orm import Session
from scripts.constants import Endpoints, ResponseCodes
from scripts.core.handlers.api_handler import APIHandler
from scripts.core.handlers.layout_handler import LayoutHandler
# from scripts.core.handlers.layout_handler import LayoutHandler
from scripts.db.psql.databases import get_db
from scripts.logging import logger
from scripts.schemas.batch_oee import GetProducts, ChartRequest
from scripts.schemas.layout import GetLayoutRequest, SaveLayoutRequest
from scripts.schemas.batch_oee import BatchesGet, ChartRequest
# from scripts.schemas.layout import GetLayoutRequest, SaveLayoutRequest
from scripts.schemas.response_models import DefaultFailureResponse, DefaultResponse
from scripts.errors import ILensError
api_handler = APIHandler()
layout_handler = LayoutHandler()
# layout_handler = LayoutHandler()
ui_service_router = APIRouter(prefix=Endpoints.api_batches, tags=["UI Services"])
@ui_service_router.post(Endpoints.api_get)
async def get_all_products(request_data: GetProducts, db: Session = Depends(get_db)):
async def get_all_batches(request_data: BatchesGet, db: Session = Depends(get_db)):
try:
data = await api_handler.get_products(request_data=request_data, db=db)
data = await api_handler.get_batches_info(request_data=request_data, db=db)
return DefaultResponse(
data=data,
status=ResponseCodes.SUCCESS,
......@@ -53,34 +53,34 @@ async def get_chart_data(request_data: ChartRequest, db: Session = Depends(get_d
return DefaultFailureResponse(error=e.args)
@ui_service_router.post(Endpoints.get_layout)
async def get_layout(request_data: GetLayoutRequest):
try:
data = await layout_handler.fetch_layout(layout_request=request_data)
return DefaultResponse(
data=data,
status=ResponseCodes.SUCCESS,
message="Layout fetched successfully",
)
except Exception as e:
tb = traceback.format_exc()
logger.exception(e)
logger.exception(tb)
return DefaultFailureResponse(error=e.args)
@ui_service_router.post(Endpoints.save_layout)
async def save_layout(request_data: SaveLayoutRequest):
try:
data = await layout_handler.save_layout(layout_request=request_data)
return DefaultResponse(
data=data, status=ResponseCodes.SUCCESS, message="Layout saved successfully"
)
except Exception as e:
tb = traceback.format_exc()
logger.exception(e)
logger.exception(tb)
return DefaultFailureResponse(error=e.args)
# @ui_service_router.post(Endpoints.get_layout)
# async def get_layout(request_data: GetLayoutRequest):
# try:
# data = await layout_handler.fetch_layout(layout_request=request_data)
# return DefaultResponse(
# data=data,
# status=ResponseCodes.SUCCESS,
# message="Layout fetched successfully",
# )
# except Exception as e:
# tb = traceback.format_exc()
# logger.exception(e)
# logger.exception(tb)
# return DefaultFailureResponse(error=e.args)
#
#
# @ui_service_router.post(Endpoints.save_layout)
# async def save_layout(request_data: SaveLayoutRequest):
# try:
# data = await layout_handler.save_layout(layout_request=request_data)
# return DefaultResponse(
# data=data, status=ResponseCodes.SUCCESS, message="Layout saved successfully"
# )
# except Exception as e:
# tb = traceback.format_exc()
# logger.exception(e)
# logger.exception(tb)
# return DefaultFailureResponse(error=e.args)
# -------------Code Demo Backup----------------#
......
......@@ -5,7 +5,7 @@ import pytz
import shortuuid
from scripts.config import PathToServices
from scripts.constants import Secrets, EndpointConstants
from scripts.constants import Secrets, EndpointConstants, UOM
from scripts.db.redis_connections import project_details_db
from scripts.logging import logger
from scripts.utils.auth_util import ILensRequest, AuthenticationError
......@@ -113,3 +113,35 @@ class CommonUtils:
db_splitting_enabled = get_db_name(project_id=project_id,
database=metric, redis_client=project_details_db)
return db_splitting_enabled
@staticmethod
def get_diff_duration_in_int(input_time: pendulum.Duration, return_type):
if return_type == "minutes":
return input_time.in_minutes()
elif return_type == "seconds":
return input_time.in_seconds()
elif return_type == "hours":
return input_time.in_hours()
elif return_type == "microseconds":
return input_time.total_seconds()
else:
return input_time.in_minutes()
@staticmethod
def get_uom_type(uom_type):
if uom_type == UOM.minutes:
divisor = UOM.time_divs.minutes
cal_type = "minutes"
elif uom_type == UOM.seconds:
divisor = UOM.time_divs.seconds
cal_type = "seconds"
elif uom_type == UOM.hours:
divisor = UOM.time_divs.hours
cal_type = "hours"
elif uom_type == UOM.millis:
divisor = UOM.time_divs.millis
cal_type = "microseconds"
else:
divisor = UOM.time_divs.minutes
cal_type = "minutes"
return cal_type
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment