Skip to content

Commit

Permalink
Merge 8702d03 into 3f4e345
Browse files Browse the repository at this point in the history
  • Loading branch information
fredkingham committed Jan 11, 2023
2 parents 3f4e345 + 8702d03 commit 0b9c88e
Show file tree
Hide file tree
Showing 5 changed files with 681 additions and 14 deletions.
10 changes: 5 additions & 5 deletions elcid/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ def get_for_lookup_list(model, values):

class MergedMRN(models.Model):
"""
Represents each time this patient has had a duplicate MRN merged.
e.g. if MRN 77456 was merged into patient 123
Patient 123 would have a patient merge object with MRN 77456
Represents an MRN (unique identifier) that has been used to
represent a patient in an upstream system but is no longer active.
This does *not* include identifiers with leading zeros that have
sometimes been added as an implementation detail of other systems.
"""
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
mrn = models.CharField(max_length=256, unique=True, db_index=True)
Expand Down Expand Up @@ -70,7 +71,6 @@ def update_from_dict(self, data, *args, **kwargs):
return super().update_from_dict(data, *args, **kwargs)



class Demographics(PreviousMRN, omodels.Demographics, ExternallySourcedModel):
_is_singleton = True
_icon = 'fa fa-user'
Expand Down
41 changes: 34 additions & 7 deletions intrahospital_api/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def create_rfh_patient_from_hospital_number(hospital_number, episode_category, r
If a patient with this hospital number already exists raise ValueError
If a hospital number prefixed with zero is passed in raise ValueError
If the hospital number has already been merged into another raise ValueError
"""
if hospital_number.startswith('0'):
raise ValueError(
Expand All @@ -99,16 +100,24 @@ def create_rfh_patient_from_hospital_number(hospital_number, episode_category, r
if emodels.Demographics.objects.filter(hospital_number=hospital_number).exists():
raise ValueError('Patient with this hospital number already exists')

patient = Patient.objects.create()
if emodels.MergedMRN.objects.filter(mrn=hospital_number).exists():
raise ValueError('MRN has already been merged into another MRN')

demographics = patient.demographics()
demographics.hospital_number = hospital_number
demographics.save()
active_mrn, merged_mrn_dicts = update_demographics.get_active_mrn_and_merged_mrn_data(
hospital_number
)

patient.create_episode(
category_name=episode_category.display_name,
start=datetime.date.today()
patient = Patient.objects.create()
patient.demographics_set.update(
hospital_number=active_mrn
)
patient.episode_set.create(
category_name=episode_category.display_name
)

for merged_mrn_dict in merged_mrn_dicts:
patient.mergedmrn_set.create(**merged_mrn_dict)

load_patient(patient, run_async=run_async)
return patient

Expand Down Expand Up @@ -424,3 +433,21 @@ def _load_patient(patient, patient_load):
patient_load.failed()
else:
patient_load.complete()


def get_or_create_patient(mrn, episode_category, run_async=None):
patient = Patient.objects.filter(
demographics__hospital_number=mrn
).first()
if not patient:
patient = Patient.objects.filter(
mergedmrn__mrn=mrn
).first()

if patient:
patient.episode_set.get_or_create(
category_name=episode_category.display_name
)
return (patient, False)
patient = create_rfh_patient_from_hospital_number(mrn, episode_category, run_async=run_async)
return patient, True
200 changes: 198 additions & 2 deletions intrahospital_api/test/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from intrahospital_api.exceptions import BatchLoadError
from intrahospital_api.constants import EXTERNAL_SYSTEM
from plugins.labtests import models as lab_test_models
from plugins.tb import episode_categories as tb_episode_categories


@override_settings(API_USER="ohc")
Expand Down Expand Up @@ -682,8 +683,20 @@ def test_synch_patient(
)


@mock.patch('intrahospital_api.loader.load_patient')
class CreateRfhPatientFromHospitalNumberTestCase(OpalTestCase):
def test_creates_patient_and_episode(self):
@mock.patch(
'.'.join([
'intrahospital_api.loader.update_demographics',
'get_active_mrn_and_merged_mrn_data'
])
)
def test_creates_patient_and_episode(self, get_active_mrn_and_merged_mrn_data, load_patient):
"""
A patient has no merged MRNs. Create the patient with
the episode category and return it.
"""
get_active_mrn_and_merged_mrn_data.return_value = ('111', [])
patient = loader.create_rfh_patient_from_hospital_number(
'111', episode_categories.InfectionService
)
Expand All @@ -694,8 +707,12 @@ def test_creates_patient_and_episode(self):
patient.episode_set.get().category_name,
episode_categories.InfectionService.display_name
)
self.assertTrue(load_patient.called)

def test_errors_if_the_hospital_number_starts_with_a_zero(self):
def test_errors_if_the_hospital_number_starts_with_a_zero(self, load_patient):
"""
The MRN starts with a zero, raise a ValueError
"""
with self.assertRaises(ValueError) as v:
loader.create_rfh_patient_from_hospital_number(
'0111', episode_categories.InfectionService
Expand All @@ -705,3 +722,182 @@ def test_errors_if_the_hospital_number_starts_with_a_zero(self):
"Hospital numbers within elCID should never start with a zero"
])
self.assertEqual(str(v.exception), expected)
self.assertFalse(load_patient.called)

def test_errors_if_the_hospital_number_has_already_been_merged(self, load_patient):
"""
The MRN has already been merged, raise a Value Error
"""
patient, _ = self.new_patient_and_episode_please()
patient.mergedmrn_set.create(
mrn="111"
)
with self.assertRaises(ValueError) as v:
loader.create_rfh_patient_from_hospital_number(
'111', episode_categories.InfectionService
)
self.assertEqual(
str(v.exception),
"MRN has already been merged into another MRN"
)
self.assertFalse(load_patient.called)

@mock.patch(
'intrahospital_api.loader.update_demographics.get_active_mrn_and_merged_mrn_data'
)
def test_create_rfh_patient_from_hospital_number(
self, get_active_mrn_and_merged_mrn_data, load_patient
):
"""
The MRN passed in is inactive and has
an associated active MRN. Create a patient with the
active MRN and the associated mergedMRNs for the
MRN passed in.
"""
MERGED_MRN_DATA = [
{
"mrn": "123",
"merge_comments": " ".join([
"Merged with MRN 234 on Oct 21 2014 4:44PM",
]),
},
{
"mrn": "234",
"merge_comments": " ".join([
"Merged with MRN 123 Oct 17 2014 11:03AM",
"Merged with MRN 123 on Oct 21 2014 4:44PM",
"Merged with MRN 456 on Apr 14 2018 1:40PM"
]),
}
]
get_active_mrn_and_merged_mrn_data.return_value = ("456", MERGED_MRN_DATA)
patient = loader.create_rfh_patient_from_hospital_number(
'123', episode_category=episode_categories.InfectionService
)
self.assertEqual(
patient.demographics_set.get().hospital_number, "456"
)
self.assertEqual(patient.mergedmrn_set.count(), 2)

self.assertTrue(
patient.mergedmrn_set.filter(
mrn="123",
merge_comments=MERGED_MRN_DATA[0]["merge_comments"],
).exists()
)
self.assertTrue(
patient.mergedmrn_set.filter(
mrn="234",
merge_comments=MERGED_MRN_DATA[1]["merge_comments"],
).exists()
)
self.assertTrue(load_patient.called)

@mock.patch(
'intrahospital_api.loader.update_demographics.get_active_mrn_and_merged_mrn_data'
)
def test_active_mrn_with_inactive_associated_mrns(
self, get_active_mrn_and_merged_mrn_data, load_patient
):
"""
The MRN passed in is active and has an associated inactive MRN.
Create a patient with the active MRN and the associated mergedMRNs for the
other MRNs
"""
MERGED_MRN_DATA = [
{
"mrn": "123",
"merge_comments": " ".join([
"Merged with MRN 234 on Oct 21 2014 4:44PM",
]),
},
{
"mrn": "234",
"merge_comments": " ".join([
"Merged with MRN 123 Oct 17 2014 11:03AM",
"Merged with MRN 123 on Oct 21 2014 4:44PM",
"Merged with MRN 456 on Apr 14 2018 1:40PM"
]),
}
]
get_active_mrn_and_merged_mrn_data.return_value = ("456", MERGED_MRN_DATA)
patient = loader.create_rfh_patient_from_hospital_number(
'456', episode_category=episode_categories.InfectionService
)
self.assertEqual(
patient.demographics_set.get().hospital_number, "456"
)
self.assertEqual(patient.mergedmrn_set.count(), 2)

self.assertTrue(
patient.mergedmrn_set.filter(
mrn="123",
merge_comments=MERGED_MRN_DATA[0]["merge_comments"],
).exists()
)
self.assertTrue(
patient.mergedmrn_set.filter(
mrn="234",
merge_comments=MERGED_MRN_DATA[1]["merge_comments"],
).exists()
)
self.assertTrue(load_patient.called)


class GetOrCreatePatientTestCase(OpalTestCase):
def setUp(self):
self.patient, _ = self.new_patient_and_episode_please()

def test_get_existing_patient(self):
self.patient.demographics_set.update(hospital_number="123")
self.patient.episode_set.update(
category_name=episode_categories.InfectionService.display_name
)
patient, created = loader.get_or_create_patient(
'123', episode_categories.InfectionService
)
self.assertEqual(self.patient, patient)
episode = self.patient.episode_set.get()
self.assertEqual(
episode.category_name,
episode_categories.InfectionService.display_name
)
self.assertFalse(created)

def test_create_new_episode_on_existing_patient(self):
self.patient.demographics_set.update(hospital_number="123")
patient, created = loader.get_or_create_patient(
'123', tb_episode_categories.TbEpisode
)
self.assertEqual(self.patient, patient)
self.assertTrue(self.patient.episode_set.filter(
category_name=tb_episode_categories.TbEpisode.display_name
).exists())
self.assertFalse(created)

@mock.patch('intrahospital_api.loader.create_rfh_patient_from_hospital_number')
def test_get_merged_patient(self, create_rfh_patient_from_hospital_number):
self.patient.demographics_set.update(hospital_number="234")
self.patient.mergedmrn_set.create(mrn="123")
patient, created = loader.get_or_create_patient(
'123', episode_categories.InfectionService
)
self.assertEqual(
patient.id, self.patient.id
)
self.assertFalse(create_rfh_patient_from_hospital_number.called)
self.assertFalse(created)

@mock.patch('intrahospital_api.loader.create_rfh_patient_from_hospital_number')
def test_create_new_patient(self, create_rfh_patient_from_hospital_number):
create_rfh_patient_from_hospital_number.return_value = self.patient
patient, created = loader.get_or_create_patient(
'123', episode_categories.InfectionService
)
create_rfh_patient_from_hospital_number.assert_called_once_with(
'123',
episode_categories.InfectionService,
run_async=None
)
self.assertEqual(self.patient, patient)
self.assertTrue(created)
Loading

0 comments on commit 0b9c88e

Please sign in to comment.