Skip to content

Commit

Permalink
Assessment service update to relevant period (#5361)
Browse files Browse the repository at this point in the history
* extend qdmmodel in assessment service, adjust template

* reorder use

* change comment

* (c)

* fixing thanks to Ken and Jerry

* fixing thanks again

* have to fix in the extended classes after all since physical exam failed

* add end date to observation form, fix for relevant period, and attr_js error in find code popup
  • Loading branch information
stephenwaite committed May 21, 2022
1 parent 1908b85 commit f3f5ede
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 32 deletions.
4 changes: 2 additions & 2 deletions interface/forms/care_plan/new.php
Expand Up @@ -102,7 +102,7 @@
<div class="forms col-md-2">
<label for="code_<?php echo attr($key) + 1; ?>" class="h5"><?php echo xlt('Code'); ?>:</label>
<input type="text" id="code_<?php echo attr($key) + 1; ?>" name="code[]" class="form-control code"
value="<?php echo attr($obj["code"]); ?>" onclick='sel_code(<?php echo js_url($GLOBALS['webroot']) ?>,
value="<?php echo attr($obj["code"]); ?>" onclick='sel_code(<?php echo attr_js($GLOBALS['webroot']) ?>,
this.parentElement.parentElement.parentElement.id);' data-toggle='tooltip' data-placement='bottom' title='<?php echo attr($obj['code']) . "'"; ?> />
<span id="displaytext_<?php echo attr($key) + 1; ?>" class="displaytext help-block"><?php echo text($obj["codetext"] ?? ''); ?></span>
<input type="hidden" id="codetext_<?php echo attr($key) + 1; ?>" name="codetext[]" class="codetext" value="<?php echo attr($obj["codetext"]); ?>" />
Expand Down Expand Up @@ -146,7 +146,7 @@
<div class="form-row">
<div class="forms col-md-2">
<label for="code_1" class="h5"><?php echo xlt('Code'); ?>:</label>
<input type="text" id="code_1" name="code[]" class="form-control code" value="<?php echo attr($obj["code"] ?? ''); ?>" onclick='sel_code(<?php echo js_url($GLOBALS['webroot']) ?>, this.parentElement.parentElement.parentElement.id || "");'>
<input type="text" id="code_1" name="code[]" class="form-control code" value="<?php echo attr($obj["code"] ?? ''); ?>" onclick='sel_code(<?php echo attr_js($GLOBALS['webroot']) ?>, this.parentElement.parentElement.parentElement.id || "");'>
<input type="hidden" id="user_1" name="user[]" class="user" value="<?php echo attr($obj["user"] ?? $_SESSION["authUser"]); ?>" />
<span id="displaytext_1" class="displaytext help-block"></span>
<input type="hidden" id="codetext_1" name="codetext[]" class="codetext" value="<?php echo attr($obj["codetext"] ?? ''); ?>">
Expand Down
14 changes: 11 additions & 3 deletions interface/forms/observation/new.php
Expand Up @@ -90,7 +90,7 @@
<div class="form-row">
<div class="forms col-md-2">
<label for="code_<?php echo attr($key) + 1; ?>" class="h5"><?php echo xlt('Code'); ?>:</label>
<input type="text" id="code_<?php echo attr($key) + 1; ?>" name="code[]" class="form-control code" value="<?php echo attr($obj["code"]); ?>" onclick='sel_code(<?php echo js_url($GLOBALS['webroot']); ?>, this.parentElement.parentElement.parentElement.id);' />
<input type="text" id="code_<?php echo attr($key) + 1; ?>" name="code[]" class="form-control code" value="<?php echo attr($obj["code"]); ?>" onclick='sel_code(<?php echo attr_js($GLOBALS['webroot']); ?>, this.parentElement.parentElement.parentElement.id);' />
<span id="displaytext_<?php echo attr($key) + 1; ?>" class="displaytext help-block"></span>
<input type="hidden" id="description_<?php echo attr($key) + 1; ?>" name="description[]" class="description" value="<?php echo attr($obj["description"]); ?>" />
<input type="hidden" id="code_type_<?php echo attr($key) + 1; ?>" name="code_type[]" class="code_type" value="<?php echo attr($obj["code_type"]); ?>" />
Expand Down Expand Up @@ -154,7 +154,11 @@
<label for="code_date_<?php echo attr($key) + 1; ?>" class="h5"><?php echo xlt('Date'); ?>:</label>
<input type='text' id="code_date_<?php echo attr($key) + 1; ?>" name='code_date[]' class="form-control code_date datepicker" value='<?php echo attr($obj["date"]); ?>' title='<?php echo xla('yyyy-mm-dd HH:MM Date of service'); ?>' />
</div>
<div class=" forms col-md-2">
<div class="forms col-md-2">
<label for="code_date_end_<?php echo attr($key) + 1; ?>" class="h5"><?php echo xlt('End Date'); ?>:</label>
<input type='text' id="code_date_end_<?php echo attr($key) + 1; ?>" name='code_date_end[]' class="form-control code_date datepicker" value='<?php echo attr($obj["date_end"]); ?>' title='<?php echo xla('yyyy-mm-dd HH:MM End Date of service'); ?>' />
</div>
<div class="forms col-md-2">
<label for="comments_<?php echo attr($key) + 1; ?>" class="h5"><?php echo xlt('Comments'); ?>:</label>
<textarea name="comments[]" id="comments_<?php echo attr($key) + 1; ?>" class="form-control comments" rows="3"><?php echo text($obj["observation"]); ?></textarea>
</div>
Expand All @@ -173,7 +177,7 @@
<div class="form-row">
<div class="forms col-md-2">
<label for="code_1" class="h5"><?php echo xlt('Code'); ?>:</label>
<input type="text" id="code_1" name="code[]" class="form-control code" value="<?php echo attr($obj["code"] ?? ''); ?>" onclick='sel_code(<?php echo js_url($GLOBALS['webroot']); ?>, this.parentElement.parentElement.parentElement.id);' />
<input type="text" id="code_1" name="code[]" class="form-control code" value="<?php echo attr($obj["code"] ?? ''); ?>" onclick='sel_code(<?php echo attr_js($GLOBALS['webroot']); ?>, this.parentElement.parentElement.parentElement.id);' />
<span id="displaytext_1" class="displaytext help-block"></span>
<input type="hidden" id="description_1" name="description[]" class="description" value="<?php echo attr($obj["description"] ?? ''); ?>" />
<input type="hidden" id="code_type_1" name="code_type[]" class="code_type" value="<?php echo attr($obj["code_type"] ?? ''); ?>" />
Expand Down Expand Up @@ -238,6 +242,10 @@
<label for="code_date_1" class="h5"><?php echo xlt('Date'); ?>:</label>
<input type='text' id="code_date_1" name='code_date[]' class="form-control code_date datepicker" value='<?php echo attr($obj["date"] ?? ''); ?>' title='<?php echo xla('yyyy-mm-dd Date of service'); ?>' />
</div>
<div class="forms col-md-2">
<label for="code_date_end_<?php echo attr($key) + 1; ?>" class="h5"><?php echo xlt('End Date'); ?>:</label>
<input type='text' id="code_date_end_<?php echo attr($key) + 1; ?>" name='code_date_end[]' class="form-control code_date datepicker" value='<?php echo attr($obj["date_end"] ?? ''); ?>' title='<?php echo xla('yyyy-mm-dd HH:MM End Date of service'); ?>' />
</div>
<div class="forms col-md-2">
<label for="comments_1" class="h5"><?php echo xlt('Comments'); ?>:</label>
<textarea name="comments[]" id="comments_1" class="form-control comments" rows="3"><?php echo text($obj["observation"] ?? ''); ?></textarea>
Expand Down
2 changes: 2 additions & 0 deletions interface/forms/observation/observation.js
Expand Up @@ -44,6 +44,7 @@ function duplicateRow(e) {
changeIds('ob_value_head');
changeIds('ob_unit_head');
changeIds('reason_code');
changeIds('code_date_end');
changeDatasetIds('toggle-container', 'toggleContainer', 'reason_code');
clearReasonCode(newRow);
removeVal(newRow.id);
Expand All @@ -63,6 +64,7 @@ function removeVal(rowid) {
document.getElementById("ob_value_" + rowid1[1]).value = '';
document.getElementById("ob_unit_" + rowid1[1]).value = '';
document.getElementById("ob_value_phin_" + rowid1[1]).value = '';
document.getElementById("code_date_end_" + rowid1[1]).value = '';
//document.getElementById("ob_value_head_" + rowid1[1]).innerHTML = '';
//document.getElementById("ob_unit_head_" + rowid1[1]).innerHTML = '';
}
Expand Down
13 changes: 10 additions & 3 deletions interface/forms/observation/save.php
Expand Up @@ -41,9 +41,14 @@
$reasonStatusCode = $_POST['reasonCodeStatus'];
$reasonCodeText = $_POST['reasonCodeText'];
$ob_type = $_POST["ob_type"];
$code_date_end = $_POST["code_date_end"];


if ($id && $id != 0) {
sqlStatement("DELETE FROM `form_observation` WHERE id=? AND pid = ? AND encounter = ?", array($id, $_SESSION["pid"], $_SESSION["encounter"]));
sqlStatement(
"DELETE FROM `form_observation` WHERE id=? AND pid = ? AND encounter = ?",
array($id, $_SESSION["pid"], $_SESSION["encounter"])
);
$newid = $id;
} else {
$res2 = sqlStatement("SELECT MAX(id) as largestId FROM `form_observation`");
Expand Down Expand Up @@ -99,7 +104,8 @@
date = ?,
ob_reason_code = ?,
ob_reason_status = ?,
ob_reason_text = ?";
ob_reason_text = ?,
date_end = ?";
sqlStatement(
"INSERT INTO form_observation SET $sets",
[
Expand All @@ -120,7 +126,8 @@
$code_date[$key],
$reasonCode[$key],
$reasonStatusCode[$key],
$reasonCodeText[$key]
$reasonCodeText[$key],
$code_date_end[$key]
]
);
endforeach;
Expand Down
32 changes: 24 additions & 8 deletions src/Services/Qdm/Services/AbstractObservationService.php
Expand Up @@ -4,13 +4,18 @@
* @package OpenEMR
* @link http://www.open-emr.org
* @author Ken Chapple <ken@mi-squared.com>
* @author Stephen Waite <stephen.waite@cmsvt.com>
* @copyright Copyright (c) 2021 Ken Chapple <ken@mi-squared.com>
* @copyright Copyright (c) 2022 Stephen Waite <stephen.waite@cmsvt.com>
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU GeneralPublic License 3
*/

namespace OpenEMR\Services\Qdm\Services;

use OpenEMR\Cqm\Qdm\BaseTypes\DateTime;
use OpenEMR\Cqm\Qdm\BaseTypes\{
DateTime,
Interval
};
use OpenEMR\Services\Qdm\Interfaces\QdmServiceInterface;
use OpenEMR\Services\Qdm\QdmRecord;

Expand All @@ -19,9 +24,9 @@ abstract class AbstractObservationService extends AbstractQdmService implements
/**
* Types of observations in ob_type field
*/
const OB_TYPE_ASSESSMENT = 'assessment';
const OB_TYPE_DIAGNOSTIC_STUDY = 'procedure_diagnostic';
const OB_TYPE_PHYSICAL_EXAM = 'physical_exam_performed';
public const OB_TYPE_ASSESSMENT = 'assessment';
public const OB_TYPE_DIAGNOSTIC_STUDY = 'procedure_diagnostic';
public const OB_TYPE_PHYSICAL_EXAM = 'physical_exam_performed';

abstract public function getObservationType();

Expand All @@ -35,10 +40,11 @@ abstract public function getModelClass();
public function getSqlStatement()
{
$observation_type = add_escape_custom($this->getObservationType());
$sql = "SELECT pid, encounter, `date`, code, code_type, ob_value, ob_unit, description, ob_code, ob_type, ob_status,
ob_reason_status, ob_reason_code
FROM form_observation
WHERE ob_type = '$observation_type'
$sql = "SELECT `pid`, `encounter`, `date`, `code`, `code_type`, `ob_value`, `ob_unit`,
`description`, `ob_code`, `ob_type`, `ob_status`,
`ob_reason_status`, `ob_reason_code`, `date_end`
FROM `form_observation`
WHERE `ob_type` = '$observation_type'
";
return $sql;
}
Expand Down Expand Up @@ -66,6 +72,16 @@ public function makeQdmModel(QdmRecord $recordObj)
'relevantDatetime' => new DateTime([
'date' => $record['date']
]),
'relevantPeriod' => new Interval([
'low' => new DateTime([
'date' => $record['date']
]),
'high' => new DateTime([
'date' => $this->validDateOrNull($record['date_end']) ? true : false
]),
'lowClosed' => $record['date'] ? true : false,
'highClosed' => $this->validDateOrNull($record['date_end']) ? true : false
]),
'authorDatetime' => new DateTime([
'date' => $record['date']
]),
Expand Down
21 changes: 12 additions & 9 deletions src/Services/Qdm/Services/AbstractQdmService.php
Expand Up @@ -22,7 +22,7 @@ abstract class AbstractQdmService
/**
* Value in ob_reason_status indicates negated observation (observation not done)
*/
const NEGATED = 'negated';
public const NEGATED = 'negated';

protected $request;
protected $codeTypesService;
Expand Down Expand Up @@ -60,7 +60,7 @@ public static function convertIdFromBSONObjectIdFormat($id)

public function validDateOrNull($date)
{
if ($date == '0000-00-00') {
if (strpos($date, '0000-00-00') !== false) {
return null;
}
return new DateTime([
Expand Down Expand Up @@ -104,7 +104,8 @@ public function executeQuery()
$result = sqlStatementThrowException($sql, $binds);
} catch (SqlQueryException $exception) {
error_log($exception->getMessage());
throw new \Exception("There is likely an error in Service query, must contain a patient ID. 'pid' not found and getPatientIdColumn() not implemented.");
throw new \Exception("There is likely an error in Service query, must contain a patient ID. " .
" 'pid' not found and getPatientIdColumn() not implemented.");
}

return $result;
Expand All @@ -120,13 +121,15 @@ public function getRequest(): QdmRequestInterface

public function getSystemForCodeType($codeType)
{
// If there is a space in the name, replace with a dash, for example "SNOMED CT" becomes "SNOMED-CT" because that's what we have in our lookup table
// If there is a space in the name, replace with a dash, for example "SNOMED CT" becomes "SNOMED-CT"
// because that's what we have in our lookup table
$codeType = str_replace(" ", "-", $codeType);

if ($codeType == 'OID') {
// When there is a negation, the code is an OID from a measure value set. There is no official code system for this, as they are OIDs
// When there is a negation, the code is an OID from a measure value set.
// There is no official code system for this, as they are OIDs
$system = '';
} else if ($codeType == 'HCPCS-Level-II') {
} elseif ($codeType == 'HCPCS-Level-II') {
$system = '2.16.840.1.113883.6.285';
} else {
$system = $this->codeTypesService->getSystemForCodeType($codeType, true);
Expand All @@ -150,12 +153,12 @@ public function makeQdmCode($openEmrCode)
$system = null;
$res = explode(":", $openEmrCode); //split diagnosis type and code

// TODO For some reason, the import imports allergy codes like this: 'RXNORM:CVX:135' OR 'RXNORM:CVX:135' so we have
// to account for the case where there are three parts to our exploded code
// TODO For some reason, the import imports allergy codes like this: 'RXNORM:CVX:135' OR 'RXNORM:CVX:135'
// so we have to account for the case where there are three parts to our exploded code
if (count($res) == 3) {
$code = $res[2];
$system = $res[1];
} else if (count($res) == 2) {
} elseif (count($res) == 2) {
$code = $res[1];
$system = $res[0];
}
Expand Down
22 changes: 15 additions & 7 deletions src/Services/Qrda/Helpers/Date.php
Expand Up @@ -116,7 +116,10 @@ public function medication_duration_author_effective_time(Mustache_Context $cont

public function prevalence_period(Mustache_Context $context)
{
$prevalencePeriod = json_decode(json_encode($context->find('prevalencePeriod')), true) ?? ['low' => null, 'high' => null];
$prevalencePeriod = json_decode(
json_encode($context->find('prevalencePeriod')),
true
) ?? ['low' => null, 'high' => null];
return "<effectiveTime>"
. "<low " . $this->value_or_null_flavor($prevalencePeriod['low'] ?? '') . "/>"
. "<high " . $this->value_or_null_flavor($prevalencePeriod['high'] ?? '') . "/>"
Expand Down Expand Up @@ -147,19 +150,24 @@ public function relevant_date_time_value(Mustache_Context $context)
}

/**
* Returns the helper function to call for the relevent date period or returns null flavor if there is no date period
* If the current context has a period we return the period helpfunction, otherwise if we have a dateTime we return
* the date time helper function
* Returns the helper function to call for the relevant date period or returns null flavor
* if there is no date period.
* If the current context has a period we return the period helpfunction,
* otherwise if we have a dateTime we return the date time helper function
*
* @param Mustache_Context $context The current stack context
* @return string Helper function name or null flavor xml
*/
public function relevant_date_period_or_null_flavor(Mustache_Context $context)
{
$relevantPeriod = $context->find('relevantPeriod');
if (!empty($relevantPeriod) && (isset($relevantPeriod['low']) || isset($relevantPeriod['high']))) {
// we return the function name to call here
return 'relevant_period';
if (
!empty($relevantPeriod) &&
(
isset($relevantPeriod['high'])
)
) {
return $this->relevant_period($context);
} elseif (!empty($context->find('relevantDatetime'))) {
return $this->relevant_date_time_value($context);
} else {
Expand Down

0 comments on commit f3f5ede

Please sign in to comment.