fix(abdm): populate salt and generic name in IPD discharge medication FHIR resources
- Populate generic salt name in MedicationRequest medicationCodeableConcept.coding[0] to prevent PHR apps displaying 'NA' subtitle - Retain brand name in medicationCodeableConcept.text and secondary coding - Extract med_salt from prescription records with automatic resolution from medicine masters and formulation heuristics - Update discharge PDF and narrative to render generic salt names - Add unit tests verifying generic salt mapping and dual coding in FHIR bundle
This commit is contained in:
parent
9272bb5a9c
commit
6f3b2a62d9
|
|
@ -3562,15 +3562,20 @@ class AbdmGateway extends BaseController
|
|||
}
|
||||
|
||||
$medications = [];
|
||||
$legacyMeds = $this->ipdRows('ipd_discharge_prescrption_prescribed', ['med_name', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], $ipdId);
|
||||
$legacyMeds = $this->ipdRows('ipd_discharge_prescrption_prescribed', ['med_id', 'med_name', 'med_salt', 'med_type', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], $ipdId);
|
||||
if (empty($legacyMeds)) {
|
||||
$legacyMeds = $this->ipdRows('ipd_discharge_prescription_prescribed', ['med_name', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], $ipdId);
|
||||
$legacyMeds = $this->ipdRows('ipd_discharge_prescription_prescribed', ['med_id', 'med_name', 'med_salt', 'med_type', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], $ipdId);
|
||||
}
|
||||
foreach ($legacyMeds as $row) {
|
||||
$name = trim((string) ($row['med_name'] ?? ''));
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
$salt = trim((string) ($row['med_salt'] ?? ''));
|
||||
$medId = (int) ($row['med_id'] ?? 0);
|
||||
if ($salt === '' || strcasecmp($salt, 'NA') === 0 || strcasecmp($salt, 'N/A') === 0) {
|
||||
$salt = $this->resolveDischargeMedSaltName($name, $medId);
|
||||
}
|
||||
$dosage = $this->resolveDischargeMedDosageLabel(
|
||||
$row['dosage'] ?? '',
|
||||
$row['dosage_when'] ?? '',
|
||||
|
|
@ -3578,19 +3583,33 @@ class AbdmGateway extends BaseController
|
|||
(string) ($row['no_of_days'] ?? ''),
|
||||
(string) ($row['remark'] ?? '')
|
||||
);
|
||||
$medications[] = ['name' => $name, 'dosage' => $dosage];
|
||||
$medications[] = [
|
||||
'name' => $name,
|
||||
'salt' => $salt,
|
||||
'generic' => $salt,
|
||||
'dosage' => $dosage,
|
||||
'med_id' => $medId,
|
||||
'type' => trim((string) ($row['med_type'] ?? '')),
|
||||
];
|
||||
}
|
||||
if (empty($medications)) {
|
||||
foreach ($this->ipdRows('ipd_discharge_drug', ['drug_name', 'drug_dose', 'drug_day'], $ipdId) as $row) {
|
||||
foreach ($this->ipdRows('ipd_discharge_drug', ['drug_code', 'drug_name', 'drug_dose', 'drug_day', 'formulation'], $ipdId) as $row) {
|
||||
$name = trim((string) ($row['drug_name'] ?? ''));
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
$salt = $this->resolveDischargeMedSaltName($name);
|
||||
$dosage = trim(implode(' ', array_filter([
|
||||
(string) ($row['drug_dose'] ?? ''),
|
||||
(string) ($row['drug_day'] ?? ''),
|
||||
], static fn ($v) => trim((string) $v) !== '')));
|
||||
$medications[] = ['name' => $name, 'dosage' => $dosage];
|
||||
$medications[] = [
|
||||
'name' => $name,
|
||||
'salt' => $salt,
|
||||
'generic' => $salt,
|
||||
'dosage' => $dosage,
|
||||
'type' => trim((string) ($row['formulation'] ?? '')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3881,6 +3900,154 @@ class AbdmGateway extends BaseController
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-resolves generic/salt name of medicine from master tables or clinical patterns.
|
||||
*/
|
||||
private function resolveDischargeMedSaltName(string $rawName, int $medId = 0): string
|
||||
{
|
||||
$rawName = trim($rawName);
|
||||
if ($rawName === '' || in_array(strtoupper($rawName), ['0', 'NA', 'N/A'], true)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->db) {
|
||||
// 1. If med_id provided, look up masters directly
|
||||
if ($medId > 0) {
|
||||
if ($this->db->tableExists('opd_med_master')) {
|
||||
$mRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->where('id', $medId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($mRow)) {
|
||||
$gen = trim((string) (!empty($mRow['genericname']) ? $mRow['genericname'] : ($mRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && ! in_array(strtoupper($gen), ['0', 'NA', 'N/A'], true)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->db->tableExists('med_product_master')) {
|
||||
$pRow = $this->db->table('med_product_master')
|
||||
->select('genericname')
|
||||
->where('id', $medId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($pRow)) {
|
||||
$gen = trim((string) ($pRow['genericname'] ?? ''));
|
||||
if ($gen !== '' && ! in_array(strtoupper($gen), ['0', 'NA', 'N/A'], true)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Clean dosage prefix and look up masters by item_name
|
||||
$clean = trim((string) preg_replace('/^(TAB|CAP|SYP|INJ|CREAM|OINT|GEL|DROPS|SPRAY)\s+/i', '', $rawName));
|
||||
if ($clean !== '') {
|
||||
if ($this->db->tableExists('opd_med_master')) {
|
||||
$mRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->where('item_name', $clean)
|
||||
->orLike('item_name', $clean, 'after')
|
||||
->orLike('item_name', $clean, 'both')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($mRow)) {
|
||||
$gen = trim((string) (!empty($mRow['genericname']) ? $mRow['genericname'] : ($mRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && ! in_array(strtoupper($gen), ['0', 'NA', 'N/A'], true)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->db->tableExists('med_product_master')) {
|
||||
$pRow = $this->db->table('med_product_master')
|
||||
->select('genericname')
|
||||
->groupStart()
|
||||
->where('item_name', $clean)
|
||||
->orLike('item_name', $clean, 'after')
|
||||
->orLike('item_name', $clean, 'both')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($pRow)) {
|
||||
$gen = trim((string) ($pRow['genericname'] ?? ''));
|
||||
if ($gen !== '' && ! in_array(strtoupper($gen), ['0', 'NA', 'N/A'], true)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Keyword / token lookup for words >= 4 letters
|
||||
$words = preg_split('/[\s\-_]+/', $clean);
|
||||
if (is_array($words)) {
|
||||
foreach ($words as $w) {
|
||||
if (strlen($w) >= 4 && !in_array(strtoupper($w), ['PLUS', 'FORTE', 'EXTRA', 'GOLD'], true)) {
|
||||
if ($this->db->tableExists('opd_med_master')) {
|
||||
$wRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->like('item_name', $w, 'after')
|
||||
->orLike('genericname', $w, 'after')
|
||||
->orLike('salt_name', $w, 'after')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($wRow)) {
|
||||
$gen = trim((string) (!empty($wRow['genericname']) ? $wRow['genericname'] : ($wRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && ! in_array(strtoupper($gen), ['0', 'NA', 'N/A'], true)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// DB fallback
|
||||
}
|
||||
|
||||
// 4. Clinical brand heuristics for common hospital prescriptions
|
||||
$u = strtoupper($rawName);
|
||||
if (preg_match('/\b(DOZPANTA|PANTA|PANTOP|PAN\s*40|PAN\s*D|PANTOCID|PANTOCID\s*DSR|PANTODAC)\b/', $u) || str_contains($u, 'PANTOP')) {
|
||||
return (str_contains($u, 'DSR') || str_contains($u, ' D')) ? 'Pantoprazole + Domperidone' : 'Pantoprazole';
|
||||
}
|
||||
if (preg_match('/\b(RABEKIND|RABEMAC|RABICIP|RABLET|RAZO)\b/', $u) || str_contains($u, 'RABE')) {
|
||||
return (str_contains($u, 'DSR') || str_contains($u, ' D')) ? 'Rabeprazole + Domperidone' : 'Rabeprazole';
|
||||
}
|
||||
if (preg_match('/\b(OMEE|OPEZ|OCID)\b/', $u) || str_contains($u, 'OMEPRAZOLE')) {
|
||||
return str_contains($u, ' D') ? 'Omeprazole + Domperidone' : 'Omeprazole';
|
||||
}
|
||||
if (preg_match('/\b(ACILOC|RANTAC|ZINETAC)\b/', $u) || str_contains($u, 'RANITIDINE')) {
|
||||
return 'Ranitidine';
|
||||
}
|
||||
if (preg_match('/\b(DOLO|CALPOL|CROCIN|PACIMOL|SUMO\s*L)\b/', $u) || str_contains($u, 'PARACETAMOL')) {
|
||||
return 'Paracetamol';
|
||||
}
|
||||
if (preg_match('/\b(AZITHRAL|AZI|AZEE|AZITHRO)\b/', $u) || str_contains($u, 'AZITHROMYCIN')) {
|
||||
return 'Azithromycin';
|
||||
}
|
||||
if (preg_match('/\b(AUGMENTIN|MOXIKIND|CLAVAM|AMOXCLAV)\b/', $u)) {
|
||||
return 'Amoxicillin + Clavulanic Acid';
|
||||
}
|
||||
if (preg_match('/\b(MONTEK|MONTICOPE|LEVO\s*M)\b/', $u)) {
|
||||
return 'Levocetirizine + Montelukast';
|
||||
}
|
||||
if (preg_match('/\b(EMESET|VOMIKIND|ONDA)\b/', $u)) {
|
||||
return 'Ondansetron';
|
||||
}
|
||||
if (str_contains($u, 'ORS') || str_contains($u, 'ELECTRAL')) {
|
||||
return 'Oral Rehydration Salts';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function resolveIpdLocation(int $ipdId): array
|
||||
{
|
||||
$bedNo = '';
|
||||
|
|
|
|||
|
|
@ -9583,15 +9583,20 @@ class Ipd_discharge extends BaseController
|
|||
}
|
||||
|
||||
$medicationRows = [];
|
||||
$legacyMeds = $this->byIpdRows('ipd_discharge_prescrption_prescribed', ['med_name', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], 'id ASC', $ipdId);
|
||||
$legacyMeds = $this->byIpdRows('ipd_discharge_prescrption_prescribed', ['med_id', 'med_name', 'med_salt', 'med_type', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], 'id ASC', $ipdId);
|
||||
if (empty($legacyMeds)) {
|
||||
$legacyMeds = $this->byIpdRows('ipd_discharge_prescription_prescribed', ['med_name', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], 'id ASC', $ipdId);
|
||||
$legacyMeds = $this->byIpdRows('ipd_discharge_prescription_prescribed', ['med_id', 'med_name', 'med_salt', 'med_type', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'remark'], 'id ASC', $ipdId);
|
||||
}
|
||||
foreach ($legacyMeds as $row) {
|
||||
$name = trim((string) ($row['med_name'] ?? ''));
|
||||
if (! $this->isMeaningfulDischargeValue($name)) {
|
||||
continue;
|
||||
}
|
||||
$salt = trim((string) ($row['med_salt'] ?? ''));
|
||||
$medId = (int) ($row['med_id'] ?? 0);
|
||||
if ($salt === '' || ! $this->isMeaningfulDischargeValue($salt)) {
|
||||
$salt = $this->resolveDischargeMedSaltName($name, $medId);
|
||||
}
|
||||
$dose = $this->formatDischargeMedDirections(
|
||||
$row['dosage'] ?? '',
|
||||
$row['dosage_when'] ?? '',
|
||||
|
|
@ -9599,19 +9604,33 @@ class Ipd_discharge extends BaseController
|
|||
(string) ($row['no_of_days'] ?? ''),
|
||||
(string) ($row['remark'] ?? '')
|
||||
);
|
||||
$medicationRows[] = ['name' => $name, 'dosage' => $dose];
|
||||
$medicationRows[] = [
|
||||
'name' => $name,
|
||||
'salt' => $salt,
|
||||
'generic' => $salt,
|
||||
'dosage' => $dose,
|
||||
'med_id' => $medId,
|
||||
'type' => trim((string) ($row['med_type'] ?? '')),
|
||||
];
|
||||
}
|
||||
if (empty($medicationRows)) {
|
||||
foreach ($this->byIpdRows('ipd_discharge_drug', ['drug_name', 'drug_dose', 'drug_day'], 'id ASC', $ipdId) as $row) {
|
||||
foreach ($this->byIpdRows('ipd_discharge_drug', ['drug_code', 'drug_name', 'drug_dose', 'drug_day', 'formulation'], 'id ASC', $ipdId) as $row) {
|
||||
$name = trim((string) ($row['drug_name'] ?? ''));
|
||||
if (! $this->isMeaningfulDischargeValue($name)) {
|
||||
continue;
|
||||
}
|
||||
$salt = $this->resolveDischargeMedSaltName($name);
|
||||
$dose = trim(implode(' ', array_filter([
|
||||
(string) ($row['drug_dose'] ?? ''),
|
||||
(string) ($row['drug_day'] ?? ''),
|
||||
], fn ($v) => $this->isMeaningfulDischargeValue((string) $v))));
|
||||
$medicationRows[] = ['name' => $name, 'dosage' => $dose];
|
||||
$medicationRows[] = [
|
||||
'name' => $name,
|
||||
'salt' => $salt,
|
||||
'generic' => $salt,
|
||||
'dosage' => $dose,
|
||||
'type' => trim((string) ($row['formulation'] ?? '')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -10070,6 +10089,154 @@ class Ipd_discharge extends BaseController
|
|||
return ! in_array(strtoupper($value), ['0', 'NA', 'N/A'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-resolves generic/salt name of medicine from master tables or clinical patterns.
|
||||
*/
|
||||
private function resolveDischargeMedSaltName(string $rawName, int $medId = 0): string
|
||||
{
|
||||
$rawName = trim($rawName);
|
||||
if ($rawName === '' || ! $this->isMeaningfulDischargeValue($rawName)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->db) {
|
||||
// 1. If med_id provided, look up masters directly
|
||||
if ($medId > 0) {
|
||||
if ($this->db->tableExists('opd_med_master')) {
|
||||
$mRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->where('id', $medId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($mRow)) {
|
||||
$gen = trim((string) (!empty($mRow['genericname']) ? $mRow['genericname'] : ($mRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && $this->isMeaningfulDischargeValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->db->tableExists('med_product_master')) {
|
||||
$pRow = $this->db->table('med_product_master')
|
||||
->select('genericname')
|
||||
->where('id', $medId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($pRow)) {
|
||||
$gen = trim((string) ($pRow['genericname'] ?? ''));
|
||||
if ($gen !== '' && $this->isMeaningfulDischargeValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Clean dosage prefix and look up masters by item_name
|
||||
$clean = trim((string) preg_replace('/^(TAB|CAP|SYP|INJ|CREAM|OINT|GEL|DROPS|SPRAY)\s+/i', '', $rawName));
|
||||
if ($clean !== '') {
|
||||
if ($this->db->tableExists('opd_med_master')) {
|
||||
$mRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->where('item_name', $clean)
|
||||
->orLike('item_name', $clean, 'after')
|
||||
->orLike('item_name', $clean, 'both')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($mRow)) {
|
||||
$gen = trim((string) (!empty($mRow['genericname']) ? $mRow['genericname'] : ($mRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && $this->isMeaningfulDischargeValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->db->tableExists('med_product_master')) {
|
||||
$pRow = $this->db->table('med_product_master')
|
||||
->select('genericname')
|
||||
->groupStart()
|
||||
->where('item_name', $clean)
|
||||
->orLike('item_name', $clean, 'after')
|
||||
->orLike('item_name', $clean, 'both')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($pRow)) {
|
||||
$gen = trim((string) ($pRow['genericname'] ?? ''));
|
||||
if ($gen !== '' && $this->isMeaningfulDischargeValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Keyword / token lookup for words >= 4 letters
|
||||
$words = preg_split('/[\s\-_]+/', $clean);
|
||||
if (is_array($words)) {
|
||||
foreach ($words as $w) {
|
||||
if (strlen($w) >= 4 && !in_array(strtoupper($w), ['PLUS', 'FORTE', 'EXTRA', 'GOLD'], true)) {
|
||||
if ($this->db->tableExists('opd_med_master')) {
|
||||
$wRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->like('item_name', $w, 'after')
|
||||
->orLike('genericname', $w, 'after')
|
||||
->orLike('salt_name', $w, 'after')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($wRow)) {
|
||||
$gen = trim((string) (!empty($wRow['genericname']) ? $wRow['genericname'] : ($wRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && $this->isMeaningfulDischargeValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// DB fallback
|
||||
}
|
||||
|
||||
// 4. Clinical brand heuristics for common hospital prescriptions
|
||||
$u = strtoupper($rawName);
|
||||
if (preg_match('/\b(DOZPANTA|PANTA|PANTOP|PAN\s*40|PAN\s*D|PANTOCID|PANTOCID\s*DSR|PANTODAC)\b/', $u) || str_contains($u, 'PANTOP')) {
|
||||
return (str_contains($u, 'DSR') || str_contains($u, ' D')) ? 'Pantoprazole + Domperidone' : 'Pantoprazole';
|
||||
}
|
||||
if (preg_match('/\b(RABEKIND|RABEMAC|RABICIP|RABLET|RAZO)\b/', $u) || str_contains($u, 'RABE')) {
|
||||
return (str_contains($u, 'DSR') || str_contains($u, ' D')) ? 'Rabeprazole + Domperidone' : 'Rabeprazole';
|
||||
}
|
||||
if (preg_match('/\b(OMEE|OPEZ|OCID)\b/', $u) || str_contains($u, 'OMEPRAZOLE')) {
|
||||
return str_contains($u, ' D') ? 'Omeprazole + Domperidone' : 'Omeprazole';
|
||||
}
|
||||
if (preg_match('/\b(ACILOC|RANTAC|ZINETAC)\b/', $u) || str_contains($u, 'RANITIDINE')) {
|
||||
return 'Ranitidine';
|
||||
}
|
||||
if (preg_match('/\b(DOLO|CALPOL|CROCIN|PACIMOL|SUMO\s*L)\b/', $u) || str_contains($u, 'PARACETAMOL')) {
|
||||
return 'Paracetamol';
|
||||
}
|
||||
if (preg_match('/\b(AZITHRAL|AZI|AZEE|AZITHRO)\b/', $u) || str_contains($u, 'AZITHROMYCIN')) {
|
||||
return 'Azithromycin';
|
||||
}
|
||||
if (preg_match('/\b(AUGMENTIN|MOXIKIND|CLAVAM|AMOXCLAV)\b/', $u)) {
|
||||
return 'Amoxicillin + Clavulanic Acid';
|
||||
}
|
||||
if (preg_match('/\b(MONTEK|MONTICOPE|LEVO\s*M)\b/', $u)) {
|
||||
return 'Levocetirizine + Montelukast';
|
||||
}
|
||||
if (preg_match('/\b(EMESET|VOMIKIND|ONDA)\b/', $u)) {
|
||||
return 'Ondansetron';
|
||||
}
|
||||
if (str_contains($u, 'ORS') || str_contains($u, 'ELECTRAL')) {
|
||||
return 'Oral Rehydration Salts';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function toIsoDateTimeOrNow(string $value): string
|
||||
{
|
||||
$value = trim($value);
|
||||
|
|
|
|||
|
|
@ -263,32 +263,64 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
|||
|
||||
foreach ($validMeds as $idx => $med) {
|
||||
$name = trim((string) ($med['name'] ?? ''));
|
||||
$medCode = trim((string) ($med['code'] ?? ''));
|
||||
$salt = trim((string) ($med['salt'] ?? $med['generic'] ?? $med['med_salt'] ?? ''));
|
||||
$medId = (int) ($med['med_id'] ?? $med['id'] ?? 0);
|
||||
if ($salt === '' || ! $this->isMeaningfulValue($salt)) {
|
||||
$salt = $this->tryResolveGenericSalt($name, $medId);
|
||||
}
|
||||
|
||||
$medCode = trim((string) ($med['code'] ?? $med['snomed_code'] ?? ''));
|
||||
$hasSalt = ($salt !== '' && $this->isMeaningfulValue($salt));
|
||||
$isSaltDistinct = ($hasSalt && strcasecmp($salt, $name) !== 0);
|
||||
|
||||
$saltCode = $this->resolveDrugSnomedCode($hasSalt ? $salt : $name);
|
||||
if ($saltCode === '105904009' && $medCode !== '' && $this->isMeaningfulValue($medCode)) {
|
||||
$saltCode = $medCode;
|
||||
}
|
||||
|
||||
$medCoding = [];
|
||||
if ($medCode !== '' && $this->isMeaningfulValue($medCode)) {
|
||||
if ($isSaltDistinct) {
|
||||
// Primary coding represents the generic substance / salt so PHR displays it in the subtitle line instead of "NA"
|
||||
$medCoding[] = [
|
||||
'system' => 'http://snomed.info/sct',
|
||||
'code' => $medCode,
|
||||
'code' => $saltCode,
|
||||
'display' => $salt,
|
||||
];
|
||||
// Secondary coding represents the prescribed brand name
|
||||
$brandCode = ($medCode !== '' && $this->isMeaningfulValue($medCode) && $medCode !== $saltCode) ? $medCode : '105904009';
|
||||
$medCoding[] = [
|
||||
'system' => 'http://snomed.info/sct',
|
||||
'code' => $brandCode,
|
||||
'display' => $name,
|
||||
];
|
||||
} else {
|
||||
$display = $hasSalt ? $salt : $name;
|
||||
$code = ($medCode !== '' && $this->isMeaningfulValue($medCode)) ? $medCode : $saltCode;
|
||||
$medCoding[] = [
|
||||
'system' => 'http://snomed.info/sct',
|
||||
'code' => '105904009', // Type of drug
|
||||
'display' => $name,
|
||||
'code' => $code,
|
||||
'display' => $display,
|
||||
];
|
||||
}
|
||||
|
||||
$dosageText = trim((string) ($med['dosage'] ?? ''));
|
||||
$structuredDosage = $this->buildStructuredDosageInstruction($dosageText, $name);
|
||||
|
||||
$divMedText = htmlspecialchars($name);
|
||||
if ($isSaltDistinct) {
|
||||
$divMedText .= ' (' . htmlspecialchars($salt) . ')';
|
||||
}
|
||||
if ($dosageText !== '') {
|
||||
$divMedText .= ' - ' . htmlspecialchars($dosageText);
|
||||
}
|
||||
|
||||
$medResource = [
|
||||
'resourceType' => 'MedicationRequest',
|
||||
'id' => 'discharge-medication-' . $recordId . '-' . $idx,
|
||||
'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/MedicationRequest']],
|
||||
'text' => [
|
||||
'status' => 'generated',
|
||||
'div' => '<div xmlns="http://www.w3.org/1999/xhtml"><p><b>Medication:</b> ' . htmlspecialchars($name) . ($dosageText !== '' ? (' - ' . htmlspecialchars($dosageText)) : '') . '</p></div>',
|
||||
'div' => '<div xmlns="http://www.w3.org/1999/xhtml"><p><b>Medication:</b> ' . $divMedText . '</p></div>',
|
||||
],
|
||||
'status' => 'active',
|
||||
'intent' => 'order',
|
||||
|
|
@ -1122,11 +1154,13 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
|||
/** @param array<string,mixed> $item */
|
||||
private function sectionItemNarrative(array $item): string
|
||||
{
|
||||
// For medications: name + dosage
|
||||
// For medications: name (salt) + dosage
|
||||
if (isset($item['name']) && $this->isMeaningfulValue((string) $item['name'])) {
|
||||
$name = trim((string) $item['name']);
|
||||
$salt = trim((string) ($item['salt'] ?? $item['generic'] ?? $item['med_salt'] ?? ''));
|
||||
$dosage = trim((string) ($item['dosage'] ?? ''));
|
||||
return trim($name . ($this->isMeaningfulValue($dosage) ? ' - ' . $dosage : ''));
|
||||
$namePart = ($salt !== '' && strcasecmp($salt, $name) !== 0) ? ($name . ' (' . $salt . ')') : $name;
|
||||
return trim($namePart . ($this->isMeaningfulValue($dosage) ? ' - ' . $dosage : ''));
|
||||
}
|
||||
|
||||
// For observations: text + value (+ unit)
|
||||
|
|
@ -1324,10 +1358,15 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
|||
if (! empty($medications)) {
|
||||
$medHtml .= '<table class="grid"><tr><th>Medication Name</th><th>Dosage & Frequency</th></tr>';
|
||||
foreach ($medications as $med) {
|
||||
$name = is_array($med) ? ($med['name'] ?? '') : '';
|
||||
$dosage = is_array($med) ? ($med['dosage'] ?? '') : '';
|
||||
$name = is_array($med) ? trim((string) ($med['name'] ?? '')) : '';
|
||||
$salt = is_array($med) ? trim((string) ($med['salt'] ?? $med['generic'] ?? $med['med_salt'] ?? '')) : '';
|
||||
$dosage = is_array($med) ? trim((string) ($med['dosage'] ?? '')) : '';
|
||||
if ($name !== '') {
|
||||
$medHtml .= '<tr><td>' . htmlspecialchars($name) . '</td><td>' . htmlspecialchars($dosage) . '</td></tr>';
|
||||
$nameDisplay = htmlspecialchars($name);
|
||||
if ($salt !== '' && strcasecmp($salt, $name) !== 0) {
|
||||
$nameDisplay .= '<br/><small style="color:#64748b;">(' . htmlspecialchars($salt) . ')</small>';
|
||||
}
|
||||
$medHtml .= '<tr><td>' . $nameDisplay . '</td><td>' . htmlspecialchars($dosage) . '</td></tr>';
|
||||
}
|
||||
}
|
||||
$medHtml .= '</table>';
|
||||
|
|
@ -1457,10 +1496,15 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
|||
$html .= '<div class="section-title">Prescribed Discharge Medications</div>';
|
||||
$html .= '<table class="grid"><tr><th>Medication Name</th><th>Dosage & Frequency</th></tr>';
|
||||
foreach ($medications as $med) {
|
||||
$name = is_array($med) ? ($med['name'] ?? '') : '';
|
||||
$dosage = is_array($med) ? ($med['dosage'] ?? '') : '';
|
||||
$name = is_array($med) ? trim((string) ($med['name'] ?? '')) : '';
|
||||
$salt = is_array($med) ? trim((string) ($med['salt'] ?? $med['generic'] ?? $med['med_salt'] ?? '')) : '';
|
||||
$dosage = is_array($med) ? trim((string) ($med['dosage'] ?? '')) : '';
|
||||
if ($name !== '') {
|
||||
$html .= '<tr><td>' . htmlspecialchars($name) . '</td><td>' . htmlspecialchars($dosage) . '</td></tr>';
|
||||
$nameDisplay = htmlspecialchars($name);
|
||||
if ($salt !== '' && strcasecmp($salt, $name) !== 0) {
|
||||
$nameDisplay .= '<br/><small style="color:#64748b;">(' . htmlspecialchars($salt) . ')</small>';
|
||||
}
|
||||
$html .= '<tr><td>' . $nameDisplay . '</td><td>' . htmlspecialchars($dosage) . '</td></tr>';
|
||||
}
|
||||
}
|
||||
$html .= '</table>';
|
||||
|
|
@ -1843,4 +1887,234 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
|||
'dosageInstruction' => [$instructionItem],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve Generic / Salt name of medicine from master database or common patterns
|
||||
*/
|
||||
private function tryResolveGenericSalt(string $medName, int $medId = 0): string
|
||||
{
|
||||
$rawName = trim($medName);
|
||||
if ($rawName === '' || ! $this->isMeaningfulValue($rawName)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
if (class_exists('\Config\Database')) {
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
// 1. By med_id if given
|
||||
if ($medId > 0) {
|
||||
if ($db->tableExists('opd_med_master')) {
|
||||
$mRow = $db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->where('id', $medId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($mRow)) {
|
||||
$gen = trim((string) (!empty($mRow['genericname']) ? $mRow['genericname'] : ($mRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && $this->isMeaningfulValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($db->tableExists('med_product_master')) {
|
||||
$pRow = $db->table('med_product_master')
|
||||
->select('genericname')
|
||||
->where('id', $medId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($pRow)) {
|
||||
$gen = trim((string) ($pRow['genericname'] ?? ''));
|
||||
if ($gen !== '' && $this->isMeaningfulValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Clean medicine name and search by item_name
|
||||
$clean = trim((string) preg_replace('/^(TAB|CAP|SYP|INJ|CREAM|OINT|GEL|DROPS|SPRAY)\s+/i', '', $rawName));
|
||||
if ($clean !== '') {
|
||||
if ($db->tableExists('opd_med_master')) {
|
||||
$mRow = $db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->where('item_name', $clean)
|
||||
->orLike('item_name', $clean, 'after')
|
||||
->orLike('item_name', $clean, 'both')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($mRow)) {
|
||||
$gen = trim((string) (!empty($mRow['genericname']) ? $mRow['genericname'] : ($mRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && $this->isMeaningfulValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($db->tableExists('med_product_master')) {
|
||||
$pRow = $db->table('med_product_master')
|
||||
->select('genericname')
|
||||
->groupStart()
|
||||
->where('item_name', $clean)
|
||||
->orLike('item_name', $clean, 'after')
|
||||
->orLike('item_name', $clean, 'both')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($pRow)) {
|
||||
$gen = trim((string) ($pRow['genericname'] ?? ''));
|
||||
if ($gen !== '' && $this->isMeaningfulValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Match significant words (>= 4 chars)
|
||||
$words = preg_split('/[\s\-_]+/', $clean);
|
||||
if (is_array($words)) {
|
||||
foreach ($words as $w) {
|
||||
if (strlen($w) >= 4 && !in_array(strtoupper($w), ['PLUS', 'FORTE', 'EXTRA', 'GOLD'], true)) {
|
||||
if ($db->tableExists('opd_med_master')) {
|
||||
$wRow = $db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->like('item_name', $w, 'after')
|
||||
->orLike('genericname', $w, 'after')
|
||||
->orLike('salt_name', $w, 'after')
|
||||
->groupEnd()
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (!empty($wRow)) {
|
||||
$gen = trim((string) (!empty($wRow['genericname']) ? $wRow['genericname'] : ($wRow['salt_name'] ?? '')));
|
||||
if ($gen !== '' && $this->isMeaningfulValue($gen)) {
|
||||
return $gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Safe fallback if database is inaccessible
|
||||
}
|
||||
|
||||
// 4. Clinical brand heuristics for common hospital prescriptions
|
||||
$u = strtoupper($rawName);
|
||||
if (preg_match('/\b(DOZPANTA|PANTA|PANTOP|PAN\s*40|PAN\s*D|PANTOCID|PANTOCID\s*DSR|PANTODAC)\b/', $u) || str_contains($u, 'PANTOP')) {
|
||||
return (str_contains($u, 'DSR') || str_contains($u, ' D')) ? 'Pantoprazole + Domperidone' : 'Pantoprazole';
|
||||
}
|
||||
if (preg_match('/\b(RABEKIND|RABEMAC|RABICIP|RABLET|RAZO)\b/', $u) || str_contains($u, 'RABE')) {
|
||||
return (str_contains($u, 'DSR') || str_contains($u, ' D')) ? 'Rabeprazole + Domperidone' : 'Rabeprazole';
|
||||
}
|
||||
if (preg_match('/\b(OMEE|OPEZ|OCID)\b/', $u) || str_contains($u, 'OMEPRAZOLE')) {
|
||||
return str_contains($u, ' D') ? 'Omeprazole + Domperidone' : 'Omeprazole';
|
||||
}
|
||||
if (preg_match('/\b(ACILOC|RANTAC|ZINETAC)\b/', $u) || str_contains($u, 'RANITIDINE')) {
|
||||
return 'Ranitidine';
|
||||
}
|
||||
if (preg_match('/\b(DOLO|CALPOL|CROCIN|PACIMOL|SUMO\s*L)\b/', $u) || str_contains($u, 'PARACETAMOL')) {
|
||||
return 'Paracetamol';
|
||||
}
|
||||
if (preg_match('/\b(AZITHRAL|AZI|AZEE|AZITHRO)\b/', $u) || str_contains($u, 'AZITHROMYCIN')) {
|
||||
return 'Azithromycin';
|
||||
}
|
||||
if (preg_match('/\b(AUGMENTIN|MOXIKIND|CLAVAM|AMOXCLAV)\b/', $u)) {
|
||||
return 'Amoxicillin + Clavulanic Acid';
|
||||
}
|
||||
if (preg_match('/\b(MONTEK|MONTICOPE|LEVO\s*M)\b/', $u)) {
|
||||
return 'Levocetirizine + Montelukast';
|
||||
}
|
||||
if (preg_match('/\b(EMESET|VOMIKIND|ONDA)\b/', $u)) {
|
||||
return 'Ondansetron';
|
||||
}
|
||||
if (str_contains($u, 'ORS') || str_contains($u, 'ELECTRAL')) {
|
||||
return 'Oral Rehydration Salts';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve SNOMED code for drug substance or generic salt
|
||||
*/
|
||||
private function resolveDrugSnomedCode(string $drugOrSalt): string
|
||||
{
|
||||
$term = trim($drugOrSalt);
|
||||
if ($term === '' || ! $this->isMeaningfulValue($term)) {
|
||||
return '105904009';
|
||||
}
|
||||
|
||||
try {
|
||||
if (class_exists('\Config\Database')) {
|
||||
$db = \Config\Database::connect();
|
||||
if ($db->tableExists('snomed_description')) {
|
||||
$clean = trim((string) preg_replace('/[^\w\s]/', ' ', $term));
|
||||
$firstWord = trim((string) explode(' ', $clean)[0]);
|
||||
if (strlen($firstWord) >= 4) {
|
||||
$row = $db->table('snomed_description')
|
||||
->select('concept_id')
|
||||
->where('active', '1')
|
||||
->whereIn('type_id', ['900000000000003001', '900000000000013009'])
|
||||
->like('term_normalized', strtolower($firstWord), 'after')
|
||||
->limit(1)
|
||||
->get()
|
||||
->getRowArray();
|
||||
if (!empty($row['concept_id'])) {
|
||||
return (string) $row['concept_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// DB fallback
|
||||
}
|
||||
|
||||
$upper = strtoupper($term);
|
||||
if (str_contains($upper, 'PANTOPRAZOLE')) {
|
||||
return '395821003';
|
||||
}
|
||||
if (str_contains($upper, 'RANITIDINE')) {
|
||||
return '372755005';
|
||||
}
|
||||
if (str_contains($upper, 'PARACETAMOL') || str_contains($upper, 'ACETAMINOPHEN')) {
|
||||
return '384977007';
|
||||
}
|
||||
if (str_contains($upper, 'AZITHROMYCIN')) {
|
||||
return '387531004';
|
||||
}
|
||||
if (str_contains($upper, 'AMOXICILLIN')) {
|
||||
return '372687004';
|
||||
}
|
||||
if (str_contains($upper, 'DOMPERIDONE')) {
|
||||
return '387181004';
|
||||
}
|
||||
if (str_contains($upper, 'ONDANSETRON')) {
|
||||
return '387570007';
|
||||
}
|
||||
if (str_contains($upper, 'METFORMIN')) {
|
||||
return '372567009';
|
||||
}
|
||||
if (str_contains($upper, 'ATORVASTATIN')) {
|
||||
return '387584000';
|
||||
}
|
||||
if (str_contains($upper, 'ASPIRIN')) {
|
||||
return '387458008';
|
||||
}
|
||||
if (str_contains($upper, 'RABEPRAZOLE')) {
|
||||
return '387180000';
|
||||
}
|
||||
if (str_contains($upper, 'OMEPRAZOLE')) {
|
||||
return '372544007';
|
||||
}
|
||||
if (str_contains($upper, 'ORAL REHYDRATION')) {
|
||||
return '260548002';
|
||||
}
|
||||
|
||||
return '105904009';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1000,6 +1000,15 @@ final class FhirGeneratorsTest extends CIUnitTestCase
|
|||
$this->assertContains('Physical Examination', $sectionTitles);
|
||||
$this->assertContains('Medications', $sectionTitles);
|
||||
$this->assertContains('Care Plan', $sectionTitles);
|
||||
|
||||
// Verify medication generic/salt is populated on MedicationRequest
|
||||
$medRequests = array_values(array_filter($bundle['entry'], static fn ($e) => ($e['resource']['resourceType'] ?? '') === 'MedicationRequest'));
|
||||
$this->assertNotEmpty($medRequests);
|
||||
$dozpanta = $medRequests[0]['resource'];
|
||||
$this->assertSame('DOZPANTA DSR', $dozpanta['medicationCodeableConcept']['text']);
|
||||
$this->assertSame('Pantoprazole + Domperidone', $dozpanta['medicationCodeableConcept']['coding'][0]['display']);
|
||||
$this->assertSame('395821003', $dozpanta['medicationCodeableConcept']['coding'][0]['code']);
|
||||
$this->assertStringContainsString('Pantoprazole + Domperidone', $dozpanta['text']['div']);
|
||||
}
|
||||
|
||||
public function testDischargeMandatoryFieldsPatientEncounterDiagnosisAndOutcome(): void
|
||||
|
|
@ -1125,6 +1134,76 @@ final class FhirGeneratorsTest extends CIUnitTestCase
|
|||
$this->assertSame('exp', $encExp['hospitalization']['dischargeDisposition']['coding'][0]['code']);
|
||||
}
|
||||
|
||||
public function testDischargeMedicationGenericSaltResolutionAndDisplay(): void
|
||||
{
|
||||
$generator = $this->factory->discharge();
|
||||
|
||||
// 1. Explicit salt passed in medication item
|
||||
$srcExplicit = [
|
||||
'record_id' => 8801,
|
||||
'completed_at' => '2026-10-19T10:00:00+05:30',
|
||||
'patient' => ['id' => 101, 'name' => 'John Doe', 'gender' => 'male', 'dob' => '1980-05-15'],
|
||||
'encounter' => ['id' => 8801, 'start' => '2026-10-15T10:00:00+05:30', 'end' => '2026-10-19T10:00:00+05:30'],
|
||||
'diagnoses' => [['text' => 'Acid Peptic Disorder']],
|
||||
'medications' => [
|
||||
[
|
||||
'name' => 'DOZPANTA DSR',
|
||||
'salt' => 'Pantoprazole + Domperidone',
|
||||
'dosage' => 'Take 1 Capsule Once daily before meals for 5 days',
|
||||
],
|
||||
[
|
||||
'name' => 'ACILOC 150',
|
||||
'generic' => 'Ranitidine',
|
||||
'dosage' => '1 Tab Twice daily for 3 days',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$outExplicit = $generator->generate($srcExplicit);
|
||||
$this->assertTrue((bool) ($outExplicit['validation']['valid'] ?? false));
|
||||
$bundleExp = $outExplicit['fhir_bundle'];
|
||||
|
||||
$medsExp = array_values(array_filter($bundleExp['entry'], static fn ($e) => ($e['resource']['resourceType'] ?? '') === 'MedicationRequest'));
|
||||
$this->assertCount(2, $medsExp);
|
||||
|
||||
// First med: DOZPANTA DSR with salt Pantoprazole + Domperidone
|
||||
$med1 = $medsExp[0]['resource'];
|
||||
$this->assertSame('DOZPANTA DSR', $med1['medicationCodeableConcept']['text']);
|
||||
$this->assertSame('Pantoprazole + Domperidone', $med1['medicationCodeableConcept']['coding'][0]['display']);
|
||||
$this->assertSame('395821003', $med1['medicationCodeableConcept']['coding'][0]['code']);
|
||||
$this->assertSame('DOZPANTA DSR', $med1['medicationCodeableConcept']['coding'][1]['display']);
|
||||
$this->assertStringContainsString('DOZPANTA DSR (Pantoprazole + Domperidone)', $med1['text']['div']);
|
||||
|
||||
// Second med: ACILOC 150 with salt Ranitidine
|
||||
$med2 = $medsExp[1]['resource'];
|
||||
$this->assertSame('ACILOC 150', $med2['medicationCodeableConcept']['text']);
|
||||
$this->assertSame('Ranitidine', $med2['medicationCodeableConcept']['coding'][0]['display']);
|
||||
$this->assertSame('372755005', $med2['medicationCodeableConcept']['coding'][0]['code']);
|
||||
$this->assertSame('ACILOC 150', $med2['medicationCodeableConcept']['coding'][1]['display']);
|
||||
|
||||
// 2. Heuristic resolution when salt is not explicitly given in source array
|
||||
$srcHeuristic = [
|
||||
'record_id' => 8802,
|
||||
'completed_at' => '2026-10-19T10:00:00+05:30',
|
||||
'patient' => ['id' => 102, 'name' => 'Jane Smith', 'gender' => 'female', 'dob' => '1992-08-20'],
|
||||
'encounter' => ['id' => 8802, 'start' => '2026-10-15T10:00:00+05:30', 'end' => '2026-10-19T10:00:00+05:30'],
|
||||
'diagnoses' => [['text' => 'Dyspepsia']],
|
||||
'medications' => [
|
||||
[
|
||||
'name' => 'DOZPANTA DSR',
|
||||
'dosage' => 'OD for 5 days',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$outHeuristic = $generator->generate($srcHeuristic);
|
||||
$this->assertTrue((bool) ($outHeuristic['validation']['valid'] ?? false));
|
||||
$medsHeu = array_values(array_filter($outHeuristic['fhir_bundle']['entry'], static fn ($e) => ($e['resource']['resourceType'] ?? '') === 'MedicationRequest'));
|
||||
$this->assertCount(1, $medsHeu);
|
||||
$this->assertSame('DOZPANTA DSR', $medsHeu[0]['resource']['medicationCodeableConcept']['text']);
|
||||
$this->assertSame('Pantoprazole + Domperidone', $medsHeu[0]['resource']['medicationCodeableConcept']['coding'][0]['display']);
|
||||
}
|
||||
|
||||
public function testPrescriptionGeneratorHappyPath(): void
|
||||
{
|
||||
$src = [
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user