From d3a1a1fceac597ae9ea7bf9aba4c78c67195d70f Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Fri, 18 Oct 2024 15:33:34 -0400 Subject: [PATCH 01/24] LEAF 4455 data.metadata read for forms and report builder cells --- LEAF-Automated-Tests | 1 + LEAF_Request_Portal/sources/Form.php | 40 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 20 deletions(-) create mode 160000 LEAF-Automated-Tests diff --git a/LEAF-Automated-Tests b/LEAF-Automated-Tests new file mode 160000 index 000000000..32f13e0a7 --- /dev/null +++ b/LEAF-Automated-Tests @@ -0,0 +1 @@ +Subproject commit 32f13e0a7331fd9135dd398abdbe5272d3cdcd57 diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 4945a1f5d..8ff67ef40 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -573,13 +573,13 @@ public function getIndicator($indicatorID, $series, $recordID = null, $parseTemp $form[$idx]['value'] = $this->fileToArray($data[0]['data']); $form[$idx]['raw'] = $data[0]['data']; } - // special handling for org chart data types + // special handling for org chart data types (request header questions, edited report builder cells) else if ($data[0]['format'] == 'orgchart_employee' && !empty($data[0]['data'])) { - $empRes = $this->employee->lookupEmpUID($data[0]['data']); - if (!empty($empRes)) { - $form[$idx]['displayedValue'] = "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; + if (isset($data[0]['metadata'])) { + $orgchartInfo = json_decode($data[0]['metadata'], true); + $form[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; } else { $form[$idx]['displayedValue'] = ''; } @@ -2605,16 +2605,14 @@ public function getCustomData(array $recordID_list, string|null $indicatorID_lis } } break; - case 'orgchart_employee': - $empRes = $this->employee->lookupEmpUID($item['data']); - if (isset($empRes[0])) - { - $item['data'] = "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; - $item['dataOrgchart'] = $empRes[0]; - } - else - { - $item['data'] = ''; + case 'orgchart_employee': //report builder cells + $item['data'] = ''; + if (isset($item['metadata'])) { + $orgchartInfo = json_decode($item['metadata'], true); + if(!empty($orgchartInfo['userName'])) { + $item['data'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; + $item['dataOrgchart'] = $orgchartInfo; + } } break; case 'orgchart_position': @@ -4308,7 +4306,7 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp { $var = array(':series' => (int)$series, ':recordID' => (int)$recordID, ); - $res2 = $this->db->prepared_query('SELECT data, timestamp, indicatorID, groupID, userID FROM data + $res2 = $this->db->prepared_query('SELECT data, metadata, timestamp, indicatorID, groupID, userID FROM data LEFT JOIN indicator_mask USING (indicatorID) WHERE indicatorID IN (' . $indicatorList . ') AND series=:series AND recordID=:recordID', $var); @@ -4316,6 +4314,7 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp { $idx = $resIn['indicatorID']; $data[$idx]['data'] = isset($resIn['data']) ? $resIn['data'] : ''; + $data[$idx]['metadata'] = isset($resIn['metadata']) ? $resIn['metadata'] : null; $data[$idx]['timestamp'] = isset($resIn['timestamp']) ? $resIn['timestamp'] : 0; $data[$idx]['groupID'] = isset($resIn['groupID']) ? $resIn['groupID'] : null; $data[$idx]['userID'] = isset($resIn['userID']) ? $resIn['userID'] : ''; @@ -4382,14 +4381,15 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp $child[$idx]['value'] = $this->fileToArray($data[$idx]['data']); } - // special handling for org chart data types + // special handling for org chart data types (request subquestions / child) if ($field['format'] == 'orgchart_employee') { - $empRes = $this->employee->lookupEmpUID($data[$idx]['data']); $child[$idx]['displayedValue'] = ''; - if (isset($empRes[0])) - { - $child[$idx]['displayedValue'] = ($child[$idx]['isMasked']) ? '[protected data]' : "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; + if (isset($data[$idx]['metadata'])) { + $orgchartInfo = json_decode($data[$idx]['metadata'], true); + if(!empty($orgchartInfo['userName'])) { + $child[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; + } } } if ($field['format'] == 'orgchart_position') From 37614a980aad4999dd711daa1a1552f5df196dc7 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Wed, 30 Oct 2024 14:21:47 -0400 Subject: [PATCH 02/24] LEAF 4455 action_history table read metadata --- LEAF-Automated-Tests | 2 +- LEAF_Request_Portal/sources/View.php | 14 +++++++++----- LEAF_Request_Portal/templates/view_status.tpl | 7 ++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/LEAF-Automated-Tests b/LEAF-Automated-Tests index 32f13e0a7..e14fa0952 160000 --- a/LEAF-Automated-Tests +++ b/LEAF-Automated-Tests @@ -1 +1 @@ -Subproject commit 32f13e0a7331fd9135dd398abdbe5272d3cdcd57 +Subproject commit e14fa09524c35ed4ae17c9edc25f2ecd91c073b7 diff --git a/LEAF_Request_Portal/sources/View.php b/LEAF_Request_Portal/sources/View.php index a31dc25f2..2a4ec937e 100644 --- a/LEAF_Request_Portal/sources/View.php +++ b/LEAF_Request_Portal/sources/View.php @@ -61,7 +61,7 @@ public function buildViewStatus(int $recordID): array $vars = array(':recordID' => $recordID); $sql1 = 'SELECT time, description, actionText, stepTitle, - dependencyID, comment, userID + dependencyID, comment, userID, userMetadata FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN workflow_steps USING (stepID) @@ -69,13 +69,13 @@ public function buildViewStatus(int $recordID): array WHERE recordID=:recordID UNION SELECT timestamp, "Note Added", "N/A", "N/A", - "N/A", note, userID + "N/A", note, userID, userMetadata FROM notes WHERE recordID = :recordID AND deleted IS NULL UNION SELECT `timestamp`, "Email Sent", "N/A", "N/A", - "N/A", concat(`recipients`, "
", `subject`), "" + "N/A", concat(`recipients`, "
", `subject`), "", "" FROM `email_tracker` WHERE recordID = :recordID ORDER BY time ASC'; @@ -102,8 +102,12 @@ public function buildViewStatus(int $recordID): array $packet['comment'] = $tmp['comment']; if (!empty($tmp['userID'])) { - $user = $dir->lookupLogin($tmp['userID']); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $tmp['userID']; + $name = $tmp['userID']; + if(isset($tmp['userMetadata'])) { + $umd = json_decode($tmp['userMetadata'], true); + $display = trim($umd['firstName'] . " " . $umd['lastName']); + $name = !empty($display) ? $display : $name; + } $packet['userName'] = $name; } diff --git a/LEAF_Request_Portal/templates/view_status.tpl b/LEAF_Request_Portal/templates/view_status.tpl index bf2455c3b..1ea210cd7 100644 --- a/LEAF_Request_Portal/templates/view_status.tpl +++ b/LEAF_Request_Portal/templates/view_status.tpl @@ -26,12 +26,13 @@ Title of request: - by + + by -
Comment:
+
Comment: -
+
From cb6420e23ffa28aa9101d953feb11ed96e45daf8 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Tue, 26 Nov 2024 16:27:03 -0500 Subject: [PATCH 03/24] LEAF exper server side get progress --- LEAF-Automated-Tests | 2 +- LEAF_Request_Portal/sources/Form.php | 340 ++++++++++++++------------- 2 files changed, 172 insertions(+), 170 deletions(-) diff --git a/LEAF-Automated-Tests b/LEAF-Automated-Tests index a7f6435a6..8d87883ef 160000 --- a/LEAF-Automated-Tests +++ b/LEAF-Automated-Tests @@ -1 +1 @@ -Subproject commit a7f6435a65ae82b646ebfd70cd3ea92015b96a38 +Subproject commit 8d87883efbef6bf4e028868c2db41ec42c2d0a35 diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 4945a1f5d..9eaf580b2 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1509,206 +1509,208 @@ public function doSubmit(int $recordID): array return $return_value; } -/** + /** * Get the progress percentage (as integer), accounting for conditinally hidden questions * @param int $recordID * @return int Percent completed */ public function getProgress($recordID) { - $returnValue = 0; - - $vars = array(':recordID' => (int)$recordID); - //get all the catIDs associated with this record and whether the forms are enabled or submitted - $resRecordInfoEachForm = $this->db->prepared_query('SELECT recordID, categoryID, `count`, submitted FROM records - LEFT JOIN category_count USING (recordID) - WHERE recordID=:recordID', $vars); - $isSubmitted = false; + $subSQL = 'SELECT submitted FROM records + LEFT JOIN category_count USING (recordID) + WHERE recordID=:recordID'; + $subVars = array(':recordID' => (int)$recordID); + //First check if submitted and just return 100 if it is. + $resRecordInfoEachForm = $this->db->prepared_query($subSQL, $subVars); foreach ($resRecordInfoEachForm as $request) { if ($request['submitted'] > 0) { - $isSubmitted = true; - break; + return 100; } } - if ($isSubmitted) { - $returnValue = 100; - } else { - //use recordInfo about forms associated with the recordID to get the total number of required questions on the request - $allRequiredIndicators = $this->db->prepared_query("SELECT categoryID, indicatorID, `format`, conditions FROM indicators WHERE required=1 AND disabled = 0", array()); - $categories = array(); - foreach($resRecordInfoEachForm as $form) { - if((int)$form['count'] === 1) { - $categories[] = $form['categoryID']; - } - } - $resRequestRequired = array(); - foreach ($allRequiredIndicators as $indicator) { - if(in_array($indicator['categoryID'], $categories)) { - $resRequestRequired[] = $indicator; - } - } - $countRequestRequired = count($resRequestRequired); - //if there are no required questions we are done - if($countRequestRequired === 0) { - $returnValue = 100; + $dataSQL = 'SELECT indicatorID, `format`, `data` FROM `data` + LEFT JOIN indicators USING (indicatorID) + WHERE recordID=:recordID + AND indicators.disabled = 0 + AND `data` != ""'; + $dataVars = array(':recordID' => (int)$recordID); + $resData = $this->db->prepared_query($dataSQL, $dataVars); - } else { - //get indicatorID, format, data, and required for all completed questions for non-disabled indicators - $resCompleted = $this->db->prepared_query('SELECT indicatorID, `format`, `data`, `required` FROM `data` LEFT JOIN indicators - USING (indicatorID) - WHERE recordID=:recordID - AND indicators.disabled = 0 - AND data != "" - AND data IS NOT NULL', $vars); - - //used to count the number of required completions and organize completed data for possible condition checks - $resCountCompletedRequired = 0; - $resCompletedIndIDs = array(); - - foreach ($resCompleted as $entry) { - $arrData = @unserialize($entry['data']) === false ? array($entry['data']) : unserialize($entry['data']); - $entryFormat = trim(explode(PHP_EOL, $entry['format'])[0]); - - /*Edgecases: Checkbox and checkboxes format entries save the value 'no' if their corresponding input checkbox is unchecked. - Verifying that entries for these formats do not consist solely of 'no' values prevents a miscount that can occur if - they are later updated to be required, since not having empty values is no longer confirmation that they are answered.*/ - $checkBoxesAllNo = strtolower($entryFormat) === 'checkbox' || strtolower($entryFormat) === 'checkboxes'; - if ($checkBoxesAllNo === true) { - foreach ($arrData as $ele) { - if ($ele !== 'no') { - $checkBoxesAllNo = false; - break; - } - } - } - /*Grid formats are likewise not necessarily answered if they are not empty strings. Unanswered grid cells are empty */ - $gridContainsEmptyValue = false; - if (strtolower($entryFormat) === 'grid' && isset($arrData['cells'])) { - $arrRowEntries = $arrData['cells']; - foreach ($arrRowEntries as $row) { - if (in_array("", $row)) { - $gridContainsEmptyValue = true; - break; - } - } - } - if ($checkBoxesAllNo === false && $gridContainsEmptyValue === false) { - if ((int) $entry['required'] === 1) { - $resCountCompletedRequired++; - if ($resCountCompletedRequired === $countRequestRequired) { - break; - } - } - //save the data entry (whether required or not) in case it is needed for condition checking - $resCompletedIndIDs[(int) $entry['indicatorID']] = $entry['data']; - } - } - - if ($resCountCompletedRequired === $countRequestRequired) { - $returnValue = 100; + $dataTable = array(); + foreach($resData as $d) { + $dataTable[$d['indicatorID']] = $d['data']; + } + $returnValue = 0; + $requiredTotal = 0; + $requiredAnswered = 0; - } else { - //finally, check if there are conditions that result in required questions being in a hidden state, and adjust count and percentage + function count_required(array $dataTable, array $formNode, bool $parentOrSelfHidden = false, int &$required_total, int &$required_answered) + { + //don't care about any of this if the question is in a hidden state + if($parentOrSelfHidden === false) { + //Check for conditions and if the state is hidden. + $format = trim(strtolower($formNode['format'])); + if(!empty($formNode['conditions']) && $formNode['conditions'] !== 'null') { + $conditions = json_decode(strip_tags($formNode['conditions'])); $multiChoiceParentFormats = array('multiselect', 'checkboxes'); $singleChoiceParentFormats = array('radio', 'dropdown', 'number', 'currency'); + $conditionMet = false; + foreach ($conditions as $c) { + if ($c->childFormat === $format && + (strtolower($c->selectedOutcome) === 'hide' || strtolower($c->selectedOutcome) === 'show')) { + + $parentFormat = $c->parentFormat; + $conditionParentValue = preg_split('/\R/', $c->selectedParentValue) ?? []; + $currentParentDataValue = preg_replace('/'/', ''', $dataTable[$c->parentIndID] ?? ''); + if ($parentFormat === 'checkbox') { //single checkbox ifthen is either checked or not checked + $currentParentDataValue = !empty($currentParentDataValue) && $currentParentDataValue !== 'no' ? '1' : '0'; + } + if (in_array($parentFormat, $multiChoiceParentFormats)) { + $currentParentDataValue = @unserialize($currentParentDataValue) === false ? + array($currentParentDataValue) : unserialize($currentParentDataValue); + } else { + $currentParentDataValue = array($currentParentDataValue); + } - foreach ($resRequestRequired as $ind) { - //if question is not complete, and there are conditions (conditions could potentially have the string null due to a past import issue) ... - if (!in_array((int) $ind['indicatorID'], array_keys($resCompletedIndIDs)) && !empty($ind['conditions']) && $ind['conditions'] !== 'null') { - - $conditions = json_decode(strip_tags($ind['conditions'])); - $currFormat = preg_split('/\R/', $ind['format'])[0] ?? ''; - - $conditionMet = false; - foreach ($conditions as $c) { - if ($c->childFormat === $currFormat //if current format and condition format match - && (strtolower($c->selectedOutcome) === 'hide' || strtolower($c->selectedOutcome) === 'show')) { //and outcome is hide or show - - $parentFormat = $c->parentFormat; - $conditionParentValue = preg_split('/\R/', $c->selectedParentValue) ?? []; - //if parent data does not exist, use an empty string, since potential 'not' comparisons would need this. - $currentParentDataValue = preg_replace('/'/', ''', $resCompletedIndIDs[(int) $c->parentIndID] ?? ''); - + $operator = $c->selectedOp; + switch ($operator) { + case '==': + case '!=': if (in_array($parentFormat, $multiChoiceParentFormats)) { - $currentParentDataValue = @unserialize($currentParentDataValue) === false ? array($currentParentDataValue) : unserialize($currentParentDataValue); - } else { - $currentParentDataValue = array($currentParentDataValue); - } - - $operator = $c->selectedOp; - switch ($operator) { - case '==': - case '!=': - if (in_array($parentFormat, $multiChoiceParentFormats)) { - //true if the current data value includes any of the condition values - foreach ($currentParentDataValue as $v) { - if (in_array($v, $conditionParentValue)) { - $conditionMet = true; - break; - } - } - } else if (in_array($parentFormat, $singleChoiceParentFormats) && $currentParentDataValue[0] === $conditionParentValue[0]) { + //true if the current data value includes any of the condition values + foreach ($currentParentDataValue as $v) { + if (in_array($v, $conditionParentValue)) { $conditionMet = true; + break; } - if($operator === "!=") { - $conditionMet = !$conditionMet; - } - break; - case 'gt': - case 'gte': - case 'lt': - case 'lte': - $arrNumVals = array(); - $arrNumComp = array(); - foreach($currentParentDataValue as $v) { - if(is_numeric($v)) { - $arrNumVals[] = (float) $v; - } - } - foreach($conditionParentValue as $cval) { - if(is_numeric($cval)) { - $arrNumComp[] = (float) $cval; - } + } + } else if (in_array($parentFormat, $singleChoiceParentFormats) && $currentParentDataValue[0] === $conditionParentValue[0]) { + $conditionMet = true; + } + if($operator === "!=") { + $conditionMet = !$conditionMet; + } + break; + case 'gt': + case 'gte': + case 'lt': + case 'lte': + $arrNumVals = array(); + $arrNumComp = array(); + foreach($currentParentDataValue as $v) { + if(is_numeric($v)) { + $arrNumVals[] = (float) $v; + } + } + foreach($conditionParentValue as $cval) { + if(is_numeric($cval)) { + $arrNumComp[] = (float) $cval; + } + } + $useOrEqual = str_contains($operator, 'e'); + $useGreaterThan = str_contains($operator, 'g'); + $lenValues = count(array_values($arrNumVals)); + $lenCompare = count(array_values($arrNumComp)); + if($lenCompare > 0) { + for ($i = 0; $i < $lenValues; $i++) { + $currVal = $arrNumVals[$i]; + if($useGreaterThan === true) { + $conditionMet = $useOrEqual === true ? $currVal >= max($arrNumComp) : $currVal > max($arrNumComp); + } else { + $conditionMet = $useOrEqual === true ? $currVal <= min($arrNumComp) : $currVal < min($arrNumComp); } - $useOrEqual = str_contains($operator, 'e'); - $useGreaterThan = str_contains($operator, 'g'); - $lenValues = count(array_values($arrNumVals)); - $lenCompare = count(array_values($arrNumComp)); - if($lenCompare > 0) { - for ($i = 0; $i < $lenValues; $i++) { - $currVal = $arrNumVals[$i]; - if($useGreaterThan === true) { - $conditionMet = $useOrEqual === true ? $currVal >= max($arrNumComp) : $currVal > max($arrNumComp); - } else { - $conditionMet = $useOrEqual === true ? $currVal <= min($arrNumComp) : $currVal < min($arrNumComp); - } - if($conditionMet === true) { - break; - } - } + if($conditionMet === true) { + break; } + } + } + break; + default: + break; + } + } + //if in hidden state, set parenthidden to true and break out of condition checking. + if (($conditionMet === false && strtolower($c->selectedOutcome) === 'show') || + ($conditionMet === true && strtolower($c->selectedOutcome) === 'hide')) { + $parentOrSelfHidden = true; + break; + } + } + } + + //if still not in hidden state and required: increment required total. Check for answer and increment answered total if answered. + if(!$parentOrSelfHidden && (int)$formNode['required'] === 1) { + $required_total += 1; + $answered = false; + $val = $formNode['value']; + if(isset($val) && $val !== '') { + /*value property is already processed based on format and could be string or array. + Convert to array for more consistent comparison and to simplify checkbox(es) and grid formats.*/ + $valType = gettype($val); + + $arrVal = array(); + if($valType === 'array') { + $arrVal = $val; + } elseif ($valType === 'string') { + $val = trim($val); + $arrVal = @unserialize($val) === false ? array($val) : unserialize($val); + } + //these formats can have values despite being unanswered ('no', or serialized data about the entry) + $specialFormat = $format === 'checkbox' || $format === 'checkboxes' || $format === 'grid'; + if ($specialFormat === true) { + if($format === 'grid') { + $hasInput = isset($arrVal['cells']); + $gridContainsEmptyValue = !$hasInput; + if($hasInput) { + $arrRowEntries = $arrVal['cells']; + foreach ($arrRowEntries as $row) { + if (in_array("", $row)) { + $gridContainsEmptyValue = true; break; - default: - break; + } } } - //if the question is not being shown due to its conditions, do not count it as a required question - if (($conditionMet === false && strtolower($c->selectedOutcome) === 'show') || - ($conditionMet === true && strtolower($c->selectedOutcome) === 'hide')) { - $countRequestRequired--; - break; + $answered = !$gridContainsEmptyValue; + + } else { + //checkbox(es) - only one needed + foreach($arrVal as $ele) { + if ($ele !== '' && $ele !== 'no') { + $answered = true; + break; + } } } + + //any other format, confirm the element is not an empty string + } else { + $answered = $arrVal[0] !== ''; } } - if ($countRequestRequired === 0) { - $returnValue = 100; - } else { - $returnValue = round(100 * ($resCountCompletedRequired / $countRequestRequired)); + + if($answered === true) { + $required_answered += 1; } } } + //progress tree depth. + if(isset($formNode['child'])) { + foreach($formNode['child'] as $child) { + count_required($dataTable, $child, $parentOrSelfHidden, $required_total, $required_answered); + } + } + } + + $fullForm = $this->getFullForm($recordID); + foreach($fullForm as $page) { + count_required($dataTable, $page, false, $requiredTotal, $requiredAnswered); + } + + error_log("R A: ".$requiredTotal." ".$requiredAnswered); + if ($requiredTotal === 0) { + $returnValue = 100; + } else { + $returnValue = round(100 * ($requiredAnswered / $requiredTotal)); } return $returnValue; } From 3643446f8267e5c2c19acb7fc68d989deedeb8a0 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Tue, 26 Nov 2024 17:10:04 -0500 Subject: [PATCH 04/24] LEAF exper, formjs side validation, remove error_log --- LEAF_Request_Portal/js/form.js | 115 ++++++++++++++++++--------- LEAF_Request_Portal/sources/Form.php | 1 - 2 files changed, 76 insertions(+), 40 deletions(-) diff --git a/LEAF_Request_Portal/js/form.js b/LEAF_Request_Portal/js/form.js index 2da387910..5d37d4604 100644 --- a/LEAF_Request_Portal/js/form.js +++ b/LEAF_Request_Portal/js/form.js @@ -227,20 +227,28 @@ var LeafForm = function (containerID) { /** cross walk end */ let childRequiredValidators = {}; + //store required validators for the controlled question and any subchildren on main entry and modals const handleChildValidators = (childID) => { - if (!childRequiredValidators[childID]) { - childRequiredValidators[childID] = { - validator: formRequired[`id${childID}`]?.setRequired, - }; - } - //reset the validator, if there is one, from the stored value - if ( - childRequiredValidators[childID].validator !== undefined && - dialog !== null - ) { - dialog.requirements[childID] = - childRequiredValidators[childID].validator; - } + let arrValidatorIDs = [ childID ]; + const arrSubchildren = Array.from( + document.querySelectorAll(`.response.blockIndicator_${childID} div.response[class*="blockIndicator_"]`) + ); + arrSubchildren.forEach(element => { + const id = +element.className.match(/(\d+)$/)?.[0]; + if(id > 0) { + arrValidatorIDs.push(id); + } + }); + arrValidatorIDs.forEach(id => { + if (!childRequiredValidators[id]) { + childRequiredValidators[id] = { + validator: formRequired[`id${id}`]?.setRequired, + }; + } + if (childRequiredValidators[id].validator !== undefined && dialog !== null) { + dialog.requirements[id] = childRequiredValidators[id].validator; + } + }); }; //validator ref for required question in a hidden state const hideShowValidator = function () { @@ -361,32 +369,61 @@ var LeafForm = function (containerID) { return sanitize(val).trim(); }; - /* clear out potential entries and set validator for hidden questions */ - const clearValues = (childFormat = "", childIndID = 0) => { - $("#" + childIndID).val(""); //clears most formats - $(`input[id^="${childIndID}_"]`).prop("checked", false); //radio and checkbox(es) formats - $(`input[id^="${childIndID}_radio0"]`).prop("checked", true); - - $(`#grid_${childIndID}_1_input tbody td`) //grid table data - .each(function () { - if ($("textarea", this).length) { - $("textarea", this).val(''); - } else if ($("select", this).length) { - $("select", this).val(''); - } else if ($("input", this).length) { - $("input", this).val(''); + /*hide the question and any subquestions. clear out potential entries and set validator for hidden questions */ + const clearValues = (childIndID = 0) => { + const arrSubchildren = Array.from( + document.querySelectorAll(`.response.blockIndicator_${childIndID} div.response[class*="blockIndicator_"]`) + ); + + //parse the IDs of any additional subquestions + let arrChildAndSubquestionIDs = [ childIndID ]; + arrSubchildren.forEach(element => { + const id = +element.className.match(/(\d+)$/)?.[0]; + if(id > 0) { + arrChildAndSubquestionIDs.push(id); } }); - if (childFormat === "multiselect") { - clearMultiSelectChild($("#" + childIndID), childIndID); - } - if ( - childRequiredValidators[childIndID].validator !== undefined && - dialog !== null - ) { - dialog.requirements[childIndID] = hideShowValidator; - } + arrChildAndSubquestionIDs.forEach(id => { + //clear values for questions in a hidden state. + $("#" + id).val(""); //most formats + $(`input[id^="${id}_"]`).prop("checked", false); //radio and checkbox(es) formats + + $(`#grid_${id}_1_input tbody td`) //grid table data + .each(function () { + if ($("textarea", this).length) { + $("textarea", this).val(''); + } else if ($("select", this).length) { + $("select", this).val(''); + } else if ($("input", this).length) { + $("input", this).val(''); + } + }); + + const isMultiselectQuestion = document.querySelector(`select[id="${id}"][multiple]`) !== null; + if (isMultiselectQuestion) { + clearMultiSelectChild($("#" + id), id); + } + + const isRadioQuestion = document.querySelector(`input[id^="${id}_radio"]`) !== null; + if(isRadioQuestion) { + const radioEmpty = $(`input[id^="${id}_radio0"]`); //need to add hidden empty input to clear radio + if (radioEmpty.length === 0) { + $(`div.response.blockIndicator_${id}`).prepend( + `` + ); + } + $(`input[id^="${id}_radio0"]`).prop("checked", true); + } + + //if the question is required, use the alternate validator + if ( + childRequiredValidators[id].validator !== undefined && + dialog !== null + ) { + dialog.requirements[id] = hideShowValidator; + } + }); }; /** @@ -526,7 +563,7 @@ var LeafForm = function (containerID) { switch (co) { case "hide": if (hideShowConditionMet === true) { - clearValues(childFormat, childID); + clearValues(childID); elChildResponse.classList.add('response-hidden'); elsChild.hide(); elsChild.attr('aria-hidden', true); @@ -542,7 +579,7 @@ var LeafForm = function (containerID) { elsChild.removeAttr('aria-hidden'); elsChild.show(); } else { - clearValues(childFormat, childID); + clearValues(childID); elChildResponse.classList.add('response-hidden'); elsChild.hide(); elsChild.attr('aria-hidden', true); @@ -611,7 +648,7 @@ var LeafForm = function (containerID) { setTimeout(() => { const closestHidden = elChildResponse.closest('.response-hidden'); if (closestHidden !== null) { - clearValues(childFormat, childID); + clearValues(childID); } elChildInput.trigger("change"); diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 9eaf580b2..36357ace0 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1706,7 +1706,6 @@ function count_required(array $dataTable, array $formNode, bool $parentOrSelfHid count_required($dataTable, $page, false, $requiredTotal, $requiredAnswered); } - error_log("R A: ".$requiredTotal." ".$requiredAnswered); if ($requiredTotal === 0) { $returnValue = 100; } else { From a8f67b9bd3b3a845c827f92c42c6398aea309b57 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Wed, 27 Nov 2024 12:11:03 -0500 Subject: [PATCH 05/24] LEAF 4604 move count_required to own method, update param --- LEAF_Request_Portal/sources/Form.php | 321 +++++++++++++-------------- 1 file changed, 160 insertions(+), 161 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 36357ace0..172b47ab8 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1509,6 +1509,163 @@ public function doSubmit(int $recordID): array return $return_value; } + private function count_required(array &$dataTable, array $formNode, bool $parentOrSelfHidden = false, int &$required_total, int &$required_answered) + { + //don't care about any of this if the question is in a hidden state + if($parentOrSelfHidden === false) { + //Check for conditions and if the state is hidden. + $format = trim(strtolower($formNode['format'])); + if(!empty($formNode['conditions']) && $formNode['conditions'] !== 'null') { + $conditions = json_decode(strip_tags($formNode['conditions'])); + $multiChoiceParentFormats = array('multiselect', 'checkboxes'); + $singleChoiceParentFormats = array('radio', 'dropdown', 'number', 'currency'); + $conditionMet = false; + foreach ($conditions as $c) { + if ($c->childFormat === $format && + (strtolower($c->selectedOutcome) === 'hide' || strtolower($c->selectedOutcome) === 'show')) { + + $parentFormat = $c->parentFormat; + $conditionParentValue = preg_split('/\R/', $c->selectedParentValue) ?? []; + $currentParentDataValue = preg_replace('/'/', ''', $dataTable[$c->parentIndID] ?? ''); + if ($parentFormat === 'checkbox') { //single checkbox ifthen is either checked or not checked + $currentParentDataValue = !empty($currentParentDataValue) && $currentParentDataValue !== 'no' ? '1' : '0'; + } + if (in_array($parentFormat, $multiChoiceParentFormats)) { + $currentParentDataValue = @unserialize($currentParentDataValue) === false ? + array($currentParentDataValue) : unserialize($currentParentDataValue); + } else { + $currentParentDataValue = array($currentParentDataValue); + } + + $operator = $c->selectedOp; + switch ($operator) { + case '==': + case '!=': + if (in_array($parentFormat, $multiChoiceParentFormats)) { + //true if the current data value includes any of the condition values + foreach ($currentParentDataValue as $v) { + if (in_array($v, $conditionParentValue)) { + $conditionMet = true; + break; + } + } + } else if (in_array($parentFormat, $singleChoiceParentFormats) && $currentParentDataValue[0] === $conditionParentValue[0]) { + $conditionMet = true; + } + if($operator === "!=") { + $conditionMet = !$conditionMet; + } + break; + case 'gt': + case 'gte': + case 'lt': + case 'lte': + $arrNumVals = array(); + $arrNumComp = array(); + foreach($currentParentDataValue as $v) { + if(is_numeric($v)) { + $arrNumVals[] = (float) $v; + } + } + foreach($conditionParentValue as $cval) { + if(is_numeric($cval)) { + $arrNumComp[] = (float) $cval; + } + } + $useOrEqual = str_contains($operator, 'e'); + $useGreaterThan = str_contains($operator, 'g'); + $lenValues = count(array_values($arrNumVals)); + $lenCompare = count(array_values($arrNumComp)); + if($lenCompare > 0) { + for ($i = 0; $i < $lenValues; $i++) { + $currVal = $arrNumVals[$i]; + if($useGreaterThan === true) { + $conditionMet = $useOrEqual === true ? $currVal >= max($arrNumComp) : $currVal > max($arrNumComp); + } else { + $conditionMet = $useOrEqual === true ? $currVal <= min($arrNumComp) : $currVal < min($arrNumComp); + } + if($conditionMet === true) { + break; + } + } + } + break; + default: + break; + } + } + //if in hidden state, set parenthidden to true and break out of condition checking. + if (($conditionMet === false && strtolower($c->selectedOutcome) === 'show') || + ($conditionMet === true && strtolower($c->selectedOutcome) === 'hide')) { + $parentOrSelfHidden = true; + break; + } + } + } + + //if still not in hidden state and required: increment required total. Check for answer and increment answered total if answered. + if(!$parentOrSelfHidden && (int)$formNode['required'] === 1) { + $required_total += 1; + $answered = false; + $val = $formNode['value']; + if(isset($val) && $val !== '') { + /*value property is already processed based on format and could be string or array. + Convert to array for more consistent comparison and to simplify checkbox(es) and grid formats.*/ + $valType = gettype($val); + + $arrVal = array(); + if($valType === 'array') { + $arrVal = $val; + } elseif ($valType === 'string') { + $val = trim($val); + $arrVal = @unserialize($val) === false ? array($val) : unserialize($val); + } + //these formats can have values despite being unanswered ('no', or serialized data about the entry) + $specialFormat = $format === 'checkbox' || $format === 'checkboxes' || $format === 'grid'; + if ($specialFormat === true) { + if($format === 'grid') { + $hasInput = isset($arrVal['cells']); + $gridContainsEmptyValue = !$hasInput; + if($hasInput) { + $arrRowEntries = $arrVal['cells']; + foreach ($arrRowEntries as $row) { + if (in_array("", $row)) { + $gridContainsEmptyValue = true; + break; + } + } + } + $answered = !$gridContainsEmptyValue; + + } else { + //checkbox(es) - only one needed + foreach($arrVal as $ele) { + if ($ele !== '' && $ele !== 'no') { + $answered = true; + break; + } + } + } + + //any other format, confirm the element is not an empty string + } else { + $answered = $arrVal[0] !== ''; + } + } + + if($answered === true) { + $required_answered += 1; + } + } + } + //progress tree depth. + if(isset($formNode['child'])) { + foreach($formNode['child'] as $child) { + $this->count_required($dataTable, $child, $parentOrSelfHidden, $required_total, $required_answered); + } + } + } + /** * Get the progress percentage (as integer), accounting for conditinally hidden questions * @param int $recordID @@ -1527,12 +1684,11 @@ public function getProgress($recordID) return 100; } } - - $dataSQL = 'SELECT indicatorID, `format`, `data` FROM `data` + $dataSQL = "SELECT `indicatorID`, `format`, `data` FROM `data` LEFT JOIN indicators USING (indicatorID) WHERE recordID=:recordID AND indicators.disabled = 0 - AND `data` != ""'; + AND `data` != ''"; $dataVars = array(':recordID' => (int)$recordID); $resData = $this->db->prepared_query($dataSQL, $dataVars); @@ -1544,166 +1700,9 @@ public function getProgress($recordID) $requiredTotal = 0; $requiredAnswered = 0; - function count_required(array $dataTable, array $formNode, bool $parentOrSelfHidden = false, int &$required_total, int &$required_answered) - { - //don't care about any of this if the question is in a hidden state - if($parentOrSelfHidden === false) { - //Check for conditions and if the state is hidden. - $format = trim(strtolower($formNode['format'])); - if(!empty($formNode['conditions']) && $formNode['conditions'] !== 'null') { - $conditions = json_decode(strip_tags($formNode['conditions'])); - $multiChoiceParentFormats = array('multiselect', 'checkboxes'); - $singleChoiceParentFormats = array('radio', 'dropdown', 'number', 'currency'); - $conditionMet = false; - foreach ($conditions as $c) { - if ($c->childFormat === $format && - (strtolower($c->selectedOutcome) === 'hide' || strtolower($c->selectedOutcome) === 'show')) { - - $parentFormat = $c->parentFormat; - $conditionParentValue = preg_split('/\R/', $c->selectedParentValue) ?? []; - $currentParentDataValue = preg_replace('/'/', ''', $dataTable[$c->parentIndID] ?? ''); - if ($parentFormat === 'checkbox') { //single checkbox ifthen is either checked or not checked - $currentParentDataValue = !empty($currentParentDataValue) && $currentParentDataValue !== 'no' ? '1' : '0'; - } - if (in_array($parentFormat, $multiChoiceParentFormats)) { - $currentParentDataValue = @unserialize($currentParentDataValue) === false ? - array($currentParentDataValue) : unserialize($currentParentDataValue); - } else { - $currentParentDataValue = array($currentParentDataValue); - } - - $operator = $c->selectedOp; - switch ($operator) { - case '==': - case '!=': - if (in_array($parentFormat, $multiChoiceParentFormats)) { - //true if the current data value includes any of the condition values - foreach ($currentParentDataValue as $v) { - if (in_array($v, $conditionParentValue)) { - $conditionMet = true; - break; - } - } - } else if (in_array($parentFormat, $singleChoiceParentFormats) && $currentParentDataValue[0] === $conditionParentValue[0]) { - $conditionMet = true; - } - if($operator === "!=") { - $conditionMet = !$conditionMet; - } - break; - case 'gt': - case 'gte': - case 'lt': - case 'lte': - $arrNumVals = array(); - $arrNumComp = array(); - foreach($currentParentDataValue as $v) { - if(is_numeric($v)) { - $arrNumVals[] = (float) $v; - } - } - foreach($conditionParentValue as $cval) { - if(is_numeric($cval)) { - $arrNumComp[] = (float) $cval; - } - } - $useOrEqual = str_contains($operator, 'e'); - $useGreaterThan = str_contains($operator, 'g'); - $lenValues = count(array_values($arrNumVals)); - $lenCompare = count(array_values($arrNumComp)); - if($lenCompare > 0) { - for ($i = 0; $i < $lenValues; $i++) { - $currVal = $arrNumVals[$i]; - if($useGreaterThan === true) { - $conditionMet = $useOrEqual === true ? $currVal >= max($arrNumComp) : $currVal > max($arrNumComp); - } else { - $conditionMet = $useOrEqual === true ? $currVal <= min($arrNumComp) : $currVal < min($arrNumComp); - } - if($conditionMet === true) { - break; - } - } - } - break; - default: - break; - } - } - //if in hidden state, set parenthidden to true and break out of condition checking. - if (($conditionMet === false && strtolower($c->selectedOutcome) === 'show') || - ($conditionMet === true && strtolower($c->selectedOutcome) === 'hide')) { - $parentOrSelfHidden = true; - break; - } - } - } - - //if still not in hidden state and required: increment required total. Check for answer and increment answered total if answered. - if(!$parentOrSelfHidden && (int)$formNode['required'] === 1) { - $required_total += 1; - $answered = false; - $val = $formNode['value']; - if(isset($val) && $val !== '') { - /*value property is already processed based on format and could be string or array. - Convert to array for more consistent comparison and to simplify checkbox(es) and grid formats.*/ - $valType = gettype($val); - - $arrVal = array(); - if($valType === 'array') { - $arrVal = $val; - } elseif ($valType === 'string') { - $val = trim($val); - $arrVal = @unserialize($val) === false ? array($val) : unserialize($val); - } - //these formats can have values despite being unanswered ('no', or serialized data about the entry) - $specialFormat = $format === 'checkbox' || $format === 'checkboxes' || $format === 'grid'; - if ($specialFormat === true) { - if($format === 'grid') { - $hasInput = isset($arrVal['cells']); - $gridContainsEmptyValue = !$hasInput; - if($hasInput) { - $arrRowEntries = $arrVal['cells']; - foreach ($arrRowEntries as $row) { - if (in_array("", $row)) { - $gridContainsEmptyValue = true; - break; - } - } - } - $answered = !$gridContainsEmptyValue; - - } else { - //checkbox(es) - only one needed - foreach($arrVal as $ele) { - if ($ele !== '' && $ele !== 'no') { - $answered = true; - break; - } - } - } - - //any other format, confirm the element is not an empty string - } else { - $answered = $arrVal[0] !== ''; - } - } - - if($answered === true) { - $required_answered += 1; - } - } - } - //progress tree depth. - if(isset($formNode['child'])) { - foreach($formNode['child'] as $child) { - count_required($dataTable, $child, $parentOrSelfHidden, $required_total, $required_answered); - } - } - } - $fullForm = $this->getFullForm($recordID); foreach($fullForm as $page) { - count_required($dataTable, $page, false, $requiredTotal, $requiredAnswered); + $this->count_required($dataTable, $page, false, $requiredTotal, $requiredAnswered); } if ($requiredTotal === 0) { From f015626cac78924905855ef6b3674794f6169538 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 2 Dec 2024 09:19:32 -0500 Subject: [PATCH 06/24] LEAF 4455 records and notes userMetadata read --- LEAF_Request_Portal/sources/Form.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 8ff67ef40..afe7b5c6f 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1008,9 +1008,9 @@ public function getRecordInfo($recordID) ); } - $dir = new VAMC_Directory; - $user = $dir->lookupLogin($res[0]['userID']); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[0]['userID']; + $userMetadata = json_decode($res[0]['userMetadata'], true); + $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[0]['userID']; $data = array('name' => $name, 'service' => $res[0]['service'], @@ -2730,14 +2730,14 @@ public function getActionComments(int $recordID): array } else { $vars = array(':recordID' => $recordID); - $sql = 'SELECT actionTextPasttense, comment, time, userID + $sql = 'SELECT actionTextPasttense, comment, time, userID, userMetadata FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN actions USING (actionType) WHERE recordID = :recordID AND comment != "" UNION - SELECT "Note Added", note, timestamp, userID + SELECT "Note Added", note, timestamp, userID, userMetadata FROM notes WHERE recordID = :recordID AND deleted IS NULL @@ -2745,13 +2745,12 @@ public function getActionComments(int $recordID): array $res = $this->db->prepared_query($sql, $vars); - $dir = new VAMC_Directory; - $total = count($res); - for ($i = 0; $i < $total; $i++) { - $user = $dir->lookupLogin($res[$i]['userID']); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[$i]['userID']; + $userMetadata = json_decode($res[$i]['userMetadata'], true); + $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[$i]['userID']; + $res[$i]['name'] = $name; } From e1ea6a5c97ed9ee6f613aa43120eab7b81e15585 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 2 Dec 2024 10:32:22 -0500 Subject: [PATCH 07/24] LEAF 4455 display val logic consistency, read approverName, fix approverName userID --- LEAF_Request_Portal/sources/Form.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index afe7b5c6f..a99949d37 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -577,11 +577,12 @@ public function getIndicator($indicatorID, $series, $recordID = null, $parseTemp else if ($data[0]['format'] == 'orgchart_employee' && !empty($data[0]['data'])) { + $form[$idx]['displayedValue'] = ''; if (isset($data[0]['metadata'])) { $orgchartInfo = json_decode($data[0]['metadata'], true); - $form[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; - } else { - $form[$idx]['displayedValue'] = ''; + if(trim("{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}") !== "") { + $form[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; + } } } else if ($data[0]['format'] == 'orgchart_position' @@ -2609,7 +2610,7 @@ public function getCustomData(array $recordID_list, string|null $indicatorID_lis $item['data'] = ''; if (isset($item['metadata'])) { $orgchartInfo = json_decode($item['metadata'], true); - if(!empty($orgchartInfo['userName'])) { + if(trim("{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}") !== "") { $item['data'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; $item['dataOrgchart'] = $orgchartInfo; } @@ -3819,14 +3820,14 @@ public function query(string $inQuery): mixed $dir = new VAMC_Directory; $actionHistorySQL = - 'SELECT recordID, stepID, userID, time, description, + 'SELECT recordID, stepID, userID, userMetadata, time, description, actionTextPasttense, actionType, comment FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN actions USING (actionType) WHERE recordID IN (' . $recordIDs . ') UNION - SELECT recordID, "-5", userID, timestamp, "Note Added", + SELECT recordID, "-5", userID, userMetadata, timestamp, "Note Added", "Note Added", "LEAF_note", note FROM notes WHERE recordID IN (' . $recordIDs . ') @@ -3836,8 +3837,10 @@ public function query(string $inQuery): mixed $res2 = $this->db->prepared_query($actionHistorySQL, array()); foreach ($res2 as $item) { - $user = $dir->lookupLogin($item['userID'], true); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[0]['userID']; + $userMetadata = json_decode($item['userMetadata'], true); + $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $item['userID']; + $item['approverName'] = $name; $data[$item['recordID']]['action_history'][] = $item; @@ -4386,7 +4389,7 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp $child[$idx]['displayedValue'] = ''; if (isset($data[$idx]['metadata'])) { $orgchartInfo = json_decode($data[$idx]['metadata'], true); - if(!empty($orgchartInfo['userName'])) { + if(trim("{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}") !== "") { $child[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; } } From b19771036ae40b920beff0031f777ac5fd2f22fb Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 2 Dec 2024 10:58:20 -0500 Subject: [PATCH 08/24] LEAF 4455 read metadata for resolvedBy, remove VAMC init for that lookup --- LEAF_Request_Portal/sources/Form.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index a99949d37..b8e1c7c2b 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3817,8 +3817,6 @@ public function query(string $inQuery): mixed if ($joinActionHistory) { - $dir = new VAMC_Directory; - $actionHistorySQL = 'SELECT recordID, stepID, userID, userMetadata, time, description, actionTextPasttense, actionType, comment @@ -3878,9 +3876,7 @@ public function query(string $inQuery): mixed } if ($joinRecordResolutionBy === true) { - $dir = new VAMC_Directory; - - $recordResolutionBySQL = "SELECT recordID, action_history.userID as resolvedBy, action_history.stepID, action_history.actionType + $recordResolutionBySQL = "SELECT recordID, action_history.userID as resolvedBy, action_history.userMetadata, action_history.stepID, action_history.actionType FROM action_history LEFT JOIN records USING (recordID) INNER JOIN workflow_routes USING (stepID) @@ -3895,8 +3891,9 @@ public function query(string $inQuery): mixed $res2 = $this->db->prepared_query($recordResolutionBySQL, array()); foreach ($res2 as $item) { - $user = $dir->lookupLogin($item['resolvedBy'], true); - $nameResolved = isset($user[0]) ? "{$user[0]['Lname']}, {$user[0]['Fname']} " : $item['resolvedBy']; + $userMetadata = json_decode($item['userMetadata'], true); + $nameResolved = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + "{$userMetadata['firstName']} {$userMetadata['lastName']} " : $item['resolvedBy']; $data[$item['recordID']]['recordResolutionBy']['resolvedBy'] = $nameResolved; } } From f2cec1b09ddfe5dea0687fe4a1007cc763902c91 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 2 Dec 2024 12:28:48 -0500 Subject: [PATCH 09/24] LEAF 4455 metadata read, dep -2 requestor followup steps --- LEAF_Request_Portal/sources/FormWorkflow.php | 31 +++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index 48603d0a0..7d8de4156 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -447,7 +447,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $strSQL = ""; if(!$selectUnfilled) { - $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, requiresDigitalSignature FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, userMetadata, requiresDigitalSignature FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -456,7 +456,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel WHERE recordID IN ({$recordIDs})"; } else { - $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID, userMetadata FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -490,18 +490,19 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $personDesignatedIndicators[$res[$i]['indicatorID_for_assigned_empUID']] = 1; break; case -2: // dependencyID -2 is for requestor followup - $dir = $this->getDirectory(); - $approver = $dir->lookupLogin($res[$i]['userID']); + $approver = json_decode($res[$i]['userMetadata'], true); - if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { + if (!isset($approver) || + (empty($approver['firstName']) && empty($approver['lastName'])) + ) { $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver[0]['Fname'] . ' ' . $approver[0]['Lname'] . ')'; - $res[$i]['approverName'] = $approver[0]['Fname'] . ' ' . $approver[0]['Lname']; - $res[$i]['approverUID'] = $approver[0]['Email']; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver['firstName'] . ' ' . $approver['lastName'] . ')'; + $res[$i]['approverName'] = $approver['firstName'] . ' ' . $approver['lastName']; + $res[$i]['approverUID'] = $approver['email']; } break; case -3: // dependencyID -3 is for a group designated by the requestor @@ -540,17 +541,19 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $res[$i]['isActionable'] = $isActionable; - $dir = $this->getDirectory(); - $approver = $dir->lookupLogin($res[$i]['userID']); - if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { + $approver = json_decode($res[$i]['userMetadata'], true); + + if (!isset($approver) || + (empty($approver['firstName']) && empty($approver['lastName'])) + ) { $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver[0]['Fname'] . ' ' . $approver[0]['Lname'] . ')'; - $res[$i]['approverName'] = $approver[0]['Fname'] . ' ' . $approver[0]['Lname']; - $res[$i]['approverUID'] = $approver[0]['Email']; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver['firstName'] . ' ' . $approver['lastName'] . ')'; + $res[$i]['approverName'] = $approver['firstName'] . ' ' . $approver['lastName']; + $res[$i]['approverUID'] = $approver['email']; } break; From e20c490e976661460acbd2e040e2ffda1ab36540 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Tue, 3 Dec 2024 07:29:37 -0500 Subject: [PATCH 10/24] LEAF 4604 rename some variables, add total tracking --- LEAF-Automated-Tests | 2 +- LEAF_Request_Portal/sources/Form.php | 79 +++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/LEAF-Automated-Tests b/LEAF-Automated-Tests index 8d87883ef..a7f6435a6 160000 --- a/LEAF-Automated-Tests +++ b/LEAF-Automated-Tests @@ -1 +1 @@ -Subproject commit 8d87883efbef6bf4e028868c2db41ec42c2d0a35 +Subproject commit a7f6435a65ae82b646ebfd70cd3ea92015b96a38 diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 172b47ab8..6d413b10c 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1509,8 +1509,29 @@ public function doSubmit(int $recordID): array return $return_value; } - private function count_required(array &$dataTable, array $formNode, bool $parentOrSelfHidden = false, int &$required_total, int &$required_answered) + /** + * Keep track of number of required questions, number visible, and form branch visibility state + * + * @param array dataTable (ref) lookup table of form data. Used to check if question is answered and for conditional logic assessment + * @param array formNode form question with potential substructure + * @param bool parentOrSelfHidden is question and children in hidden state + * @param int required_visible (ref) number of required questions that are visible + * @param int required_answered (ref) number of required questions that are answered + * @param int required_total (ref) total number of required questions found during checking + * @param int res_max_required total number of required questions on the form + */ + private function count_required( + array &$dataTable, + array $formNode, + bool $parentOrSelfHidden = false, + int &$required_visible, + int &$required_answered, + int &$required_total, + int $res_max_required) { + if((int)$formNode['required'] === 1) { + $required_total += 1; //keep track to skip calls once all required questions are found. + } //don't care about any of this if the question is in a hidden state if($parentOrSelfHidden === false) { //Check for conditions and if the state is hidden. @@ -1601,11 +1622,12 @@ private function count_required(array &$dataTable, array $formNode, bool $parent break; } } + unset($conditions); } - //if still not in hidden state and required: increment required total. Check for answer and increment answered total if answered. + //if not in hidden state and required: increment required total. Check for answer and increment answered total if answered. if(!$parentOrSelfHidden && (int)$formNode['required'] === 1) { - $required_total += 1; + $required_visible += 1; $answered = false; $val = $formNode['value']; if(isset($val) && $val !== '') { @@ -1658,10 +1680,20 @@ private function count_required(array &$dataTable, array $formNode, bool $parent } } } - //progress tree depth. + //progress tree depth if required total is not at max. if(isset($formNode['child'])) { foreach($formNode['child'] as $child) { - $this->count_required($dataTable, $child, $parentOrSelfHidden, $required_total, $required_answered); + if($required_total < $res_max_required) { + $this->count_required( + $dataTable, + $child, + $parentOrSelfHidden, + $required_visible, + $required_answered, + $required_total, + $res_max_required + ); + } } } } @@ -1673,22 +1705,39 @@ private function count_required(array &$dataTable, array $formNode, bool $parent */ public function getProgress($recordID) { - $subSQL = 'SELECT submitted FROM records + $subSQL = 'SELECT submitted, categoryID FROM records LEFT JOIN category_count USING (recordID) WHERE recordID=:recordID'; $subVars = array(':recordID' => (int)$recordID); - //First check if submitted and just return 100 if it is. + $resRecordInfoEachForm = $this->db->prepared_query($subSQL, $subVars); + + //Check if submitted, return 100 if it is. Get catIDs for otherwise. + $categoryIDs = array(); foreach ($resRecordInfoEachForm as $request) { + $categoryIDs[] = $request['categoryID']; if ($request['submitted'] > 0) { return 100; } } + + $maxRequiredSQL = "SELECT `indicatorID` FROM `indicators` + WHERE `required`=1 AND `disabled`=0 AND FIND_IN_SET(categoryID, :categoryIDs)"; + $maxRequiredVars = array( + ":categoryIDs" => implode(",", $categoryIDs) + ); + $resMaxRequired = count($this->db->prepared_query($maxRequiredSQL, $maxRequiredVars)); + + //Check max count. Return 100 if there are none. Otherwise use this count for total checking. + if ($resMaxRequired === 0) { + return 100; + } + $dataSQL = "SELECT `indicatorID`, `format`, `data` FROM `data` LEFT JOIN indicators USING (indicatorID) WHERE recordID=:recordID AND indicators.disabled = 0 - AND `data` != ''"; + AND TRIM(`data`) != ''"; $dataVars = array(':recordID' => (int)$recordID); $resData = $this->db->prepared_query($dataSQL, $dataVars); @@ -1696,19 +1745,23 @@ public function getProgress($recordID) foreach($resData as $d) { $dataTable[$d['indicatorID']] = $d['data']; } - $returnValue = 0; - $requiredTotal = 0; + + $requiredVisible = 0; $requiredAnswered = 0; + $requiredTotal = 0; $fullForm = $this->getFullForm($recordID); foreach($fullForm as $page) { - $this->count_required($dataTable, $page, false, $requiredTotal, $requiredAnswered); + if($requiredTotal < $resMaxRequired) { + $this->count_required($dataTable, $page, false, $requiredVisible, $requiredAnswered, $requiredTotal, $resMaxRequired); + } } - if ($requiredTotal === 0) { + $returnValue = 0; + if ($requiredVisible === 0) { $returnValue = 100; } else { - $returnValue = round(100 * ($requiredAnswered / $requiredTotal)); + $returnValue = round(100 * ($requiredAnswered / $requiredVisible)); } return $returnValue; } From aeec897b53fd56f06dbfa137d555ff08d4cb5c87 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Tue, 3 Dec 2024 07:53:21 -0500 Subject: [PATCH 11/24] LEAF 4604 comment unused / pending checkbox logic, add trim to data value --- LEAF_Request_Portal/sources/Form.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 6d413b10c..d0061f888 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1548,9 +1548,9 @@ private function count_required( $parentFormat = $c->parentFormat; $conditionParentValue = preg_split('/\R/', $c->selectedParentValue) ?? []; $currentParentDataValue = preg_replace('/'/', ''', $dataTable[$c->parentIndID] ?? ''); - if ($parentFormat === 'checkbox') { //single checkbox ifthen is either checked or not checked + /* if ($parentFormat === 'checkbox') { //single checkbox ifthen is either checked or not checked (pending parent checkbox) $currentParentDataValue = !empty($currentParentDataValue) && $currentParentDataValue !== 'no' ? '1' : '0'; - } + } */ if (in_array($parentFormat, $multiChoiceParentFormats)) { $currentParentDataValue = @unserialize($currentParentDataValue) === false ? array($currentParentDataValue) : unserialize($currentParentDataValue); @@ -1733,7 +1733,7 @@ public function getProgress($recordID) return 100; } - $dataSQL = "SELECT `indicatorID`, `format`, `data` FROM `data` + $dataSQL = "SELECT `indicatorID`, `format`, TRIM(`data`) as `data` FROM `data` LEFT JOIN indicators USING (indicatorID) WHERE recordID=:recordID AND indicators.disabled = 0 From 1911d7aeea30edcafbf0dfc4cb07265c18dcaadc Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Wed, 4 Dec 2024 09:53:49 -0500 Subject: [PATCH 12/24] Revert "LEAF 4455 metadata read, dep -2 requestor followup steps" This reverts commit f2cec1b09ddfe5dea0687fe4a1007cc763902c91. Keep lookup so that display will reflect current account status --- LEAF_Request_Portal/sources/FormWorkflow.php | 31 +++++++++----------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index 7d8de4156..48603d0a0 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -447,7 +447,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $strSQL = ""; if(!$selectUnfilled) { - $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, userMetadata, requiresDigitalSignature FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, requiresDigitalSignature FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -456,7 +456,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel WHERE recordID IN ({$recordIDs})"; } else { - $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID, userMetadata FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -490,19 +490,18 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $personDesignatedIndicators[$res[$i]['indicatorID_for_assigned_empUID']] = 1; break; case -2: // dependencyID -2 is for requestor followup - $approver = json_decode($res[$i]['userMetadata'], true); + $dir = $this->getDirectory(); + $approver = $dir->lookupLogin($res[$i]['userID']); - if (!isset($approver) || - (empty($approver['firstName']) && empty($approver['lastName'])) - ) { + if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver['firstName'] . ' ' . $approver['lastName'] . ')'; - $res[$i]['approverName'] = $approver['firstName'] . ' ' . $approver['lastName']; - $res[$i]['approverUID'] = $approver['email']; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver[0]['Fname'] . ' ' . $approver[0]['Lname'] . ')'; + $res[$i]['approverName'] = $approver[0]['Fname'] . ' ' . $approver[0]['Lname']; + $res[$i]['approverUID'] = $approver[0]['Email']; } break; case -3: // dependencyID -3 is for a group designated by the requestor @@ -541,19 +540,17 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $res[$i]['isActionable'] = $isActionable; - $approver = json_decode($res[$i]['userMetadata'], true); - - if (!isset($approver) || - (empty($approver['firstName']) && empty($approver['lastName'])) - ) { + $dir = $this->getDirectory(); + $approver = $dir->lookupLogin($res[$i]['userID']); + if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver['firstName'] . ' ' . $approver['lastName'] . ')'; - $res[$i]['approverName'] = $approver['firstName'] . ' ' . $approver['lastName']; - $res[$i]['approverUID'] = $approver['email']; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (' . $approver[0]['Fname'] . ' ' . $approver[0]['Lname'] . ')'; + $res[$i]['approverName'] = $approver[0]['Fname'] . ' ' . $approver[0]['Lname']; + $res[$i]['approverUID'] = $approver[0]['Email']; } break; From 39b09e3937d6d1a85c2c08c4eb7e5ab569b74693 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Wed, 4 Dec 2024 12:18:04 -0500 Subject: [PATCH 13/24] LEAF 4455 keep lookup if pending action, use metadata if avail for more info for disabled accts --- LEAF_Request_Portal/sources/FormWorkflow.php | 26 ++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index 48603d0a0..5ced50e7e 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -447,7 +447,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $strSQL = ""; if(!$selectUnfilled) { - $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, requiresDigitalSignature FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, userMetadata, requiresDigitalSignature FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -456,7 +456,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel WHERE recordID IN ({$recordIDs})"; } else { - $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID, userMetadata FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -494,8 +494,11 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; - $res[$i]['approverName'] = '(Requestor followup)'; + $approverMetadata = json_decode($res[$i]['userMetadata'], true); + $nameInfo = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? + " - " . $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : ''; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup' . $nameInfo . ')'; + $res[$i]['approverName'] = '(Requestor followup' . $nameInfo . ')'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -543,8 +546,11 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $dir = $this->getDirectory(); $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; - $res[$i]['approverName'] = '(Requestor followup)'; + $approverMetadata = json_decode($res[$i]['userMetadata'], true); + $nameInfo = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? + " - " . $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : ''; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup' . $nameInfo . ')'; + $res[$i]['approverName'] = '(Requestor followup' . $nameInfo . ')'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -716,11 +722,11 @@ public function getLastAction(): array|null|int if (isset($res[0]) && $res[0]['dependencyID'] == -1) { - $dir = $this->getDirectory(); - - $approver = $dir->lookupLogin($res[0]['userID']); + $approverMetadata = json_decode($res[0]['userMetadata'], true); + $display = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? + $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : $res[0]['userID']; - $res[0]['description'] = "{$approver[0]['firstName']} {$approver[0]['lastName']}"; + $res[0]['description'] = $display; } // dependencyID -3 is for a group designated by the requestor if (isset($res[0]) From fdd9aa07df99ae7f5226243e8422ba061f3dc92d Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Wed, 4 Dec 2024 14:49:31 -0500 Subject: [PATCH 14/24] LEAF 4604 method signature per feedback --- LEAF_Request_Portal/ajaxJSON.php | 2 +- LEAF_Request_Portal/api/controllers/FormController.php | 2 +- LEAF_Request_Portal/sources/Form.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LEAF_Request_Portal/ajaxJSON.php b/LEAF_Request_Portal/ajaxJSON.php index 00ded8753..16454291a 100644 --- a/LEAF_Request_Portal/ajaxJSON.php +++ b/LEAF_Request_Portal/ajaxJSON.php @@ -32,7 +32,7 @@ // this method does not exist in Form class // echo $form->getProgressJSON($_GET['recordID']); // but this one does - echo $form->getProgress($_GET['recordID']); + echo $form->getProgress((int)$_GET['recordID']); break; case 'getrecentactions': diff --git a/LEAF_Request_Portal/api/controllers/FormController.php b/LEAF_Request_Portal/api/controllers/FormController.php index 36c35ef50..4c862b198 100644 --- a/LEAF_Request_Portal/api/controllers/FormController.php +++ b/LEAF_Request_Portal/api/controllers/FormController.php @@ -121,7 +121,7 @@ public function get($act) }); $this->index['GET']->register('form/[digit]/progress', function ($args) use ($form) { - $return = $form->getProgress($args[0]); + $return = $form->getProgress((int)$args[0]); return $return; }); diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index d0061f888..d92116efd 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1527,7 +1527,7 @@ private function count_required( int &$required_visible, int &$required_answered, int &$required_total, - int $res_max_required) + int $res_max_required): void { if((int)$formNode['required'] === 1) { $required_total += 1; //keep track to skip calls once all required questions are found. @@ -1703,7 +1703,7 @@ private function count_required( * @param int $recordID * @return int Percent completed */ - public function getProgress($recordID) + public function getProgress(int $recordID): int { $subSQL = 'SELECT submitted, categoryID FROM records LEFT JOIN category_count USING (recordID) From a60a75aa23f815b520d07893b38846664c5c8dbe Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 5 Dec 2024 11:21:40 -0500 Subject: [PATCH 15/24] LEAF 4455 update q to use record usermetadata instead of join --- LEAF_Request_Portal/sources/Form.php | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index b8e1c7c2b..c78066685 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3578,7 +3578,6 @@ public function query(string $inQuery): mixed $joinActionHistory = false; $joinRecordResolutionData = false; $joinRecordResolutionBy = false; - $joinInitiatorNames = false; $joinUnfilledDependencies = false; if (isset($query['joins'])) { @@ -3625,10 +3624,6 @@ public function query(string $inQuery): mixed case 'recordResolutionBy': $joinRecordResolutionBy = true; - break; - case 'initiatorName': - $joinInitiatorNames = true; - break; case 'destructionDate': $joinRecordResolutionData = true; @@ -3710,14 +3705,14 @@ public function query(string $inQuery): mixed WHERE format = 'orgchart_employee') rj_OCEmployeeData ON (lj_data.indicatorID = rj_OCEmployeeData.indicatorID) "; } - if ($joinInitiatorNames) - { - $joins .= "LEFT JOIN (SELECT userName, lastName, firstName FROM {$this->oc_dbName}.employee) lj_OCinitiatorNames ON records.userID = lj_OCinitiatorNames.userName "; - } + $resSQL = 'SELECT *, + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")) AS `firstName`, + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")) AS `lastName` + FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; if(isset($_GET['debugQuery'])) { if($this->login->checkGroup(1)) { - $debugQuery = str_replace(["\r", "\n","\t", "%0d","%0a","%09","%20", ";"], ' ', 'SELECT * FROM records ' . $joins . 'WHERE ' . $conditions . $sort . $limit); + $debugQuery = str_replace(["\r", "\n","\t", "%0d","%0a","%09","%20", ";"], ' ', $resSQL); $debugVars = []; foreach($vars as $key => $value) { if(strpos($key, ':data') !== false @@ -3731,17 +3726,14 @@ public function query(string $inQuery): mixed header('X-LEAF-Query: '. str_replace(array_keys($debugVars), $debugVars, $debugQuery)); - return $res = $this->db->prepared_query('EXPLAIN SELECT * FROM records - ' . $joins . ' - WHERE ' . $conditions . $sort . $limit, $vars); + return $res = $this->db->prepared_query('EXPLAIN ' . $resSQL, $vars); } else { return XSSHelpers::scrubObjectOrArray(json_decode(html_entity_decode(html_entity_decode($_GET['q'])), true)); } } - $res = $this->db->prepared_query('SELECT * FROM records - ' . $joins . ' - WHERE ' . $conditions . $sort . $limit, $vars); + + $res = $this->db->prepared_query($resSQL, $vars); $data = array(); $recordIDs = ''; From f9b7b155821b32e89ca5c5b0b364036e2e40a587 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 5 Dec 2024 12:11:16 -0500 Subject: [PATCH 16/24] LEAF 4455 use metadata info for comment when setting initiator --- LEAF_Request_Portal/sources/Form.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index c78066685..ad9470e76 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -2903,11 +2903,9 @@ public function setInitiator($recordID, $userID) userID=:userID, userMetadata=:userMetadata WHERE recordID=:recordID', $vars); - // write log entry - $dir = new VAMC_Directory; - $user = $dir->lookupLogin($userID); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $userID; + $newInitiatorInfo = json_decode($newInitiatorMetadata, true); + $name = "{$newInitiatorInfo['firstName']} {$newInitiatorInfo['lastName']}"; $actionUserID = $this->login->getUserID(); $actionUserMetadata = $this->employee->getInfoForUserMetadata($actionUserID, false); From 56140cef7233d07665ff34a54ca38b882f8ce6fe Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 5 Dec 2024 14:17:20 -0500 Subject: [PATCH 17/24] LEAF 4455 Report Builder, userID instead of null for inactive accounts --- LEAF_Request_Portal/templates/view_reports.tpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/LEAF_Request_Portal/templates/view_reports.tpl b/LEAF_Request_Portal/templates/view_reports.tpl index 61b91ef80..c113950f6 100644 --- a/LEAF_Request_Portal/templates/view_reports.tpl +++ b/LEAF_Request_Portal/templates/view_reports.tpl @@ -131,10 +131,12 @@ function addHeader(column) { case 'initiator': filterData['lastName'] = 1; filterData['firstName'] = 1; - leafSearch.getLeafFormQuery().join('initiatorName'); + filterData['userID'] = 1; headers.push({ name: 'Initiator', indicatorID: 'initiator', editable: false, callback: function(data, blob) { - document.querySelector(`#${data.cellContainerID}`).innerHTML = blob[data.recordID].lastName + ', ' + blob[data.recordID].firstName; + const textContent = blob[data.recordID]?.lastName || "" !== "" ? + `${blob[data.recordID].lastName}, ${blob[data.recordID].firstName}` : blob[data.recordID].userID; + document.querySelector(`#${data.cellContainerID}`).innerHTML = textContent; }}); break; case 'dateCancelled': From 4955503b31a0ed4bf0230f798042d7268b0bce7a Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 5 Dec 2024 16:06:08 -0500 Subject: [PATCH 18/24] LEAF 4455 add actionType to filterData for cancelled by display, userID for site search initiator --- .../templates/reports/LEAF_Sitemap_Search.tpl | 7 +++++-- LEAF_Request_Portal/templates/view_reports.tpl | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl index f48ed746f..d9f158d89 100644 --- a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl +++ b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl @@ -188,16 +188,19 @@ function addHeader(column) { case 'initiator': filterData['lastName'] = 1; filterData['firstName'] = 1; - leafSearch.getLeafFormQuery().join('initiatorName'); + filterData['userID'] = 1; headers.push({ name: 'Initiator', indicatorID: 'initiator', editable: false, callback: function(data, blob) { let d = grid.getDataByIndex(data.index); - $('#'+data.cellContainerID).html(d.lastName + ', ' + d.firstName); + const textContent = d?.lastName || "" !== "" ? + d.lastName + ', ' + d.firstName : d.userID; + $('#'+data.cellContainerID).html(textContent); }}); break; case 'dateCancelled': filterData['deleted'] = 1; filterData['action_history.approverName'] = 1; + filterData['action_history.actionType'] = 1; leafSearch.getLeafFormQuery().join('action_history'); headers.push({ name: 'Date Cancelled', indicatorID: 'dateCancelled', editable: false, callback: function(data, blob) { diff --git a/LEAF_Request_Portal/templates/view_reports.tpl b/LEAF_Request_Portal/templates/view_reports.tpl index c113950f6..a6be81f42 100644 --- a/LEAF_Request_Portal/templates/view_reports.tpl +++ b/LEAF_Request_Portal/templates/view_reports.tpl @@ -142,6 +142,7 @@ function addHeader(column) { case 'dateCancelled': filterData['deleted'] = 1; filterData['action_history.approverName'] = 1; + filterData['action_history.actionType'] = 1; leafSearch.getLeafFormQuery().join('action_history'); headers.push({ name: 'Date Cancelled', indicatorID: 'dateCancelled', editable: false, callback: function(data, blob) { From 4b0b014ded0d8c7ba7cb066d250c26917cab3ab7 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Fri, 6 Dec 2024 12:06:13 -0500 Subject: [PATCH 19/24] LEAF 4455 revert view reports change except for join call, handle display on backend --- LEAF_Request_Portal/sources/Form.php | 13 +++++++++++-- .../templates/reports/LEAF_Sitemap_Search.tpl | 5 +---- LEAF_Request_Portal/templates/view_reports.tpl | 5 +---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index ad9470e76..9389d7d31 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3703,9 +3703,18 @@ public function query(string $inQuery): mixed WHERE format = 'orgchart_employee') rj_OCEmployeeData ON (lj_data.indicatorID = rj_OCEmployeeData.indicatorID) "; } + //backwards compat: userMetadata properties are empty for accounts that were inactive when prior md values were updated. + //userMetadata alternatives here prevent the initiator field from displaying 'null, null' if metadata is empty. + //Handled here due to high customization of view_reports, view_search and other reports $resSQL = 'SELECT *, - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")) AS `firstName`, - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")) AS `lastName` + IF( + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.userName")) != "", + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")), "(inactive account)" + ) AS `firstName`, + IF( + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.userName")) != "", + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")), `userID` + ) AS `lastName` FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; if(isset($_GET['debugQuery'])) { diff --git a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl index d9f158d89..a1d3ae6c8 100644 --- a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl +++ b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl @@ -188,13 +188,10 @@ function addHeader(column) { case 'initiator': filterData['lastName'] = 1; filterData['firstName'] = 1; - filterData['userID'] = 1; headers.push({ name: 'Initiator', indicatorID: 'initiator', editable: false, callback: function(data, blob) { let d = grid.getDataByIndex(data.index); - const textContent = d?.lastName || "" !== "" ? - d.lastName + ', ' + d.firstName : d.userID; - $('#'+data.cellContainerID).html(textContent); + $('#'+data.cellContainerID).html(d.lastName + ', ' + d.firstName); }}); break; case 'dateCancelled': diff --git a/LEAF_Request_Portal/templates/view_reports.tpl b/LEAF_Request_Portal/templates/view_reports.tpl index a6be81f42..b8fcacdc7 100644 --- a/LEAF_Request_Portal/templates/view_reports.tpl +++ b/LEAF_Request_Portal/templates/view_reports.tpl @@ -131,12 +131,9 @@ function addHeader(column) { case 'initiator': filterData['lastName'] = 1; filterData['firstName'] = 1; - filterData['userID'] = 1; headers.push({ name: 'Initiator', indicatorID: 'initiator', editable: false, callback: function(data, blob) { - const textContent = blob[data.recordID]?.lastName || "" !== "" ? - `${blob[data.recordID].lastName}, ${blob[data.recordID].firstName}` : blob[data.recordID].userID; - document.querySelector(`#${data.cellContainerID}`).innerHTML = textContent; + document.querySelector(`#${data.cellContainerID}`).innerHTML = blob[data.recordID].lastName + ', ' + blob[data.recordID].firstName; }}); break; case 'dateCancelled': From f3cfc8a01c45f0003a1efc71dfc1c1767e6277a1 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Fri, 6 Dec 2024 14:58:44 -0500 Subject: [PATCH 20/24] LEAF 4455 remove unneeded sql trim for comparison --- LEAF_Request_Portal/sources/Form.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 9389d7d31..7d40a4808 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3708,11 +3708,11 @@ public function query(string $inQuery): mixed //Handled here due to high customization of view_reports, view_search and other reports $resSQL = 'SELECT *, IF( - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.userName")) != "", + JSON_EXTRACT(`userMetadata`, "$.userName") != "", TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")), "(inactive account)" ) AS `firstName`, IF( - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.userName")) != "", + JSON_EXTRACT(`userMetadata`, "$.userName") != "", TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")), `userID` ) AS `lastName` FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; From a5ac942451c7d86fa423528fcc3c99e9a9cb2820 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 9 Dec 2024 08:17:55 -0500 Subject: [PATCH 21/24] LEAF 4455 revert -2 text update since this info is already elsewhere --- LEAF_Request_Portal/sources/FormWorkflow.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index 5ced50e7e..f54bed92c 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -494,11 +494,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $approverMetadata = json_decode($res[$i]['userMetadata'], true); - $nameInfo = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? - " - " . $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : ''; - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup' . $nameInfo . ')'; - $res[$i]['approverName'] = '(Requestor followup' . $nameInfo . ')'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; + $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -546,11 +543,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $dir = $this->getDirectory(); $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $approverMetadata = json_decode($res[$i]['userMetadata'], true); - $nameInfo = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? - " - " . $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : ''; - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup' . $nameInfo . ')'; - $res[$i]['approverName'] = '(Requestor followup' . $nameInfo . ')'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; + $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { From a6ea2613942825b47027eae232a486ce66aff53e Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 9 Dec 2024 16:29:49 -0500 Subject: [PATCH 22/24] LEAF 4455 keep initiatorName query distinct from general records query --- LEAF_Request_Portal/sources/Form.php | 33 ++++++++++++------- .../templates/reports/LEAF_Sitemap_Search.tpl | 1 + .../templates/view_reports.tpl | 1 + 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 7d40a4808..d049cc003 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3576,6 +3576,7 @@ public function query(string $inQuery): mixed $joinActionHistory = false; $joinRecordResolutionData = false; $joinRecordResolutionBy = false; + $joinInitiatorNames = false; $joinUnfilledDependencies = false; if (isset($query['joins'])) { @@ -3622,6 +3623,10 @@ public function query(string $inQuery): mixed case 'recordResolutionBy': $joinRecordResolutionBy = true; + break; + case 'initiatorName': + $joinInitiatorNames = true; + break; case 'destructionDate': $joinRecordResolutionData = true; @@ -3703,19 +3708,23 @@ public function query(string $inQuery): mixed WHERE format = 'orgchart_employee') rj_OCEmployeeData ON (lj_data.indicatorID = rj_OCEmployeeData.indicatorID) "; } - //backwards compat: userMetadata properties are empty for accounts that were inactive when prior md values were updated. - //userMetadata alternatives here prevent the initiator field from displaying 'null, null' if metadata is empty. + + //joinInitiatorNames backwards compat. userMetadata properties are empty for accounts that were inactive when prior metadata + //values were updated. Alternatives here prevent the initiator field from displaying 'null, null' if metadata is empty. //Handled here due to high customization of view_reports, view_search and other reports - $resSQL = 'SELECT *, - IF( - JSON_EXTRACT(`userMetadata`, "$.userName") != "", - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")), "(inactive account)" - ) AS `firstName`, - IF( - JSON_EXTRACT(`userMetadata`, "$.userName") != "", - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")), `userID` - ) AS `lastName` - FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; + $initiatorNamesSQL = ''; + if ($joinInitiatorNames) { + $initiatorNamesSQL = ', + IF( + JSON_EXTRACT(`userMetadata`, "$.userName") != "", + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")), "(inactive account)" + ) AS `firstName`, + IF( + JSON_EXTRACT(`userMetadata`, "$.userName") != "", + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")), `userID` + ) AS `lastName`'; + } + $resSQL = 'SELECT * ' . $initiatorNamesSQL . ' FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; if(isset($_GET['debugQuery'])) { if($this->login->checkGroup(1)) { diff --git a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl index a1d3ae6c8..445aff1df 100644 --- a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl +++ b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl @@ -188,6 +188,7 @@ function addHeader(column) { case 'initiator': filterData['lastName'] = 1; filterData['firstName'] = 1; + leafSearch.getLeafFormQuery().join('initiatorName'); headers.push({ name: 'Initiator', indicatorID: 'initiator', editable: false, callback: function(data, blob) { let d = grid.getDataByIndex(data.index); diff --git a/LEAF_Request_Portal/templates/view_reports.tpl b/LEAF_Request_Portal/templates/view_reports.tpl index b8fcacdc7..6ac37fac9 100644 --- a/LEAF_Request_Portal/templates/view_reports.tpl +++ b/LEAF_Request_Portal/templates/view_reports.tpl @@ -131,6 +131,7 @@ function addHeader(column) { case 'initiator': filterData['lastName'] = 1; filterData['firstName'] = 1; + leafSearch.getLeafFormQuery().join('initiatorName'); headers.push({ name: 'Initiator', indicatorID: 'initiator', editable: false, callback: function(data, blob) { document.querySelector(`#${data.cellContainerID}`).innerHTML = blob[data.recordID].lastName + ', ' + blob[data.recordID].firstName; From f8c11b725b8b98b3ef50e9e6a0bc041af7ea6f08 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Tue, 10 Dec 2024 09:04:47 -0500 Subject: [PATCH 23/24] LEAF 4455 inactive user verbiage, simplify empty metadata check --- LEAF_Request_Portal/sources/Form.php | 16 ++++++++-------- LEAF_Request_Portal/sources/FormWorkflow.php | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index d049cc003..de810ccd1 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -580,7 +580,7 @@ public function getIndicator($indicatorID, $series, $recordID = null, $parseTemp $form[$idx]['displayedValue'] = ''; if (isset($data[0]['metadata'])) { $orgchartInfo = json_decode($data[0]['metadata'], true); - if(trim("{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}") !== "") { + if(!empty(trim($orgchartInfo['lastName']))) { $form[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; } } @@ -1010,7 +1010,7 @@ public function getRecordInfo($recordID) } $userMetadata = json_decode($res[0]['userMetadata'], true); - $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + $name = isset($userMetadata) && !empty(trim($userMetadata['lastName'])) ? "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[0]['userID']; $data = array('name' => $name, @@ -2610,7 +2610,7 @@ public function getCustomData(array $recordID_list, string|null $indicatorID_lis $item['data'] = ''; if (isset($item['metadata'])) { $orgchartInfo = json_decode($item['metadata'], true); - if(trim("{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}") !== "") { + if(!empty(trim($orgchartInfo['lastName']))) { $item['data'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; $item['dataOrgchart'] = $orgchartInfo; } @@ -2749,7 +2749,7 @@ public function getActionComments(int $recordID): array $total = count($res); for ($i = 0; $i < $total; $i++) { $userMetadata = json_decode($res[$i]['userMetadata'], true); - $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + $name = isset($userMetadata) && !empty(trim($userMetadata['lastName'])) ? "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[$i]['userID']; $res[$i]['name'] = $name; @@ -3709,9 +3709,9 @@ public function query(string $inQuery): mixed } - //joinInitiatorNames backwards compat. userMetadata properties are empty for accounts that were inactive when prior metadata - //values were updated. Alternatives here prevent the initiator field from displaying 'null, null' if metadata is empty. - //Handled here due to high customization of view_reports, view_search and other reports + //joinInitiatorNames backwards compat - additional SQL for records.userMetadata replaces previous join with orgchart.employee. + //userMetadata properties are empty for accounts that were inactive when prior metadata values were updated. + //Alternatives here display 'userID (inactive account)' instead of 'null, null' if metadata is empty. $initiatorNamesSQL = ''; if ($joinInitiatorNames) { $initiatorNamesSQL = ', @@ -4394,7 +4394,7 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp $child[$idx]['displayedValue'] = ''; if (isset($data[$idx]['metadata'])) { $orgchartInfo = json_decode($data[$idx]['metadata'], true); - if(trim("{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}") !== "") { + if(!empty(trim($orgchartInfo['lastName']))) { $child[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; } } diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index f54bed92c..42142e947 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -494,8 +494,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; - $res[$i]['approverName'] = '(Requestor followup)'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Inactive User)'; + $res[$i]['approverName'] = '(Inactive User)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -543,8 +543,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $dir = $this->getDirectory(); $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; - $res[$i]['approverName'] = '(Requestor followup)'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Inactive User)'; + $res[$i]['approverName'] = '(Inactive User)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { From 53146f424a1fa8bcad3f563eace6e396ff72940c Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 12 Dec 2024 15:36:21 -0500 Subject: [PATCH 24/24] Revert "Merge pull request #2615 from department-of-veterans-affairs/enhance/LEAF-4455/metadata_read_all" This reverts commit ab2d96e8bc16a352eecf0fd61f5a7f02b7f4a425, reversing changes made to 9f6733fb97f0fcf678a9551393b4cadf19c30e24. --- LEAF_Request_Portal/sources/Form.php | 121 +++++++++--------- LEAF_Request_Portal/sources/FormWorkflow.php | 20 +-- LEAF_Request_Portal/sources/View.php | 14 +- .../templates/reports/LEAF_Sitemap_Search.tpl | 1 - .../templates/view_reports.tpl | 1 - LEAF_Request_Portal/templates/view_status.tpl | 7 +- 6 files changed, 75 insertions(+), 89 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index cea57e765..d92116efd 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -573,16 +573,15 @@ public function getIndicator($indicatorID, $series, $recordID = null, $parseTemp $form[$idx]['value'] = $this->fileToArray($data[0]['data']); $form[$idx]['raw'] = $data[0]['data']; } - // special handling for org chart data types (request header questions, edited report builder cells) + // special handling for org chart data types else if ($data[0]['format'] == 'orgchart_employee' && !empty($data[0]['data'])) { - $form[$idx]['displayedValue'] = ''; - if (isset($data[0]['metadata'])) { - $orgchartInfo = json_decode($data[0]['metadata'], true); - if(!empty(trim($orgchartInfo['lastName']))) { - $form[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; - } + $empRes = $this->employee->lookupEmpUID($data[0]['data']); + if (!empty($empRes)) { + $form[$idx]['displayedValue'] = "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; + } else { + $form[$idx]['displayedValue'] = ''; } } else if ($data[0]['format'] == 'orgchart_position' @@ -1009,9 +1008,9 @@ public function getRecordInfo($recordID) ); } - $userMetadata = json_decode($res[0]['userMetadata'], true); - $name = isset($userMetadata) && !empty(trim($userMetadata['lastName'])) ? - "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[0]['userID']; + $dir = new VAMC_Directory; + $user = $dir->lookupLogin($res[0]['userID']); + $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[0]['userID']; $data = array('name' => $name, 'service' => $res[0]['service'], @@ -2659,14 +2658,16 @@ public function getCustomData(array $recordID_list, string|null $indicatorID_lis } } break; - case 'orgchart_employee': //report builder cells - $item['data'] = ''; - if (isset($item['metadata'])) { - $orgchartInfo = json_decode($item['metadata'], true); - if(!empty(trim($orgchartInfo['lastName']))) { - $item['data'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; - $item['dataOrgchart'] = $orgchartInfo; - } + case 'orgchart_employee': + $empRes = $this->employee->lookupEmpUID($item['data']); + if (isset($empRes[0])) + { + $item['data'] = "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; + $item['dataOrgchart'] = $empRes[0]; + } + else + { + $item['data'] = ''; } break; case 'orgchart_position': @@ -2784,14 +2785,14 @@ public function getActionComments(int $recordID): array } else { $vars = array(':recordID' => $recordID); - $sql = 'SELECT actionTextPasttense, comment, time, userID, userMetadata + $sql = 'SELECT actionTextPasttense, comment, time, userID FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN actions USING (actionType) WHERE recordID = :recordID AND comment != "" UNION - SELECT "Note Added", note, timestamp, userID, userMetadata + SELECT "Note Added", note, timestamp, userID FROM notes WHERE recordID = :recordID AND deleted IS NULL @@ -2799,12 +2800,13 @@ public function getActionComments(int $recordID): array $res = $this->db->prepared_query($sql, $vars); + $dir = new VAMC_Directory; + $total = count($res); - for ($i = 0; $i < $total; $i++) { - $userMetadata = json_decode($res[$i]['userMetadata'], true); - $name = isset($userMetadata) && !empty(trim($userMetadata['lastName'])) ? - "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[$i]['userID']; + for ($i = 0; $i < $total; $i++) { + $user = $dir->lookupLogin($res[$i]['userID']); + $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[$i]['userID']; $res[$i]['name'] = $name; } @@ -2956,9 +2958,11 @@ public function setInitiator($recordID, $userID) userID=:userID, userMetadata=:userMetadata WHERE recordID=:recordID', $vars); + // write log entry + $dir = new VAMC_Directory; - $newInitiatorInfo = json_decode($newInitiatorMetadata, true); - $name = "{$newInitiatorInfo['firstName']} {$newInitiatorInfo['lastName']}"; + $user = $dir->lookupLogin($userID); + $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $userID; $actionUserID = $this->login->getUserID(); $actionUserMetadata = $this->employee->getInfoForUserMetadata($actionUserID, false); @@ -3761,27 +3765,14 @@ public function query(string $inQuery): mixed WHERE format = 'orgchart_employee') rj_OCEmployeeData ON (lj_data.indicatorID = rj_OCEmployeeData.indicatorID) "; } - - //joinInitiatorNames backwards compat - additional SQL for records.userMetadata replaces previous join with orgchart.employee. - //userMetadata properties are empty for accounts that were inactive when prior metadata values were updated. - //Alternatives here display 'userID (inactive account)' instead of 'null, null' if metadata is empty. - $initiatorNamesSQL = ''; - if ($joinInitiatorNames) { - $initiatorNamesSQL = ', - IF( - JSON_EXTRACT(`userMetadata`, "$.userName") != "", - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")), "(inactive account)" - ) AS `firstName`, - IF( - JSON_EXTRACT(`userMetadata`, "$.userName") != "", - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")), `userID` - ) AS `lastName`'; + if ($joinInitiatorNames) + { + $joins .= "LEFT JOIN (SELECT userName, lastName, firstName FROM {$this->oc_dbName}.employee) lj_OCinitiatorNames ON records.userID = lj_OCinitiatorNames.userName "; } - $resSQL = 'SELECT * ' . $initiatorNamesSQL . ' FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; if(isset($_GET['debugQuery'])) { if($this->login->checkGroup(1)) { - $debugQuery = str_replace(["\r", "\n","\t", "%0d","%0a","%09","%20", ";"], ' ', $resSQL); + $debugQuery = str_replace(["\r", "\n","\t", "%0d","%0a","%09","%20", ";"], ' ', 'SELECT * FROM records ' . $joins . 'WHERE ' . $conditions . $sort . $limit); $debugVars = []; foreach($vars as $key => $value) { if(strpos($key, ':data') !== false @@ -3795,14 +3786,17 @@ public function query(string $inQuery): mixed header('X-LEAF-Query: '. str_replace(array_keys($debugVars), $debugVars, $debugQuery)); - return $res = $this->db->prepared_query('EXPLAIN ' . $resSQL, $vars); + return $res = $this->db->prepared_query('EXPLAIN SELECT * FROM records + ' . $joins . ' + WHERE ' . $conditions . $sort . $limit, $vars); } else { return XSSHelpers::scrubObjectOrArray(json_decode(html_entity_decode(html_entity_decode($_GET['q'])), true)); } } - - $res = $this->db->prepared_query($resSQL, $vars); + $res = $this->db->prepared_query('SELECT * FROM records + ' . $joins . ' + WHERE ' . $conditions . $sort . $limit, $vars); $data = array(); $recordIDs = ''; @@ -3878,15 +3872,17 @@ public function query(string $inQuery): mixed if ($joinActionHistory) { + $dir = new VAMC_Directory; + $actionHistorySQL = - 'SELECT recordID, stepID, userID, userMetadata, time, description, + 'SELECT recordID, stepID, userID, time, description, actionTextPasttense, actionType, comment FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN actions USING (actionType) WHERE recordID IN (' . $recordIDs . ') UNION - SELECT recordID, "-5", userID, userMetadata, timestamp, "Note Added", + SELECT recordID, "-5", userID, timestamp, "Note Added", "Note Added", "LEAF_note", note FROM notes WHERE recordID IN (' . $recordIDs . ') @@ -3896,10 +3892,8 @@ public function query(string $inQuery): mixed $res2 = $this->db->prepared_query($actionHistorySQL, array()); foreach ($res2 as $item) { - $userMetadata = json_decode($item['userMetadata'], true); - $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? - "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $item['userID']; - + $user = $dir->lookupLogin($item['userID'], true); + $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[0]['userID']; $item['approverName'] = $name; $data[$item['recordID']]['action_history'][] = $item; @@ -3937,7 +3931,9 @@ public function query(string $inQuery): mixed } if ($joinRecordResolutionBy === true) { - $recordResolutionBySQL = "SELECT recordID, action_history.userID as resolvedBy, action_history.userMetadata, action_history.stepID, action_history.actionType + $dir = new VAMC_Directory; + + $recordResolutionBySQL = "SELECT recordID, action_history.userID as resolvedBy, action_history.stepID, action_history.actionType FROM action_history LEFT JOIN records USING (recordID) INNER JOIN workflow_routes USING (stepID) @@ -3952,9 +3948,8 @@ public function query(string $inQuery): mixed $res2 = $this->db->prepared_query($recordResolutionBySQL, array()); foreach ($res2 as $item) { - $userMetadata = json_decode($item['userMetadata'], true); - $nameResolved = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? - "{$userMetadata['firstName']} {$userMetadata['lastName']} " : $item['resolvedBy']; + $user = $dir->lookupLogin($item['resolvedBy'], true); + $nameResolved = isset($user[0]) ? "{$user[0]['Lname']}, {$user[0]['Fname']} " : $item['resolvedBy']; $data[$item['recordID']]['recordResolutionBy']['resolvedBy'] = $nameResolved; } } @@ -4366,7 +4361,7 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp { $var = array(':series' => (int)$series, ':recordID' => (int)$recordID, ); - $res2 = $this->db->prepared_query('SELECT data, metadata, timestamp, indicatorID, groupID, userID FROM data + $res2 = $this->db->prepared_query('SELECT data, timestamp, indicatorID, groupID, userID FROM data LEFT JOIN indicator_mask USING (indicatorID) WHERE indicatorID IN (' . $indicatorList . ') AND series=:series AND recordID=:recordID', $var); @@ -4374,7 +4369,6 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp { $idx = $resIn['indicatorID']; $data[$idx]['data'] = isset($resIn['data']) ? $resIn['data'] : ''; - $data[$idx]['metadata'] = isset($resIn['metadata']) ? $resIn['metadata'] : null; $data[$idx]['timestamp'] = isset($resIn['timestamp']) ? $resIn['timestamp'] : 0; $data[$idx]['groupID'] = isset($resIn['groupID']) ? $resIn['groupID'] : null; $data[$idx]['userID'] = isset($resIn['userID']) ? $resIn['userID'] : ''; @@ -4441,15 +4435,14 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp $child[$idx]['value'] = $this->fileToArray($data[$idx]['data']); } - // special handling for org chart data types (request subquestions / child) + // special handling for org chart data types if ($field['format'] == 'orgchart_employee') { + $empRes = $this->employee->lookupEmpUID($data[$idx]['data']); $child[$idx]['displayedValue'] = ''; - if (isset($data[$idx]['metadata'])) { - $orgchartInfo = json_decode($data[$idx]['metadata'], true); - if(!empty(trim($orgchartInfo['lastName']))) { - $child[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; - } + if (isset($empRes[0])) + { + $child[$idx]['displayedValue'] = ($child[$idx]['isMasked']) ? '[protected data]' : "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; } } if ($field['format'] == 'orgchart_position') diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index 0c39dbc18..e5960b8e6 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -447,7 +447,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $strSQL = ""; if(!$selectUnfilled) { - $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, userMetadata, requiresDigitalSignature FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, requiresDigitalSignature FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -456,7 +456,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel WHERE recordID IN ({$recordIDs})"; } else { - $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID, userMetadata FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -494,8 +494,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Inactive User)'; - $res[$i]['approverName'] = '(Inactive User)'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; + $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -543,8 +543,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $dir = $this->getDirectory(); $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Inactive User)'; - $res[$i]['approverName'] = '(Inactive User)'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; + $res[$i]['approverName'] = '(Requestor followup)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -716,11 +716,11 @@ public function getLastAction(): array|null|int if (isset($res[0]) && $res[0]['dependencyID'] == -1) { - $approverMetadata = json_decode($res[0]['userMetadata'], true); - $display = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? - $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : $res[0]['userID']; + $dir = $this->getDirectory(); + + $approver = $dir->lookupLogin($res[0]['userID']); - $res[0]['description'] = $display; + $res[0]['description'] = "{$approver[0]['firstName']} {$approver[0]['lastName']}"; } // dependencyID -3 is for a group designated by the requestor if (isset($res[0]) diff --git a/LEAF_Request_Portal/sources/View.php b/LEAF_Request_Portal/sources/View.php index 2a4ec937e..a31dc25f2 100644 --- a/LEAF_Request_Portal/sources/View.php +++ b/LEAF_Request_Portal/sources/View.php @@ -61,7 +61,7 @@ public function buildViewStatus(int $recordID): array $vars = array(':recordID' => $recordID); $sql1 = 'SELECT time, description, actionText, stepTitle, - dependencyID, comment, userID, userMetadata + dependencyID, comment, userID FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN workflow_steps USING (stepID) @@ -69,13 +69,13 @@ public function buildViewStatus(int $recordID): array WHERE recordID=:recordID UNION SELECT timestamp, "Note Added", "N/A", "N/A", - "N/A", note, userID, userMetadata + "N/A", note, userID FROM notes WHERE recordID = :recordID AND deleted IS NULL UNION SELECT `timestamp`, "Email Sent", "N/A", "N/A", - "N/A", concat(`recipients`, "
", `subject`), "", "" + "N/A", concat(`recipients`, "
", `subject`), "" FROM `email_tracker` WHERE recordID = :recordID ORDER BY time ASC'; @@ -102,12 +102,8 @@ public function buildViewStatus(int $recordID): array $packet['comment'] = $tmp['comment']; if (!empty($tmp['userID'])) { - $name = $tmp['userID']; - if(isset($tmp['userMetadata'])) { - $umd = json_decode($tmp['userMetadata'], true); - $display = trim($umd['firstName'] . " " . $umd['lastName']); - $name = !empty($display) ? $display : $name; - } + $user = $dir->lookupLogin($tmp['userID']); + $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $tmp['userID']; $packet['userName'] = $name; } diff --git a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl index 445aff1df..f48ed746f 100644 --- a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl +++ b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl @@ -198,7 +198,6 @@ function addHeader(column) { case 'dateCancelled': filterData['deleted'] = 1; filterData['action_history.approverName'] = 1; - filterData['action_history.actionType'] = 1; leafSearch.getLeafFormQuery().join('action_history'); headers.push({ name: 'Date Cancelled', indicatorID: 'dateCancelled', editable: false, callback: function(data, blob) { diff --git a/LEAF_Request_Portal/templates/view_reports.tpl b/LEAF_Request_Portal/templates/view_reports.tpl index 6ac37fac9..61b91ef80 100644 --- a/LEAF_Request_Portal/templates/view_reports.tpl +++ b/LEAF_Request_Portal/templates/view_reports.tpl @@ -140,7 +140,6 @@ function addHeader(column) { case 'dateCancelled': filterData['deleted'] = 1; filterData['action_history.approverName'] = 1; - filterData['action_history.actionType'] = 1; leafSearch.getLeafFormQuery().join('action_history'); headers.push({ name: 'Date Cancelled', indicatorID: 'dateCancelled', editable: false, callback: function(data, blob) { diff --git a/LEAF_Request_Portal/templates/view_status.tpl b/LEAF_Request_Portal/templates/view_status.tpl index 1ea210cd7..bf2455c3b 100644 --- a/LEAF_Request_Portal/templates/view_status.tpl +++ b/LEAF_Request_Portal/templates/view_status.tpl @@ -26,13 +26,12 @@ Title of request:
- - by + by -
Comment: +
Comment:
-
+