FHIR Appointment/Patient/Encounter/ValueSet (#7066)
[openemr.git] / src / Services / FHIR / FhirValueSetService.php
blob31f26b4df7f341572e6501a51662ceb697e4eacb
1 <?php
3 /**
4 * FhirDeviceService.php
5 * @package openemr
6 * @link http://www.open-emr.org
7 * @author Robert Jones (Analog Informatics Corporation) <robert@analoginfo.com>, <robert@justjones.org>
8 * @copyright Copyright (c) 2023 Analog Informatics Corporation <https://analoginfo.com>
9 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
12 namespace OpenEMR\Services\FHIR;
14 use OpenEMR\FHIR\R4\FHIRDomainResource\FHIRValueSet;
15 use OpenEMR\FHIR\R4\FHIRResource\FHIRValueSet\FHIRValueSetCompose;
16 use OpenEMR\FHIR\R4\FHIRResource\FHIRValueSet\FHIRValueSetInclude;
17 use OpenEMR\FHIR\R4\FHIRResource\FHIRValueSet\FHIRValueSetConcept;
18 use OpenEMR\FHIR\R4\FHIRElement\FHIRCode;
19 use OpenEMR\FHIR\R4\FHIRElement\FHIRDateTime;
20 use OpenEMR\FHIR\R4\FHIRElement\FHIRId;
21 use OpenEMR\Services\AppointmentService;
22 use OpenEMR\Services\ListService;
23 use OpenEMR\Services\FHIR\Traits\BulkExportSupportAllOperationsTrait;
24 use OpenEMR\Services\FHIR\Traits\FhirBulkExportDomainResourceTrait;
25 use OpenEMR\Services\FHIR\Traits\FhirServiceBaseEmptyTrait;
26 use OpenEMR\Services\Search\FhirSearchParameterDefinition;
27 use OpenEMR\Services\Search\SearchFieldType;
28 use OpenEMR\Services\Search\ServiceField;
29 use OpenEMR\Validators\ProcessingResult;
31 class FhirValueSetService extends FhirServiceBase implements IResourceUSCIGProfileService, IFhirExportableResourceService
33 use FhirServiceBaseEmptyTrait;
34 use BulkExportSupportAllOperationsTrait;
35 use FhirBulkExportDomainResourceTrait;
37 /**
38 * @var AppointmentService
40 private $appointmentService;
42 /**
43 * @var ListService
45 private $listOptionService;
47 /**
48 * NB: started w Device as a base, but DocumentReference is what I needed... no underlying service either
49 * pc_catid => openemr_postcalendar_categories
50 * doc category => categories
51 * facility POS code
52 * customlists ??
53 * option_lists by list_id
55 * MariaDB [openemr]> select list_id , option_id , title , seq , is_default , option_value , mapping , notes, codes from list_options limit 40;
56 * +---------------------------------+-------------------+-----------------------+-----+------------+--------------+---------+-------+-------+
57 * | list_id | option_id | title | seq | is_default | option_value | mapping | notes | codes |
58 * +---------------------------------+-------------------+-----------------------+-----+------------+--------------+---------+-------+-------+
59 * | abook_type | bill_svc | Billing Service | 120 | 0 | 3 | | NULL | |
60 * | abook_type | ccda | Care Coordination | 35 | 0 | 2 | | NULL | |
61 * | abook_type | dist | Distributor | 30 | 0 | 3 | | NULL | |
62 * | abook_type | emr_direct | EMR Direct | 105 | 0 | 4 | | NULL | |
63 * | abook_type | external_org | External Organization | 120 | 0 | 1 | | NULL | |
64 * | abook_type | external_provider | External Provider | 110 | 0 | 1 | | NULL | |
65 * | abook_type | ord_img | Imaging Service | 5 | 0 | 3 | | NULL | |
66 * | abook_type | ord_imm | Immunization Service | 10 | 0 | 3 | | NULL | |
67 * | abook_type | ord_lab | Lab Service | 15 | 0 | 3 | | NULL | |
68 * | abook_type | oth | Other | 95 | 0 | 1 | | NULL | |
69 * | abook_type | spe | Specialist | 20 | 0 | 2 | | NULL | |
70 * | abook_type | vendor | Vendor | 25 | 0 | 3 | | NULL | |
71 * | address-types | both | Postal & Physical | 30 | 0 | 0 | | NULL | |
72 * | address-types | physical | Physical | 20 | 0 | 0 | | NULL | |
73 * | address-types | postal | Postal | 10 | 0 | 0 | | NULL | |
74 * | address-uses | billing | Billing | 50 | 0 | 0 | | NULL | |
75 * | address-uses | home | Home | 10 | 0 | 0 | | NULL | |
76 * | address-uses | old | Old/Incorrect | 40 | 0 | 0 | | NULL | |
77 * | address-uses | temp | Temporary | 30 | 0 | 0 | | NULL | |
78 * | address-uses | work | Work | 20 | 0 | 0 | | NULL | |
79 * | adjreason | Adm adjust | Adm adjust | 5 | 0 | 1 | | NULL | |
80 * | adjreason | After hrs calls | After hrs calls | 10 | 0 | 1 | | NULL | |
81 * | adjreason | Bad check | Bad check | 15 | 0 | 1 | | NULL | |
82 * | adjreason | Bad debt | Bad debt | 20 | 0 | 1 | | NULL | |
83 * | adjreason | Coll w/o | Coll w/o | 25 | 0 | 1 | | NULL | |
89 const USCGI_PROFILE_URI = 'http://hl7.org/fhir/StructureDefinition/shareablevalueset';
90 const APPOINTMENT_TYPE = 'appointment-type';
92 public function __construct()
94 parent::__construct();
95 $this->appointmentService = new AppointmentService();
96 $this->listOptionService = new ListService();
99 /**
100 * Returns an array mapping FHIR Resource search parameters to OpenEMR search parameters
102 protected function loadSearchParameters()
104 return [
105 '_id' => new FhirSearchParameterDefinition('_id', SearchFieldType::TOKEN, [new ServiceField('id', ServiceField::TYPE_STRING)]),
110 * Retrieves all of the fhir observation resources mapped to the underlying openemr data elements.
111 * @param $fhirSearchParameters The FHIR resource search parameters
112 * @return processing result
114 public function getAll($fhirSearchParameters, $puuidBind = null): ProcessingResult
116 $fhirSearchResult = new ProcessingResult();
117 try {
118 if (
119 !isset($fhirSearchParameters[ '_id' ])
120 // could be array (AND) or comma-delimited string value (OR)
121 // check array first but should only be len 1 ("AND", becuase cannot be 2 simultaneous)
122 || ( is_array($fhirSearchParameters[ '_id' ])
123 && count($fhirSearchParameters[ '_id' ]) == 1
124 && $fhirSearchParameters[ '_id' ][ 0 ] == self::APPOINTMENT_TYPE )
125 // and string which could be comma-delimiter OR of exploded values
126 || ( !is_array($fhirSearchParameters[ '_id' ])
127 && in_array(self::APPOINTMENT_TYPE, explode(",", $fhirSearchParameters[ '_id' ])) )
129 $calendarCategories = $this->appointmentService->getCalendarCategories();
130 $valueSet = new FHIRValueSet();
131 $valueSet->setId(self::APPOINTMENT_TYPE);
132 $compose = new FHIRValueSetCompose();
133 $include = new FHIRValueSetInclude();
134 foreach ($calendarCategories as $category) {
135 if ($category["pc_cattype"] != 0) {
136 continue; // only cat_type==0
138 $concept = new FHIRValueSetConcept();
139 $code = new FHIRCode();
140 $code->setValue($category[ "pc_constant_id"]);
141 $concept->setCode($code);
142 $concept->setDisplay($category[ "pc_catname" ]);
143 $include->addConcept($concept);
145 $compose->addInclude($include);
146 $valueSet->setCompose($compose);
147 $fhirSearchResult->addData($valueSet);
150 // Now the same for list_options selected in $listNames
151 $list_ids = $this->listOptionService->getListIds();
152 foreach ($list_ids as $listName) {
153 if (
154 isset($fhirSearchParameters[ '_id' ])
155 // could be array (AND) or comma-delimited string value (OR)
156 // check array first but should only be len 1 ("AND", becuase cannot be 2 simultaneous)
157 && ( ( is_array($fhirSearchParameters[ '_id' ])
158 && count($fhirSearchParameters[ '_id' ]) == 1
159 && $fhirSearchParameters[ '_id' ][ 0 ] != $listName )
160 // and string which could be comma-delimiter OR of exploded values
161 || ( !is_array($fhirSearchParameters[ '_id' ])
162 && !in_array($listName, explode(",", $fhirSearchParameters[ '_id' ])) ) )
164 continue;
166 $options = $this->listOptionService->getOptionsByListName($listName); // does not return title
167 if (count($options) == 0) {
168 continue;
170 $valueSet = new FHIRValueSet();
171 $valueSet->setId($listName);
172 $compose = new FHIRValueSetCompose();
173 $include = new FHIRValueSetInclude();
174 foreach ($options as $option) {
175 $concept = new FHIRValueSetConcept();
176 $code = new FHIRCode();
177 $code->setValue($option[ "option_id"]);
178 $concept->setCode($code);
179 $concept->setDisplay($option[ "title" ]);
180 $include->addConcept($concept);
182 $compose->addInclude($include);
183 $valueSet->setCompose($compose);
184 $fhirSearchResult->addData($valueSet);
186 } catch (SearchFieldException $exception) {
187 (new SystemLogger())->errorLogCaller("search exception thrown", ['message' => $exception->getMessage(),
188 'field' => $exception->getField()]);
189 // put our exception information here
190 $fhirSearchResult->setValidationMessages([$exception->getField() => $exception->getMessage()]);
192 return $fhirSearchResult;
197 * Returns the Canonical URIs for the FHIR resource for each of the US Core Implementation Guide Profiles that the
198 * resource implements. Most resources have only one profile, but several like DiagnosticReport and Observation
199 * has multiple profiles that must be conformed to.
200 * @see https://www.hl7.org/fhir/us/core/CapabilityStatement-us-core-server.html for the list of profiles
201 * @return string[]
203 function getProfileURIs(): array
205 return [self::USCGI_PROFILE_URI];