You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

570 lines
32 KiB

<?php
/**
* Administrative loader for lab compendium data.
*
* Supports loading of lab order codes and related order entry questions from CSV
* format into the procedure_order and procedure_questions tables, respectively.
*
* Copyright (C) 2012-2013 Rod Roark <rod@sunsetsystems.com>
*
* LICENSE: This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>.
*
* @package OpenEMR
* @author Rod Roark <rod@sunsetsystems.com>
*/
set_time_limit(0);
require_once("../globals.php");
use OpenEMR\Common\Acl\AclMain;
use OpenEMR\Common\Twig\TwigContainer;
use OpenEMR\Core\Header;
// This array is an important reference for the supported labs and their NPI
// numbers as known to this program. The clinic must define at least one
// procedure provider entry for a lab that has a supported NPI number.
//
$lab_npi = array(
'1235138868' => 'Diagnostic Pathology Medical Group',
'1235186800' => 'Pathgroup Labs LLC',
'1598760985' => 'Yosemite Pathology Medical Group',
);
/**
* Get lab's ID from the users table given its NPI. If none return 0.
*
* @param string $npi The lab's NPI number as known to the system
* @return integer The numeric value of the lab's address book entry
*/
function getLabID($npi)
{
$lrow = sqlQuery(
"SELECT ppid FROM procedure_providers WHERE " .
"npi = ? ORDER BY ppid LIMIT 1",
array($npi)
);
if (empty($lrow['ppid'])) {
return 0;
}
return intval($lrow['ppid']);
}
if (!AclMain::aclCheckCore('admin', 'super')) {
echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("Load Compendium")]);
exit;
}
$form_step = isset($_POST['form_step']) ? trim($_POST['form_step']) : '0';
$form_status = isset($_POST['form_status' ]) ? trim($_POST['form_status' ]) : '';
if (!empty($_POST['form_import'])) {
$form_step = 1;
}
// When true the current form will submit itself after a brief pause.
$auto_continue = false;
// Set up main paths.
$EXPORT_FILE = $GLOBALS['temporary_files_dir'] . "/openemr_config.sql";
?>
<html>
<head>
<?php Header::setupHeader(); ?>
<title><?php echo xlt('Load Compendium'); ?></title>
</head>
<body>
<div class="container mt-3">
<div class="row">
<div class="col-12">
<h2><?php echo xlt('Load Lab Compendium'); ?></h2>
</div>
</div>
<form class="jumbotron py-4" method='post' action='load_compendium.php' enctype='multipart/form-data'>
<table class="table table-borderless">
<?php if ($form_step == 0) { ?>
<tr>
<td class="text-nowrap">
<?php echo xlt('Vendor'); ?>
</td>
<td>
<select class='form-control' name='vendor'>
<?php foreach ($lab_npi as $key => $value) {
echo "<option value='" . attr($key) . "'";
if (!getLabID($key)) {
// Entries with no matching address book entry will be disabled.
echo " disabled";
}
echo ">" . text($key) . ": " . text($value) . "</option>";
} ?>
</select>
</td>
</tr>
<tr>
<td class="text-nowrap">
<?php echo xlt('Action'); ?>
</td>
<td>
<select class='form-control' name='action'>
<option value='1'><?php echo xlt('Load Order Definitions'); ?></option>
<option value='2'><?php echo xlt('Load Order Entry Questions'); ?></option>
<option value='3'><?php echo xlt('Load OE Question Options'); ?></option>
</select>
</td>
</tr>
<tr>
<td class="text-nowrap">
<?php echo xlt('Container Group Name'); ?>
</td>
<td>
<select class='form-control' name='group'>
<?php
$gres = sqlStatement("SELECT procedure_type_id, name FROM procedure_type " .
"WHERE procedure_type = 'grp' ORDER BY name, procedure_type_id");
while ($grow = sqlFetchArray($gres)) {
echo "<option value='" . attr($grow['procedure_type_id']) . "'>" .
text($grow['name']) . "</option>";
}?>
</select>
</td>
</tr>
<tr>
<td class="text-nowrap">
<?php echo xlt('File to Upload'); ?>
</td>
<td>
<div class="custom-file">
<label class="custom-file-label" for="userfile"><?php echo xlt('Choose file'); ?></label>
<input type='hidden' class="custom-file-input" name='MAX_FILE_SIZE' value='4000000' />
<input class='form-control' type='file' name='userfile' id='userfile' />
</div>
</td>
</tr>
<tr>
<td colspan="2">
<button type="submit" class="btn btn-primary btn-save" value='<?php echo xla('Submit'); ?>'>
<?php echo xlt('Submit'); ?>
</button>
</td>
</tr>
<?php }
echo " <tr>\n";
echo " <td colspan='2'>\n";
if ($form_step == 1) {
// Process uploaded config file.
if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
$form_vendor = $_POST['vendor'];
$form_action = intval($_POST['action']);
$form_group = intval($_POST['group']);
$lab_id = getLabID($form_vendor);
$form_status .= xlt('Applying') . "...<br />";
echo nl2br(text($form_status));
$fhcsv = fopen($_FILES['userfile']['tmp_name'], "r");
if ($fhcsv) {
// Vendor = Pathgroup
//
if ($form_vendor == '1235186800') {
if ($form_action == 1) { // load compendium
// Mark all "ord" rows having the indicated parent as inactive.
sqlStatement(
"UPDATE procedure_type SET activity = 0 WHERE " .
"parent = ? AND procedure_type = 'ord'",
array($form_group)
);
// What should be uploaded is the "Compendium" spreadsheet provided by
// PathGroup, saved in "Text CSV" format from OpenOffice, using its
// default settings. Values for each row are:
// 0: Order Code : mapped to procedure_code of order type
// 1: Order Name : mapped to name of order type
// 2: Result Code : mapped to procedure_code of result type
// 3: Result Name : mapped to name of result type
//
while (!feof($fhcsv)) {
$acsv = fgetcsv($fhcsv, 4096);
if (count($acsv) < 4 || $acsv[0] == "Order Code") {
continue;
}
$standard_code = empty($acsv[2]) ? '' : ('CPT4:' . $acsv[2]);
// Update or insert the order row, if not already done.
$trow = sqlQuery(
"SELECT * FROM procedure_type WHERE " .
"parent = ? AND procedure_code = ? AND procedure_type = 'ord' " .
"ORDER BY procedure_type_id DESC LIMIT 1",
array($form_group, $acsv[0])
);
if (empty($trow['procedure_type_id']) || $trow['activity'] == 0) {
if (empty($trow['procedure_type_id'])) {
$ptid = sqlInsert(
"INSERT INTO procedure_type SET " .
"parent = ?, name = ?, lab_id = ?, procedure_code = ?, procedure_type = ?",
array($form_group, $acsv[1], $lab_id, $acsv[0], 'ord')
);
} else {
$ptid = $trow['procedure_type_id'];
sqlStatement(
"UPDATE procedure_type SET " .
"parent = ?, name = ?, lab_id = ?, procedure_code = ?, procedure_type = ?, " .
"activity = 1 WHERE procedure_type_id = ?",
array($form_group, $acsv[1], $lab_id, $acsv[0], 'ord', $ptid)
);
}
sqlStatement(
"UPDATE procedure_type SET activity = 0 WHERE " .
"parent = ? AND procedure_type = 'res'",
array($ptid)
);
}
// Update or insert the result row.
// Not sure we need this, but what the hell.
$trow = sqlQuery(
"SELECT * FROM procedure_type WHERE " .
"parent = ? AND procedure_code = ? AND procedure_type = 'res' " .
"ORDER BY procedure_type_id DESC LIMIT 1",
array($ptid, $acsv[2])
);
// The following should always be true, otherwise duplicate input row.
if (empty($trow['procedure_type_id']) || $trow['activity'] == 0) {
if (empty($trow['procedure_type_id'])) {
sqlStatement(
"INSERT INTO procedure_type SET " .
"parent = ?, name = ?, lab_id = ?, procedure_code = ?, procedure_type = ?",
array($ptid, $acsv[3], $lab_id, $acsv[2], 'res')
);
} else {
$resid = $trow['procedure_type_id'];
sqlStatement(
"UPDATE procedure_type SET " .
"parent = ?, name = ?, lab_id = ?, procedure_code = ?, procedure_type = ?, " .
"activity = 1 WHERE procedure_type_id = ?",
array($ptid, $acsv[3], $lab_id, $acsv[2], 'res', $resid)
);
}
} // end if
} // end while
// end SFTP
} elseif ($form_action == 2) { // load questions
// Delete the vendor's current questions.
sqlStatement(
"DELETE FROM procedure_questions WHERE lab_id = ?",
array($lab_id)
);
// What should be uploaded is the "AOE Questions" spreadsheet provided by
// PathGroup, saved in "Text CSV" format from OpenOffice, using its
// default settings. Values for each row are:
// 0: OBRCode (order code)
// 1: Question Code
// 2: Question
// 3: "Tips"
// 4: Required (0 = No, 1 = Yes)
// 5: Maxchar (integer length)
// 6: FieldType (FT = free text, DD = dropdown, ST = string)
//
$seq = 0;
$last_code = '';
while (!feof($fhcsv)) {
$acsv = fgetcsv($fhcsv, 4096);
if (count($acsv) < 7 || $acsv[4] == "Required") {
continue;
}
$code = trim($acsv[0]);
if (empty($code)) {
continue;
}
if ($code != $last_code) {
$seq = 0;
$last_code = $code;
}
++$seq;
$required = 0 + $acsv[4];
$maxsize = 0 + $acsv[5];
$fldtype = 'T';
// Figure out field type.
if ($acsv[6] == 'DD') {
$fldtype = 'S';
} elseif (stristr($acsv[3], 'mm/dd/yy') !== false) {
$fldtype = 'D';
} elseif (stristr($acsv[3], 'wks_days') !== false) {
$fldtype = 'G';
} elseif ($acsv[6] == 'FT') {
$fldtype = 'T';
} else {
$fldtype = 'N';
}
$qrow = sqlQuery(
"SELECT * FROM procedure_questions WHERE " .
"lab_id = ? AND procedure_code = ? AND question_code = ?",
array($lab_id, $code, $acsv[1])
);
if (empty($qrow['question_code'])) {
sqlStatement(
"INSERT INTO procedure_questions SET " .
"lab_id = ?, procedure_code = ?, question_code = ?, question_text = ?, " .
"required = ?, maxsize = ?, fldtype = ?, options = '', tips = ?,
activity = 1, seq = ?",
array($lab_id, $code, $acsv[1], $acsv[2], $required, $maxsize, $fldtype, $acsv[3], $seq)
);
} else {
sqlStatement(
"UPDATE procedure_questions SET " .
"question_text = ?, required = ?, maxsize = ?, fldtype = ?, " .
"options = '', tips = ?, activity = 1, seq = ? WHERE " .
"lab_id = ? AND procedure_code = ? AND question_code = ?",
array($acsv[2], $required, $maxsize, $fldtype, $acsv[3], $seq,
$lab_id,
$code,
$acsv[1])
);
}
} // end while
// end load questions
} elseif ($form_action == 3) { // load question options
// What should be uploaded is the "AOE Options" spreadsheet provided
// by YPMG, saved in "Text CSV" format from OpenOffice, using its
// default settings. Values for each row are:
// 0: OBXCode (question code)
// 1: OBRCode (procedure code)
// 2: Option1 (option text)
// 3: Optioncode (the row is duplicated for each possible value)
//
while (!feof($fhcsv)) {
$acsv = fgetcsv($fhcsv, 4096);
if (count($acsv) < 4 || ($acsv[0] == "OBXCode")) {
continue;
}
$pcode = trim($acsv[1]);
$qcode = trim($acsv[0]);
$options = trim($acsv[2]) . ':' . trim($acsv[3]);
if (empty($pcode) || empty($qcode)) {
continue;
}
$qrow = sqlQuery(
"SELECT * FROM procedure_questions WHERE " .
"lab_id = ? AND procedure_code = ? AND question_code = ?",
array($lab_id, $pcode, $qcode)
);
if (empty($qrow['procedure_code'])) {
continue; // should not happen
} else {
if ($qrow['activity'] == '1' && $qrow['options'] !== '') {
$options = $qrow['options'] . ';' . $options;
}
sqlStatement(
"UPDATE procedure_questions SET " .
"options = ? WHERE " .
"lab_id = ? AND procedure_code = ? AND question_code = ?",
array($options, $lab_id, $pcode, $qcode)
);
}
} // end while
} // end load questions
} // End Pathgroup
// Vendor = YPMG or DPMG
//
if ($form_vendor == '1598760985' || $form_vendor == '1235138868') {
if ($form_action == 1) { // load compendium
// Mark all "ord" rows having the indicated parent as inactive.
sqlStatement(
"UPDATE procedure_type SET activity = 0 WHERE " .
"parent = ? AND procedure_type = 'ord'",
array($form_group)
);
// What should be uploaded is the Order Compendium spreadsheet provided
// by YPMG, saved in "Text CSV" format from OpenOffice, using its
// default settings. Values for each row are:
// 0: Order code : mapped to procedure_code
// 1: Order Name : mapped to name
// 2: Result Code : ignored (will cause multiple occurrences of the same order code)
// 3: Result Name : ignored
//
while (!feof($fhcsv)) {
$acsv = fgetcsv($fhcsv, 4096);
$ordercode = trim($acsv[0]);
if (count($acsv) < 2 || $ordercode == "Order Code") {
continue;
}
$trow = sqlQuery(
"SELECT * FROM procedure_type WHERE " .
"parent = ? AND procedure_code = ? AND procedure_type = 'ord' " .
"ORDER BY procedure_type_id DESC LIMIT 1",
array($form_group, $ordercode)
);
if (empty($trow['procedure_type_id'])) {
sqlStatement(
"INSERT INTO procedure_type SET " .
"parent = ?, name = ?, lab_id = ?, procedure_code = ?, procedure_type = ?, " .
"activity = 1",
array($form_group, trim($acsv[1]), $lab_id, $ordercode, 'ord')
);
} else {
sqlStatement(
"UPDATE procedure_type SET " .
"parent = ?, name = ?, lab_id = ?, procedure_code = ?, procedure_type = ?, " .
"activity = 1 " .
"WHERE procedure_type_id = ?",
array($form_group, trim($acsv[1]), $lab_id, $ordercode, 'ord',
$trow['procedure_type_id'])
);
}
}
} elseif ($form_action == 2) { // load questions
// Mark the vendor's current questions inactive.
sqlStatement(
"DELETE FROM procedure_questions WHERE lab_id = ?",
array($lab_id)
);
// What should be uploaded is the "AOE Questions" spreadsheet provided
// by YPMG, saved in "Text CSV" format from OpenOffice, using its
// default settings. Values for each row are:
// 0: Order Code
// 1: Question Code
// 2: Question
// 3: Is Required (always "false")
// 4: Field Type ("Free Text", "Pre-Defined Text" or "Drop Down";
// "Drop Down" was previously "Multiselect Pre-Defined Text" and
// indicates that more than one choice is allowed)
// 5: Response (just one; the row is duplicated for each possible value)
//
$seq = 0;
$last_code = '';
while (!feof($fhcsv)) {
$acsv = fgetcsv($fhcsv, 4096);
if (count($acsv) < 5 || ($acsv[3] !== "false" && $acsv[3] !== "true")) {
continue;
}
$pcode = trim($acsv[0]);
$qcode = trim($acsv[1]);
$required = strtolower(substr($acsv[3], 0, 1)) == 't' ? 1 : 0;
$options = trim($acsv[5]);
if (empty($pcode) || empty($qcode)) {
continue;
}
if ($pcode != $last_code) {
$seq = 0;
$last_code = $pcode;
}
++$seq;
// Figure out field type.
$fldtype = 'T';
if (strpos($acsv[4], 'Drop') !== false) {
$fldtype = 'S';
} elseif (strpos($acsv[4], 'Multiselect') !== false) {
$fldtype = 'S';
}
$qrow = sqlQuery(
"SELECT * FROM procedure_questions WHERE " .
"lab_id = ? AND procedure_code = ? AND question_code = ?",
array($lab_id, $pcode, $qcode)
);
// If this is the first option value and it's a multi-select list,
// then prepend '+;' here to indicate that. YPMG does not use those
// but keep this note here for future reference.
if (empty($qrow['procedure_code'])) {
sqlStatement(
"INSERT INTO procedure_questions SET " .
"lab_id = ?, procedure_code = ?, question_code = ?, question_text = ?, " .
"fldtype = ?, required = ?, options = ?, seq = ?, activity = 1",
array($lab_id, $pcode, $qcode, trim($acsv[2]), $fldtype, $required, $options, $seq)
);
} else {
if ($qrow['activity'] == '1' && $qrow['options'] !== '' && $options !== '') {
$options = $qrow['options'] . ';' . $options;
}
sqlStatement(
"UPDATE procedure_questions SET " .
"question_text = ?, fldtype = ?, required = ?, options = ?, activity = 1 WHERE " .
"lab_id = ? AND procedure_code = ? AND question_code = ?",
array(trim($acsv[2]), $fldtype, $required, $options, $lab_id, $pcode, $qcode)
);
}
} // end while
} // end load questions
} // End YPMG
fclose($fhcsv);
} else {
echo "<p class='text-danger'>" . xlt('Internal error accessing uploaded file!') . "</p>";
$form_step = -1;
}
} else {
echo "<p class='text-danger'>" . xlt('Upload failed!') . "</p>";
$form_step = -1;
}
$auto_continue = true;
}
if ($form_step == 2) {
$form_status .= xlt('Done') . ".";
echo nl2br(text($form_status));
}
++$form_step;
?>
</td>
</tr>
</table>
<input type='hidden' name='form_step' value='<?php echo attr($form_step); ?>' />
<input type='hidden' name='form_status' value='<?php echo attr($form_status); ?>' />
</form>
<?php
ob_flush();
flush();
?>
<?php if ($auto_continue) { ?>
<script>
setTimeout("document.forms[0].submit();", 500);
</script>
<?php } ?>
</div>
</body>
</html>