Skip to content

Commit

Permalink
Migration for Orgs, Facility, Patients and Consultations
Browse files Browse the repository at this point in the history
  • Loading branch information
sainak committed Jan 21, 2025
1 parent d3c263a commit 4094827
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
# Generated by Django 5.1.4 on 2025-01-14 09:20

import django.db.models.deletion
from django.db import migrations, models

import logging
from django.core.paginator import Paginator

logger = logging.getLogger(__name__)


MIGRARION_ID = 413370
COUNTRY = "India"

def _get_org(Organization, obj):
if obj.ward_id:
return Organization.objects.get(name=obj.ward.name)
elif obj.local_body_id:
return Organization.objects.get(name=obj.local_body.name)
elif obj.district_id:
return Organization.objects.get(name=obj.district.name)
elif obj.state_id:
return Organization.objects.get(name=obj.state.name)
return None

def migrate_organizations(apps, schema_editor):
Organization = apps.get_model("emr", "Organization")
State = apps.get_model("users", "State")
District = apps.get_model("users", "District")
LocalBody = apps.get_model("users", "LocalBody")
Ward = apps.get_model("users", "Ward")

logger.debug("Migrating Organization")
for state_obj in State.objects.all():
state_org = Organization.objects.create(
name=state_obj.name,
org_type="govt",
system_generated=True,
metadata={
"country": COUNTRY,
"govt_org_type": "state",
"govt_org_children_type": "district",
},
meta= {"migration_id": MIGRARION_ID},
)
logger.debug(f"Created State: {state_org.name=}")
for district_obj in District.objects.filter(state=state_obj):
district_org = Organization.objects.create(
name=district_obj.name,
root_org=state_org,
parent=state_org,
org_type="govt",
system_generated=True,
metadata={
"country": COUNTRY,
"govt_org_type": "district",
"govt_org_children_type": "local_body",
},
meta= {"migration_id": MIGRARION_ID},
)
logger.debug(f"Created District: {state_org.name=}, {district_org.name=}")
for local_body_obj in LocalBody.objects.filter(district=district_obj):
local_body_org = Organization.objects.create(
name=local_body_obj.name,
root_org=state_org,
parent=district_org,
org_type="govt",
system_generated=True,
metadata={
#TODO: add old types
"country": COUNTRY,
"govt_org_type": "local_body",
"govt_org_children_type": "ward",
},
meta= {"migration_id": MIGRARION_ID},
)
logger.debug(f"Created Local Body: {state_org.name=}, \
{district_org.name=}, {local_body_org.name=}")
for ward_obj in Ward.objects.filter(local_body=local_body_obj):
ward_org = Organization.objects.create(
name=ward_obj.name,
root_org=state_org,
parent=local_body_org,
org_type="govt",
system_generated=True,
metadata={
#TODO: add ward numbers
"country": COUNTRY,
"govt_org_type": "ward",
},
meta= {"migration_id": MIGRARION_ID},
)
logger.debug(f"Created Ward: {state_org.name=}, \
{district_org.name=}, {local_body_org.name=}, \
{ward_org.name=}")


def reverse_migrate_organizations(apps, schema_editor):
logger.debug("Reversing Migration Organization")
schema_editor.execute("DELETE FROM emr_organization WHERE meta->>'migration_id' = %s", [MIGRARION_ID])


def migrate_users(apps, schema_editor):
User = apps.get_model("users", "User")
Organization = apps.get_model("emr", "Organization")
logger.debug("Migrating Users")
bulk_update = []
for user in User.objects.all().select_related("state", "district", "local_body", "ward"):
if user.geo_organization:
continue
geo_org = _get_org(Organization, user)
if not geo_org:
continue
user.geo_organization = geo_org
logger.debug(f"User: {user.name=}, {geo_org.name=}")
bulk_update.append(user)
User.objects.bulk_update(bulk_update, ["geo_organization"])

def reverse_migrate_users(apps, schema_editor):
User = apps.get_model("users", "User")
User.objects.filter(
geo_organization__meta__migration_id=MIGRARION_ID
).update(
geo_organization=None
)


def migrate_facilities(apps, schema_editor):
Facility = apps.get_model("facility", "Facility")
Organization = apps.get_model("emr", "Organization")
bulk_update = []
for facility in Facility.objects.all().select_related("state", "district", "local_body", "ward"):
if facility.geo_organization:
continue
geo_org = _get_org(Organization, facility)
if not geo_org:
continue
facility.geo_organization = geo_org
#TODO: create facility organization
bulk_update.append(facility)
Facility.objects.bulk_update(bulk_update, ["geo_organization"])

def reverse_migrate_facilities(apps, schema_editor):
Facility = apps.get_model("facility", "Facility")
Facility.objects.filter(
geo_organization__meta__migration_id=MIGRARION_ID
).update(
geo_organization=None
)

def migrate_patient_registrations(apps, schema_editor):
PatientRegistration = apps.get_model("facility", "PatientRegistration")
Patient = apps.get_model("emr", "Patient")
Organization = apps.get_model("emr", "Organization")

gender_map = {
1: "male",
2: "female",
3: "non_binary",
}
blood_group_map = {
"A+": "A_positive",
"A-": "A_negative",
"B+": "B_positive",
"B-": "B_negative",
"AB+": "AB_positive",
"AB-": "AB_negative",
"O+": "O_positive",
"O-": "O_negative",
"UNK": "unknown",
}

logger.debug("Migrating Patient Registrations")
patient_registrations = PatientRegistration.objects.all()
paginator = Paginator(patient_registrations, 2000)

for page_number in paginator.page_range:
page = paginator.page(page_number)
bulk = []
for patient_registration in page.object_list:
patient = Patient.objects.create(
name=patient_registration.name,
gender=gender_map.get(patient_registration.gender, ""),
phone_number=patient_registration.phone_number,
emergency_phone_number=patient_registration.emergency_phone_number,
address=patient_registration.address,
permanent_address=patient_registration.permanent_address,
pincode=patient_registration.pincode,
date_of_birth=patient_registration.date_of_birth,
year_of_birth=patient_registration.year_of_birth,
deceased_datetime=patient_registration.death_datetime,
blood_group=blood_group_map.get(patient_registration.blood_group, ""),
geo_organization=_get_org(Organization, patient_registration),
meta={
"migration_id": MIGRARION_ID,
},
created_by=patient_registration.created_by,
updated_by=patient_registration.updated_by,
created_at=patient_registration.created_at,
updated_at=patient_registration.updated_at,
)
patient_registration.migrated_emr_patient_id = patient.id
bulk.append(patient_registration)
logger.debug(f"Created Patient: {patient.name=}")
PatientRegistration.objects.bulk_update(bulk, ["migrated_emr_patient_id"])

def reverse_migrate_patient_registrations(apps, schema_editor):
PatientRegistration = apps.get_model("facility", "PatientRegistration")
PatientRegistration.objects.update(migrated_emr_patient_id=None)
schema_editor.execute("DELETE FROM emr_patient WHERE meta->>'migration_id' = %s", [MIGRARION_ID])


def migrate_consultations(apps, schema_editor):
PatientConsultation = apps.get_model("facility", "PatientConsultation")
Encounter = apps.get_model("emr", "Encounter")

paginator = Paginator(PatientConsultation.objects.all(), 2000)

for page_number in paginator.page_range:
page = paginator.page(page_number)
bulk = []
for patient_consultation in page.object_list:
encounter = Encounter.objects.create(
meta={
"migration_id": MIGRARION_ID,
},
created_by=patient_consultation.created_by,
updated_by=patient_consultation.updated_by,
created_at=patient_consultation.created_at,
updated_at=patient_consultation.updated_at,
)
patient_consultation.migrated_emr_encounter_id = encounter.id
bulk.append(patient_consultation)
logger.debug(f"Created Encounter: {encounter.id=}")
PatientConsultation.objects.bulk_update(bulk, ["migrated_emr_encounter_id"])



def reverse_migrate_consultations(apps, schema_editor):
pass

class Migration(migrations.Migration):

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('facility', '0476_facility_default_internal_organization_and_more'),
]

operations = [
migrations.DeleteModel(
name='HistoricalPatientRegistration',
),
migrations.AddField(
model_name='patientconsultation',
name='migrated_emr_encounter_id',
field=models.BigIntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='patientregistration',
name='migrated_emr_patient_id',
field=models.BigIntegerField(blank=True, null=True),
),
migrations.CreateModel(
name='MigrationTracking',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('old_model_obj_id', models.BigIntegerField()),
('new_model_obj_id', models.BigIntegerField()),
('field', models.CharField(max_length=255)),
('data', models.TimeField()),
('new_model', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='new_model', to='contenttypes.contenttype')),
('old_model', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='old_model', to='contenttypes.contenttype')),
],
),
migrations.RunPython(migrate_organizations, reverse_migrate_organizations),
migrations.RunPython(migrate_users, reverse_migrate_users),
migrations.RunPython(migrate_facilities, reverse_migrate_facilities),
migrations.RunPython(migrate_patient_registrations, reverse_migrate_patient_registrations),
migrations.RunPython(migrate_consultations, reverse_migrate_consultations),
]
1 change: 1 addition & 0 deletions care/facility/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
from .shifting import * # noqa
from .stats import * # noqa
from .notification import * # noqa
from .migration_tracking import * # noqa
22 changes: 22 additions & 0 deletions care/facility/models/migration_tracking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.contrib.contenttypes.models import ContentType
from django.db import models


class MigrationTracking(models.Model):
"""
Model to track the migrations that have been run on the database.
"""

old_model = models.ForeignKey(
ContentType, on_delete=models.CASCADE, related_name="old_model"
)
old_model_obj_id = models.BigIntegerField()
new_model = models.ForeignKey(
ContentType, on_delete=models.CASCADE, related_name="new_model"
)
new_model_obj_id = models.BigIntegerField()
field = models.CharField(max_length=255)
data = models.TimeField()

def __str__(self):
return f"{self.old_model}({self.old_model_obj_id}) -> {self.new_model} : {self.field}"
5 changes: 3 additions & 2 deletions care/facility/models/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from django.template.defaultfilters import pluralize
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from simple_history.models import HistoricalRecords

from care.facility.models import (
DISEASE_CHOICES,
Expand Down Expand Up @@ -447,7 +446,9 @@ class TestTypeEnum(enum.Enum):

organization_cache = ArrayField(models.IntegerField(), default=list)

history = HistoricalRecords(excluded_fields=["meta_info"])
migrated_emr_patient_id = models.BigIntegerField(null=True, blank=True)

# history = HistoricalRecords(excluded_fields=["meta_info"])

objects = BaseManager()

Expand Down
2 changes: 2 additions & 0 deletions care/facility/models/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ class PatientConsultation(PatientBaseModel, ConsultationRelatedPermissionMixin):
default=list,
)

migrated_emr_encounter_id = models.BigIntegerField(null=True, blank=True)

def get_related_consultation(self):
return self

Expand Down

0 comments on commit 4094827

Please sign in to comment.