diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..50088769 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,9 @@ +# Repo Working Notes + +- Verify the actual file, class name, and call site before changing a library/controller reference. +- If a class load error appears, check the existing library file and the current repo usage pattern first. +- Do not swap to a different library name on assumption alone. +- Keep fixes minimal and local unless the user asks for a broader refactor. +- If a task changes live DB objects such as table schema, trigger, stored procedure, or function, always add a SQL record file under `sql/manual_changes/`. +- Name the SQL record file with the pattern `YYYY-MM-DD-.sql`. +- The SQL record file must include the actual SQL change that was applied, not just a note. diff --git a/application/controllers/mockup/process/resultentry-v23/Re_px.php b/application/controllers/mockup/process/resultentry-v23/Re_px.php index 200cc5d0..2552eb8b 100644 --- a/application/controllers/mockup/process/resultentry-v23/Re_px.php +++ b/application/controllers/mockup/process/resultentry-v23/Re_px.php @@ -493,19 +493,27 @@ class Re_px extends MY_Controller } } } - if ($lang == $this->lang_default_code) { - $this->db_smartone->set('T_OrderDetailResult', $v->result) - ->set('T_OrderDetailResultFlag', $result_flag) - ->set('T_OrderDetailNote', $v->note) - ->set('T_OrderDetailReqStatus', $req_status) - ->where('T_OrderDetailID', $v->id) - ->update('t_orderdetail'); - } else { - $this->db_smartone->set('T_OrderDetailLangResult', $v->result) - ->set('T_OrderDetailLangNote', $v->note) - ->where('T_OrderDetailLangID', $v->id) - ->update('t_orderdetaillang'); - } + if ($lang == $this->lang_default_code) { + $result_save = $this->db_smartone->set('T_OrderDetailResult', $v->result) + ->set('T_OrderDetailResultFlag', $result_flag) + ->set('T_OrderDetailNote', $v->note) + ->set('T_OrderDetailReqStatus', $req_status) + ->where('T_OrderDetailID', $v->id) + ->update('t_orderdetail'); + if (!$result_save) { + $this->sys_error_db("Save result entry", $this->db_smartone); + return; + } + } else { + $result_save = $this->db_smartone->set('T_OrderDetailLangResult', $v->result) + ->set('T_OrderDetailLangNote', $v->note) + ->where('T_OrderDetailLangID', $v->id) + ->update('t_orderdetaillang'); + if (!$result_save) { + $this->sys_error_db("Save result entry lang", $this->db_smartone); + return; + } + } diff --git a/sql/manual_changes/2026-04-23-fix-resultentry-save-trigger-log-created.sql b/sql/manual_changes/2026-04-23-fix-resultentry-save-trigger-log-created.sql new file mode 100644 index 00000000..45961ac6 --- /dev/null +++ b/sql/manual_changes/2026-04-23-fix-resultentry-save-trigger-log-created.sql @@ -0,0 +1,346 @@ +-- Date: 2026-04-23 +-- Commit message stem: Fix resultentry save trigger log created +-- Target: devone / one_lab +-- Reason: +-- t_orderdetail_au failed on UPDATE with: +-- ERROR 1136 (21S01): Column count doesn't match value count at row 1 +-- Root cause: +-- INSERT into one_lab_log.log_orderdetail listed Log_OrderDetailCreated +-- but did not provide a corresponding VALUES entry. +-- Fix: +-- restore the trigger and add NOW() for Log_OrderDetailCreated. + +DELIMITER // + +DROP TRIGGER IF EXISTS t_orderdetail_au// + +CREATE TRIGGER t_orderdetail_au AFTER UPDATE ON t_orderdetail +FOR EACH ROW +BEGIN + +DECLARE count_lab INTEGER; +DECLARE cnt_rst_a INTEGER; +DECLARE cnt_rst_b INTEGER; +DECLARE cnt_ver_n INTEGER; +DECLARE cnt_val_n INTEGER; +DECLARE cnt_rst CHAR(1); +DECLARE cnt_ver CHAR(1); +DECLARE cnt_val CHAR(1); +DECLARE ROUNDING double; +DECLARE TYPE_LOG VARCHAR(50); + +DECLARE ref CHAR(1); +DECLARE ref_id INTEGER; + +DECLARE nat_test_id INTEGER; +DECLARE curr_pre_analytic CHAR(1); +DECLARE pre_analytic CHAR(1) DEFAULT 'N'; + +DECLARE sumx DOUBLE; +SET sumx = 0; + +SET sumx = ( + SELECT SUM(IFNULL(T_OrderDetailTotal, 0)) + FROM t_orderdetail + WHERE T_OrderDetailT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID + AND T_OrderDetailIsActive = 'Y' +); + +SET sumx = ( + SELECT SUM(IFNULL(T_OrderDetailTotal, 0)) + FROM t_orderdetail + WHERE T_OrderDetailT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID + AND T_OrderDetailIsActive = 'Y' +); + +IF sumx IS NULL THEN + SET sumx = 0; +END IF; + +SET ROUNDING = MOD(sumx, 500); +SET sumx = sumx - MOD(sumx, 500); + +UPDATE t_orderheader +SET T_OrderHeaderSubTotal = sumx, + T_OrderHeaderRounding = ROUNDING +WHERE T_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID; + +IF NEW.T_OrderDetailIsActive = 'N' + AND OLD.T_OrderDetailIsActive = 'Y' + AND NEW.T_OrderDetailT_TestIsPrice = 'Y' THEN + INSERT INTO one_log.log_px(Log_PxCode, Log_PxJson, Log_PxUserID) + SELECT 'FO.DELPX', + JSON_OBJECT('test_id', NEW.T_OrderDetailT_TestID, 'old_is_active', 'Y', 'new_is_active', 'N'), + 0; +END IF; + +IF NEW.T_OrderDetailIsActive = 'N' AND OLD.T_OrderDetailIsActive = 'Y' THEN + UPDATE so_resultentry + SET So_ResultEntryIsActive = 'N' + WHERE So_ResultEntryT_OrderDetailID = NEW.T_OrderDetailID; + + UPDATE t_samplingso + SET T_SamplingSoIsActive = 'N' + WHERE T_SamplingSoT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID + AND T_SamplingSoT_TestID = NEW.T_OrderDetailT_TestID; + + SET count_lab = ( + SELECT COUNT(T_OrderDetailID) + FROM t_orderdetail + JOIN t_test ON T_OrderDetailT_TestID = T_TestID + JOIN nat_group ON Nat_GroupID = T_TestNat_GroupID + AND Nat_GroupCode = 1 + AND Nat_GroupIsActive = 'Y' + WHERE T_OrderDetailIsActive = 'Y' + AND T_OrderDetailT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID + ); + + IF count_lab = 0 THEN + UPDATE helper_order + SET Helper_OrderIsLAB = 'N' + WHERE Helper_OrderT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID; + ELSE + UPDATE helper_order + SET Helper_OrderIsLAB = 'Y' + WHERE Helper_OrderT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID; + END IF; +END IF; + +IF NEW.T_OrderDetailT_TestIsResult = 'Y' THEN + SELECT COUNT(T_OrderDetailID), + SUM(IF(T_OrderDetailResult <> '' AND T_OrderDetailResult IS NOT NULL, 1, 0)), + SUM(IF(T_OrderDetailVerification = 'Y', 1, 0)), + SUM(IF(T_OrderDetailValidation = 'Y', 1, 0)) + INTO cnt_rst_a, cnt_rst_b, cnt_ver_n, cnt_val_n + FROM t_orderdetail + JOIN t_test ON T_OrderDetailT_TestID = T_TestID + JOIN documentation_group_detail ON DocumentationGroupDetailNat_SubGroupID = T_TestNat_SubGroupID + AND DocumentationGroupDetailIsActive = 'Y' + JOIN documentation_group ON DocumentationGroupDetailDocumentationGroupID = DocumentationGroupID + AND DocumentationGroupName = 'lab' + WHERE T_OrderDetailIsActive = 'Y' + AND T_OrderDetailT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID + AND T_OrderDetailT_TestIsResult = 'Y'; + + IF OLD.T_OrderDetailResult <> NEW.T_OrderDetailResult THEN + IF cnt_rst_a = cnt_rst_b THEN + SET cnt_rst = 'Y'; + ELSE + SET cnt_rst = 'N'; + END IF; + + UPDATE t_orderheaderaddon + SET T_OrderHeaderAddonResultDone = cnt_rst + WHERE T_OrderHeaderAddOnT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID; + END IF; + + IF OLD.T_OrderDetailVerification <> NEW.T_OrderDetailVerification THEN + IF cnt_rst_a = cnt_ver_n THEN + SET cnt_ver = 'Y'; + ELSE + SET cnt_ver = 'N'; + END IF; + + IF cnt_rst_a <> cnt_ver_n AND cnt_ver_n > 0 THEN + SET cnt_ver = 'P'; + END IF; + + UPDATE t_orderheaderaddon + SET T_OrderHeaderAddonVerificationDone = cnt_ver + WHERE T_OrderHeaderAddOnT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID; + END IF; + + IF OLD.T_OrderDetailValidation <> NEW.T_OrderDetailValidation THEN + IF cnt_rst_a = cnt_val_n THEN + SET cnt_val = 'Y'; + ELSE + SET cnt_val = 'N'; + END IF; + + IF cnt_rst_a <> cnt_val_n AND cnt_val_n > 0 THEN + SET cnt_val = 'P'; + END IF; + + UPDATE t_orderheaderaddon + SET T_OrderHeaderAddonValidationDone = cnt_val + WHERE T_OrderHeaderAddOnT_OrderHeaderID = NEW.T_OrderDetailT_OrderHeaderID; + END IF; +END IF; + +IF NEW.T_OrderDetailT_TestIsResult = 'Y' THEN + IF NEW.T_OrderDetailResult <> OLD.T_OrderDetailResult + OR (NEW.T_OrderDetailResult IS NOT NULL AND OLD.T_OrderDetailResult IS NULL) THEN + SELECT T_OrderDetailAddOnRef, T_OrderDetailAddOnRefID + INTO ref, ref_id + FROM t_orderdetailaddon + WHERE T_OrderDetailAddOnT_OrderDetailID = NEW.T_OrderDetailID + AND T_OrderDetailAddOnIsActive = 'Y' + LIMIT 1; + + IF ref = 'X' THEN + INSERT INTO xfer_internal( + Xfer_InternalType, + Xfer_InternalDataType, + Xfer_InternalSrcM_BranchID, + Xfer_InternalDestM_BranchID, + Xfer_InternalRefID, + Xfer_InternalJson + ) + SELECT 'O', + 'RES.RESULT', + Xfer_InternalDestM_BranchID, + Xfer_InternalSrcM_BranchID, + Xfer_InternalRefID, + JSON_OBJECT( + 'ref_detail_id', Xfer_InternalDetailSrcRefID, + 'test_id', NEW.T_OrderDetailT_TestID, + 'test_result', NEW.T_OrderDetailResult, + 'test_result_note', IFNULL(NEW.T_OrderDetailNote, ''), + 'normal_id', NEW.T_OrderDetailNat_NormalValueID, + 'methode_id', NEW.T_OrderDetailNat_MethodeID + ) + FROM xfer_internaldetail + JOIN xfer_internal ON Xfer_InternalID = Xfer_InternalDetailXfer_InternalID + WHERE Xfer_InternalDetailID = ref_id; + END IF; + + SET nat_test_id = ( + SELECT T_TestNat_TestID + FROM t_test + WHERE T_TestID = NEW.T_OrderDetailT_TestID + ); + + SET curr_pre_analytic = ( + SELECT T_OrderDetailAddOnPreAnalytic + FROM t_orderdetailaddon + WHERE T_OrderDetailAddOnT_OrderDetailID = NEW.T_OrderDetailID + AND T_OrderDetailAddOnIsActive = 'Y' + ); + + IF curr_pre_analytic = 'N' THEN + SET pre_analytic = ( + SELECT PreAnalyticIsOk + FROM pre_analytic + WHERE PreAnalyticNat_TestID = nat_test_id + AND PreAnalyticDate = DATE(NOW()) + AND PreAnalyticIsActive = 'Y' + LIMIT 1 + ); + + IF pre_analytic IS NULL THEN + SET pre_analytic = 'N'; + END IF; + + UPDATE t_orderdetailaddon + SET T_OrderDetailAddOnPreAnalytic = pre_analytic, + T_OrderDetailAddOnPreAnalyticDate = NOW() + WHERE T_OrderDetailAddOnT_OrderDetailID = NEW.T_OrderDetailID; + END IF; + END IF; + + IF OLD.T_OrderDetailVerification <> 'Y' AND NEW.T_OrderDetailVerification = 'Y' THEN + SELECT T_OrderDetailAddOnRef, T_OrderDetailAddOnRefID + INTO ref, ref_id + FROM t_orderdetailaddon + WHERE T_OrderDetailAddOnT_OrderDetailID = NEW.T_OrderDetailID + AND T_OrderDetailAddOnIsActive = 'Y' + LIMIT 1; + + IF ref = 'X' THEN + INSERT INTO xfer_internal( + Xfer_InternalType, + Xfer_InternalDataType, + Xfer_InternalSrcM_BranchID, + Xfer_InternalDestM_BranchID, + Xfer_InternalRefID, + Xfer_InternalJson + ) + SELECT 'O', + 'RES.VERIFY', + Xfer_InternalDestM_BranchID, + Xfer_InternalSrcM_BranchID, + Xfer_InternalRefID, + JSON_OBJECT( + 'ref_detail_id', Xfer_InternalDetailSrcRefID, + 'test_id', NEW.T_OrderDetailT_TestID, + 'test_result', NEW.T_OrderDetailResult, + 'delta_check', NEW.T_OrderDetailVerDeltaCheck, + 'trend_analysis', NEW.T_OrderDetailVerTrendAnalysis, + 'verification', NEW.T_OrderDetailVerification, + 'verification_date', NEW.T_OrderDetailVerDate, + 'normal_id', NEW.T_OrderDetailNat_NormalValueID + ) + FROM xfer_internaldetail + JOIN xfer_internal ON Xfer_InternalID = Xfer_InternalDetailXfer_InternalID + WHERE Xfer_InternalDetailID = ref_id; + END IF; + END IF; +END IF; + +UPDATE t_orderdetail_ss +SET t_orderDetailSsH1Result = NEW.T_OrderDetailResult +WHERE t_orderDetailSsH1ID = NEW.T_OrderDetailID; + +IF NEW.T_OrderDetailResult <> OLD.T_OrderDetailResult THEN + SET TYPE_LOG = 'RESULTENTRY_TR'; + + INSERT INTO one_lab_log.log_orderdetail( + Log_OrderDetailStatus, + Log_OrderDetailT_OrderDetailID, + Log_OrderDetailResult, + Log_OrderDetailJSON, + Log_OrderDetailCreated, + Log_OrderDetailUserID + ) + VALUES( + TYPE_LOG, + NEW.T_OrderDetailID, + NEW.T_OrderDetailResult, + JSON_OBJECT( + 'T_OrderDetailID', NEW.T_OrderDetailID, + 'T_OrderDetailT_TestID', NEW.T_OrderDetailT_TestID, + 'T_OrderDetailT_TestCode', NEW.T_OrderDetailT_TestCode, + 'T_OrderDetailT_TestSasCode', NEW.T_OrderDetailT_TestSasCode, + 'T_OrderDetailT_TestName', NEW.T_OrderDetailT_TestName, + 'T_OrderDetailT_TestIsResult', NEW.T_OrderDetailT_TestIsResult, + 'T_OrderDetailT_TestIsPrice', NEW.T_OrderDetailT_TestIsPrice, + 'T_OrderDetailReq', NEW.T_OrderDetailReq, + 'T_OrderDetailReqNote', NEW.T_OrderDetailReqNote, + 'T_OrderDetailIsCito', NEW.T_OrderDetailIsCito, + 'T_OrderDetailPrice', NEW.T_OrderDetailPrice, + 'T_OrderDetailDisc', NEW.T_OrderDetailDisc, + 'T_OrderDetailDiscAmount', NEW.T_OrderDetailDiscAmount, + 'T_OrderDetailDiscTotal', NEW.T_OrderDetailDiscTotal, + 'T_OrderDetailTotal', NEW.T_OrderDetailTotal, + 'T_OrderDetailHasResult', NEW.T_OrderDetailHasResult, + 'T_OrderDetailResult', NEW.T_OrderDetailResult, + 'T_OrderDetailResult_OLD', OLD.T_OrderDetailResult, + 'T_OrderDetailResultFlag', NEW.T_OrderDetailResultFlag, + 'T_OrderDetailNote', NEW.T_OrderDetailNote, + 'T_OrderDetailNat_UnitID', NEW.T_OrderDetailNat_UnitID, + 'T_OrderDetailNat_UnitName', NEW.T_OrderDetailNat_UnitName, + 'T_OrderDetailT_OrderPromiseID', NEW.T_OrderDetailT_OrderPromiseID, + 'T_OrderDetailNat_InstrumentID', NEW.T_OrderDetailNat_InstrumentID, + 'T_OrderDetailVerDeltaCheck', NEW.T_OrderDetailVerDeltaCheck, + 'T_OrderDetailVerTrendAnalysis', NEW.T_OrderDetailVerTrendAnalysis, + 'T_OrderDetailVerification', NEW.T_OrderDetailVerification, + 'T_OrderDetailVerDate', NEW.T_OrderDetailVerDate, + 'T_OrderDetailVerUserID', NEW.T_OrderDetailVerUserID, + 'T_OrderDetailValMRState', NEW.T_OrderDetailValMRState, + 'T_OrderDetailValidation', NEW.T_OrderDetailValidation, + 'T_OrderDetailValDate', NEW.T_OrderDetailValDate, + 'T_OrderDetailValUserID', NEW.T_OrderDetailValUserID, + 'T_OrderDetailNat_NormalValueID', NEW.T_OrderDetailNat_NormalValueID, + 'T_OrderDetailNormalValueNote', NEW.T_OrderDetailNormalValueNote, + 'T_OrderDetailNormalValueDescription', NEW.T_OrderDetailNormalValueDescription, + 'T_OrderDetailMinValue', NEW.T_OrderDetailMinValue, + 'T_OrderDetailMaxValue', NEW.T_OrderDetailMaxValue + ), + NOW(), + NEW.T_OrderDetailLastUpdatedUserID + ); +END IF; + +END// + +DELIMITER ;