SET PATH *LIBL ; 

CREATE OR REPLACE FUNCTION RESTAPI.SFP_GET_WORK_ORDERS ( 
	IN_PARM CLOB(2147483647) ) 
	RETURNS CLOB(2147483647)   
	LANGUAGE SQL 
	SPECIFIC RESTAPI.SFP_GET_WORK_ORDERS 
	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_WC VARCHAR ( 5 ) DEFAULT '' ; 
DECLARE V_SITE VARCHAR ( 3 ) DEFAULT '' ; 
DECLARE V_CUTOFF DECIMAL ( 7 , 0 ) DEFAULT 9999999 ; 
DECLARE V_SORT CHAR ( 1 ) DEFAULT 'D' ; 
DECLARE V_TODAY DECIMAL ( 7 , 0 ) ; 
DECLARE LL VARCHAR ( 1024 ) DEFAULT '' ; 
DECLARE V_IN_PARM CLOB ( 2 G ) 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 ; 
-- Parse input parameters 
SET V_WC = COALESCE ( JSON_VALUE ( IN_PARM , '$.workcenter' ) , '' ) ; 
SET V_SITE = COALESCE ( JSON_VALUE ( IN_PARM , '$.site' ) , '' ) ; 
SET V_SORT = COALESCE ( UPPER ( JSON_VALUE ( IN_PARM , '$.sort' ) ) , 'D' ) ; 
SET V_CUTOFF = COALESCE ( 
DECIMAL ( JSON_VALUE ( IN_PARM , '$.cutoffDate' ) , 7 , 0 ) , 9999999 ) ; 
-- 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 
-- Get all orders with routing operations at this workcenter 
BASE_ORDERS AS ( 
SELECT R . ORDNO , R . OPSEQ , R . AWRKC AS WKCTR , R . OPSTC , R . SSTDT , 
R . SCODT , R . TQCTD , R . SCRAP , R . OPDSC , M . FITEM , M . FDESC , 
M . OSTAT , M . ORQTY , M . QTDEV , M . QTYRC , M . QTSCP , M . QTSPL , 
M . ODUDT , M . SSTDT AS MO_SSTDT , M . STID , M . UU40MY , 
-- Calculate open at operation 
M . ORQTY + M . QTDEV - COALESCE ( M . QTSPL , 0 ) AS ADJ_QTY 
FROM MOROUT R 
JOIN MOMAST M 
ON R . ORDNO = M . ORDNO 
WHERE R . AWRKC = COALESCE ( NULLIF ( V_WC , '' ) , R . AWRKC ) 
AND R . OPSTC BETWEEN '10' AND '30' 
AND M . OSTAT BETWEEN '10' AND '40' 
AND M . ORLCD = 5 
AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) 
AND ( V_CUTOFF = 9999999 
OR M . ODUDT <= V_CUTOFF ) 
) , 
-- Get active ON transactions (employees currently on jobs) 
ACTIVE_TRANS AS ( 
SELECT T . ORDNO , T . OPSEQ , T . BADGE , T . SUBTP , T . TRFMT , T . TDATE ,T . TTIME , ROW_NUMBER ( ) OVER ( 
PARTITION BY T . ORDNO , T . OPSEQ , T . BADGE 
ORDER BY T . TDATE DESC , T . TTIME DESC 
) AS RN 
FROM TRDATA T 
JOIN MOMAST M 
ON T . ORDNO = M . ORDNO 
WHERE T . TRFMT IN ( 'ON' , 'OF' ) 
AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) 
AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) 
AND T . ACREC = 'Y' 
AND T . TSTAT < 5 
) , 
-- Filter to only currently ON (latest trans is ON) 
CURRENTLY_ON AS ( 
SELECT ORDNO , OPSEQ , BADGE , SUBTP 
FROM ACTIVE_TRANS 
WHERE RN = 1 
AND TRFMT = 'ON' 
) , 
-- Aggregate active employees per order/operation 
ACTIVE_EMPS AS ( 
SELECT ORDNO , OPSEQ , COUNT ( DISTINCT BADGE ) AS ACTIVE_COUNT , 
MAX ( 
CASE 
WHEN SUBTP = 'R' THEN 1 
ELSE 0 
END ) AS HAS_RUN , MAX ( 
CASE 
WHEN SUBTP = 'S' THEN 1 
ELSE 0 
END ) AS HAS_SETUP , MAX ( 
CASE 
WHEN SUBTP = 'I' THEN 1 
ELSE 0 
END ) AS HAS_INDIRECT , 
LISTAGG ( 
DISTINCT CAST ( BADGE AS VARCHAR ( 10 ) ) , ',' ) 
WITHIN GROUP ( ORDER BY BADGE ) AS EMP_LIST 
FROM CURRENTLY_ON 
GROUP BY ORDNO , OPSEQ 
) , 
-- Get management priorities 
PRIORITIES AS ( 
SELECT SMORDR AS ORDNO , SMOPSQ AS OPSEQ , SMPRI AS PRIORITY 
FROM SFMPRI 
WHERE SMPRI <> '' 
) , 
-- Get prior operation quantities for open at operation calc 
PRIOR_OPS AS ( 
SELECT R . ORDNO , R . OPSEQ , COALESCE ( SUM ( 
CASE 
WHEN PR . OPSEQ < R . OPSEQ THEN PR . TQCTD 
ELSE 0 
END ) , 0 ) AS PRIOR_COMPLETE 
FROM MOROUT R 
LEFT JOIN MOROUT PR 
ON R . ORDNO = PR . ORDNO 
AND PR . OPSEQ < R . OPSEQ 
GROUP BY R . ORDNO , R . OPSEQ 
) , 
-- Combine all data 
COMBINED AS ( 
SELECT B . * , COALESCE ( A . ACTIVE_COUNT , 0 ) AS ACTIVE_EMP_COUNT , 
COALESCE ( A . HAS_RUN , 0 ) AS HAS_RUN , 
COALESCE ( A . HAS_SETUP , 0 ) AS HAS_SETUP , 
COALESCE ( A . HAS_INDIRECT , 0 ) AS HAS_INDIRECT , 
A . EMP_LIST , P . PRIORITY AS MGMT_PRIORITY , 
-- Calculate open at operation 
B . ADJ_QTY - COALESCE ( PO . PRIOR_COMPLETE , 0 ) 
AS OPEN_AT_OP , 
-- Determine status/sort priority 
CASE 
WHEN A . ACTIVE_COUNT > 0 THEN 'A'  -- Active 
WHEN P . PRIORITY IS NOT NULL THEN 'B'  -- Priority 
ELSE 'C'  -- Normal 
END AS SORT_PRIORITY , 
-- Determine active type 
CASE 
WHEN A . HAS_RUN = 1 THEN 'R' 
WHEN A . HAS_SETUP = 1 THEN 'S' 
WHEN A . HAS_INDIRECT = 1 THEN 'I' 
ELSE '' 
END AS ACTIVE_TYPE 
FROM BASE_ORDERS B 
LEFT JOIN ACTIVE_EMPS A 
ON B . ORDNO = A . ORDNO 
AND B . OPSEQ = A . OPSEQ 
LEFT JOIN PRIORITIES P 
ON B . ORDNO = P . ORDNO 
AND ( P . OPSEQ = COALESCE ( 
NULLIF ( B . OPSEQ , '' ) , P . OPSEQ ) ) 
LEFT JOIN PRIOR_OPS PO 
ON B . ORDNO = PO . ORDNO 
AND B . OPSEQ = PO . OPSEQ 
) , 
-- Build JSON for each order 
JSON_ORDERS AS ( 
SELECT 
JSON_OBJECT ( 
'orderNumber' : CAST ( 
TRIM ( ORDNO ) AS VARCHAR ( 7 ) CCSID 37 ) , 
'operationSequence' : CAST ( 
TRIM ( OPSEQ ) AS VARCHAR ( 4 ) CCSID 37 ) , 
'workcenter' : CAST ( 
TRIM ( WKCTR ) AS VARCHAR ( 5 ) CCSID 37 ) , 
'site' : CAST ( TRIM ( STID ) AS VARCHAR ( 3 ) CCSID 37 ) , 
'itemNumber' : CAST ( 
TRIM ( FITEM ) AS VARCHAR ( 15 ) CCSID 37 ) , 
'itemDescription' : CAST ( 
TRIM ( FDESC ) AS VARCHAR ( 40 ) CCSID 37 ) , 
'operationDescription' : CAST ( 
TRIM ( OPDSC ) AS VARCHAR ( 40 ) CCSID 37 ) , 
'orderStatus' : CAST ( 
TRIM ( OSTAT ) AS VARCHAR ( 2 ) CCSID 37 ) , 
'operationStatus' : CAST ( 
TRIM ( OPSTC ) AS VARCHAR ( 2 ) CCSID 37 ) , 
'orderQuantity' : DEC ( ORQTY , 11 , 3 ) , 
'quantityComplete' : DEC ( QTYRC , 11 , 3 ) , 
'quantityScrap' : DEC ( QTSCP , 11 , 3 ) , 
'openAtOperation' : DEC ( 
COALESCE ( OPEN_AT_OP , ADJ_QTY ) , 11 , 3 ) , 
'operationScrap' : DEC ( SCRAP , 11 , 3 ) , 
'orderDueDate' : 
CASE 
WHEN 
ODUDT > 0 
THEN 
TO_CHAR ( 
DATE ( 
TIMESTAMP_FORMAT ( 
CHAR ( ODUDT + 19000000 ) , 
'YYYYMMDD' ) ) , 'YYYY-MM-DD' ) 
ELSE NULL 
END , 'operationStartDate' : 
CASE 
WHEN 
SSTDT > 0 
THEN 
TO_CHAR ( 
DATE ( 
TIMESTAMP_FORMAT ( 
CHAR ( SSTDT + 19000000 ) , 
'YYYYMMDD' ) ) , 'YYYY-MM-DD' ) 
ELSE NULL 
END , 'operationDueDate' : 
CASE 
WHEN 
SCODT > 0 
THEN 
TO_CHAR ( 
DATE ( 
TIMESTAMP_FORMAT ( 
CHAR ( SCODT + 19000000 ) , 
'YYYYMMDD' ) ) , 'YYYY-MM-DD' ) 
ELSE NULL 
END , 'managementPriority' : CAST ( 
TRIM ( COALESCE ( MGMT_PRIORITY , '' ) ) AS VARCHAR ( 4 ) 
CCSID 37 ) , 'sortPriority' : SORT_PRIORITY , 
'isActive' : 
CASE 
WHEN ACTIVE_EMP_COUNT > 0 THEN 'true' 
ELSE 'false' 
END FORMAT JSON , 'activeType' : CAST ( 
ACTIVE_TYPE AS VARCHAR ( 1 ) CCSID 37 ) , 
'activeTypeLabel' : 
CASE ACTIVE_TYPE 
WHEN 'R' THEN 'Run' 
WHEN 'S' THEN 'Setup' 
WHEN 'I' THEN 'Indirect' 
ELSE '' 
END , 'activeEmployeeCount' : ACTIVE_EMP_COUNT , 
'activeEmployees' : CAST ( 
COALESCE ( EMP_LIST , '' ) AS VARCHAR ( 100 ) CCSID 37 
) 
) AS ORDER_OBJ , SORT_PRIORITY , 
CASE V_SORT 
WHEN 'D' THEN CHAR ( ODUDT ) 
WHEN 'S' THEN CHAR ( SSTDT ) 
WHEN 'M' THEN ORDNO 
WHEN 'I' THEN FITEM 
WHEN 'E' THEN FDESC 
ELSE CHAR ( ODUDT ) 
END AS SORT_FIELD 
FROM COMBINED 
) , 
-- Count totals 
TOTALS AS ( 
SELECT MAX ( WKCTR ) AS WKCTR , MAX ( STID ) AS STID , 
COUNT ( * ) AS TOTAL_ORDERS , SUM ( 
CASE 
WHEN ACTIVE_EMP_COUNT > 0 THEN 1 
ELSE 0 
END ) AS ACTIVE_ORDERS , SUM ( 
CASE 
WHEN MGMT_PRIORITY IS NOT NULL THEN 1 
ELSE 0 
END ) AS PRIORITY_ORDERS , 
SUM ( ACTIVE_EMP_COUNT ) AS TOTAL_ACTIVE_EMPS 
FROM COMBINED 
) SELECT JSON_OBJECT ( 
'workcenter' : CAST ( WKCTR AS VARCHAR ( 5 ) CCSID 37 ) , 
'site' : CAST ( STID AS VARCHAR ( 3 ) CCSID 37 ) , 'orders' : ( 
SELECT JSON_ARRAYAGG ( 
ORDER_OBJ FORMAT JSON 
ORDER BY SORT_PRIORITY , SORT_FIELD 
) 
FROM JSON_ORDERS ) FORMAT JSON , 'summary' : ( 
SELECT JSON_OBJECT ( 
'totalOrders' : TOTAL_ORDERS , 
'activeOrders' : ACTIVE_ORDERS , 
'priorityOrders' : PRIORITY_ORDERS , 
'totalActiveEmployees' : TOTAL_ACTIVE_EMPS 
) 
FROM TOTALS ) FORMAT JSON , 'sortBy' : V_SORT , 
'sortLabel' : 
CASE V_SORT 
WHEN 'D' THEN 'Due Date' 
WHEN 'S' THEN 'Start Date' 
WHEN 'M' THEN 'Order Number' 
WHEN 'I' THEN 'Item Number' 
WHEN 'E' THEN 'Description' 
ELSE 'Due Date' 
END , 'generatedAt' : TO_CHAR ( 
CURRENT_TIMESTAMP , 'YYYY-MM-DD HH24:MI:SS' ) 
) 
FROM TOTALS ; 
END  ; 

GRANT ALTER , EXECUTE   
ON SPECIFIC FUNCTION RESTAPI.SFP_GET_WORK_ORDERS 
TO AMAPICS WITH GRANT OPTION ; 

GRANT EXECUTE   
ON SPECIFIC FUNCTION RESTAPI.SFP_GET_WORK_ORDERS 
TO PUBLIC ; 

