Added a new order type picker for the procedure order form.
[openemr.git] / interface / forms / procedure_order / new.php
bloba0537307003be7ae0d6a86d78d67cb3222cd1c2c
1 <?php
2 /**
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>.
18 * @package OpenEMR
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/formdata.inc.php");
27 require_once("$srcdir/formatting.inc.php");
28 require_once("../../orders/qoe.inc.php");
29 require_once("../../orders/gen_hl7_order.inc.php");
31 // Defaults for new orders.
32 $row = array(
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) {
47 global $row;
48 $ret = "<input type='checkbox' name='$name' value='1'";
49 if ($row[$colname]) $ret .= " checked";
50 $ret .= " />";
51 return $ret;
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";
60 return "'$fld'";
63 $formid = formData('id', 'G') + 0;
65 // If Save or Transmit was clicked, save the info.
67 if ($_POST['bn_save'] || $_POST['bn_xmit']) {
68 $ppid = formData('form_lab_id') + 0;
70 $sets =
71 "date_ordered = " . QuotedOrNull(formData('form_date_ordered')) . ", " .
72 "provider_id = " . (formData('form_provider_id') + 0) . ", " .
73 "lab_id = " . $ppid . ", " .
74 "date_collected = " . QuotedOrNull(formData('form_date_collected')) . ", " .
75 "order_priority = '" . formData('form_order_priority') . "', " .
76 "order_status = '" . formData('form_order_status') . "', " .
77 "diagnoses = '" . formData('form_diagnoses') . "', " .
78 "patient_instructions = '" . formData('form_patient_instructions') . "', " .
79 "patient_id = '" . $pid . "', " .
80 "encounter_id = '" . $encounter . "'";
82 // If updating an existing form...
84 if ($formid) {
85 $query = "UPDATE procedure_order SET $sets " .
86 "WHERE procedure_order_id = '$formid'";
87 sqlStatement($query);
90 // If adding a new form...
92 else {
93 $query = "INSERT INTO procedure_order SET $sets";
94 $formid = sqlInsert($query);
95 addForm($encounter, "Procedure Order", $formid, "procedure_order", $pid, $userauthorized);
98 // Remove any existing procedures and their answers for this order and
99 // replace them from the form.
101 sqlStatement("DELETE FROM procedure_answers WHERE procedure_order_id = ?",
102 array($formid));
103 sqlStatement("DELETE FROM procedure_order_code WHERE procedure_order_id = ?",
104 array($formid));
106 for ($i = 0; isset($_POST['form_proc_type'][$i]); ++$i) {
107 $ptid = $_POST['form_proc_type'][$i] + 0;
108 if ($ptid <= 0) continue;
110 $prefix = "ans$i" . "_";
112 $poseq = sqlInsert("INSERT INTO procedure_order_code SET ".
113 "procedure_order_id = ?, " .
114 "procedure_code = (SELECT procedure_code FROM procedure_type WHERE procedure_type_id = ?), " .
115 "procedure_name = (SELECT name FROM procedure_type WHERE procedure_type_id = ?)",
116 array($formid, $ptid, $ptid));
118 $qres = sqlStatement("SELECT " .
119 "q.procedure_code, q.question_code, q.options, q.fldtype " .
120 "FROM procedure_type AS t " .
121 "JOIN procedure_questions AS q ON q.lab_id = t.lab_id " .
122 "AND q.procedure_code = t.procedure_code AND q.activity = 1 " .
123 "WHERE t.procedure_type_id = ? " .
124 "ORDER BY q.seq, q.question_text", array($ptid));
126 while ($qrow = sqlFetchArray($qres)) {
127 $options = trim($qrow['options']);
128 $qcode = trim($qrow['question_code']);
129 $fldtype = $qrow['fldtype'];
130 $data = '';
131 if ($fldtype == 'G') {
132 if ($_POST["G1_$prefix$qcode"]) {
133 $data = $_POST["G1_$prefix$qcode"] * 7 + $_POST["G2_$prefix$qcode"];
136 else {
137 $data = $_POST["$prefix$qcode"];
139 if (!isset($data) || $data === '') continue;
140 if (!is_array($data)) $data = array($data);
141 foreach ($data as $datum) {
142 // Note this will auto-assign the seq value.
143 sqlStatement("INSERT INTO procedure_answers SET ".
144 "procedure_order_id = ?, " .
145 "procedure_order_seq = ?, " .
146 "question_code = ?, " .
147 "answer = ?",
148 array($formid, $poseq, $qcode, strip_escape_custom($datum)));
153 $alertmsg = '';
154 if ($_POST['bn_xmit']) {
155 $hl7 = '';
156 $alertmsg = gen_hl7_order($formid, $hl7);
157 if (empty($alertmsg)) {
158 $alertmsg = send_hl7_order($ppid, $hl7);
162 // TBD: Implement and set a transmit date in the order.
163 // Add code elsewhere to show a warning if a previously transmitted order is opened.
165 formHeader("Redirecting....");
166 if ($alertmsg) {
167 echo "\n<script language='Javascript'>alert('";
168 echo addslashes(xl('Transmit failed') . ': ' . $alertmsg);
169 echo "')</script>\n";
171 formJump();
172 formFooter();
173 exit;
176 if ($formid) {
177 $row = sqlQuery ("SELECT * FROM procedure_order WHERE " .
178 "procedure_order_id = ?",
179 array($formid)) ;
182 $enrow = sqlQuery("SELECT p.fname, p.mname, p.lname, fe.date FROM " .
183 "form_encounter AS fe, forms AS f, patient_data AS p WHERE " .
184 "p.pid = ? AND f.pid = p.pid AND f.encounter = ? AND " .
185 "f.formdir = 'newpatient' AND f.deleted = 0 AND " .
186 "fe.id = f.form_id LIMIT 1",
187 array($pid, $encounter));
189 <html>
190 <head>
191 <?php html_header_show(); ?>
192 <link rel="stylesheet" href="<?php echo $css_header;?>" type="text/css" />
194 <style>
196 td {
197 font-size:10pt;
200 .inputtext {
201 padding-left:2px;
202 padding-right:2px;
205 </style>
207 <style type="text/css">@import url(<?php echo $GLOBALS['webroot'] ?>/library/dynarch_calendar.css);</style>
208 <script type="text/javascript" src="<?php echo $GLOBALS['webroot'] ?>/library/dynarch_calendar.js"></script>
209 <?php include_once("{$GLOBALS['srcdir']}/dynarch_calendar_en.inc.php"); ?>
210 <script type="text/javascript" src="<?php echo $GLOBALS['webroot'] ?>/library/dynarch_calendar_setup.js"></script>
212 <script type="text/javascript" src="../../../library/dialog.js"></script>
213 <script type="text/javascript" src="<?php echo $GLOBALS['webroot'] ?>/library/textformat.js"></script>
215 <script language='JavaScript'>
217 // This invokes the find-procedure-type popup.
218 // formseq = 0-relative index in the form.
219 var gbl_formseq;
220 function sel_proc_type(formseq) {
221 var f = document.forms[0];
222 // if (!f.form_lab_id.value) {
223 // alert('<?php echo xls('Please select a procedure provider'); ?>');
224 // return;
225 // }
226 gbl_formseq = formseq;
227 var ptvarname = 'form_proc_type[' + formseq + ']';
228 /********************************************************************
229 dlgopen('../../orders/types.php?popup=1' +
230 '&labid=' + f.form_lab_id.value +
231 '&order=' + f[ptvarname].value +
232 '&formid=<?php echo $formid; ?>' +
233 '&formseq=' + formseq,
234 '_blank', 800, 500);
235 ********************************************************************/
236 // This replaces the above for an easier/faster order picker tool.
237 dlgopen('../../orders/find_order_popup.php' +
238 '?labid=' + f.form_lab_id.value +
239 '&order=' + f[ptvarname].value +
240 '&formid=<?php echo $formid; ?>' +
241 '&formseq=' + formseq,
242 '_blank', 800, 500);
245 // This is for callback by the find-procedure-type popup.
246 // Sets both the selected type ID and its descriptive name.
247 function set_proc_type(typeid, typename) {
248 var f = document.forms[0];
249 var ptvarname = 'form_proc_type[' + gbl_formseq + ']';
250 var ptdescname = 'form_proc_type_desc[' + gbl_formseq + ']';
251 f[ptvarname].value = typeid;
252 f[ptdescname].value = typename;
255 // This is also for callback by the find-procedure-type popup.
256 // Sets the contents of the table containing the form fields for questions.
257 function set_proc_html(s, js) {
258 document.getElementById('qoetable[' + gbl_formseq + ']').innerHTML = s;
259 eval(js);
262 // New lab selected so clear all procedures and questions from the form.
263 function lab_id_changed() {
264 var f = document.forms[0];
265 for (var i = 0; true; ++i) {
266 var ix = '[' + i + ']';
267 if (!f['form_proc_type' + ix]) break;
268 f['form_proc_type' + ix].value = '-1';
269 f['form_proc_type_desc' + ix].value = '';
270 document.getElementById('qoetable' + ix).innerHTML = '';
274 // Add a line for entry of another procedure.
275 function addProcLine() {
276 var f = document.forms[0];
277 var table = document.getElementById('proctable');
278 // Compute i = next procedure index.
279 var i = 0;
280 for (; f['form_proc_type[' + i + ']']; ++i);
281 var row = table.insertRow(table.rows.length);
282 var cell = row.insertCell(0);
283 cell.vAlign = 'top';
284 cell.innerHTML = "<b><?php echo xls('Procedure'); ?> " + (i + 1) + ":</b>";
285 var cell = row.insertCell(1);
286 cell.vAlign = 'top';
287 cell.innerHTML =
288 "<input type='text' size='50' name='form_proc_type_desc[" + i + "]'" +
289 " onclick='sel_proc_type(" + i + ")'" +
290 " onfocus='this.blur()'" +
291 " title='<?php echo xla('Click to select the desired procedure'); ?>'" +
292 " style='width:100%;cursor:pointer;cursor:hand' readonly />" +
293 " <input type='hidden' name='form_proc_type[" + i + "]' value='-1' />" +
294 " <div style='width:95%;' id='qoetable[" + i + "]'></div>";
295 sel_proc_type(i);
296 return false;
299 // The name of the form field for find-code popup results.
300 var rcvarname;
302 // This is for callback by the find-code popup.
303 // Appends to or erases the current list of related codes.
304 function set_related(codetype, code, selector, codedesc) {
305 var f = document.forms[0];
306 var s = f[rcvarname].value;
307 if (code) {
308 if (s.length > 0) s += ';';
309 s += codetype + ':' + code;
310 } else {
311 s = '';
313 f[rcvarname].value = s;
316 // This invokes the find-code popup.
317 function sel_related(varname) {
318 rcvarname = varname;
319 // codetype is just to make things easier and avoid mistakes.
320 // Might be nice to have a lab parameter for acceptable code types.
321 // Also note the controlling script here runs from interface/patient_file/encounter/.
322 dlgopen('find_code_popup.php?codetype=ICD9', '_blank', 500, 400);
325 </script>
327 </head>
329 <body class="body_top">
331 <form method="post" action="<?php echo $rootdir ?>/forms/procedure_order/new.php?id=<?php echo $formid ?>" onsubmit="return top.restoreSession()">
333 <p class='title' style='margin-top:8px;margin-bottom:8px;text-align:center'>
334 <?php
335 echo xl('Procedure Order for') . ' ';
336 echo $enrow['fname'] . ' ' . $enrow['mname'] . ' ' . $enrow['lname'];
337 echo ' ' . xl('on') . ' ' . oeFormatShortDate(substr($enrow['date'], 0, 10));
339 </p>
341 <center>
344 <table border='1' width='95%' id='proctable'>
346 <tr>
347 <td width='1%' valign='top' nowrap><b><?php xl('Ordering Provider','e'); ?>:</b></td>
348 <td valign='top'>
349 <?php
350 generate_form_field(array('data_type'=>10,'field_id'=>'provider_id'),
351 $row['provider_id']);
353 </td>
354 </tr>
356 <tr>
357 <td width='1%' valign='top' nowrap><b><?php xl('Sending To','e'); ?>:</b></td>
358 <td valign='top'>
359 <select name='form_lab_id' onchange='lab_id_changed()'>
360 <?php
361 $ppres = sqlStatement("SELECT ppid, name FROM procedure_providers " .
362 "ORDER BY name, ppid");
363 while ($pprow = sqlFetchArray($ppres)) {
364 echo "<option value='" . attr($pprow['ppid']) . "'";
365 if ($pprow['ppid'] == $row['lab_id']) echo " selected";
366 echo ">" . text($pprow['name']) . "</option>";
369 </select>
370 </td>
371 </tr>
373 <tr>
374 <td width='1%' valign='top' nowrap><b><?php xl('Order Date','e'); ?>:</b></td>
375 <td valign='top'>
376 <?php
377 echo "<input type='text' size='10' name='form_date_ordered' id='form_date_ordered'" .
378 " value='" . $row['date_ordered'] . "'" .
379 " title='" . xl('Date of this order') . "'" .
380 " onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)'" .
381 " />" .
382 "<img src='$rootdir/pic/show_calendar.gif' align='absbottom' width='24' height='22'" .
383 " id='img_date_ordered' border='0' alt='[?]' style='cursor:pointer'" .
384 " title='" . xl('Click here to choose a date') . "' />";
386 </td>
387 </tr>
389 <tr>
390 <td width='1%' valign='top' nowrap><b><?php xl('Internal Time Collected','e'); ?>:</b></td>
391 <td valign='top'>
392 <?php
393 echo "<input type='text' size='16' name='form_date_collected' id='form_date_collected'" .
394 " value='" . substr($row['date_collected'], 0, 16) . "'" .
395 " title='" . xl('Date and time that the sample was collected') . "'" .
396 // " onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)'" .
397 " />" .
398 "<img src='$rootdir/pic/show_calendar.gif' align='absbottom' width='24' height='22'" .
399 " id='img_date_collected' border='0' alt='[?]' style='cursor:pointer'" .
400 " title='" . xl('Click here to choose a date and time') . "' />";
402 </td>
403 </tr>
405 <tr>
406 <td width='1%' valign='top' nowrap><b><?php xl('Priority','e'); ?>:</b></td>
407 <td valign='top'>
408 <?php
409 generate_form_field(array('data_type'=>1,'field_id'=>'order_priority',
410 'list_id'=>'ord_priority'), $row['order_priority']);
412 </td>
413 </tr>
415 <tr>
416 <td width='1%' valign='top' nowrap><b><?php xl('Status','e'); ?>:</b></td>
417 <td valign='top'>
418 <?php
419 generate_form_field(array('data_type'=>1,'field_id'=>'order_status',
420 'list_id'=>'ord_status'), $row['order_status']);
422 </td>
423 </tr>
425 <tr>
426 <td width='1%' valign='top' nowrap><b><?php xl('Diagnoses','e'); ?>:</b></td>
427 <td valign='top'>
428 <input type='text' size='50' name='form_diagnoses'
429 value='<?php echo $row['diagnoses'] ?>' onclick='sel_related(this.name)'
430 title='<?php echo xla('Click to add a diagnosis'); ?>'
431 onfocus='this.blur()'
432 style='width:100%;cursor:pointer;cursor:hand' readonly />
433 </td>
434 </tr>
436 <tr>
437 <td width='1%' valign='top' nowrap><b><?php xl('Patient Instructions','e'); ?>:</b></td>
438 <td valign='top'>
439 <textarea rows='3' cols='40' name='form_patient_instructions' style='width:100%'
440 wrap='virtual' class='inputtext' /><?php echo $row['patient_instructions'] ?></textarea>
441 </td>
442 </tr>
444 <?php
446 // This section merits some explanation. :)
448 // If any procedures have already been saved for this form, then a top-level table row is
449 // created for each of them, and includes the relevant questions and any existing answers.
450 // Otherwise a single empty table row is created for entering the first or only procedure.
452 // If a new procedure is selected or changed, the questions for it are (re)generated from
453 // the dialog window from which the procedure is selected, via JavaScript. The sel_proc_type
454 // function and the types.php script that it invokes collaborate to support this feature.
456 // The generate_qoe_html function in qoe.inc.php contains logic to generate the HTML for
457 // the questions, and can be invoked either from this script or from types.php.
459 // The $i counter that you see below is to resolve the need for unique names for form fields
460 // that may occur for each of the multiple procedure requests within the same order.
461 // procedure_order_seq serves a similar need for uniqueness at the database level.
463 $oparr = array();
464 if ($formid) {
465 $opres = sqlStatement("SELECT " .
466 "pc.procedure_order_seq, pc.procedure_code, pc.procedure_name, " .
467 "pt.procedure_type_id " .
468 "FROM procedure_order_code AS pc " .
469 "LEFT JOIN procedure_type AS pt ON pt.lab_id = ? AND " .
470 "pt.procedure_code = pc.procedure_code " .
471 "WHERE pc.procedure_order_id = ? " .
472 "ORDER BY pc.procedure_order_seq",
473 array($row['lab_id'], $formid));
474 while ($oprow = sqlFetchArray($opres)) {
475 $oparr[] = $oprow;
478 if (empty($oparr)) $oparr[] = array('procedure_name' => '');
480 $i = 0;
481 foreach ($oparr as $oprow) {
482 $ptid = -1; // -1 means no procedure is selected yet
483 if (!empty($oprow['procedure_type_id'])) {
484 $ptid = $oprow['procedure_type_id'];
487 <tr>
488 <td width='1%' valign='top'><b><?php echo xl('Procedure') . ' ' . ($i + 1); ?>:</b></td>
489 <td valign='top'>
490 <input type='text' size='50' name='form_proc_type_desc[<?php echo $i; ?>]'
491 value='<?php echo attr($oprow['procedure_name']) ?>'
492 onclick="sel_proc_type(<?php echo $i; ?>)"
493 onfocus='this.blur()'
494 title='<?php xla('Click to select the desired procedure','e'); ?>'
495 style='width:100%;cursor:pointer;cursor:hand' readonly />
496 <input type='hidden' name='form_proc_type[<?php echo $i; ?>]' value='<?php echo $ptid ?>' />
497 <!-- MSIE innerHTML property for a TABLE element is read-only, so using a DIV here. -->
498 <div style='width:95%;' id='qoetable[<?php echo $i; ?>]'>
499 <?php
500 $qoe_init_javascript = '';
501 echo generate_qoe_html($ptid, $formid, $oprow['procedure_order_seq'], $i);
502 if ($qoe_init_javascript)
503 echo "<script language='JavaScript'>$qoe_init_javascript</script>";
505 </div>
506 </td>
507 </tr>
508 <?php
509 ++$i;
513 </table>
516 <input type='button' value='<?php echo xla('Add Procedure'); ?>' onclick="addProcLine()" />
517 &nbsp;
518 <input type='submit' name='bn_save' value='<?php echo xla('Save'); ?>' />
519 &nbsp;
520 <input type='submit' name='bn_xmit' value='<?php echo xla('Save and Transmit'); ?>' />
521 &nbsp;
522 <input type='button' value='<?php echo xla('Cancel'); ?>' onclick="top.restoreSession();location='<?php echo $GLOBALS['form_exit_url']; ?>'" />
523 </p>
525 </center>
527 <script language='JavaScript'>
528 Calendar.setup({inputField:'form_date_ordered', ifFormat:'%Y-%m-%d',
529 button:'img_date_ordered'});
530 Calendar.setup({inputField:'form_date_collected', ifFormat:'%Y-%m-%d %H:%M',
531 button:'img_date_collected', showsTime:true});
532 </script>
534 </form>
535 </body>
536 </html>