3 * Encounter form for entering procedure orders.
5 * Copyright (C) 2010-2013 Rod Roark <rod@sunsetsystems.com>
7 * LICENSE: This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>.
19 * @author Rod Roark <rod@sunsetsystems.com>
22 require_once("../../globals.php");
23 require_once("$srcdir/api.inc");
24 require_once("$srcdir/forms.inc");
25 require_once("$srcdir/options.inc.php");
26 require_once("$srcdir/formatting.inc.php");
27 require_once("../../orders/qoe.inc.php");
28 require_once("../../orders/gen_hl7_order.inc.php");
29 require_once("../../../custom/code_types.inc.php");
31 // Defaults for new orders.
33 'provider_id' => $_SESSION['authUserID'],
34 'date_ordered' => date('Y-m-d'),
35 'date_collected' => date('Y-m-d H:i'),
38 if (! $encounter) { // comes from globals.php
39 die("Internal error: we do not seem to be in an encounter!");
42 function cbvalue($cbname) {
43 return $_POST[$cbname] ?
'1' : '0';
46 function cbinput($name, $colname) {
48 $ret = "<input type='checkbox' name='$name' value='1'";
49 if ($row[$colname]) $ret .= " checked";
54 function cbcell($name, $desc, $colname) {
55 return "<td width='25%' nowrap>" . cbinput($name, $colname) . "$desc</td>\n";
58 function QuotedOrNull($fld) {
59 if (empty($fld)) return "NULL";
63 function getListOptions($list_id , $fieldnames=array('option_id', 'title', 'seq'))
66 $query = sqlStatement("SELECT ".implode(',',$fieldnames)." FROM list_options where list_id = ? AND activity = 1 order by seq", array($list_id));
67 while($ll = sqlFetchArray($query)) {
68 foreach($fieldnames as $val)
69 $output[$ll['option_id']][$val] = $ll[$val];
73 $formid = formData('id', 'G') +
0;
75 // If Save or Transmit was clicked, save the info.
77 if ($_POST['bn_save'] ||
$_POST['bn_xmit']) {
78 $ppid = formData('form_lab_id') +
0;
81 "date_ordered = " . QuotedOrNull(formData('form_date_ordered')) . ", " .
82 "provider_id = " . (formData('form_provider_id') +
0) . ", " .
83 "lab_id = " . $ppid . ", " .
84 "date_collected = " . QuotedOrNull(formData('form_date_collected')) . ", " .
85 "order_priority = '" . formData('form_order_priority') . "', " .
86 "order_status = '" . formData('form_order_status') . "', " .
87 "clinical_hx = '" . formData('form_clinical_hx') . "', " .
88 "patient_instructions = '" . formData('form_patient_instructions') . "', " .
89 "patient_id = '" . $pid . "', " .
90 "encounter_id = '" . $encounter . "', " .
91 "history_order= '". formData('form_history_order'). "'";
93 // If updating an existing form...
96 $query = "UPDATE procedure_order SET $sets " .
97 "WHERE procedure_order_id = '$formid'";
101 // If adding a new form...
104 $query = "INSERT INTO procedure_order SET $sets";
105 $formid = sqlInsert($query);
106 addForm($encounter, "Procedure Order", $formid, "procedure_order", $pid, $userauthorized);
109 // Remove any existing procedures and their answers for this order and
110 // replace them from the form.
112 sqlStatement("DELETE FROM procedure_answers WHERE procedure_order_id = ?",
114 sqlStatement("DELETE FROM procedure_order_code WHERE procedure_order_id = ?",
117 for ($i = 0; isset($_POST['form_proc_type'][$i]); ++
$i) {
118 $ptid = $_POST['form_proc_type'][$i] +
0;
119 if ($ptid <= 0) continue;
121 $prefix = "ans$i" . "_";
124 $procedure_order_seq = sqlQuery( "SELECT IFNULL(MAX(procedure_order_seq),0) + 1 AS increment FROM procedure_order_code WHERE procedure_order_id = ? ", array($formid));
125 $poseq = sqlInsert("INSERT INTO procedure_order_code SET ".
126 "procedure_order_id = ?, " .
128 "procedure_order_title = ?, " .
129 "procedure_code = (SELECT procedure_code FROM procedure_type WHERE procedure_type_id = ?), " .
130 "procedure_name = (SELECT name FROM procedure_type WHERE procedure_type_id = ?)," .
131 "procedure_order_seq = ? ",
132 array($formid, strip_escape_custom($_POST['form_proc_type_diag'][$i]), strip_escape_custom($_POST['form_proc_order_title'][$i]), $ptid, $ptid, $procedure_order_seq['increment']));
135 $qres = sqlStatement("SELECT " .
136 "q.procedure_code, q.question_code, q.options, q.fldtype " .
137 "FROM procedure_type AS t " .
138 "JOIN procedure_questions AS q ON q.lab_id = t.lab_id " .
139 "AND q.procedure_code = t.procedure_code AND q.activity = 1 " .
140 "WHERE t.procedure_type_id = ? " .
141 "ORDER BY q.seq, q.question_text", array($ptid));
143 while ($qrow = sqlFetchArray($qres)) {
144 $options = trim($qrow['options']);
145 $qcode = trim($qrow['question_code']);
146 $fldtype = $qrow['fldtype'];
148 if ($fldtype == 'G') {
149 if ($_POST["G1_$prefix$qcode"]) {
150 $data = $_POST["G1_$prefix$qcode"] * 7 +
$_POST["G2_$prefix$qcode"];
154 $data = $_POST["$prefix$qcode"];
156 if (!isset($data) ||
$data === '') continue;
157 if (!is_array($data)) $data = array($data);
158 foreach ($data as $datum) {
159 // Note this will auto-assign the seq value.
161 $answer_seq = sqlQuery( "SELECT IFNULL(MAX(answer_seq),0) + 1 AS increment FROM procedure_answers WHERE procedure_order_id = ? AND procedure_order_seq = ? AND question_code = ? ", array($formid, $poseq, $qcode));
162 sqlStatement("INSERT INTO procedure_answers SET ".
163 "procedure_order_id = ?, " .
164 "procedure_order_seq = ?, " .
165 "question_code = ?, " .
168 array($formid, $poseq, $qcode, $answer_seq['increment'], strip_escape_custom($datum)));
175 if ($_POST['bn_xmit']) {
177 $alertmsg = gen_hl7_order($formid, $hl7);
178 if (empty($alertmsg)) {
179 $alertmsg = send_hl7_order($ppid, $hl7);
181 if (empty($alertmsg)) {
182 sqlStatement("UPDATE procedure_order SET date_transmitted = NOW() WHERE " .
183 "procedure_order_id = ?", array($formid));
187 formHeader("Redirecting....");
189 echo "\n<script language='Javascript'>alert('";
190 echo addslashes(xl('Transmit failed') . ': ' . $alertmsg);
191 echo "')</script>\n";
199 $row = sqlQuery ("SELECT * FROM procedure_order WHERE " .
200 "procedure_order_id = ?",
204 $enrow = sqlQuery("SELECT p.fname, p.mname, p.lname, fe.date FROM " .
205 "form_encounter AS fe, forms AS f, patient_data AS p WHERE " .
206 "p.pid = ? AND f.pid = p.pid AND f.encounter = ? AND " .
207 "f.formdir = 'newpatient' AND f.deleted = 0 AND " .
208 "fe.id = f.form_id LIMIT 1",
209 array($pid, $encounter));
213 <?php
html_header_show(); ?
>
214 <link rel
="stylesheet" href
="<?php echo $css_header;?>" type
="text/css" />
229 <style type
="text/css">@import
url(<?php
echo $GLOBALS['webroot'] ?
>/library
/dynarch_calendar
.css
);</style
>
230 <script type
="text/javascript" src
="<?php echo $GLOBALS['webroot'] ?>/library/dynarch_calendar.js"></script
>
231 <?php
include_once("{$GLOBALS['srcdir']}/dynarch_calendar_en.inc.php"); ?
>
232 <script type
="text/javascript" src
="<?php echo $GLOBALS['webroot'] ?>/library/dynarch_calendar_setup.js"></script
>
234 <script type
="text/javascript" src
="../../../library/dialog.js?v=<?php echo $v_js_includes; ?>"></script
>
235 <script type
="text/javascript" src
="<?php echo $GLOBALS['webroot'] ?>/library/textformat.js"></script
>
237 <script language
='JavaScript'>
239 // This invokes the find-procedure-type popup.
240 // formseq = 0-relative index in the form.
242 function sel_proc_type(formseq
) {
243 var f
= document
.forms
[0];
244 // if (!f.form_lab_id.value) {
245 // alert('<?php echo xls('Please select a procedure provider'); ?>');
248 gbl_formseq
= formseq
;
249 var ptvarname
= 'form_proc_type[' + formseq +
']';
250 /********************************************************************
251 dlgopen('../../orders/types.php?popup=1' +
252 '&labid=' + f.form_lab_id.value +
253 '&order=' + f[ptvarname].value +
254 '&formid=<?php echo $formid; ?>' +
255 '&formseq=' + formseq,
257 ********************************************************************/
258 // This replaces the above for an easier/faster order picker tool.
259 dlgopen('../../orders/find_order_popup.php' +
260 '?labid=' + f
.form_lab_id
.value +
261 '&order=' + f
[ptvarname
].value +
262 '&formid=<?php echo $formid; ?>' +
263 '&formseq=' + formseq
,
267 // This is for callback by the find-procedure-type popup.
268 // Sets both the selected type ID and its descriptive name.
269 function set_proc_type(typeid
, typename
) {
270 var f
= document
.forms
[0];
271 var ptvarname
= 'form_proc_type[' + gbl_formseq +
']';
272 var ptdescname
= 'form_proc_type_desc[' + gbl_formseq +
']';
273 f
[ptvarname
].value
= typeid
;
274 f
[ptdescname
].value
= typename
;
277 // This is also for callback by the find-procedure-type popup.
278 // Sets the contents of the table containing the form fields for questions.
279 function set_proc_html(s
, js
) {
280 document
.getElementById('qoetable[' + gbl_formseq +
']').innerHTML
= s
;
284 // New lab selected so clear all procedures and questions from the form.
285 function lab_id_changed() {
286 var f
= document
.forms
[0];
287 for (var i
= 0; true; ++i
) {
288 var ix
= '[' + i +
']';
289 if (!f
['form_proc_type' + ix
]) break;
290 f
['form_proc_type' + ix
].value
= '-1';
291 f
['form_proc_type_desc' + ix
].value
= '';
292 document
.getElementById('qoetable' + ix
).innerHTML
= '';
296 // Add a line for entry of another procedure.
297 function addProcLine() {
298 var f
= document
.forms
[0];
299 var table
= document
.getElementById('proctable');
300 var e
= document
.getElementById("procedure_type_names");
301 var prc_name
= e
.options
[e
.selectedIndex
].value
;
302 // Compute i = next procedure index.
304 for (; f
['form_proc_type[' + i +
']']; ++i
);
305 var row
= table
.insertRow(table
.rows
.length
);
306 var cell
= row
.insertCell(0);
308 //cell.innerHTML = "<b><?php echo xl('Procedure'); ?> " + (i + 1) + ":</b>";
309 cell
.innerHTML
= "<b>"+prc_name+
"<input type='hidden' name='form_proc_order_title[" + i +
"]' value='"+ prc_name +
"'></b>";
310 var cell
= row
.insertCell(1);
313 "<input type='text' size='50' name='form_proc_type_desc[" + i +
"]'" +
314 " onclick='sel_proc_type(" + i +
")'" +
315 " onfocus='this.blur()'" +
316 " title='<?php echo xla('Click to select the desired procedure'); ?>'" +
317 " style='width:100%;cursor:pointer;cursor:hand' readonly />" +
318 " <input type='hidden' name='form_proc_type[" + i +
"]' value='-1' />" +
319 "<br /><?php echo xla('Diagnosis Codes'); ?>: " +
320 "<input type='text' size='50' name='form_proc_type_diag[" + i +
"]'" +
321 " onclick='sel_related(this.name)'" +
322 " title='<?php echo xla('Click to add a diagnosis'); ?>'" +
323 " onfocus='this.blur()'" +
324 " style='cursor:pointer;cursor:hand' readonly />" +
325 " <div style='width:95%;' id='qoetable[" + i +
"]'></div>";
330 // The name of the form field for find-code popup results.
333 // This is for callback by the find-code popup.
334 // Appends to or erases the current list of related codes.
335 function set_related(codetype
, code
, selector
, codedesc
) {
336 var f
= document
.forms
[0];
337 var s
= f
[rcvarname
].value
;
339 if (s
.length
> 0) s +
= ';';
340 s +
= codetype +
':' + code
;
344 f
[rcvarname
].value
= s
;
347 // This invokes the find-code popup.
348 function sel_related(varname
) {
350 // codetype is just to make things easier and avoid mistakes.
351 // Might be nice to have a lab parameter for acceptable code types.
352 // Also note the controlling script here runs from interface/patient_file/encounter/.
353 dlgopen('find_code_popup.php?codetype=<?php echo attr(collect_codetypes("diagnosis","csv")) ?>', '_blank', 500, 400);
356 var transmitting
= false;
358 // Issue a Cancel/OK warning if a previously transmitted order is being transmitted again.
359 function validate(f
) {
360 <?php
if (!empty($row['date_transmitted'])) { ?
>
362 if (!confirm('<?php echo xls('This order was already transmitted on
') . ' ' .
363 addslashes($row['date_transmitted
']) . '. ' .
364 xls('Are you sure you want to transmit it again?
'); ?>')) {
369 top
.restoreSession();
377 <body
class="body_top">
379 <form method
="post" action
="<?php echo $rootdir ?>/forms/procedure_order/new.php?id=<?php echo $formid ?>"
380 onsubmit
="return validate(this)">
382 <p
class='title' style
='margin-top:8px;margin-bottom:8px;text-align:center'>
384 echo xl('Procedure Order for') . ' ';
385 echo $enrow['fname'] . ' ' . $enrow['mname'] . ' ' . $enrow['lname'];
386 echo ' ' . xl('on') . ' ' . oeFormatShortDate(substr($enrow['date'], 0, 10));
393 <table border
='1' width
='95%' id
='proctable'>
396 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Ordering Provider','e'); ?
>:</b
></td
>
399 generate_form_field(array('data_type'=>10,'field_id'=>'provider_id'),
400 $row['provider_id']);
406 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Sending To','e'); ?
>:</b
></td
>
408 <select name
='form_lab_id' onchange
='lab_id_changed()'>
410 $ppres = sqlStatement("SELECT ppid, name FROM procedure_providers " .
411 "ORDER BY name, ppid");
412 while ($pprow = sqlFetchArray($ppres)) {
413 echo "<option value='" . attr($pprow['ppid']) . "'";
414 if ($pprow['ppid'] == $row['lab_id']) echo " selected";
415 echo ">" . text($pprow['name']) . "</option>";
423 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Order Date','e'); ?
>:</b
></td
>
426 echo "<input type='text' size='10' name='form_date_ordered' id='form_date_ordered'" .
427 " value='" . $row['date_ordered'] . "'" .
428 " title='" . xl('Date of this order') . "'" .
429 " onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)'" .
431 "<img src='$rootdir/pic/show_calendar.gif' align='absbottom' width='24' height='22'" .
432 " id='img_date_ordered' border='0' alt='[?]' style='cursor:pointer'" .
433 " title='" . xl('Click here to choose a date') . "' />";
439 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Internal Time Collected','e'); ?
>:</b
></td
>
442 echo "<input type='text' size='16' name='form_date_collected' id='form_date_collected'" .
443 " value='" . substr($row['date_collected'], 0, 16) . "'" .
444 " title='" . xl('Date and time that the sample was collected') . "'" .
445 // " onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)'" .
447 "<img src='$rootdir/pic/show_calendar.gif' align='absbottom' width='24' height='22'" .
448 " id='img_date_collected' border='0' alt='[?]' style='cursor:pointer'" .
449 " title='" . xl('Click here to choose a date and time') . "' />";
455 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Priority','e'); ?
>:</b
></td
>
458 generate_form_field(array('data_type'=>1,'field_id'=>'order_priority',
459 'list_id'=>'ord_priority'), $row['order_priority']);
465 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Status','e'); ?
>:</b
></td
>
468 generate_form_field(array('data_type'=>1,'field_id'=>'order_status',
469 'list_id'=>'ord_status'), $row['order_status']);
474 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('History order','e'); ?
>:</b
>
476 <?php
generate_form_field(array('data_type'=>1,'field_id'=>'history_order','list_id'=>'boolean'),$row['history_order']); ?
>
480 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Clinical History','e'); ?
>:</b
></td
>
482 <input type
='text' maxlength
='255' name
='form_clinical_hx' style
='width:100%'
483 class='inputtext' value
='<?php echo attr($row['clinical_hx
']); ?>' />
487 <!-- Will enable this later
, nothing uses it yet
. -->
488 <tr style
='display:none'>
489 <td width
='1%' valign
='top' nowrap
><b
><?php
xl('Patient Instructions','e'); ?
>:</b
></td
>
491 <textarea rows
='3' cols
='40' name
='form_patient_instructions' style
='width:100%'
492 wrap
='virtual' class='inputtext' /><?php
echo $row['patient_instructions'] ?
></textarea
>
498 // This section merits some explanation. :)
500 // If any procedures have already been saved for this form, then a top-level table row is
501 // created for each of them, and includes the relevant questions and any existing answers.
502 // Otherwise a single empty table row is created for entering the first or only procedure.
504 // If a new procedure is selected or changed, the questions for it are (re)generated from
505 // the dialog window from which the procedure is selected, via JavaScript. The sel_proc_type
506 // function and the types.php script that it invokes collaborate to support this feature.
508 // The generate_qoe_html function in qoe.inc.php contains logic to generate the HTML for
509 // the questions, and can be invoked either from this script or from types.php.
511 // The $i counter that you see below is to resolve the need for unique names for form fields
512 // that may occur for each of the multiple procedure requests within the same order.
513 // procedure_order_seq serves a similar need for uniqueness at the database level.
517 $opres = sqlStatement("SELECT " .
518 "pc.procedure_order_seq, pc.procedure_code, pc.procedure_name, " .
519 "pc.diagnoses,pc.procedure_order_title, pt.procedure_type_id " .
520 "FROM procedure_order_code AS pc " .
521 "LEFT JOIN procedure_type AS pt ON pt.lab_id = ? AND " .
522 "pt.procedure_code = pc.procedure_code " .
523 "WHERE pc.procedure_order_id = ? " .
524 "ORDER BY pc.procedure_order_seq",
525 array($row['lab_id'], $formid));
526 while ($oprow = sqlFetchArray($opres)) {
530 if (empty($oparr)) $oparr[] = array('procedure_name' => '');
533 foreach ($oparr as $oprow) {
534 $ptid = -1; // -1 means no procedure is selected yet
535 if (!empty($oprow['procedure_type_id'])) {
536 $ptid = $oprow['procedure_type_id'];
540 <!--<td width
='1%' valign
='top'><b
><?php
echo xl('Procedure') . ' ' . ($i +
1); ?
>:</b
></td
>-->
541 <?php
if(empty($formid) ||
empty($oprow['procedure_order_title'])) {?
>
542 <td width
='1%' valign
='top'><input type
='hidden' name
='form_proc_order_title[<?php echo $i; ?>]' value
='Procedure'><b
><?php
echo xlt('Procedure');?
></b
></td
>
544 <td width
='1%' valign
='top'>
545 <input type
='hidden' name
='form_proc_order_title[<?php echo $i; ?>]' value
='<?php echo attr($oprow['procedure_order_title
']) ?>'><b
><?php
echo text($oprow['procedure_order_title']) ?
></b
>
549 <input type
='text' size
='50' name
='form_proc_type_desc[<?php echo $i; ?>]'
550 value
='<?php echo attr($oprow['procedure_name
']) ?>'
551 onclick
="sel_proc_type(<?php echo $i; ?>)"
552 onfocus
='this.blur()'
553 title
='<?php xla('Click to select the desired procedure
','e
'); ?>'
554 style
='width:100%;cursor:pointer;cursor:hand' readonly
/>
555 <input type
='hidden' name
='form_proc_type[<?php echo $i; ?>]' value
='<?php echo $ptid ?>' />
556 <br
/><?php
echo xlt('Diagnosis Codes'); ?
>:
557 <input type
='text' size
='50' name
='form_proc_type_diag[<?php echo $i; ?>]'
558 value
='<?php echo attr($oprow['diagnoses
']) ?>' onclick
='sel_related(this.name)'
559 title
='<?php echo xla('Click to add a diagnosis
'); ?>'
560 onfocus
='this.blur()'
561 style
='cursor:pointer;cursor:hand' readonly
/>
562 <!-- MSIE innerHTML property
for a TABLE element is read
-only
, so using a DIV here
. -->
563 <div style
='width:95%;' id
='qoetable[<?php echo $i; ?>]'>
565 $qoe_init_javascript = '';
566 echo generate_qoe_html($ptid, $formid, $oprow['procedure_order_seq'], $i);
567 if ($qoe_init_javascript)
568 echo "<script language='JavaScript'>$qoe_init_javascript</script>";
581 <?php
$procedure_order_type = getListOptions('order_type' , array('option_id', 'title')); ?
>
582 <select name
="procedure_type_names" id
="procedure_type_names">
583 <?php
foreach($procedure_order_type as $ordered_types){?
>
584 <option value
="<?php echo attr($ordered_types['option_id']); ?>" ><?php
echo text(xl_list_label($ordered_types['title'])) ; ?
></option
>
587 <input type
='button' value
='<?php echo xla('Add Procedure
'); ?>' onclick
="addProcLine()" />
589 <input type
='submit' name
='bn_save' value
='<?php echo xla('Save
'); ?>' onclick
='transmitting = false;' />
591 <input type
='submit' name
='bn_xmit' value
='<?php echo xla('Save
and Transmit
'); ?>' onclick
='transmitting = true;' />
593 <input type
='button' value
='<?php echo xla('Cancel
'); ?>' onclick
="top.restoreSession();location='<?php echo $GLOBALS['form_exit_url']; ?>'" />
598 <script language
='JavaScript'>
599 Calendar
.setup({inputField
:'form_date_ordered', ifFormat
:'%Y-%m-%d',
600 button
:'img_date_ordered'});
601 Calendar
.setup({inputField
:'form_date_collected', ifFormat
:'%Y-%m-%d %H:%M',
602 button
:'img_date_collected', showsTime
:true});