7 * @link http://www.open-emr.org
8 * @author Yash Bothra <yashrajbothra786gmail.com>
9 * @copyright Copyright (c) 2020 Yash Bothra <yashrajbothra786gmail.com>
10 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
13 namespace OpenEMR\Services
;
15 use OpenEMR\Common\Database\QueryUtils
;
16 use OpenEMR\Common\Database\SqlQueryException
;
17 use OpenEMR\Common\Logging\SystemLogger
;
18 use OpenEMR\Common\Uuid\UuidRegistry
;
19 use OpenEMR\Services\Search\FhirSearchWhereClauseBuilder
;
20 use OpenEMR\Services\Search\ISearchField
;
21 use OpenEMR\Services\Search\ReferenceSearchField
;
22 use OpenEMR\Services\Search\ReferenceSearchValue
;
23 use OpenEMR\Services\Search\SearchFieldException
;
24 use OpenEMR\Services\Search\SearchModifier
;
25 use OpenEMR\Services\Search\StringSearchField
;
26 use OpenEMR\Services\Search\TokenSearchField
;
27 use OpenEMR\Services\Search\TokenSearchValue
;
28 use OpenEMR\Validators\ProcessingResult
;
30 class DrugService
extends BaseService
32 private const DRUG_TABLE
= "drugs";
35 * Default constructor.
37 public function __construct()
39 parent
::__construct(self
::DRUG_TABLE
);
40 UuidRegistry
::createMissingUuidsForTables([self
::DRUG_TABLE
]);
43 public function getUuidFields(): array
49 * Returns a list of drugs matching optional search criteria.
50 * Search criteria is conveyed by array where key = field/column name, value = field value.
51 * If no search criteria is provided, all records are returned.
53 * @param $search search array parameters
54 * @param $isAndCondition specifies if AND condition is used for multiple criteria. Defaults to true.
55 * @param $puuidBind - Patient uuid to return drug resources that are only visible to the current patient
56 * @return ProcessingResult which contains validation messages, internal error messages, and the data
59 public function getAll($search = array(), $isAndCondition = true, $puuidBind = null)
62 foreach ($search as $key => $value) {
63 if (!$value instanceof ISearchField
) {
64 $newSearch[] = new StringSearchField($key, [$value], SearchModifier
::EXACT
);
66 $newSearch[$key] = $value;
69 // so if we have a puuid we need to make sure we only return drugs that are connected to the current patient.
70 if (isset($puuidBind)) {
71 $newSearch['puuid'] = new TokenSearchField('puuid', $puuidBind, true);
74 return $this->search($newSearch, $isAndCondition);
78 * Returns a single drug record by id.
79 * @param $uuid - The drug uuid identifier in string format.
80 * @return ProcessingResult which contains validation messages, internal error messages, and the data
83 public function getOne($uuid)
86 'uuid' => new TokenSearchField('uuid', [new TokenSearchValue($uuid, null, false)])
88 // so if we have a puuid we need to make sure we only return drugs that are connected to the current patient.
90 $search['puuid'] = new ReferenceSearchField('puuid', [new ReferenceSearchValue($puuid, 'Patient', true)]);
92 return $this->search($search);
95 public function search($search, $isAndCondition = true)
97 $sql = "SELECT drugs.drug_id,
108 IF(drug_prescriptions.rxnorm_drugcode!=''
109 ,drug_prescriptions.rxnorm_drugcode
110 ,IF(drug_code IS NULL, '', concat('RXCUI:',drug_code))
111 ) AS 'rxnorm_drugcode',
112 drug_inventory.manufacturer,
113 drug_inventory.lot_number,
114 drug_inventory.expiration
116 LEFT JOIN drug_inventory
117 ON drugs.drug_id = drug_inventory.drug_id
120 uuid AS prescription_uuid
123 ,patient_id as prescription_patient_id
127 ON drug_prescriptions.drug_id = drugs.drug_id
133 ON patient.pid = drug_prescriptions.prescription_patient_id";
135 $processingResult = new ProcessingResult();
137 $whereClause = FhirSearchWhereClauseBuilder
::build($search, $isAndCondition);
139 $sql .= $whereClause->getFragment();
140 $sqlBindArray = $whereClause->getBoundValues();
141 $statementResults = QueryUtils
::sqlStatementThrowException($sql, $sqlBindArray);
143 while ($row = sqlFetchArray($statementResults)) {
144 $resultRecord = $this->createResultRecordFromDatabaseResult($row);
145 $processingResult->addData($resultRecord);
147 } catch (SqlQueryException
$exception) {
148 // we shouldn't hit a query exception
149 (new SystemLogger())->error($exception->getMessage(), ['trace' => $exception->getTraceAsString()]);
150 $processingResult->addInternalError("Error selecting data from database");
151 } catch (SearchFieldException
$exception) {
152 (new SystemLogger())->error($exception->getMessage(), ['trace' => $exception->getTraceAsString(), 'field' => $exception->getField()]);
153 $processingResult->setValidationMessages([$exception->getField() => $exception->getMessage()]);
156 return $processingResult;
159 protected function createResultRecordFromDatabaseResult($row)
161 $record = parent
::createResultRecordFromDatabaseResult($row);
163 if ($record['rxnorm_drugcode'] != "") {
164 $codes = $this->addCoding($row['rxnorm_drugcode']);
166 foreach ($codes as $code => $codeValues) {
167 if (empty($codeValues['description'])) {
168 // use the drug name if for some reason we have no rxnorm description from the lookup
169 $codeValues['description'] = $row['drug'];
171 $updatedCodes[$code] = $codeValues;
173 $record['drug_code'] = $updatedCodes;
176 if ($row['rxnorm_drugcode'] != "") {
177 $row['drug_code'] = $this->addCoding($row['drug_code']);