SET PATH *LIBL ; CREATE OR REPLACE FUNCTION RESTAPI.SFP_GET_WORKCENTERS_DETAILS ( IN_PARM CLOB(2147483647) ) RETURNS CLOB(2147483647) LANGUAGE SQL SPECIFIC RESTAPI.SFP_GET_WORKCENTERS_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 V_SITE VARCHAR ( 3 ) DEFAULT '' ; DECLARE V_WC VARCHAR ( 5 ) DEFAULT '' ; DECLARE V_DEPT VARCHAR ( 5 ) DEFAULT '' ; DECLARE V_POSITION VARCHAR ( 5 ) DEFAULT '' ; DECLARE V_SHOW_ALL VARCHAR ( 5 ) DEFAULT 'false' ; DECLARE V_INDIRECT VARCHAR ( 5 ) DEFAULT 'false' ; DECLARE LL VARCHAR ( 1024 ) DEFAULT '' ; DECLARE V_IN_PARM CLOB ( 2 G ) DEFAULT '' ; DECLARE V_TODAY DECIMAL ( 7 , 0 ) DEFAULT 0 ; DECLARE V_CUTOFF DECIMAL ( 7 , 0 ) DEFAULT 9999999 ; -- 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 ; -- Parse input parameters SET V_SITE = COALESCE ( JSON_VALUE ( IN_PARM , '$.site' ) , '' ) ; SET V_WC = COALESCE ( JSON_VALUE ( IN_PARM , '$.workcenter' ) , '' ) ; SET V_DEPT = COALESCE ( JSON_VALUE ( IN_PARM , '$.department' ) , '' ) ; SET V_POSITION = COALESCE ( JSON_VALUE ( IN_PARM , '$.positionTo' ) , '' ) ; SET V_SHOW_ALL = COALESCE ( JSON_VALUE ( IN_PARM , '$.showAll' ) , 'false' ) ;SET V_INDIRECT = COALESCE ( JSON_VALUE ( IN_PARM , '$.indirectOnly' ) , 'false' ) ; -- 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 ) ; -- 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 ; -- Calculate today's date in CYYMMDD SET V_TODAY = ZONED ( CURRENT_DATE ) - 19000000 ; RETURN WITH -- Base workcenter list from FACMST (EPDM) joined with SITMST -- Excludes simulation sites (sims = '0') WC_BASE AS ( SELECT F . WKCTR , F . WCDSC , F . FRMAN , F . DPTNO , F . STID , TRIM ( F . WKGRP ) AS WKGRP , F . WLNCD FROM FACMST F JOIN SITMST S ON F . STID = S . STID WHERE S . SIMS = '0' AND F . STID = COALESCE ( NULLIF ( V_SITE , '' ) , F . STID ) AND F . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , F . WKCTR ) AND F . DPTNO = COALESCE ( NULLIF ( V_DEPT , '' ) , F . DPTNO ) AND F . WKCTR >= COALESCE ( NULLIF ( V_POSITION , '' ) , F . WKCTR ) AND ( V_INDIRECT <> 'true' OR F . WKGRP = 'IND' ) AND ( V_INDIRECT = 'true' OR F . WKGRP <> 'IND' OR V_SHOW_ALL = 'true' ) ) , -- Down status from SFCCWKS joined with SFCDWR for reason description DOWN_STATUS AS ( SELECT W . WSWKCT AS WKCTR , W . WSSTID AS STID , TRIM ( W . WSDWNR ) AS DOWN_REASON , TRIM ( D . KDRDESC ) AS DOWN_DESCRIPTION , D . KDSCHED AS SCHEDULED_DOWN , W . WSSF1B , W . WSSF1E , W . WSSF2B , W . WSSF2E , W . WSSF3B , W . WSSF3E , W . WSDEND , W . WSCCRW AS CURRENT_CREW FROM SFCCWKS W LEFT JOIN SFCDWR D ON TRIM ( W . WSDWNR ) = TRIM ( D . KDREASN ) ) , -- Latest transaction per badge/ordno/opseq to determine ON status -- Mimics SFP002R get_oncnt logic LATEST_TRANS AS ( SELECT T . BADGE , T . ORDNO , T . OPSEQ , T . TRFMT , ROW_NUMBER ( ) OVER ( PARTITION BY T . BADGE , T . ORDNO , T . OPSEQ ORDER BY T . TDATE DESC , T . TTIME DESC ) AS RN FROM TRDATA T WHERE T . TRFMT IN ( 'ON' , 'OF' ) AND T . TSTAT < 5 AND T . ACREC = 'Y' ) , -- Active employees per workcenter/site ACTIVE_EMPS AS ( SELECT R . AWRKC AS WKCTR , M . STID , COUNT ( * ) AS ACTIVE_OPS , COUNT ( DISTINCT L . BADGE ) AS UNIQUE_EMPS FROM LATEST_TRANS L JOIN MOMAST M ON L . ORDNO = M . ORDNO JOIN MOROUT R ON L . ORDNO = R . ORDNO AND L . OPSEQ = R . OPSEQ WHERE L . RN = 1 AND L . TRFMT = 'ON' GROUP BY R . AWRKC , M . STID ) , -- Open order count per workcenter/site -- Orders with opstc > '00' and < '40', ostat > '00' and < '45' OPEN_ORDERS AS ( SELECT R . AWRKC AS WKCTR , M . STID , COUNT ( DISTINCT R . ORDNO ) AS OPEN_COUNT FROM MOROUT R JOIN MOMAST M ON R . ORDNO = M . ORDNO WHERE R . OPSTC > '00' AND R . OPSTC < '40' AND M . OSTAT > '00' AND M . OSTAT < '45' AND M . ODUDT <= V_CUTOFF GROUP BY R . AWRKC , M . STID ) , -- Planned order count per workcenter/site (from LRP) PLANNED_ORDERS AS ( SELECT W . RPWKCT AS WKCTR , W . RPSTID AS STID , COUNT ( DISTINCT W . RPORTK ) AS PLANNED_COUNT FROM LRPWKCT W JOIN ORDREV O ON W . RPORTK = O . TKEN WHERE W . RPODUD <= V_CUTOFF AND W . RPORTK <> ' ' AND O . NNUMB = ' ' GROUP BY W . RPWKCT , W . RPSTID ) , -- Combine all data WC_COMBINED AS ( SELECT B . WKCTR , B . WCDSC , B . FRMAN , B . DPTNO , B . STID , B . WKGRP , B . WLNCD , COALESCE ( D . DOWN_REASON , '' ) AS DOWN_REASON , COALESCE ( D . DOWN_DESCRIPTION , '' ) AS DOWN_DESCRIPTION , COALESCE ( D . SCHEDULED_DOWN , '' ) AS SCHEDULED_DOWN , COALESCE ( D . CURRENT_CREW , '' ) AS CURRENT_CREW , COALESCE ( D . WSSF1B , 0 ) AS SF1_BEGIN , COALESCE ( D . WSSF1E , 0 ) AS SF1_END , COALESCE ( D . WSSF2B , 0 ) AS SF2_BEGIN , COALESCE ( D . WSSF2E , 0 ) AS SF2_END , COALESCE ( D . WSSF3B , 0 ) AS SF3_BEGIN , COALESCE ( D . WSSF3E , 0 ) AS SF3_END , COALESCE ( D . WSDEND , 0 ) AS DAY_END , COALESCE ( A . ACTIVE_OPS , 0 ) AS ACTIVE_OPS , COALESCE ( A . UNIQUE_EMPS , 0 ) AS UNIQUE_EMPS , COALESCE ( O . OPEN_COUNT , 0 ) AS OPEN_ORDERS , COALESCE ( P . PLANNED_COUNT , 0 ) AS PLANNED_ORDERS FROM WC_BASE B LEFT JOIN DOWN_STATUS D ON B . WKCTR = D . WKCTR AND B . STID = D . STID LEFT JOIN ACTIVE_EMPS A ON B . WKCTR = A . WKCTR AND B . STID = A . STID LEFT JOIN OPEN_ORDERS O ON B . WKCTR = O . WKCTR AND B . STID = O . STID LEFT JOIN PLANNED_ORDERS P ON B . WKCTR = P . WKCTR AND B . STID = P . STID ) , -- Build JSON for each workcenter JSON_ROWS AS ( SELECT JSON_OBJECT ( 'workcenterId' : TRIM ( CAST ( WKCTR AS VARCHAR ( 5 ) CCSID 37 ) ) , 'workcenterDescription' : TRIM ( CAST ( WCDSC AS VARCHAR ( 50 ) CCSID 37 ) ) , 'site' : TRIM ( CAST ( STID AS VARCHAR ( 5 ) CCSID 37 ) ) , 'department' : TRIM ( CAST ( DPTNO AS VARCHAR ( 5 ) CCSID 37 ) ) , 'foreman' : TRIM ( CAST ( FRMAN AS VARCHAR ( 5 ) CCSID 37 ) ) , 'workGroup' : CASE WHEN WKGRP = '' THEN NULL ELSE CAST ( WKGRP AS VARCHAR ( 50 ) CCSID 37 ) END , 'isProductionLine' : CASE WHEN WLNCD = '1' THEN 'true' ELSE 'false' END FORMAT JSON , 'isIndirect' : CASE WHEN WKGRP = 'IND' THEN 'true' ELSE 'false' END FORMAT JSON , 'isDown' : CASE WHEN DOWN_REASON <> '' THEN 'true' ELSE 'false' END FORMAT JSON , 'downReason' : CASE WHEN DOWN_REASON = '' THEN NULL ELSE JSON_OBJECT ( 'reasonCode' : DOWN_REASON , 'description' : DOWN_DESCRIPTION , 'scheduled' : CASE WHEN SCHEDULED_DOWN = 'Y' THEN 'true' ELSE 'false' END FORMAT JSON ) END FORMAT JSON , 'currentCrew' : CASE WHEN CURRENT_CREW = '' THEN NULL ELSE CURRENT_CREW END , 'activeOperations' : ACTIVE_OPS , 'uniqueEmployees' : UNIQUE_EMPS , 'employeeDisplay' : CASE WHEN ACTIVE_OPS > 0 THEN TRIM ( CHAR ( UNIQUE_EMPS ) ) || ' / ' || TRIM ( CHAR ( ACTIVE_OPS ) ) ELSE NULL END , 'openOrders' : OPEN_ORDERS , 'plannedOrders' : PLANNED_ORDERS , 'shiftTimes' : JSON_OBJECT ( 'shift1Begin' : CASE WHEN SF1_BEGIN > 0 THEN SUBSTRING ( LPAD ( SF1_BEGIN , 6 , '0' ) , 1 , 2 ) || ':' || SUBSTRING ( LPAD ( SF1_BEGIN , 6 , '0' ) , 3 , 2 ) ELSE NULL END , 'shift1End' : CASE WHEN SF1_END > 0 THEN SUBSTRING ( LPAD ( SF1_END , 6 , '0' ) , 1 , 2 ) || ':' || SUBSTRING ( LPAD ( SF1_END , 6 , '0' ) , 3 , 2 ) ELSE NULL END , 'shift2Begin' : CASE WHEN SF2_BEGIN > 0 THEN SUBSTRING ( LPAD ( SF2_BEGIN , 6 , '0' ) , 1 , 2 ) || ':' || SUBSTRING ( LPAD ( SF2_BEGIN , 6 , '0' ) , 3 , 2 ) ELSE NULL END , 'shift2End' : CASE WHEN SF2_END > 0 THEN SUBSTRING ( LPAD ( SF2_END , 6 , '0' ) , 1 , 2 ) || ':' || SUBSTRING ( LPAD ( SF2_END , 6 , '0' ) , 3 , 2 ) ELSE NULL END , 'shift3Begin' : CASE WHEN SF3_BEGIN > 0 THEN SUBSTRING ( LPAD ( SF3_BEGIN , 6 , '0' ) , 1 , 2 ) || ':' || SUBSTRING ( LPAD ( SF3_BEGIN , 6 , '0' ) , 3 , 2 ) ELSE NULL END , 'shift3End' : CASE WHEN SF3_END > 0 THEN SUBSTRING ( LPAD ( SF3_END , 6 , '0' ) , 1 , 2 ) || ':' || SUBSTRING ( LPAD ( SF3_END , 6 , '0' ) , 3 , 2 ) ELSE NULL END , 'dayEnd' : CASE WHEN DAY_END > 0 THEN SUBSTRING ( LPAD ( DAY_END , 6 , '0' ) , 1 , 2 ) || ':' || SUBSTRING ( LPAD ( DAY_END , 6 , '0' ) , 3 , 2 ) ELSE NULL END ) ) AS WC_OBJ , ACTIVE_OPS , UNIQUE_EMPS FROM WC_COMBINED ORDER BY WKCTR ) , -- Calculate totals TOTALS AS ( SELECT SUM ( ACTIVE_OPS ) AS TOTAL_ACTIVE_OPS , SUM ( UNIQUE_EMPS ) AS TOTAL_UNIQUE_EMPS , COUNT ( * ) AS WORKCENTER_COUNT FROM WC_COMBINED ) SELECT JSON_OBJECT ( 'workcenters' : ( SELECT JSON_ARRAYAGG ( WC_OBJ FORMAT JSON ) FROM JSON_ROWS ) FORMAT JSON , 'totals' : JSON_OBJECT ( 'workcenterCount' : T . WORKCENTER_COUNT , 'totalActiveOperations' : COALESCE ( T . TOTAL_ACTIVE_OPS , 0 ) , 'totalUniqueEmployees' : COALESCE ( T . TOTAL_UNIQUE_EMPS , 0 ) , 'employeeDisplay' : TRIM ( CHAR ( COALESCE ( T . TOTAL_UNIQUE_EMPS , 0 ) ) ) || ' / ' || TRIM ( CHAR ( COALESCE ( T . TOTAL_ACTIVE_OPS , 0 ) ) ) ) , 'filters' : JSON_OBJECT ( 'site' : CASE WHEN V_SITE = '' THEN NULL ELSE V_SITE END , 'workcenter' : CASE WHEN V_WC = '' THEN NULL ELSE V_WC END , 'department' : CASE WHEN V_DEPT = '' THEN NULL ELSE V_DEPT END , 'showAll' : CASE WHEN V_SHOW_ALL = 'true' THEN 'true' ELSE 'false' END FORMAT JSON , 'indirectOnly' : CASE WHEN V_INDIRECT = 'true' THEN 'true' ELSE 'false' END FORMAT JSON ) , 'generatedAt' : TO_CHAR ( CURRENT_TIMESTAMP , 'YYYY-MM-DD HH24:MI:SS' ) ) FROM TOTALS T ; END ; GRANT ALTER , EXECUTE ON SPECIFIC FUNCTION RESTAPI.SFP_GET_WORKCENTERS_DETAILS TO AMAPICS WITH GRANT OPTION ; GRANT EXECUTE ON SPECIFIC FUNCTION RESTAPI.SFP_GET_WORKCENTERS_DETAILS TO PUBLIC ;