diff --git a/RESTAPI/Functions/SFP_GET_HOURLY_OEE_LIVE.sql b/RESTAPI/Functions/SFP_GET_HOURLY_OEE_LIVE.sql
index 3a6ad12..7568f10 100644
--- a/RESTAPI/Functions/SFP_GET_HOURLY_OEE_LIVE.sql
+++ b/RESTAPI/Functions/SFP_GET_HOURLY_OEE_LIVE.sql
@@ -1 +1,749 @@
-âÅã@×ÁãÈ@\ÓÉÂÓ@^@
%
%ÃÙÅÁãÅ@ÖÙ@ÙÅ×ÓÁÃÅ@ÆäÕÃãÉÖÕ@ÙÅâãÁ×ÉKâÆ×mÇÅãmÈÖäÙÓèmÖÅÅmÓÉåÅ@M@
%ÉÕm×ÁÙÔ@ÃÓÖÂMòñô÷ôøóöô÷]@]@
%ÙÅãäÙÕâ@ÃÓÖÂMòñô÷ôøóöô÷]@@@
%ÓÁÕÇäÁÇÅ@âØÓ@
%â×ÅÃÉÆÉÃ@ÙÅâãÁ×ÉKâÆ×mÇÅãmÈÖäÙÓèmÖÅÅmÓÉåÅ@
%ÕÖã@ÄÅãÅÙÔÉÕÉâãÉÃ@
%ÔÖÄÉÆÉÅâ@âØÓ@ÄÁãÁ@
%ÃÁÓÓÅÄ@ÖÕ@ÕäÓÓ@ÉÕ×äã@
%âÅã@Ö×ãÉÖÕ@@ÁÓæÂÓÒ@~@\ÁÓÓÙÅÁÄ@k@
%ÁÓæÃ×èÄãÁ@~@\Ö×ãÉÔÉéÅ@k@
%ÃÖÔÔÉã@~@\ÕÖÕÅ@k@
%ÄÅÃÙÅâäÓã@~@Móñk@óñk@ðð]@k@
%ÄèÕÄÆãÃÖÓ@~@\ÕÖ@k@
%ÄèÕäâÙ×ÙÆ@~@\äâÅÙ@k@
%âÙãâÅØ@~@\ÈÅç@@@
%ÂÅÇÉÕ@
%ÄÅÃÓÁÙÅ@ÅÕå@åÁÙÃÈÁÙ@M@òð@]@ÄÅÆÁäÓã@}}@^@
%ÄÅÃÓÁÙÅ@åmÄÁãÅ@ÄÁãÅ@^@
%ÄÅÃÓÁÙÅ@åmÄÁãÅmâãÙ@åÁÙÃÈÁÙ@M@ñð@]@ÄÅÆÁäÓã@}}@^@
%ÄÅÃÓÁÙÅ@åmæÃ@åÁÙÃÈÁÙ@M@õ@]@ÄÅÆÁäÓã@}}@^@
%ÄÅÃÓÁÙÅ@åmâÉãÅ@åÁÙÃÈÁÙ@M@ó@]@ÄÅÆÁäÓã@}}@^@
%ÄÅÃÓÁÙÅ@åmÄÁãÅmÃè@ÄÅÃÉÔÁÓ@M@÷@k@ð@]@ÄÅÆÁäÓã@ð@^@
%ÄÅÃÓÁÙÅ@åmÄÁãÅm×ÙÉÖÙmÃè@ÄÅÃÉÔÁÓ@M@÷@k@ð@]@ÄÅÆÁäÓã@ð@^@
%ÄÅÃÓÁÙÅ@ÓÓ@åÁÙÃÈÁÙ@M@ñðòô@]@ÄÅÆÁäÓã@}}@^@
%ÄÅÃÓÁÙÅ@åmÉÕm×ÁÙÔ@ÃÓÖÂ@M@ò@Ç@]@ÄÅÆÁäÓã@}}@^@
%``@×�™¢…@‰•—¤£@—�™�”…£…™¢@†‰™¢£@M‚…†–™…@…•¥@…§£™�ƒ£‰–•@”–„‰†‰…¢@É•m×�™”]@
%âÅã@åmÄÁãÅmâãÙ@~@ÃÖÁÓÅâÃÅ@M@ÑâÖÕmåÁÓäÅ@M@ÉÕm×ÁÙÔ@k@}[K„�£…}@]@k@}}@]@^@
%âÅã@åmæÃ@~@ÃÖÁÓÅâÃÅ@M@ÑâÖÕmåÁÓäÅ@M@ÉÕm×ÁÙÔ@k@}[K¦–™’ƒ…•£…™}@]@k@}}@]@^@
%âÅã@åmâÉãÅ@~@ÃÖÁÓÅâÃÅ@M@ÑâÖÕmåÁÓäÅ@M@ÉÕm×ÁÙÔ@k@}[K¢‰£…}@]@k@}}@]@^@
%``@×�™¢…@„�£…@`@¢…£@£–@Ã¤™™…•£mÄ�£…@‰†@•–£@—™–¥‰„…„@
%ÉÆ@åmÄÁãÅmâãÙ@Ln@}}@ãÈÅÕ@
%âÅã@åmÄÁãÅ@~@ÄÁãÅ@M@åmÄÁãÅmâãÙ@]@^@
%ÅÓâÅ@
%âÅã@åmÄÁãÅ@~@ÃäÙÙÅÕãmÄÁãÅ@^@
%ÅÕÄ@ÉÆ@^@
%``@Å§£™�ƒ£@…•¥@ˆ�•„“‰•‡@�““@‰•—¤£@†–™”�£¢@M–‚‘…ƒ£k@�™™�¨k@¢£™‰•‡]@
%âÅã@åmÉÕm×ÁÙÔ@~@ÉÕm×ÁÙÔ@^@
%æÈÉÓÅ@ÃÉâãÖÖÓâ@K@ÑâÖÕmãè×Å@M@åmÉÕm×ÁÙÔ@]@ÉÕ@M@}–‚‘…ƒ£}@k@}�™™�¨}@k@}¢£™‰•‡}@]@
%ÄÖ@
%âÅã@åmÉÕm×ÁÙÔ@~@
%ÃÁâÅ@ÃÉâãÖÖÓâ@K@ÑâÖÕmãè×Å@M@åmÉÕm×ÁÙÔ@]@
%æÈÅÕ@}–‚‘…ƒ£}@ãÈÅÕ@ÑâÖÕmåÁÓäÅ@M@åmÉÕm×ÁÙÔ@k@}[K…•¥}@]@
%æÈÅÕ@}�™™�¨}@ãÈÅÕ@ÑâÖÕmåÁÓäÅ@M@åmÉÕm×ÁÙÔ@k@}[ºð»}@]@
%æÈÅÕ@}¢£™‰•‡}@ãÈÅÕ@ÙÅ×ÓÁÃÅ@M@åmÉÕm×ÁÙÔ@k@}}@k@}}@]@
%ÅÓâÅ@ãÙÉÔ@M@åmÉÕm×ÁÙÔ@]@
%ÅÕÄ@^@
%ÅÕÄ@æÈÉÓÅ@^@
%âÅã@ÅÕå@~@åmÉÕm×ÁÙÔ@^@
%âÅã@ÓÓ@~@ÃÉâãÖÖÓâ@K@âÅãmÓÉÂÙÁÙèmÓÉâã@M@ÅÕå@]@^@
%``@Ã�“ƒ¤“�£…@ÃèèÔÔÄÄ@„�£…¢@
%âÅã@åmÄÁãÅmÃè@~@éÖÕÅÄ@M@åmÄÁãÅ@]@`@ñùðððððð@^@
%âÅã@åmÄÁãÅm×ÙÉÖÙmÃè@~@éÖÕÅÄ@M@åmÄÁãÅ@`@ñ@ÄÁè@]@`@ñùðððððð@^@
%ÙÅãäÙÕ@
%æÉãÈ@
%``@~~~~~~~~~~@ÙäÕ@ãÙÁÕâÁÃãÉÖÕâ@MÖÕaÖÆ]@~~~~~~~~~~@
%ÙäÕmÖÕ@Áâ@M@
%âÅÓÅÃã@ã@K@ÖÙÄÕÖ@k@ã@K@Ö×âÅØ@k@ã@K@ÉãÕÂÙ@k@ã@K@æÒÃãÙ@k@
%ÃÖÁÓÅâÃÅ@M@ã@K@ÅÔ×ÕÖ@k@ã@K@ÂÁÄÇÅ@]@Áâ@ÅÔ×mÒÅè@k@
%ã@K@ãÄÁãÅ@Áâ@ÖÕmÄÁãÅ@k@ã@K@ããÉÔÅ@Áâ@ÖÕmãÉÔÅ@k@ã@K@ÙäÕÃÄ@k@
%Ô@K@âãÉÄ@k@
%ãÖmÄÁãÅ@M@
%éÖÕÅÄ@M@ÃÉâãÖÖÓâ@K@ÃèÔÄòÄÁãÅ@M@ã@K@ãÄÁãÅ@]@]@OO@
%Ó×ÁÄ@M@ã@K@ããÉÔÅ@k@ö@k@}ð}@]@k@}èèèèÔÔÄÄÈÈòôÔÉââ}@]@
%Áâ@ÖÕmãâ@k@
%ÙÖæmÕäÔÂÅÙ@M@]@ÖåÅÙ@M@
%×ÁÙãÉãÉÖÕ@Âè@ã@K@ÖÙÄÕÖ@k@ã@K@Ö×âÅØ@k@ÃÖÁÓÅâÃÅ@M@
%ã@K@ÅÔ×ÕÖ@k@ã@K@ÂÁÄÇÅ@]@k@ã@K@ÙäÕÃÄ@k@ã@K@æÒÃãÙ@
%ÖÙÄÅÙ@Âè@ã@K@ãÄÁãÅ@k@ã@K@ããÉÔÅ@
%]@Áâ@âÅØ@
%ÆÙÖÔ@ÔÖãÙÁÕ@ã@
%ÑÖÉÕ@ÔÖÔÁâã@Ô@
%ÖÕ@ã@K@ÖÙÄÕÖ@~@Ô@K@ÖÙÄÕÖ@
%æÈÅÙÅ@ã@K@ãÃÖÄÅ@~@}ÖÕ}@
%ÁÕÄ@ã@K@ÙäÕÃÄ@~@}Ù}@
%ÁÕÄ@ã@K@æÒÃãÙ@~@ÃÖÁÓÅâÃÅ@M@ÕäÓÓÉÆ@M@åmæÃ@k@}}@]@k@ã@K@æÒÃãÙ@]@
%ÁÕÄ@Ô@K@âãÉÄ@~@ÃÖÁÓÅâÃÅ@M@ÕäÓÓÉÆ
\ No newline at end of file
+SET PATH *LIBL ; 
+
+CREATE OR REPLACE FUNCTION RESTAPI.SFP_GET_HOURLY_OEE_LIVE ( 
+	IN_PARM CLOB(2147483647) ) 
+	RETURNS CLOB(2147483647)   
+	LANGUAGE SQL 
+	SPECIFIC RESTAPI.SFP_GET_HOURLY_OEE_LIVE 
+	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 V_DATE DATE ; 
+DECLARE V_DATE_STR VARCHAR ( 10 ) DEFAULT '' ; 
+DECLARE V_WC VARCHAR ( 5 ) DEFAULT '' ; 
+DECLARE V_SITE VARCHAR ( 3 ) DEFAULT '' ; 
+DECLARE V_DATE_CY DECIMAL ( 7 , 0 ) DEFAULT 0 ; 
+DECLARE V_DATE_PRIOR_CY DECIMAL ( 7 , 0 ) DEFAULT 0 ; 
+DECLARE LL VARCHAR ( 1024 ) DEFAULT '' ; 
+DECLARE V_IN_PARM CLOB ( 2 G ) DEFAULT '' ; 
+-- Parse input parameters first (before env extraction modifies In_Parm) 
+SET V_DATE_STR = COALESCE ( JSON_VALUE ( IN_PARM , '$.date' ) , '' ) ; 
+SET V_WC = COALESCE ( JSON_VALUE ( IN_PARM , '$.workcenter' ) , '' ) ; 
+SET V_SITE = COALESCE ( JSON_VALUE ( IN_PARM , '$.site' ) , '' ) ; 
+-- Parse date - set to Current_Date if not provided 
+IF V_DATE_STR <> '' THEN 
+SET V_DATE = DATE ( V_DATE_STR ) ; 
+ELSE 
+SET V_DATE = CURRENT_DATE ; 
+END IF ; 
+-- Extract env handling all input formats (object, array, string) 
+SET V_IN_PARM = IN_PARM ; 
+WHILE CISTOOLS . JSON_TYPE ( V_IN_PARM ) IN ( 'object' , 'array' , 'string' ) 
+DO 
+SET V_IN_PARM = 
+CASE CISTOOLS . JSON_TYPE ( V_IN_PARM ) 
+WHEN 'object' THEN JSON_VALUE ( V_IN_PARM , '$.env' ) 
+WHEN 'array' THEN JSON_VALUE ( V_IN_PARM , '$[0]' ) 
+WHEN 'string' THEN REPLACE ( V_IN_PARM , '"' , '' ) 
+ELSE TRIM ( V_IN_PARM ) 
+END ; 
+END WHILE ; 
+SET ENV = V_IN_PARM ; 
+SET LL = CISTOOLS . SET_LIBRARY_LIST ( ENV ) ; 
+-- Calculate CYYMMDD dates 
+SET V_DATE_CY = ZONED ( V_DATE ) - 19000000 ; 
+SET V_DATE_PRIOR_CY = ZONED ( V_DATE - 1 DAY ) - 19000000 ; 
+RETURN 
+WITH 
+-- ========== RUN TRANSACTIONS (ON/OF) ========== 
+RUN_ON AS ( 
+SELECT T . ORDNO , T . OPSEQ , T . ITNBR , T . WKCTR , 
+COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , 
+T . TDATE AS ON_DATE , T . TTIME AS ON_TIME , T . RUNCD , 
+M . STID , 
+TO_DATE ( 
+ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || 
+LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) 
+AS ON_TS , 
+ROW_NUMBER ( ) OVER ( 
+PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( 
+T . EMPNO , T . BADGE ) , T . RUNCD , T . WKCTR 
+ORDER BY T . TDATE , T . TTIME 
+) AS SEQ 
+FROM MOTRAN T 
+JOIN MOMAST M 
+ON T . ORDNO = M . ORDNO 
+WHERE T . TCODE = 'ON' 
+AND T . RUNCD = 'R' 
+AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) 
+AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) 
+AND T . ACREC = 'A' 
+AND T . TDATE BETWEEN V_DATE_PRIOR_CY AND V_DATE_CY 
+) , 
+RUN_OFF AS ( 
+SELECT T . ORDNO , T . OPSEQ , T . WKCTR , 
+COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , 
+T . TDATE AS OFF_DATE , T . TTIME AS OFF_TIME , T . QTCOM , 
+T . QTSCP , T . RUNCD , M . STID , 
+TO_DATE ( 
+ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || 
+LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) 
+AS OFF_TS , 
+ROW_NUMBER ( ) OVER ( 
+PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( 
+T . EMPNO , T . BADGE ) , T . RUNCD , T . WKCTR 
+ORDER BY T . TDATE , T . TTIME 
+) AS SEQ 
+FROM MOTRAN T 
+JOIN MOMAST M 
+ON T . ORDNO = M . ORDNO 
+WHERE T . TCODE = 'OF' 
+AND T . RUNCD = 'R' 
+AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) 
+AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) 
+AND T . ACREC = 'A' 
+AND T . TDATE = V_DATE_CY 
+) , 
+CURRENT_END AS ( 
+SELECT 
+CASE 
+WHEN V_DATE = CURRENT_DATE THEN CURRENT_TIMESTAMP 
+ELSE 
+TO_DATE ( 
+ZONED ( V_DATE ) || '235959' , 'YYYYMMDDHH24MISS' ) 
+END AS DEFAULT_END_TS 
+FROM SYSIBM . SYSDUMMY1 
+) , 
+RUN_MATCHED AS ( 
+SELECT ON_T . ORDNO , ON_T . ITNBR , ON_T . WKCTR , ON_T . STID , 
+ON_T . ON_TS AS START_TS , 
+COALESCE ( OFF_T . OFF_TS , CE . DEFAULT_END_TS ) AS END_TS , 
+COALESCE ( OFF_T . OFF_DATE , V_DATE_CY ) AS OFF_DATE , 
+COALESCE ( 
+OFF_T . OFF_TIME , 
+CASE 
+WHEN 
+V_DATE = CURRENT_DATE 
+THEN ZONED ( CURRENT_TIME ) 
+ELSE 235959 
+END ) AS OFF_TIME , 
+COALESCE ( OFF_T . QTCOM , 0 ) AS QTY_COMPLETE , 
+COALESCE ( OFF_T . QTSCP , 0 ) AS QTY_SCRAP , 
+CASE 
+COALESCE ( R . TBCDE , ' ' ) 
+WHEN 
+' ' 
+THEN 
+CASE 
+WHEN 
+COALESCE ( R . SRLHU , 0 ) > 0 
+THEN 1.0 / R . SRLHU / 60 
+ELSE 0 
+END 
+WHEN 'P' THEN COALESCE ( R . SRLHU , 0 ) / 60 
+WHEN 
+'M' 
+THEN 
+CASE 
+WHEN 
+COALESCE ( R . SRLHU , 0 ) > 0 
+THEN 1.0 / R . SRLHU 
+ELSE 0 
+END 
+WHEN 
+'1' 
+THEN 
+CASE 
+WHEN 
+COALESCE ( R . SRLHU , 0 ) > 0 
+THEN 10.0 / R . SRLHU / 60 
+ELSE 0 
+END 
+WHEN 
+'2' 
+THEN 
+CASE 
+WHEN 
+COALESCE ( R . SRLHU , 0 ) > 0 
+THEN 100.0 / R . SRLHU / 60 
+ELSE 0 
+END 
+WHEN 
+'3' 
+THEN 
+CASE 
+WHEN 
+COALESCE ( R . SRLHU , 0 ) > 0 
+THEN 1000.0 / R . SRLHU / 60 
+ELSE 0 
+END 
+ELSE 0 
+END AS PCS_PER_MIN 
+FROM RUN_ON ON_T 
+CROSS JOIN CURRENT_END CE 
+LEFT JOIN RUN_OFF OFF_T 
+ON ON_T . ORDNO = OFF_T . ORDNO 
+AND ON_T . OPSEQ = OFF_T . OPSEQ 
+AND ON_T . EMP_KEY = OFF_T . EMP_KEY 
+AND ON_T . RUNCD = OFF_T . RUNCD 
+AND ON_T . SEQ = OFF_T . SEQ 
+AND ON_T . WKCTR = OFF_T . WKCTR 
+AND ON_T . STID = OFF_T . STID 
+LEFT JOIN MOROUT R 
+ON ON_T . ORDNO = R . ORDNO 
+AND ON_T . OPSEQ = R . OPSEQ 
+) , 
+-- ========== DOWNTIME TRANSACTIONS (DB/DE) ========== 
+DOWN_BEGIN AS ( 
+SELECT T . ORDNO , T . OPSEQ , 
+CAST ( 
+CAST ( T . RECD AS VARCHAR ( 6 ) CCSID 37 ) AS VARCHAR ( 6 ) 
+CCSID 1208 ) AS REASON_CODE , T . WKCTR , 
+COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , 
+T . TDATE AS DB_DATE , T . TTIME AS DB_TIME , M . STID , 
+TO_DATE ( 
+ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || 
+LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) 
+AS DB_TS , 
+ROW_NUMBER ( ) OVER ( 
+PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( 
+T . EMPNO , T . BADGE ) , T . WKCTR 
+ORDER BY T . TDATE , T . TTIME 
+) AS SEQ 
+FROM MOTRAN T 
+JOIN MOMAST M 
+ON T . ORDNO = M . ORDNO 
+WHERE T . TCODE = 'DB' 
+AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) 
+AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) 
+AND T . ACREC = 'A' 
+AND T . TDATE BETWEEN V_DATE_PRIOR_CY AND V_DATE_CY 
+) , 
+DOWN_END AS ( 
+SELECT T . ORDNO , T . OPSEQ , T . WKCTR , 
+COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , 
+T . TDATE AS DE_DATE , T . TTIME AS DE_TIME , M . STID , 
+TO_DATE ( 
+ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || 
+LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) 
+AS DE_TS , 
+ROW_NUMBER ( ) OVER ( 
+PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( 
+T . EMPNO , T . BADGE ) , T . WKCTR 
+ORDER BY T . TDATE , T . TTIME 
+) AS SEQ 
+FROM MOTRAN T 
+JOIN MOMAST M 
+ON T . ORDNO = M . ORDNO 
+WHERE T . TCODE = 'DE' 
+AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) 
+AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) 
+AND T . ACREC = 'A' 
+AND T . TDATE = V_DATE_CY 
+) , 
+DOWN_MATCHED AS ( 
+SELECT DB . ORDNO , DB . REASON_CODE , DB . WKCTR , DB . STID , 
+COALESCE ( R . KDSCHED , 'N' ) AS IS_SCHEDULED , 
+DB . DB_TS AS START_TS , 
+COALESCE ( DE . DE_TS , CE . DEFAULT_END_TS ) AS END_TS 
+FROM DOWN_BEGIN DB 
+CROSS JOIN CURRENT_END CE 
+LEFT JOIN DOWN_END DE 
+ON DB . ORDNO = DE . ORDNO 
+AND DB . OPSEQ = DE . OPSEQ 
+AND DB . EMP_KEY = DE . EMP_KEY 
+AND DB . SEQ = DE . SEQ 
+AND DB . WKCTR = DE . WKCTR 
+AND DB . STID = DE . STID 
+LEFT JOIN SFCDWR R 
+ON DB . REASON_CODE = R . KDREASN 
+) , 
+-- ========== WORKCENTER/SITE LIST ========== 
+WC_SITE_LIST AS ( 
+SELECT DISTINCT WKCTR , STID 
+FROM RUN_MATCHED 
+UNION 
+SELECT DISTINCT WKCTR , STID 
+FROM DOWN_MATCHED 
+) , 
+-- ========== HOURLY BREAKDOWN ========== 
+ALL_HOURS AS ( 
+SELECT HR AS HOUR_NUM , 
+TO_DATE ( 
+ZONED ( V_DATE ) || LPAD ( HR * 10000 , 6 , '0' ) , 
+'YYYYMMDDHH24MISS' ) AS HR_START_TS , 
+CASE 
+WHEN 
+HR = 23 
+THEN 
+TO_DATE ( 
+ZONED ( V_DATE + 1 DAY ) || '000000' , 
+'YYYYMMDDHH24MISS' ) 
+ELSE 
+TO_DATE ( 
+ZONED ( V_DATE ) || 
+LPAD ( ( HR + 1 ) * 10000 , 6 , '0' ) , 
+'YYYYMMDDHH24MISS' ) 
+END AS HR_END_TS 
+FROM ( 
+VALUES ( 0 ) , ( 1 ) , ( 2 ) , ( 3 ) , ( 4 ) , ( 5 ) , ( 6 ) , ( 7 ) , ( 8 ) ,( 9 ) , ( 10 ) , ( 11 ) , ( 12 ) , ( 13 ) , ( 14 ) , ( 15 ) , 
+( 16 ) , ( 17 ) , ( 18 ) , ( 19 ) , ( 20 ) , ( 21 ) , ( 22 ) , 
+( 23 ) 
+) T ( HR ) 
+) , 
+-- Run time by hour per workcenter/site 
+RUN_HOURLY AS ( 
+SELECT H . HOUR_NUM , R . WKCTR , R . STID , 
+GREATEST ( 
+0 , TIMESTAMPDIFF ( 
+2 , CHAR ( 
+LEAST ( R . END_TS , H . HR_END_TS ) - 
+GREATEST ( R . START_TS , H . HR_START_TS ) ) ) ) 
+AS RUN_SECONDS , R . PCS_PER_MIN , R . QTY_COMPLETE , 
+R . QTY_SCRAP , R . OFF_DATE , R . OFF_TIME , R . ITNBR , R . ORDNO 
+FROM RUN_MATCHED R , ALL_HOURS H 
+WHERE R . START_TS < H . HR_END_TS 
+AND R . END_TS > H . HR_START_TS 
+) , 
+RUN_BY_HOUR AS ( 
+SELECT HOUR_NUM , WKCTR , STID , SUM ( RUN_SECONDS ) AS RUN_SEC , 
+DEC ( 
+SUM ( 
+DEC ( RUN_SECONDS , 15 , 4 ) * 
+DEC ( PCS_PER_MIN , 15 , 8 ) / 60 ) , 15 , 4 ) 
+AS EXPECTED_QTY , 
+SUM ( 
+CASE 
+WHEN 
+HOUR ( 
+TO_DATE ( 
+ZONED ( CISTOOLS . CYMD2DATE ( OFF_DATE ) ) || 
+LPAD ( OFF_TIME , 6 , '0' ) , 
+'YYYYMMDDHH24MISS' ) ) = HOUR_NUM 
+AND CISTOOLS . CYMD2DATE ( OFF_DATE ) = V_DATE 
+THEN QTY_COMPLETE 
+ELSE 0 
+END ) AS ACTUAL_QTY , 
+SUM ( 
+CASE 
+WHEN 
+HOUR ( 
+TO_DATE ( 
+ZONED ( CISTOOLS . CYMD2DATE ( OFF_DATE ) ) || 
+LPAD ( OFF_TIME , 6 , '0' ) , 
+'YYYYMMDDHH24MISS' ) ) = HOUR_NUM 
+AND CISTOOLS . CYMD2DATE ( OFF_DATE ) = V_DATE 
+THEN QTY_SCRAP 
+ELSE 0 
+END ) AS SCRAP_QTY 
+FROM RUN_HOURLY 
+WHERE RUN_SECONDS > 0 
+GROUP BY HOUR_NUM , WKCTR , STID 
+) , 
+-- Items per hour/wkctr/stid 
+HOURLY_ITEMS AS ( 
+SELECT DISTINCT HOUR_NUM , WKCTR , STID , ORDNO , ITNBR 
+FROM RUN_HOURLY 
+WHERE RUN_SECONDS > 0 
+) , 
+HOURLY_ITEMS_AGG AS ( 
+SELECT HOUR_NUM , WKCTR , STID , 
+JSON_ARRAYAGG ( 
+JSON_OBJECT ( 
+'orderNumber' : CAST ( 
+CAST ( TRIM ( ORDNO ) AS VARCHAR ( 15 ) CCSID 37 ) AS 
+VARCHAR ( 15 ) CCSID 1208 ) , 'itemNumber' : CAST ( 
+CAST ( TRIM ( ITNBR ) AS VARCHAR ( 15 ) CCSID 37 ) AS 
+VARCHAR ( 15 ) CCSID 1208 ) 
+) FORMAT JSON 
+) AS ITEMS 
+FROM HOURLY_ITEMS 
+GROUP BY HOUR_NUM , WKCTR , STID 
+) , 
+-- Downtime by hour per workcenter/site 
+DOWN_HOURLY AS ( 
+SELECT H . HOUR_NUM , D . WKCTR , D . STID , D . IS_SCHEDULED , 
+GREATEST ( 
+0 , TIMESTAMPDIFF ( 
+2 , CHAR ( 
+LEAST ( D . END_TS , H . HR_END_TS ) - 
+GREATEST ( D . START_TS , H . HR_START_TS ) ) ) ) 
+AS DOWN_SECONDS 
+FROM DOWN_MATCHED D , ALL_HOURS H 
+WHERE D . START_TS < H . HR_END_TS 
+AND D . END_TS > H . HR_START_TS 
+) , 
+DOWN_BY_HOUR AS ( 
+SELECT HOUR_NUM , WKCTR , STID , SUM ( 
+CASE 
+WHEN IS_SCHEDULED = 'Y' THEN DOWN_SECONDS 
+ELSE 0 
+END ) AS SCHED_DOWN_SEC , SUM ( 
+CASE 
+WHEN IS_SCHEDULED <> 'Y' THEN DOWN_SECONDS 
+ELSE 0 
+END ) AS UNSCHED_DOWN_SEC 
+FROM DOWN_HOURLY 
+WHERE DOWN_SECONDS > 0 
+GROUP BY HOUR_NUM , WKCTR , STID 
+) , 
+-- ========== COMBINE AND CALCULATE OEE ========== 
+HOURLY_COMBINED AS ( 
+SELECT A . HOUR_NUM , W . WKCTR , W . STID , 
+COALESCE ( R . RUN_SEC , 0 ) AS RUN_SEC , 
+COALESCE ( R . EXPECTED_QTY , DEC ( 0 , 15 , 4 ) ) 
+AS EXPECTED_QTY , 
+COALESCE ( R . ACTUAL_QTY , DEC ( 0 , 15 , 4 ) ) AS ACTUAL_QTY , 
+COALESCE ( R . SCRAP_QTY , DEC ( 0 , 15 , 4 ) ) AS SCRAP_QTY , 
+COALESCE ( D . SCHED_DOWN_SEC , 0 ) AS SCHED_DOWN_SEC , 
+COALESCE ( D . UNSCHED_DOWN_SEC , 0 ) AS UNSCHED_DOWN_SEC , 
+I . ITEMS , 
+LEAST ( 
+COALESCE ( R . RUN_SEC , 0 ) + 
+COALESCE ( D . SCHED_DOWN_SEC , 0 ) + 
+COALESCE ( D . UNSCHED_DOWN_SEC , 0 ) , 3600 ) 
+AS TOTAL_ACTIVE_SEC 
+FROM ALL_HOURS A 
+CROSS JOIN WC_SITE_LIST W 
+LEFT JOIN RUN_BY_HOUR R 
+ON A . HOUR_NUM = R . HOUR_NUM 
+AND W . WKCTR = R . WKCTR 
+AND W . STID = R . STID 
+LEFT JOIN DOWN_BY_HOUR D 
+ON A . HOUR_NUM = D . HOUR_NUM 
+AND W . WKCTR = D . WKCTR 
+AND W . STID = D . STID 
+LEFT JOIN HOURLY_ITEMS_AGG I 
+ON A . HOUR_NUM = I . HOUR_NUM 
+AND W . WKCTR = I . WKCTR 
+AND W . STID = I . STID 
+) , 
+HOURLY_WITH_CUM AS ( 
+SELECT H . * , SUM ( RUN_SEC ) OVER ( 
+PARTITION BY WKCTR , STID 
+ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING 
+) AS CUM_RUN , SUM ( EXPECTED_QTY ) OVER ( 
+PARTITION BY WKCTR , STID 
+ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING 
+) AS CUM_EXPECTED , SUM ( ACTUAL_QTY ) OVER ( 
+PARTITION BY WKCTR , STID 
+ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING 
+) AS CUM_ACTUAL , SUM ( SCRAP_QTY ) OVER ( 
+PARTITION BY WKCTR , STID 
+ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING 
+) AS CUM_SCRAP , SUM ( SCHED_DOWN_SEC ) OVER ( 
+PARTITION BY WKCTR , STID 
+ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING 
+) AS CUM_SCHED_DOWN , SUM ( UNSCHED_DOWN_SEC ) OVER ( 
+PARTITION BY WKCTR , STID 
+ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING 
+) AS CUM_UNSCHED_DOWN , SUM ( TOTAL_ACTIVE_SEC ) OVER ( 
+PARTITION BY WKCTR , STID 
+ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING 
+) AS CUM_ACTIVE 
+FROM HOURLY_COMBINED H 
+) , 
+HOURLY_OEE AS ( 
+SELECT H . * , 
+CASE 
+WHEN 
+TOTAL_ACTIVE_SEC > 0 
+THEN 
+INT ( 
+( CAST ( RUN_SEC AS DOUBLE ) / 
+CAST ( TOTAL_ACTIVE_SEC AS DOUBLE ) ) * 100 
++ 0.5 ) 
+ELSE 0 
+END AS HRLY_AVAIL , 
+CASE 
+WHEN 
+EXPECTED_QTY > 0 
+THEN 
+LEAST ( 
+INT ( 
+( ACTUAL_QTY / EXPECTED_QTY ) * 100 + 
+0.5 ) , 999 ) 
+ELSE 0 
+END AS HRLY_PERF , 
+CASE 
+WHEN 
+( ACTUAL_QTY + SCRAP_QTY ) > 0 
+THEN 
+INT ( 
+( ACTUAL_QTY / ( ACTUAL_QTY + SCRAP_QTY ) ) * 
+100 + 0.5 ) 
+ELSE 100 
+END AS HRLY_QUAL , 
+CASE 
+WHEN 
+CUM_ACTIVE > 0 
+THEN 
+INT ( 
+( CAST ( CUM_RUN AS DOUBLE ) / 
+CAST ( CUM_ACTIVE AS DOUBLE ) ) * 100 + 
+0.5 ) 
+ELSE 0 
+END AS CUM_AVAIL , 
+CASE 
+WHEN 
+CUM_EXPECTED > 0 
+THEN 
+LEAST ( 
+INT ( 
+( CUM_ACTUAL / CUM_EXPECTED ) * 100 + 
+0.5 ) , 999 ) 
+ELSE 0 
+END AS CUM_PERF , 
+CASE 
+WHEN 
+( CUM_ACTUAL + CUM_SCRAP ) > 0 
+THEN 
+INT ( 
+( CUM_ACTUAL / ( CUM_ACTUAL + CUM_SCRAP ) ) * 
+100 + 0.5 ) 
+ELSE 100 
+END AS CUM_QUAL 
+FROM HOURLY_WITH_CUM H 
+) , 
+HOURLY_FINAL AS ( 
+SELECT H . * , 
+CASE 
+WHEN 
+HRLY_AVAIL > 0 
+AND HRLY_PERF > 0 
+AND HRLY_QUAL > 0 
+THEN 
+INT ( 
+( CAST ( HRLY_AVAIL AS DOUBLE ) * 
+CAST ( HRLY_PERF AS DOUBLE ) * 
+CAST ( HRLY_QUAL AS DOUBLE ) / 10000 ) + 
+0.5 ) 
+ELSE 0 
+END AS HRLY_OEE , 
+CASE 
+WHEN 
+CUM_AVAIL > 0 
+AND CUM_PERF > 0 
+AND CUM_QUAL > 0 
+THEN 
+INT ( 
+( CAST ( CUM_AVAIL AS DOUBLE ) * 
+CAST ( CUM_PERF AS DOUBLE ) * 
+CAST ( CUM_QUAL AS DOUBLE ) / 10000 ) + 
+0.5 ) 
+ELSE 0 
+END AS CUM_OEE 
+FROM HOURLY_OEE H 
+) , 
+-- ========== SHIFT TIMES PER WORKCENTER ========== 
+SHIFT_TIMES AS ( 
+SELECT W . WSWKCT AS WKCTR , W . WSSTID AS STID , 
+W . WSSF1B AS SHIFT1_BEGIN , W . WSSF1E AS SHIFT1_END , 
+W . WSSF2B AS SHIFT2_BEGIN , W . WSSF2E AS SHIFT2_END , 
+W . WSSF3B AS SHIFT3_BEGIN , W . WSSF3E AS SHIFT3_END , 
+W . WSDEND AS DAY_END 
+FROM SFCCWKS W 
+) , 
+-- ========== BUILD JSON ========== 
+JSON_HOURS AS ( 
+SELECT WKCTR , STID , HOUR_NUM , 
+JSON_OBJECT ( 
+'hour' : HOUR_NUM , 'hourLabel' : 
+CASE 
+WHEN HOUR_NUM = 0 THEN '12AM' 
+WHEN 
+HOUR_NUM < 12 
+THEN TRIM ( CHAR ( HOUR_NUM ) ) || 'AM' 
+WHEN HOUR_NUM = 12 THEN '12PM' 
+ELSE TRIM ( CHAR ( HOUR_NUM - 12 ) ) || 'PM' 
+END , 
+'items' : COALESCE ( ITEMS , JSON_ARRAY ( ) ) FORMAT JSON , 
+'runMinutes' : INT ( RUN_SEC / 60 ) , 
+'scheduledDownMinutes' : INT ( SCHED_DOWN_SEC / 60 ) , 
+'unscheduledDownMinutes' : INT ( 
+UNSCHED_DOWN_SEC / 60 ) , 'expectedQty' : DEC ( 
+EXPECTED_QTY , 10 , 2 ) , 'actualQty' : DEC ( 
+ACTUAL_QTY , 10 , 2 ) , 'scrapQty' : DEC ( 
+SCRAP_QTY , 10 , 2 ) , 'cumulativeExpected' : DEC ( 
+CUM_EXPECTED , 10 , 2 ) , 'cumulativeActual' : DEC ( 
+CUM_ACTUAL , 10 , 2 ) , 'cumulativeScrap' : DEC ( 
+CUM_SCRAP , 10 , 2 ) , 'variance' : DEC ( 
+CUM_ACTUAL - CUM_EXPECTED , 10 , 2 ) , 
+'hourlyAvailability' : HRLY_AVAIL , 
+'hourlyPerformance' : HRLY_PERF , 
+'hourlyQuality' : HRLY_QUAL , 'hourlyOee' : HRLY_OEE , 
+'cumulativeAvailability' : CUM_AVAIL , 
+'cumulativePerformance' : CUM_PERF , 
+'cumulativeQuality' : CUM_QUAL , 
+'cumulativeOee' : CUM_OEE 
+) AS HOUR_OBJ 
+FROM HOURLY_FINAL 
+) , 
+WC_TOTALS AS ( 
+SELECT WKCTR , STID , MAX ( CUM_ACTUAL ) AS TOTAL_ACTUAL , 
+MAX ( CUM_EXPECTED ) AS TOTAL_EXPECTED , 
+MAX ( CUM_SCRAP ) AS TOTAL_SCRAP , 
+MAX ( CUM_RUN ) AS TOTAL_RUN_SEC , 
+MAX ( CUM_SCHED_DOWN ) AS TOTAL_SCHED_DOWN , 
+MAX ( CUM_UNSCHED_DOWN ) AS TOTAL_UNSCHED_DOWN , 
+MAX ( CUM_OEE ) AS FINAL_OEE , 
+MAX ( CUM_AVAIL ) AS FINAL_AVAIL , 
+MAX ( CUM_PERF ) AS FINAL_PERF , 
+MAX ( CUM_QUAL ) AS FINAL_QUAL 
+FROM HOURLY_FINAL 
+GROUP BY WKCTR , STID 
+) , 
+JSON_WORKCENTERS AS ( 
+SELECT 
+JSON_OBJECT ( 
+'workcenter' : CAST ( 
+CAST ( T . WKCTR AS VARCHAR ( 5 ) CCSID 37 ) AS VARCHAR ( 
+5 ) CCSID 1208 ) , 'site' : CAST ( 
+CAST ( T . STID AS VARCHAR ( 3 ) CCSID 37 ) AS VARCHAR ( 3 ) 
+CCSID 1208 ) , 'hours' : ( SELECT JSON_ARRAYAGG ( 
+H . HOUR_OBJ FORMAT JSON 
+ORDER BY H . HOUR_NUM 
+) 
+FROM JSON_HOURS H 
+WHERE H . WKCTR = T . WKCTR 
+AND H . STID = T . STID ) FORMAT JSON , 
+'totals' : JSON_OBJECT ( 
+'actualQty' : DEC ( 
+COALESCE ( T . TOTAL_ACTUAL , DEC ( 0 , 15 , 4 ) ) , 10 , 
+2 ) , 'expectedQty' : DEC ( 
+COALESCE ( T . TOTAL_EXPECTED , DEC ( 0 , 15 , 4 ) ) , 10 , 
+2 ) , 
+'scrapQty' : DEC ( 
+COALESCE ( T . TOTAL_SCRAP , DEC ( 0 , 15 , 4 ) ) , 10 , 2 
+) , 'variance' : DEC ( 
+COALESCE ( 
+T . TOTAL_ACTUAL - T . TOTAL_EXPECTED , DEC ( 
+0 , 15 , 4 ) ) , 10 , 2 ) , 'runMinutes' : INT ( 
+COALESCE ( T . TOTAL_RUN_SEC , 0 ) / 60 ) , 
+'scheduledDownMinutes' : INT ( 
+COALESCE ( T . TOTAL_SCHED_DOWN , 0 ) / 60 ) , 
+'unscheduledDownMinutes' : INT ( 
+COALESCE ( T . TOTAL_UNSCHED_DOWN , 0 ) / 60 ) , 
+'oeePercentage' : COALESCE ( T . FINAL_OEE , 0 ) , 
+'availabilityPercentage' : COALESCE ( 
+T . FINAL_AVAIL , 0 ) , 
+'performancePercentage' : COALESCE ( 
+T . FINAL_PERF , 0 ) , 
+'qualityPercentage' : COALESCE ( T . FINAL_QUAL , 0 ) 
+) , 'shiftTimes' : ( 
+SELECT JSON_OBJECT ( 
+'shift1Begin' : 
+CASE 
+WHEN 
+S . SHIFT1_BEGIN > 0 
+THEN 
+SUBSTRING ( 
+LPAD ( S . SHIFT1_BEGIN , 6 , '0' ) , 
+1 , 2 ) || ':' || 
+SUBSTRING ( 
+LPAD ( 
+S . SHIFT1_BEGIN , 6 , '0' ) , 
+3 , 2 ) 
+ELSE NULL 
+END , 'shift1End' : 
+CASE 
+WHEN 
+S . SHIFT1_END > 0 
+THEN 
+SUBSTRING ( 
+LPAD ( S . SHIFT1_END , 6 , '0' ) , 1 , 
+2 ) || ':' || 
+SUBSTRING ( 
+LPAD ( S . SHIFT1_END , 6 , '0' ) , 
+3 , 2 ) 
+ELSE NULL 
+END , 'shift2Begin' : 
+CASE 
+WHEN 
+S . SHIFT2_BEGIN > 0 
+THEN 
+SUBSTRING ( 
+LPAD ( S . SHIFT2_BEGIN , 6 , '0' ) , 
+1 , 2 ) || ':' || 
+SUBSTRING ( 
+LPAD ( 
+S . SHIFT2_BEGIN , 6 , '0' ) , 
+3 , 2 ) 
+ELSE NULL 
+END , 'shift2End' : 
+CASE 
+WHEN 
+S . SHIFT2_END > 0 
+THEN 
+SUBSTRING ( 
+LPAD ( S . SHIFT2_END , 6 , '0' ) , 1 , 
+2 ) || ':' || 
+SUBSTRING ( 
+LPAD ( S . SHIFT2_END , 6 , '0' ) , 
+3 , 2 ) 
+ELSE NULL 
+END , 'shift3Begin' : 
+CASE 
+WHEN 
+S . SHIFT3_BEGIN > 0 
+THEN 
+SUBSTRING ( 
+LPAD ( S . SHIFT3_BEGIN , 6 , '0' ) , 
+1 , 2 ) || ':' || 
+SUBSTRING ( 
+LPAD ( 
+S . SHIFT3_BEGIN , 6 , '0' ) , 
+3 , 2 ) 
+ELSE NULL 
+END , 'shift3End' : 
+CASE 
+WHEN 
+S . SHIFT3_END > 0 
+THEN 
+SUBSTRING ( 
+LPAD ( S . SHIFT3_END , 6 , '0' ) , 1 , 
+2 ) || ':' || 
+SUBSTRING ( 
+LPAD ( S . SHIFT3_END , 6 , '0' ) , 
+3 , 2 ) 
+ELSE NULL 
+END , 'dayEnd' : 
+CASE 
+WHEN 
+S . DAY_END > 0 
+THEN 
+SUBSTRING ( 
+LPAD ( S . DAY_END , 6 , '0' ) , 1 , 2 ) 
+|| ':' || 
+SUBSTRING ( 
+LPAD ( S . DAY_END , 6 , '0' ) , 3 , 
+2 ) 
+ELSE NULL 
+END 
+) 
+FROM SHIFT_TIMES S 
+WHERE S . WKCTR = T . WKCTR 
+AND S . STID = T . STID 
+FETCH FIRST 1 ROW ONLY ) FORMAT JSON 
+) AS WC_OBJ 
+FROM WC_TOTALS T 
+ORDER BY T . WKCTR , T . STID ) SELECT JSON_ARRAY ( 
+JSON_OBJECT ( 
+'date' : TO_CHAR ( V_DATE , 'YYYY-MM-DD' ) , 'workcenters' : ( 
+SELECT JSON_ARRAYAGG ( 
+WC_OBJ FORMAT JSON 
+) 
+FROM JSON_WORKCENTERS ) FORMAT JSON , 
+'dataSource' : 'MOTRAN (Live)' , 'generatedAt' : TO_CHAR ( 
+CURRENT_TIMESTAMP , 'YYYY-MM-DD HH24:MI:SS' ) 
+) ) 
+FROM SYSIBM . SYSDUMMY1 ; 
+END  ; 
+
+GRANT ALTER , EXECUTE   
+ON SPECIFIC FUNCTION RESTAPI.SFP_GET_HOURLY_OEE_LIVE 
+TO AMAPICS WITH GRANT OPTION ; 
+
+GRANT EXECUTE   
+ON SPECIFIC FUNCTION RESTAPI.SFP_GET_HOURLY_OEE_LIVE 
+TO PUBLIC ; 
+
