DELIMITER // CREATE OR REPLACE PROCEDURE bpmm02_sign_active ( IN p_token VARCHAR(100), -- 可轉為 userid IN p_sign_type VARCHAR(1), -- A:同意 R:拒絕 C:作廢 IN p_uuid VARCHAR(100), -- 也可以傳入 functiontag IN p_source_pk_value VARCHAR(100), -- 單號 IN p_sign_note NVARCHAR(600), -- 簽核意見 IN p_next_signer VARCHAR(20) -- 下一關簽核人(New) ) /* 功能 : 本程式主要管理簽核時的 同意/拒絕/作廢 等核心控制,並負責回寫原單的相關資料 描述 : 範例 : CALL bpmm02_sign_active('token123','A','hrsm11','221030-001','gm ok', '') 建立日期 : 2022/11/11 修改歷史 項目 誰 日期 修改說明 ==== ========== ========== ================================================ 1 Michael 2022-11-11 Init 2 Michael 2022-11-16 改為 token, 加強安全性 3 Michael 2022-11-28 加入指定簽核人 assign_to 的設定(解決多人指定派工的 issue) 4 Michale 2023-04-14 配合 Node 機制, 加入 bpm 發送 mail 的通用機制 */ BEGIN DECLARE v_sql LONGTEXT; DECLARE v_tablename VARCHAR(100); DECLARE v_source_pk VARCHAR(100); DECLARE v_flow_status VARCHAR(1); DECLARE v_userid VARCHAR(20); DECLARE v_id INT; -- 當前 id DECLARE v_id_next INT; -- 另一筆 id DECLARE v_flow_level INT; -- 當前 id 的 flow_level DECLARE v_all_signers VARCHAR(200); DECLARE v_done INT DEFAULT FALSE; DECLARE v_has_error INT DEFAULT 0; -- 根據傳入的 token 取得 userid proc_label: BEGIN SELECT checktoken(p_token) INTO v_userid; IF v_userid = '' THEN LEAVE proc_label; END IF; -- 以請假單為例(由 tag 轉 uuid) IF LENGTH(p_uuid) < 20 THEN SELECT flow_id INTO p_uuid FROM bpm_list WHERE functiontag = p_uuid; END IF; -- 取得當前待簽核的 id, 及前一或後一步驟的 id SELECT id, flow_level INTO v_id, v_flow_level FROM bpm_flow_sign WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND signerid = v_userid AND sign_status = 'P'; -- 如果不符合條件, 就直接離開 IF v_id IS NULL THEN LEAVE proc_label; END IF; -- api 參數不能為空, 所以會傳 * IF p_next_signer = '*' OR p_next_signer IS NULL OR p_next_signer = '' THEN SET p_next_signer = ''; END IF; -- 開始交易 /* DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN SET v_has_error = 1; GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE, @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT; SET @error_message = CONCAT('Error occurred: ', @errno, ' (', @sqlstate, '): ', @text); ROLLBACK; END; */ START TRANSACTION; /* step 1: 要變更2筆記錄 目前這一筆 前或後一筆(Reject or Agree) */ -- update bpm_flow_sign UPDATE bpm_flow_sign SET sign_status = p_sign_type WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND id = v_id; SET v_flow_status = 'P'; SET v_id_next = 0; IF p_sign_type = 'A' THEN -- 同意, 下一關 SELECT id INTO v_id_next FROM bpm_flow_sign WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND flow_level = v_flow_level + 1; -- 如果是同意, 且是最後一關, 就結案 IF v_id_next IS NULL THEN SET v_flow_status = 'Z'; ELSE SET v_flow_status = 'P'; END IF; ELSEIF p_sign_type = 'R' THEN -- 駁回, 前一關(改為可以往前任意指派) -- 若不指定, 就自動往前一關(已簽核過的人) IF p_next_signer = '' THEN SELECT id INTO v_id_next FROM bpm_flow_sign WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND flow_level = v_flow_level - 1; ELSE -- 注意防錯, 如果同一人多次出現在已簽核中, 取最近的一筆 SELECT id INTO v_id_next FROM bpm_flow_sign WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND flow_level < v_flow_level AND signerid = p_next_signer ORDER BY flow_level DESC LIMIT 1; END IF; SET v_flow_status = 'P'; ELSEIF p_sign_type = 'C' THEN SET v_flow_status = 'C'; END IF; -- 作廢就不必看下一步 -- 加入 mail 機制, 使用的是 Node.js 的 Schedule mail 機制 IF p_sign_type <> 'C' AND v_id_next IS NOT NULL THEN -- update bpm_flow_sign UPDATE bpm_flow_sign SET sign_status = 'P' WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND id = v_id_next; /* 寫入發送 mail 的統一管控檔(use zenclouddb) 使用 sys_users.user_extend1 = Y 判斷是否要送 mail */ INSERT INTO zen_mail_list (corp_db, recipient, mail_subject, content, mail_status, create_date) SELECT p.pvalue, u.email, CONCAT('簽核通知:【', s.flow_name, '】', bs.sign_note), CONCAT('Hi ', u.username, ',\n', '您有一個待簽核的電子表單,請登入簽核系統後,速審速核,感謝您的配合 !!\n', '送達時間:', DATE_FORMAT(bs.create_date, '%Y-%m-%d %H:%i:%s'), '\n', '主旨:', bs.sign_note, '\n', '簽核步驟:', bs.stepname), 0, NOW() FROM bpm_flow_sign bs LEFT JOIN sys_users u ON bs.signerid = u.userid LEFT JOIN sys_parameter p ON p.pid = 'corpid' LEFT JOIN bpm_list s ON s.flow_id = bs.flow_id WHERE bs.flow_id = p_uuid AND bs.sourceid = p_source_pk_value AND bs.id = v_id_next AND IFNULL(u.user_extend1, '') = 'Y'; -- 如果 next_signer 不為空, 且存在下一關, assign_to=Y(TBD), 相關 sp 要一併檢查並修正 -- 先將之前的設定重置, 再重設 UPDATE bpm_flow_sign SET assign_to = 'N' WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND id = v_id_next; IF p_next_signer <> '' THEN UPDATE bpm_flow_sign SET assign_to = 'Y' WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND id = v_id_next AND signerid = p_next_signer; ELSE -- 如果沒有指定, 就要全部都設為 Y UPDATE bpm_flow_sign SET assign_to = 'Y' WHERE flow_id = p_uuid AND sourceid = p_source_pk_value AND id = v_id_next; END IF; -- 取得下一關的人(多人用逗號分隔) SELECT bpmm02_udf_next_signer(p_uuid, p_source_pk_value, 1) INTO v_all_signers; IF v_all_signers IS NULL THEN SET v_all_signers = ''; -- 防錯 END IF; END IF; /* step 2: 要寫入 log */ -- insert bpm_flow_sign_log INSERT INTO bpm_flow_sign_log (flow_id, sourceid, signerid, sign_status, sign_note, create_date) VALUES (p_uuid, p_source_pk_value, v_userid, p_sign_type, p_sign_note, NOW()); /* step 3: 寫回原單的 flow_status N:待簽核 P:簽核中 Z:結案 C:作廢 */ -- update 原單(hrs_leave), flow_level 及 flowstatus SELECT source_table, source_pk INTO v_tablename, v_source_pk FROM bpm_list WHERE flow_id = p_uuid; -- 動態SQL更新原表 SET v_sql = CONCAT( 'UPDATE ', v_tablename, ' SET flow_status = ''', v_flow_status, ''', flow_signer = ''', IFNULL(v_all_signers, ''), ''' WHERE ', v_source_pk, ' = ''', p_source_pk_value, ''''); -- 執行動態SQL SET @dynamic_sql = v_sql; PREPARE stmt FROM @dynamic_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 沒問題就確認交易完成 IF v_has_error = 0 THEN COMMIT; END IF; END; END // DELIMITER ;