3 namespace OpenEMR\Services\FHIR
;
5 use OpenEMR\FHIR\R4\FHIRElement\FHIRCodeableConcept
;
6 use OpenEMR\FHIR\R4\FHIRElement\FHIRCoding
;
7 use OpenEMR\FHIR\R4\FHIRElement\FHIRId
;
8 use OpenEMR\FHIR\R4\FHIRElement\FHIRMeta
;
9 use OpenEMR\FHIR\R4\FHIRElement\FHIRReference
;
10 use OpenEMR\FHIR\R4\FHIRDomainResource\FHIRCondition
;
11 use OpenEMR\Services\FHIR\FhirServiceBase
;
12 use OpenEMR\Services\ConditionService
;
13 use OpenEMR\Services\FHIR\Traits\BulkExportSupportAllOperationsTrait
;
14 use OpenEMR\Services\FHIR\Traits\FhirBulkExportDomainResourceTrait
;
15 use OpenEMR\Services\FHIR\Traits\FhirServiceBaseEmptyTrait
;
16 use OpenEMR\Services\Search\FhirSearchParameterDefinition
;
17 use OpenEMR\Services\Search\ISearchField
;
18 use OpenEMR\Services\Search\SearchFieldType
;
19 use OpenEMR\Services\Search\ServiceField
;
20 use OpenEMR\Validators\ProcessingResult
;
23 * FHIR Condition Service
25 * @coversDefaultClass OpenEMR\Services\FHIR\FhirConditionService
27 * @link http://www.open-emr.org
28 * @author Yash Bothra <yashrajbothra786gmail.com>
29 * @copyright Copyright (c) 2020 Yash Bothra <yashrajbothra786gmail.com>
30 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
32 class FhirConditionService
extends FhirServiceBase
implements IResourceUSCIGProfileService
, IFhirExportableResourceService
, IPatientCompartmentResourceService
34 use FhirServiceBaseEmptyTrait
;
35 use BulkExportSupportAllOperationsTrait
;
36 use FhirBulkExportDomainResourceTrait
;
39 * @var ConditionService
41 private $conditionService;
44 const USCGI_PROFILE_URI
= 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition';
46 public function __construct()
48 parent
::__construct();
49 $this->conditionService
= new ConditionService();
53 * Returns an array mapping FHIR Condition Resource search parameters to OpenEMR Condition search parameters
55 * @return array The search parameters
57 protected function loadSearchParameters()
60 'patient' => $this->getPatientContextSearchField(),
61 '_id' => new FhirSearchParameterDefinition('_id', SearchFieldType
::TOKEN
, [new ServiceField('condition_uuid', ServiceField
::TYPE_UUID
)]),
62 '_lastUpdated' => $this->getLastModifiedSearchField(),
66 public function getLastModifiedSearchField(): ?FhirSearchParameterDefinition
68 return new FhirSearchParameterDefinition('_lastUpdated', SearchFieldType
::DATETIME
, ['last_updated_time']);
72 * Parses an OpenEMR condition record, returning the equivalent FHIR Condition Resource
74 * @param array $dataRecord The source OpenEMR data record
75 * @param boolean $encode Indicates if the returned resource is encoded into a string. Defaults to false.
76 * @return FHIRCondition
78 public function parseOpenEMRRecord($dataRecord = array(), $encode = false)
80 $conditionResource = new FHIRCondition();
82 $meta = new FHIRMeta();
83 $meta->setVersionId('1');
84 if (!empty($dataRecord['last_updated_time'])) {
85 $meta->setLastUpdated(UtilsService
::getLocalDateAsUTC($dataRecord['last_updated_time']));
87 $meta->setLastUpdated(UtilsService
::getDateFormattedAsUTC());
89 $conditionResource->setMeta($meta);
92 $id->setValue($dataRecord['uuid']);
93 $conditionResource->setId($id);
96 $this->populateClinicalStatus($dataRecord, $conditionResource);
97 $this->populateCategory($dataRecord, $conditionResource);
98 $this->populateVerificationStatus($dataRecord, $conditionResource);
99 $this->populateCode($dataRecord, $conditionResource);
100 $this->populateSubject($dataRecord, $conditionResource);
102 // non-ONC requirements
103 $this->populateEncounter($dataRecord, $conditionResource);
107 return json_encode($conditionResource);
109 return $conditionResource;
113 private function populateEncounter($dataRecord, FHIRCondition
$conditionResource)
115 if (isset($dataRecord['encounter_uuid'])) {
116 $encounter = new FHIRReference();
117 $encounter->setReference('Encounter/' . $dataRecord['encounter_uuid']);
118 $conditionResource->setEncounter($encounter);
122 private function populateSubject($dataRecord, FHIRCondition
$conditionResource)
124 if (isset($dataRecord['puuid'])) {
125 $patient = new FHIRReference();
126 $patient->setReference('Patient/' . $dataRecord['puuid']);
127 $conditionResource->setSubject($patient);
131 private function populateCode($dataRecord, FHIRCondition
$conditionResource)
133 if (!empty($dataRecord['diagnosis'])) {
134 $diagnosisCoding = new FHIRCoding();
135 $diagnosisCode = new FHIRCodeableConcept();
136 foreach ($dataRecord['diagnosis'] as $code => $codeValues) {
137 if (!is_string($code)) {
138 $code = "$code"; // FHIR expects a string
140 $diagnosisCoding->setCode($code);
141 $diagnosisCoding->setDisplay($codeValues['description']);
142 $diagnosisCoding->setSystem($codeValues['system']);
143 $diagnosisCode->addCoding($diagnosisCoding);
145 $conditionResource->setCode($diagnosisCode);
149 private function populateVerificationStatus($dataRecord, FHIRCondition
$conditionResource)
151 $verificationStatus = new FHIRCodeableConcept();
152 $verificationCoding = array(
153 'system' => "http://terminology.hl7.org/CodeSystem/condition-ver-status",
154 'code' => 'unconfirmed',
155 'display' => 'Unconfirmed',
157 if (!empty($dataRecord['verification'])) {
158 $verificationCoding = array(
159 'system' => "http://terminology.hl7.org/CodeSystem/condition-ver-status",
160 'code' => $dataRecord['verification'],
161 'display' => $dataRecord['verification_title']
164 $verificationStatus->addCoding($verificationCoding);
165 $conditionResource->setVerificationStatus($verificationStatus);
168 private function populateCategory($dataRecord, $conditionResource)
171 $conditionCategory = new FHIRCodeableConcept();
172 $conditionCategory->addCoding(
174 'system' => "http://terminology.hl7.org/CodeSystem/condition-category",
175 'code' => 'problem-list-item',
176 'display' => 'Problem List Item'
179 $conditionResource->addCategory($conditionCategory);
182 private function populateClinicalStatus($dataRecord, FHIRCondition
$conditionResource)
184 $clinicalStatus = "inactive";
185 $clinicalSysytem = "http://terminology.hl7.org/CodeSystem/condition-clinical";
187 (!isset($dataRecord['enddate']) && isset($dataRecord['begdate']))
188 ||
isset($dataRecord['enddate']) && strtotime($dataRecord['enddate']) >= strtotime("now")
190 // Active if Only Begin Date isset OR End Date isnot expired
191 $clinicalStatus = "active";
192 if ($dataRecord['occurrence'] == 1 ||
$dataRecord['outcome'] == 1) {
193 $clinicalStatus = "resolved";
194 } elseif ($dataRecord['occurrence'] > 1) {
195 $clinicalStatus = "recurrence";
197 } elseif (isset($dataRecord['enddate']) && strtotime($dataRecord['enddate']) < strtotime("now")) {
198 //Inactive if End Date is expired
199 $clinicalStatus = "inactive";
201 $clinicalSysytem = "http://terminology.hl7.org/CodeSystem/data-absent-reason";
202 $clinicalStatus = "unknown";
204 $clinical_Status = new FHIRCodeableConcept();
205 $clinical_Status->addCoding(
207 'system' => $clinicalSysytem,
208 'code' => $clinicalStatus,
209 'display' => ucwords($clinicalStatus),
212 $conditionResource->setClinicalStatus($clinical_Status);
216 * Searches for OpenEMR records using OpenEMR search parameters
218 * @param array openEMRSearchParameters OpenEMR search fields
219 * @param $puuidBind - Optional variable to only allow visibility of the patient with this puuid.
220 * @return ProcessingResult
222 protected function searchForOpenEMRRecords($openEMRSearchParameters, $puuidBind = null): ProcessingResult
224 $result = $this->conditionService
->getAll($openEMRSearchParameters, true, $puuidBind);
228 public function createProvenanceResource($dataRecord = array(), $encode = false)
230 if (!($dataRecord instanceof FHIRCondition
)) {
231 throw new \
BadMethodCallException("Data record should be correct instance class");
233 $fhirProvenanceService = new FhirProvenanceService();
234 $fhirProvenance = $fhirProvenanceService->createProvenanceForDomainResource($dataRecord);
236 return json_encode($fhirProvenance);
238 return $fhirProvenance;
243 * Returns the Canonical URIs for the FHIR resource for each of the US Core Implementation Guide Profiles that the
244 * resource implements. Most resources have only one profile, but several like DiagnosticReport and Observation
245 * has multiple profiles that must be conformed to.
246 * @see https://www.hl7.org/fhir/us/core/CapabilityStatement-us-core-server.html for the list of profiles
249 function getProfileURIs(): array
251 return [self
::USCGI_PROFILE_URI
];
254 public function getPatientContextSearchField(): FhirSearchParameterDefinition
256 return new FhirSearchParameterDefinition('patient', SearchFieldType
::REFERENCE
, [new ServiceField('puuid', ServiceField
::TYPE_UUID
)]);