diff --git a/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql b/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql
index 0e49bb4..3eb35ec 100644
--- a/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql
+++ b/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql
@@ -1 +1,408 @@
-âÅã@×ÁãÈ@\ÓÉÂÓ@^@
%
%ÃÙÅÁãÅ@ÖÙ@ÙÅ×ÓÁÃÅ@ÆäÕÃãÉÖÕ@ÙÅâãÁ×ÉKâÆ×mÇÅãmÖÅÅmÄÅãÁÉÓâ@M@
%ÉÕm×ÁÙÔ@ÃÓÖÂMòñô÷ôøóöô÷]@]@
%ÙÅãäÙÕâ@ÃÓÖÂMòñô÷ôøóöô÷]@@@
%ÓÁÕÇäÁÇÅ@âØÓ@
%â×ÅÃÉÆÉÃ@ÙÅâãÁ×ÉKâÆ×mÇÅãmÖÅÅmÄÅãÁÉÓâ@
%ÕÖã@ÄÅãÅÙÔÉÕÉâãÉÃ@
%ÔÖÄÉÆÉÅâ@âØÓ@ÄÁãÁ@
%ÃÁÓÓÅÄ@ÖÕ@ÕäÓÓ@ÉÕ×äã@
%âÅã@Ö×ãÉÖÕ@@ÁÓæÂÓÒ@~@\ÁÓÓÙÅÁÄ@k@
%ÁÓæÃ×èÄãÁ@~@\Ö×ãÉÔÉéÅ@k@
%ÃÖÔÔÉã@~@\ÕÖÕÅ@k@
%ÄÅÃÙÅâäÓã@~@Móñk@óñk@ðð]@k@
%ÄèÕÄÆãÃÖÓ@~@\ÕÖ@k@
%ÄèÕäâÙ×ÙÆ@~@\äâÅÙ@k@
%âÙãâÅØ@~@\ÈÅç@@@
%ÂÅÇÉÕ@
%ÄÅÃÓÁÙÅ@ÅÕå@åÁÙÃÈÁÙ@M@òð@]@ÄÅÆÁäÓã@}}@^@
%ÄÅÃÓÁÙÅ@ÓÓ@åÁÙÃÈÁÙ@M@ñðòô@]@ÄÅÆÁäÓã@}}@^@
%``@Å™™–™@ˆ�•„“‰•‡@¥�™‰�‚“…¢@
%ÄÅÃÓÁÙÅ@åmâØÓâãÁãÅ@ÃÈÁÙ@M@õ@]@ÄÅÆÁäÓã@}ððððð}@^@
%ÄÅÃÓÁÙÅ@åmâØÓÃÖÄÅ@ÉÕãÅÇÅÙ@ÄÅÆÁäÓã@ð@^@
%ÄÅÃÓÁÙÅ@åmÅÙÙÔâÇ@åÁÙÃÈÁÙ@M@õðð@]@ÄÅÆÁäÓã@}}@^@
%ÄÅÃÓÁÙÅ@åmÈãã×mâãÁãäâ@ÉÕãÅÇÅÙ@ÄÅÆÁäÓã@òðð@^@
%ÄÅÃÓÁÙÅ@åmÈÁâmÅÙÙÖÙ@ÉÕãÅÇÅÙ@ÄÅÆÁäÓã@ð@^@
%``@Ã–•£‰•¤…@ˆ�•„“…™¢@†–™@…™™–™@ƒ�—£¤™…@
%ÄÅÃÓÁÙÅ@ÃÖÕãÉÕäÅ@ÈÁÕÄÓÅÙ@ÆÖÙ@âØÓâãÁãÅ@}òòðð÷}@@``@É•¥�“‰„@„�£…£‰”…@
%ÂÅÇÉÕ@
%âÅã@åmâØÓâãÁãÅ@~@}òòðð÷}@^@
%ÇÅã@ÄÉÁÇÕÖâãÉÃâ@ÃÖÕÄÉãÉÖÕ@ñ@åmÅÙÙÔâÇ@~@ÔÅââÁÇÅmãÅçã@^@
%âÅã@åmÈãã×mâãÁãäâ@~@ôðð@^@
%âÅã@åmÈÁâmÅÙÙÖÙ@~@ñ@^@
%ÅÕÄ@^@
%ÄÅÃÓÁÙÅ@ÃÖÕãÉÕäÅ@ÈÁÕÄÓÅÙ@ÆÖÙ@âØÓâãÁãÅ@}òòððó}@@``@Õ¤”…™‰ƒ@–¤£@–†@™�•‡…@
%ÂÅÇÉÕ@
%âÅã@åmâØÓâãÁãÅ@~@}òòððó}@^@
%ÇÅã@ÄÉÁÇÕÖâãÉÃâ@ÃÖÕÄÉãÉÖÕ@ñ@åmÅÙÙÔâÇ@~@ÔÅââÁÇÅmãÅçã@^@
%âÅã@åmÈãã×mâãÁãäâ@~@ôðð@^@
%âÅã@åmÈÁâmÅÙÙÖÙ@~@ñ@^@
%ÅÕÄ@^@
%ÄÅÃÓÁÙÅ@ÃÖÕãÉÕäÅ@ÈÁÕÄÓÅÙ@ÆÖÙ@âØÓâãÁãÅ@}ðòððð}@@``@Õ–@„�£�@†–¤•„@
%ÂÅÇÉÕ@
%âÅã@åmâØÓâãÁãÅ@~@}ðòððð}@^@
%âÅã@åmÅÙÙÔâÇ@~@}Õ–@„�£�@†–¤•„@†–™@£ˆ…@¢—…ƒ‰†‰…„@ƒ™‰£…™‰�}@^@
%âÅã@åmÈãã×mâãÁãäâ@~@ôðô@^@
%âÅã@åmÈÁâmÅÙÙÖÙ@~@ñ@^@
%ÅÕÄ@^@
%ÄÅÃÓÁÙÅ@ÃÖÕãÉÕäÅ@ÈÁÕÄÓÅÙ@ÆÖÙ@âØÓâãÁãÅ@}ôòõðñ}@@``@Õ–£@�¤£ˆ–™‰©…„@
%ÂÅÇÉÕ@
%âÅã@åmâØÓâãÁãÅ@~@}ôòõðñ}@^@
%ÇÅã@ÄÉÁÇÕÖâãÉÃâ@ÃÖÕÄÉãÉÖÕ@ñ@åmÅÙÙÔâÇ@~@ÔÅââÁÇÅmãÅçã@^@
%âÅã@åmÈãã×mâãÁãäâ@~@ôðó@^@
%âÅã@åmÈÁâmÅÙÙÖÙ@~@ñ@^@
%ÅÕÄ@^@
%ÄÅÃÓÁÙÅ@ÃÖÕãÉÕäÅ@ÈÁÕÄÓÅÙ@ÆÖÙ@âØÓâãÁãÅ@}ôò÷ðô}@@``@Ö‚‘…ƒ£@•–£@†–¤•„@
%ÂÅÇÉÕ@
%âÅã@åmâØÓâãÁãÅ@~@}ôò÷ðô}@^@
%ÇÅã@ÄÉÁÇÕÖâãÉÃâ@ÃÖÕÄÉãÉÖÕ@ñ@åmÅÙÙÔâÇ@~@ÔÅââÁÇÅmãÅçã@^@
%âÅã@åmÈãã×mâãÁãäâ@~@ôðô@^@
%âÅã@åmÈÁâmÅÙÙÖÙ@~@ñ@^@
%ÅÕÄ@^@
%ÄÅÃÓÁÙÅ@ÃÖÕãÉÕäÅ@ÈÁÕÄÓÅÙ@ÆÖÙ@âØÓÅçÃÅ×ãÉÖÕ@
%ÂÅÇÉÕ@
%ÇÅã@ÄÉÁÇÕÖâãÉÃâ@ÃÖÕÄÉãÉÖÕ@ñ@
%åmâØÓâãÁãÅ@~@ÙÅãäÙÕÅÄmâØÓâãÁãÅ@k@
%åmâØÓÃÖÄÅ@~@ÄÂòmÙÅãäÙÕÅÄmâØÓÃÖÄÅ@k@åmÅÙÙÔâÇ@~@ÔÅââÁÇÅmãÅçã@^@
%âÅã@åmÈãã×mâãÁãäâ@~@õðð@^@
%âÅã@åmÈÁâmÅÙÙÖÙ@~@ñ@^@
%ÅÕÄ@^@
%æÈÉÓÅ@ÃÉâãÖÖÓâ@K@ÑâÖÕmãè×Å@M@ÉÕm×ÁÙÔ@]@ÉÕ@M@}–‚‘…ƒ£}@k@}�™™�¨}@k@}¢£™‰•‡}@]@ÄÖâÅã@ÉÕm×ÁÙÔ@~@
%ÃÁâÅ@ÃÉâãÖÖÓâ@K@ÑâÖÕmãè×Å@M@ÉÕm×ÁÙÔ@]@
%æÈÅÕ@}–‚‘…ƒ£}@ãÈÅÕ@ÑâÖÕmåÁÓäÅ@M@ÉÕm×ÁÙÔ@k@}[K…•¥}@]@
%æÈÅÕ@}�™™�¨}@ãÈÅÕ@ÑâÖÕmåÁÓäÅ@M@ÉÕm×ÁÙÔ@k@}[ºð»}@]@
%æÈÅÕ@}¢£™‰•‡}@ãÈÅÕ@ÙÅ×ÓÁÃÅ@M@ÉÕm×ÁÙÔ@k@}}@k@}}@]@
%ÅÓâÅ@ãÙÉÔ@M@ÉÕm×ÁÙÔ@]@
%ÅÕÄ@^@
%ÅÕÄ@æÈÉÓÅ@^@
%âÅã@ÅÕå@~@ÉÕm×ÁÙÔ@^@
%âÅã@ÓÓ@~@ÃÉâãÖÖÓâ@K@âÅãmÓÉÂÙÁÙèmÓÉâã@M@ÅÕå@]@^@
%``@å�“‰„�£…@…•¥‰™–•”…•£@¦�¢@¢…£@
%ÉÆ@ÅÕå@~@}}@
%ÖÙ@ÅÕå@Éâ@ÕäÓÓ@ãÈÅÕ@
%ÙÅãäÙÕ@
%ÑâÖÕmÖÂÑÅÃã@M@
%}…™™–™}@z@ÑâÖÕmÖÂÑÅÃã@M@
%}ˆ££—m¢£�£¤¢}@z@ôðð
\ No newline at end of file
+SET PATH *LIBL ; 
+
+CREATE OR REPLACE FUNCTION RESTAPI.SFP_GET_OEE_DETAILS ( 
+	IN_PARM CLOB(2147483647) ) 
+	RETURNS CLOB(2147483647)   
+	LANGUAGE SQL 
+	SPECIFIC RESTAPI.SFP_GET_OEE_DETAILS 
+	NOT DETERMINISTIC 
+	MODIFIES SQL DATA 
+	CALLED ON NULL INPUT 
+	SET OPTION  ALWBLK = *ALLREAD , 
+	ALWCPYDTA = *OPTIMIZE , 
+	COMMIT = *NONE , 
+	DECRESULT = (31, 31, 00) , 
+	DYNDFTCOL = *NO , 
+	DYNUSRPRF = *USER , 
+	SRTSEQ = *HEX   
+	BEGIN 
+DECLARE ENV VARCHAR ( 20 ) DEFAULT '' ; 
+DECLARE LL VARCHAR ( 1024 ) DEFAULT '' ; 
+-- Error handling variables 
+DECLARE V_SQLSTATE CHAR ( 5 ) DEFAULT '00000' ; 
+DECLARE V_SQLCODE INTEGER DEFAULT 0 ; 
+DECLARE V_ERRMSG VARCHAR ( 500 ) DEFAULT '' ; 
+DECLARE V_HTTP_STATUS INTEGER DEFAULT 200 ; 
+DECLARE V_HAS_ERROR INTEGER DEFAULT 0 ; 
+-- Continue handlers for error capture 
+DECLARE CONTINUE HANDLER FOR SQLSTATE '22007'  -- Invalid datetime 
+BEGIN 
+SET V_SQLSTATE = '22007' ; 
+GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; 
+SET V_HTTP_STATUS = 400 ; 
+SET V_HAS_ERROR = 1 ; 
+END ; 
+DECLARE CONTINUE HANDLER FOR SQLSTATE '22003'  -- Numeric out of range 
+BEGIN 
+SET V_SQLSTATE = '22003' ; 
+GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; 
+SET V_HTTP_STATUS = 400 ; 
+SET V_HAS_ERROR = 1 ; 
+END ; 
+DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'  -- No data found 
+BEGIN 
+SET V_SQLSTATE = '02000' ; 
+SET V_ERRMSG = 'No data found for the specified criteria' ; 
+SET V_HTTP_STATUS = 404 ; 
+SET V_HAS_ERROR = 1 ; 
+END ; 
+DECLARE CONTINUE HANDLER FOR SQLSTATE '42501'  -- Not authorized 
+BEGIN 
+SET V_SQLSTATE = '42501' ; 
+GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; 
+SET V_HTTP_STATUS = 403 ; 
+SET V_HAS_ERROR = 1 ; 
+END ; 
+DECLARE CONTINUE HANDLER FOR SQLSTATE '42704'  -- Object not found 
+BEGIN 
+SET V_SQLSTATE = '42704' ; 
+GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; 
+SET V_HTTP_STATUS = 404 ; 
+SET V_HAS_ERROR = 1 ; 
+END ; 
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 
+BEGIN 
+GET DIAGNOSTICS CONDITION 1 
+V_SQLSTATE = RETURNED_SQLSTATE , 
+V_SQLCODE = DB2_RETURNED_SQLCODE , V_ERRMSG = MESSAGE_TEXT ; 
+SET V_HTTP_STATUS = 500 ; 
+SET V_HAS_ERROR = 1 ; 
+END ; 
+WHILE CISTOOLS . JSON_TYPE ( IN_PARM ) IN ( 'object' , 'array' , 'string' ) DOSET IN_PARM = 
+CASE CISTOOLS . JSON_TYPE ( IN_PARM ) 
+WHEN 'object' THEN JSON_VALUE ( IN_PARM , '$.env' ) 
+WHEN 'array' THEN JSON_VALUE ( IN_PARM , '$[0]' ) 
+WHEN 'string' THEN REPLACE ( IN_PARM , '"' , '' ) 
+ELSE TRIM ( IN_PARM ) 
+END ; 
+END WHILE ; 
+SET ENV = IN_PARM ; 
+SET LL = CISTOOLS . SET_LIBRARY_LIST ( ENV ) ; 
+-- Validate environment was set 
+IF ENV = '' 
+OR ENV IS NULL THEN 
+RETURN 
+JSON_OBJECT ( 
+'error' : JSON_OBJECT ( 
+'http_status' : 400 , 'sqlstate' : '22001' , 
+'message' : 'Environment parameter is required' 
+) 
+) ; 
+END IF ; 
+-- Check for errors from library list setup 
+IF V_HAS_ERROR = 1 THEN 
+RETURN 
+JSON_OBJECT ( 
+'error' : JSON_OBJECT ( 
+'http_status' : V_HTTP_STATUS , 'sqlstate' : V_SQLSTATE , 
+'message' : V_ERRMSG 
+) 
+) ; 
+END IF ; 
+RETURN 
+WITH BOUNDS AS ( 
+SELECT CURRENT_DATE AS FOR_DATE , 1 AS WEEK_END_DOW , 
+2 AS WEEK_START_DOW , 
+ZONED ( CURRENT_DATE ) AS YYYYMMDD_FOR , 
+ZONED ( 
+LAST_DAY ( ADD_MONTHS ( CURRENT_DATE , - 1 ) ) + 1 DAY ) 
+AS YYYYMMDD_MONTH_FROM , 
+ZONED ( LAST_DAY ( CURRENT_DATE ) ) 
+AS YYYYMMDD_MONTH_THRU , 
+DAYOFWEEK ( CURRENT_DATE ) AS DOW_FOR 
+FROM SYSIBM . SYSDUMMY1 
+) , 
+WEEK_CALC AS ( 
+SELECT B . * , 
+MOD ( B . DOW_FOR - B . WEEK_START_DOW + 7 , 7 ) 
+AS DELTA_DAYS 
+FROM BOUNDS B 
+) , 
+RANGES AS ( 
+SELECT 'M' AS RANGE_TYPE , 
+( YYYYMMDD_MONTH_FROM - 19000000 ) AS FROM_CY , 
+( YYYYMMDD_MONTH_THRU - 19000000 ) AS THRU_CY 
+FROM WEEK_CALC 
+UNION ALL 
+SELECT 'W' AS RANGE_TYPE , 
+( ( YEAR ( FOR_DATE - DELTA_DAYS DAYS ) * 10000 + 
+MONTH ( FOR_DATE - DELTA_DAYS DAYS ) * 100 + 
+DAY ( FOR_DATE - DELTA_DAYS DAYS ) ) - 19000000 ) 
+AS FROM_CY , ( YYYYMMDD_FOR - 19000000 ) AS THRU_CY 
+FROM WEEK_CALC 
+UNION ALL 
+SELECT 'D' AS RANGE_TYPE , 
+( YYYYMMDD_FOR - 19000000 ) AS FROM_CY , 
+( YYYYMMDD_FOR - 19000000 ) AS THRU_CY 
+FROM WEEK_CALC 
+) , 
+-- Work center level data 
+WC_DATA AS ( 
+SELECT R . RANGE_TYPE , TRIM ( P . KIGRP1 ) AS PLANT , 
+TRIM ( P . KIGRP2 ) AS DEPT , TRIM ( P . KIWKCTR ) AS WC , 
+SUM ( P . KIUP ) AS UP_SEC , SUM ( P . KISDWN ) AS SDWN_SEC , 
+SUM ( P . KIUDWN ) AS UDWN_SEC , SUM ( P . KIGAP ) AS GAP_SEC , 
+SUM ( P . KIUA ) AS UA_SEC , SUM ( P . KIRCVD ) AS GOOD_QTY , 
+SUM ( P . KISCRP ) AS BAD_QTY , 
+SUM ( P . KIEXPT ) AS TARGET_QTY , 
+SUM ( P . KIARUN ) AS ARUN_SEC , 
+SUM ( P . KIASET ) AS ASET_SEC , 
+SUM ( P . KIASDW ) AS ASDW_SEC , SUM ( P . KIAUDW ) AS AUDW_SEC 
+FROM RANGES R 
+JOIN SFCPERI P 
+ON P . KIDATE BETWEEN R . FROM_CY AND R . THRU_CY 
+GROUP BY R . RANGE_TYPE , P . KIGRP1 , P . KIGRP2 , P . KIWKCTR 
+) , 
+-- Calculate metrics at WC level 
+WC_CALC AS ( 
+SELECT RANGE_TYPE , PLANT , DEPT , WC , UP_SEC , SDWN_SEC , 
+UDWN_SEC , GAP_SEC , UA_SEC , GOOD_QTY , BAD_QTY , 
+TARGET_QTY , ARUN_SEC , ASET_SEC , ASDW_SEC , AUDW_SEC , 
+INT ( 
+( COALESCE ( 
+( DECFLOAT ( UP_SEC - UDWN_SEC - GAP_SEC ) / 
+NULLIF ( DECFLOAT ( UP_SEC ) , 0 ) ) , 0 ) * 
+COALESCE ( 
+( DECFLOAT ( GOOD_QTY + BAD_QTY ) / 
+NULLIF ( DECFLOAT ( TARGET_QTY ) , 0 ) ) , 0 ) * 
+COALESCE ( 
+( DECFLOAT ( GOOD_QTY ) / 
+NULLIF ( DECFLOAT ( GOOD_QTY + BAD_QTY ) , 0 ) 
+) , 0 ) * 100 ) + 0.5 ) AS OEE_PCT , 
+DEC ( 
+DEC ( 
+UP_SEC + SDWN_SEC + UDWN_SEC + GAP_SEC , 31 , 
+10 ) / 3600 , 13 , 2 ) AS ELAPSED_HRS , 
+DEC ( 
+DEC ( 
+ARUN_SEC + ASET_SEC + ASDW_SEC + AUDW_SEC , 31 , 
+10 ) / 3600 , 13 , 2 ) AS APPLIED_HRS , 
+DEC ( DEC ( UP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) 
+AS TIME_UP_HRS , 
+DEC ( 
+DEC ( 
+SDWN_SEC + UDWN_SEC + GAP_SEC + UA_SEC , 31 , 
+10 ) / 3600 , 13 , 2 ) AS DOWN_TOTAL_HRS , 
+DEC ( DEC ( SDWN_SEC , 31 , 10 ) / 3600 , 13 , 2 ) 
+AS SCHED_DOWN_HRS , 
+DEC ( DEC ( UDWN_SEC , 31 , 10 ) / 3600 , 13 , 2 ) 
+AS UNSCHED_DOWN_HRS , 
+DEC ( DEC ( GAP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) AS GAP_HRS , 
+DEC ( DEC ( UA_SEC , 31 , 10 ) / 3600 , 13 , 2 ) 
+AS UNAVAIL_HRS , 
+DEC ( GOOD_QTY , 31 , 2 ) AS GOOD_PARTS , 
+DEC ( BAD_QTY , 31 , 2 ) AS BAD_PARTS , 
+DEC ( TARGET_QTY , 31 , 2 ) AS TARGET_PARTS , 
+INT ( 
+( COALESCE ( 
+( DECFLOAT ( UP_SEC - UDWN_SEC - GAP_SEC ) / 
+NULLIF ( DECFLOAT ( UP_SEC ) , 0 ) ) , 0 ) * 100 ) + 
+0.5 ) AS AVAILABILITY_PCT , 
+INT ( 
+( COALESCE ( 
+( DECFLOAT ( GOOD_QTY + BAD_QTY ) / 
+NULLIF ( DECFLOAT ( TARGET_QTY ) , 0 ) ) , 0 ) * 100 ) 
++ 0.5 ) AS PERFORMANCE_PCT , 
+INT ( 
+( COALESCE ( 
+( DECFLOAT ( GOOD_QTY ) / 
+NULLIF ( DECFLOAT ( GOOD_QTY + BAD_QTY ) , 0 ) ) , 
+0 ) * 100 ) + 0.5 ) AS QUALITY_PCT , 
+DEC ( DEC ( ARUN_SEC , 31 , 10 ) / 3600 , 13 , 2 ) AS RUN_HRS , 
+DEC ( DEC ( ASET_SEC , 31 , 10 ) / 3600 , 13 , 2 ) 
+AS SETUP_HRS , 
+DEC ( DEC ( ASDW_SEC , 31 , 10 ) / 3600 , 13 , 2 ) 
+AS APPL_SDWN_HRS , 
+DEC ( DEC ( AUDW_SEC , 31 , 10 ) / 3600 , 13 , 2 ) 
+AS APPL_UDWN_HRS 
+FROM WC_DATA 
+) , 
+-- Pre-aggregate totals at each level to avoid join multiplication 
+DEPT_TOTALS AS ( 
+SELECT RANGE_TYPE , PLANT , DEPT , SUM ( UP_SEC ) AS UP_SEC , 
+SUM ( SDWN_SEC ) AS SDWN_SEC , 
+SUM ( UDWN_SEC ) AS UDWN_SEC , SUM ( GAP_SEC ) AS GAP_SEC , 
+SUM ( GOOD_QTY ) AS GOOD_QTY , SUM ( BAD_QTY ) AS BAD_QTY , 
+SUM ( TARGET_QTY ) AS TARGET_QTY 
+FROM WC_DATA 
+GROUP BY RANGE_TYPE , PLANT , DEPT 
+) , 
+PLANT_TOTALS AS ( 
+SELECT RANGE_TYPE , PLANT , SUM ( UP_SEC ) AS UP_SEC , 
+SUM ( SDWN_SEC ) AS SDWN_SEC , 
+SUM ( UDWN_SEC ) AS UDWN_SEC , SUM ( GAP_SEC ) AS GAP_SEC , 
+SUM ( GOOD_QTY ) AS GOOD_QTY , SUM ( BAD_QTY ) AS BAD_QTY , 
+SUM ( TARGET_QTY ) AS TARGET_QTY 
+FROM WC_DATA 
+GROUP BY RANGE_TYPE , PLANT 
+) , 
+GRAND_TOTALS AS ( 
+SELECT RANGE_TYPE , SUM ( UP_SEC ) AS UP_SEC , 
+SUM ( SDWN_SEC ) AS SDWN_SEC , 
+SUM ( UDWN_SEC ) AS UDWN_SEC , SUM ( GAP_SEC ) AS GAP_SEC , 
+SUM ( GOOD_QTY ) AS GOOD_QTY , SUM ( BAD_QTY ) AS BAD_QTY , 
+SUM ( TARGET_QTY ) AS TARGET_QTY 
+FROM WC_DATA 
+GROUP BY RANGE_TYPE 
+) , 
+-- Build workcenter JSON objects 
+WC_JSON AS ( 
+SELECT RANGE_TYPE , PLANT , DEPT , 
+JSON_OBJECT ( 
+'workcenterName' : WC , 'oeePercentage' : OEE_PCT , 
+'elapsedHours' : ELAPSED_HRS , 
+'appliedHours' : APPLIED_HRS , 
+'timeUpHours' : TIME_UP_HRS , 
+'totalDownHours' : DOWN_TOTAL_HRS , 
+'scheduledDownHours' : SCHED_DOWN_HRS , 
+'unscheduledDownHours' : UNSCHED_DOWN_HRS , 
+'gapHours' : GAP_HRS , 
+'unavailableHours' : UNAVAIL_HRS , 
+'goodParts' : GOOD_PARTS , 'badParts' : BAD_PARTS , 
+'targetParts' : TARGET_PARTS , 
+'availabilityPercentage' : AVAILABILITY_PCT , 
+'performancePercentage' : PERFORMANCE_PCT , 
+'qualityPercentage' : QUALITY_PCT , 
+'runHours' : RUN_HRS , 'setupHours' : SETUP_HRS , 
+'appliedScheduledDownHours' : APPL_SDWN_HRS , 
+'appliedUnscheduledDownHours' : APPL_UDWN_HRS 
+) AS WC_OBJ 
+FROM WC_CALC 
+) , 
+-- Build dept JSON with pre-aggregated totals 
+DEPT_JSON AS ( 
+SELECT W . RANGE_TYPE , W . PLANT , W . DEPT , 
+JSON_OBJECT ( 
+'departmentName' : W . DEPT , 'oeePercentage' : INT ( 
+( COALESCE ( 
+( DECFLOAT ( 
+T . UP_SEC - T . UDWN_SEC - T . GAP_SEC ) / 
+NULLIF ( DECFLOAT ( T . UP_SEC ) , 0 ) ) , 0 ) * 
+COALESCE ( 
+( DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) / 
+NULLIF ( DECFLOAT ( T . TARGET_QTY ) , 0 ) ) , 
+0 ) * 
+COALESCE ( 
+( DECFLOAT ( T . GOOD_QTY ) / 
+NULLIF ( 
+DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) , 
+0 ) ) , 0 ) * 100 ) + 0.5 ) , 
+'elapsedHours' : DEC ( 
+DEC ( 
+T . UP_SEC + T . SDWN_SEC + T . UDWN_SEC + 
+T . GAP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , 
+'timeUpHours' : DEC ( 
+DEC ( T . UP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , 
+'goodParts' : DEC ( T . GOOD_QTY , 31 , 2 ) , 
+'targetParts' : DEC ( T . TARGET_QTY , 31 , 2 ) , 
+'workcenters' : JSON_ARRAYAGG ( 
+W . WC_OBJ FORMAT JSON 
+ORDER BY W . DEPT 
+) 
+) AS DEPT_OBJ 
+FROM WC_JSON W 
+JOIN DEPT_TOTALS T 
+ON W . RANGE_TYPE = T . RANGE_TYPE 
+AND W . PLANT = T . PLANT 
+AND W . DEPT = T . DEPT 
+GROUP BY W . RANGE_TYPE , W . PLANT , W . DEPT , T . UP_SEC , 
+T . SDWN_SEC , T . UDWN_SEC , T . GAP_SEC , T . GOOD_QTY , 
+T . BAD_QTY , T . TARGET_QTY 
+) , 
+-- Build plant JSON with pre-aggregated totals 
+PLANT_JSON AS ( 
+SELECT D . RANGE_TYPE , D . PLANT , 
+JSON_OBJECT ( 
+'plantName' : D . PLANT , 'oeePercentage' : INT ( 
+( COALESCE ( 
+( DECFLOAT ( 
+T . UP_SEC - T . UDWN_SEC - T . GAP_SEC ) / 
+NULLIF ( DECFLOAT ( T . UP_SEC ) , 0 ) ) , 0 ) * 
+COALESCE ( 
+( DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) / 
+NULLIF ( DECFLOAT ( T . TARGET_QTY ) , 0 ) ) , 
+0 ) * 
+COALESCE ( 
+( DECFLOAT ( T . GOOD_QTY ) / 
+NULLIF ( 
+DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) , 
+0 ) ) , 0 ) * 100 ) + 0.5 ) , 
+'elapsedHours' : DEC ( 
+DEC ( 
+T . UP_SEC + T . SDWN_SEC + T . UDWN_SEC + 
+T . GAP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , 
+'timeUpHours' : DEC ( 
+DEC ( T . UP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , 
+'goodParts' : DEC ( T . GOOD_QTY , 31 , 2 ) , 
+'targetParts' : DEC ( T . TARGET_QTY , 31 , 2 ) , 
+'departments' : JSON_ARRAYAGG ( 
+D . DEPT_OBJ FORMAT JSON 
+ORDER BY D . DEPT 
+) 
+) AS PLANT_OBJ 
+FROM DEPT_JSON D 
+JOIN PLANT_TOTALS T 
+ON D . RANGE_TYPE = T . RANGE_TYPE 
+AND D . PLANT = T . PLANT 
+GROUP BY D . RANGE_TYPE , D . PLANT , T . UP_SEC , T . SDWN_SEC , 
+T . UDWN_SEC , T . GAP_SEC , T . GOOD_QTY , T . BAD_QTY , 
+T . TARGET_QTY 
+) , 
+GROUPED AS ( 
+SELECT P . RANGE_TYPE , 
+JSON_OBJECT ( 
+'rangeLabel' : 
+CASE P . RANGE_TYPE 
+WHEN 'M' THEN 'Monthly' 
+WHEN 'W' THEN 'Weekly' 
+WHEN 'D' THEN 'Daily' 
+END , 
+'generatedAt' : TO_CHAR ( 
+CURRENT_TIMESTAMP , 'YYYY-MM-DD HH24:MI:SS' 
+) , 'totalOeePercentage' : INT ( 
+( COALESCE ( 
+( DECFLOAT ( 
+T . UP_SEC - T . UDWN_SEC - T . GAP_SEC ) / 
+NULLIF ( DECFLOAT ( T . UP_SEC ) , 0 ) ) , 0 ) * 
+COALESCE ( 
+( DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) / 
+NULLIF ( DECFLOAT ( T . TARGET_QTY ) , 0 ) 
+) , 0 ) * 
+COALESCE ( 
+( DECFLOAT ( T . GOOD_QTY ) / 
+NULLIF ( 
+DECFLOAT ( 
+T . GOOD_QTY + T . BAD_QTY ) , 0 ) 
+) , 0 ) * 100 ) + 0.5 ) , 
+'plants' : JSON_ARRAYAGG ( 
+P . PLANT_OBJ FORMAT JSON 
+ORDER BY P . PLANT 
+) 
+) AS JSON_DATA 
+FROM PLANT_JSON P 
+JOIN GRAND_TOTALS T 
+ON P . RANGE_TYPE = T . RANGE_TYPE 
+GROUP BY P . RANGE_TYPE , T . UP_SEC , T . SDWN_SEC , 
+T . UDWN_SEC , T . GAP_SEC , T . GOOD_QTY , 
+T . BAD_QTY , T . TARGET_QTY 
+ORDER BY 
+CASE P . RANGE_TYPE 
+WHEN 'D' THEN 3 
+WHEN 'W' THEN 2 
+ELSE 1 
+END ) SELECT JSON_OBJECT ( 
+'ranges' VALUE JSON_ARRAYAGG ( 
+JSON_DATA FORMAT JSON 
+) 
+) 
+FROM GROUPED ; 
+END  ; 
+
+GRANT ALTER , EXECUTE   
+ON SPECIFIC FUNCTION RESTAPI.SFP_GET_OEE_DETAILS 
+TO AMAPICS WITH GRANT OPTION ; 
+
+GRANT EXECUTE   
+ON SPECIFIC FUNCTION RESTAPI.SFP_GET_OEE_DETAILS 
+TO PUBLIC ; 
+
