Exemple #1
0
 def _patient_wrapper(row):
     """
     The wrapper bolts the patient object onto the case, if we find
     it, otherwise does what the view would have done in the first
     place and adds an empty patient property
     """
     from bhoma.apps.patient.models import CPatient
     data = row.get('value')
     docid = row.get('id')
     doc = row.get('doc')
     if not data or data is None:
         return row
     if not isinstance(data, dict) or not docid:
         return row
     else:
         if 'rev' in data:
             data['_rev'] = data.pop('rev')
         case = cls.wrap(data)
         case.patient = None
         if doc == None:
             # there's (I think) a bug in couchdb causing these to come back empty
             try:
                 doc = CPatient.get_db().get(docid)
             except Exception, e:
                 pass
         if doc and doc.get("doc_type") == "CPatient":
             case.patient = CPatient.wrap(doc)
         return case
Exemple #2
0
def patient_excel(request):  
    # we have to make sure to update any patients without export tags
    # before redirecting to the export view.
    for pat in CPatient.view("patient/missing_export_tag", include_docs=True):
        try:
            pat.save()
        except ResourceConflict:
            # workaround potential conflicts by trying twice
            pat = CPatient.get(pat.get_id)
            pat.save()
    
    return HttpResponseRedirect("%s?export_tag=CPatient&filename=Patients" % reverse("export_data_async"))
Exemple #3
0
def create_patients(count, clinic_id):
    from bhoma.utils.data import random_person, random_clinic_id
    from bhoma.apps.patient.models import CPatient
    if clinic_id is None:  
        print "no clinic specified, will randomly assign ids"
    CPatient.get_db()
    for i in range(count):
        p = random_person()
        this_clinic_id = clinic_id if clinic_id else random_clinic_id()
        p.clinic_ids = [this_clinic_id,]
        p.save()
    print "successfully generated %s new patients" % count
Exemple #4
0
 def testRegeneratePatient(self):
     folder_name = os.path.join(os.path.dirname(__file__), "data", "chw")
     patient = export.import_patient_json_file(os.path.join(folder_name, "patient.json"))
     self.assertEqual(0, len(patient.encounters))
     with open(os.path.join(folder_name, "non_life_threatening_referral.xml"), "r") as f:
         formbody = f.read()
     formdoc = post_xform_to_couch(formbody)
     new_form_workflow(formdoc, SENDER_PHONE, None)
     patient = CPatient.get(patient.get_id)
     self.assertEqual(1, len(patient.encounters))
     self.assertTrue(reprocess(patient.get_id))
     patient = CPatient.get(patient.get_id)
     self.assertEqual(1, len(patient.encounters))
Exemple #5
0
def reprocess(patient_id):
    """
    Reprocess a patient's data from xforms, by playing them back in the order
    they are found.
    
    Returns true if successfully regenerated, otherwise false.
    """ 
    # you can't call the loader because the loader calls this
    patient = CPatient.get(patient_id)
    # first create a backup in case anything goes wrong
    backup_id = CPatient.copy(patient)
    try:
        # have to change types, otherwise we get conflicts with our cases
        backup = CPatient.get(backup_id)
        backup.doc_type = "PatientBackup"
        backup.save()
        
        # reload the original and blank out encounters/cases/version 
        patient = CPatient.get(patient_id)
        patient.encounters = []
        patient.cases = []
        
        # don't blank out pregnancies. we need them in order to preserve ids
        # patient.pregnancies = []
        patient.backup_id = backup_id
        patient.app_version = None # blanking out the version marks it "upgraded" to the current version
        patient.save()
        
        for form in patient.unique_xforms():
            add_form_to_patient(patient_id, form)
            # save to stick the new version on so we know we've upgraded this form
            if form.requires_upgrade():
                form.save()
        
        # only send the updated signal when all the dust has settled    
        patient_updated.send(sender="reprocessing", patient_id=patient_id)
        get_db().delete_doc(backup_id)
        return True
    
    except Exception, e:
        logging.exception("problem regenerating patient case data (patient: %s)" % patient_id)
        current_rev = get_db().get_rev(patient_id)
        patient = get_db().get(backup_id)
        patient["_rev"] = current_rev
        patient["_id"] = patient_id
        patient["doc_type"] = "CPatient"
        get_db().save_doc(patient)
        get_db().delete_doc(backup_id)
        return False
Exemple #6
0
def random_person():
    gender = random.choice([gen[0] for gen in GENDERS])
    first_name, last_name = random_male_name() if gender == GENDER_MALE else random_female_name()
    clinic = random_clinic_id()
    patient_id = "%s%06d" % (clinic, random.randint(0, 999999))
    patient = CPatient(first_name=first_name,
                       middle_name="",
                       patient_id=patient_id,
                       last_name=last_name,
                       birthdate=random_dob(),
                       birthdate_estimated = False,
                       gender = gender,
                       created_on = datetime.datetime.utcnow())
    patient.address = CAddress()
    patient.address.clinic_id = clinic
    return patient
Exemple #7
0
def pi_details(request):
    year = int(request.GET["year"])
    month = int(request.GET["month"])
    clinic = request.GET["clinic"]
    report_slug = request.GET["report"]
    col_slug = request.GET["col"]
    results = get_db().view(const.get_view_name(report_slug), reduce=False,
                            key=[year, month -1, clinic, col_slug], include_docs=True)
    forms = []
    for row in results:
        num, denom = row["value"]
        # only count forms for now, and make sure they have a patient id 
        # and contributed to the report denominator
        if row["doc"]["doc_type"] == "CXFormInstance" and denom > 0:
            form = CXFormInstance.wrap(row["doc"])
            try:
                form.patient_id = form.xpath("case/patient_id")
                form.bhoma_patient_id = CPatient.get(form.patient_id).formatted_id
            except ResourceNotFound:
                form.patient = form.patient_id = form.bhoma_patient_id = None
            form.num = num
            form.denom = denom
            form.good = num == denom
            forms.append(form)
        elif row["doc"]["doc_type"] == "PregnancyReportRecord" and denom > 0:
            # for the pregnancy PI force the aggregated pregnancy docs
            # to look like forms 
            preg = PregnancyReportRecord.wrap(row["doc"])
            try:
                preg.bhoma_patient_id = CPatient.get(preg.patient_id).formatted_id
            except ResourceNotFound:
                form.patient = form.patient_id = form.bhoma_patient_id = None
            preg.num = num
            preg.denom = denom
            preg.good = num == denom
            preg.encounter_date = preg.first_visit_date
            forms.append(preg)  
        
    title = "PI Details - %s: %s (%s, %s)" % (const.get_name(report_slug), 
                                              const.get_display_name(report_slug, col_slug),
                                              datetime(year, month, 1).strftime("%B %Y"),
                                              clinic_display_name(clinic))   
                                             
    return render_to_response(request, "reports/pi_details.html", 
                              {"report": {"name": title},
                               "forms": forms})
Exemple #8
0
def get_patient(patient_id):
    """
    Loads a patient from the database.  If any conflicts are detected this
    will run through all the xforms and regenerate the patient, deleting 
    all other revisions.
    """
    resolve_conflicts(patient_id)
    return CPatient.get(patient_id)
Exemple #9
0
 def wrapper_func(row):
     """
     Given a row of the view, get out a json representation of a patient row
     """
     patient = CPatient.wrap(row["doc"])
     return [patient.get_id,
             patient.formatted_id,
             patient.gender,
             patient.birthdate.strftime("%Y-%m-%d") if patient.birthdate else "",
             patient.current_clinic_display]
Exemple #10
0
def patient_case(request, patient_id, case_id):
    pat = CPatient.get(patient_id)
    found_case = None
    for case in pat.cases:
        if case.get_id == case_id:
            found_case = case
            break
    return render_to_response(request, "case/single_case.html", 
                              {"patient": pat,
                               "case": found_case,
                               "options": TouchscreenOptions.default()})
Exemple #11
0
def search_results(request):
    query = request.GET.get('q', '')
    if not query:
        return HttpResponseRedirect(reverse("patient_search"))
    patients = CPatient.view(VIEW_PATIENT_SEARCH, key=query.lower(), include_docs=True)
    minus_duplicates = SortedDict()
    for patient in patients:
        if not patient.get_id in minus_duplicates:
            minus_duplicates[patient.get_id] = patient
    return render_to_response(request, "patient/search_results.html", 
                              {"patients": minus_duplicates.values(), 
                               "query": query} ) 
Exemple #12
0
def lookup_by_id(request):
    """
    Get a patient by ID, returning the json representation of the patient
    """
    pat_id = request.GET.get('id')
    if pat_id != None:
        patients = CPatient.view(VIEW_PATIENT_BY_BHOMA_ID, key=pat_id, reduce=False, include_docs=True).all()
        return _patient_list_response(patients)
    else:
        pat_uuid = request.GET.get('uuid')
        patient = loader.get_patient(pat_uuid)
        return HttpResponse(json.dumps(patient.to_json()), mimetype='text/json')
Exemple #13
0
def export_patient_download(request, patient_id):
    """
    Export a patient's forms to a zip file.
    """
    # this may not perform with huge amounts of data, but for a single 
    # patient should be fine
    patient = CPatient.get(patient_id)
    temp_file = export.export_patient(patient)
    data = temp_file.read()
    response = HttpResponse(data, content_type='application/zip')
    response['Content-Disposition'] = 'attachment; filename=%s' % export.get_zip_filename(patient)
    response['Content-Length'] = len(data)
    return response
Exemple #14
0
def export_patient(request, patient_id):
    patient = CPatient.get(patient_id)
    count = 1
    form_filenames = []
    for form in patient.xforms():
        form_filenames.append(export.get_form_filename(count,  form))
        count += 1
    return render_to_response(request, "patient/export_instructions.html", 
                              {"patient": patient,
                               "zip_filename": export.get_zip_filename(patient),
                               "foldername": export.get_zip_filename(patient).split(".")[0],
                               "pat_filename": export.get_patient_filename(patient),
                               "forms": form_filenames})
Exemple #15
0
 def testUpdate(self):
     patient = random_person()
     case = bootstrap_case_from_xml(self, "create_update.xml")
     patient.cases=[case,]
     patient.save()
     # make sure we can get it back from our shared view
     case_back = CommCareCase.get_with_patient("case/all_and_patient", case.case_id)
     self.assertEqual(case.case_id, case_back.case_id)
     self.assertEqual(patient.first_name, case_back.patient.first_name)
     self.assertEqual(patient.last_name, case_back.patient.last_name)
     self.assertEqual(patient.get_id, case_back.patient.get_id)
     self.assertEqual(1, len(patient.cases))
     self.assertEqual(case._id, patient.cases[0]._id)
     
     # update
     case = bootstrap_case_from_xml(self, "update.xml", case.case_id)
     self.assertEqual(patient.get_id, case.patient.get_id)
     case.save()
     
     patient = CPatient.get(patient.get_id)
     self.assertEqual(1, len(patient.cases))
     case_in_patient = patient.cases[0]
     self.assertEqual(case._id, case_in_patient._id)
     
     self.assertEqual(False, case_in_patient.closed)
     self.assertEqual(3, len(case_in_patient.actions))
     new_update_action = case_in_patient.actions[2]
     self.assertEqual(const.CASE_ACTION_UPDATE, new_update_action["action_type"])
     
     # some properties didn't change
     self.assertEqual("123", str(case["someotherprop"]))
     
     # but some should have
     self.assertEqual("abcd", case_in_patient["someprop"])
     self.assertEqual("abcd", new_update_action["someprop"])
     
     # and there are new ones
     self.assertEqual("efgh", case_in_patient["somenewprop"])
     self.assertEqual("efgh", new_update_action["somenewprop"])
     
     # we also changed everything originally in the case
     self.assertEqual("a_new_type", case_in_patient.type)
     self.assertEqual("a_new_type", new_update_action["type"])
     self.assertEqual("a new name", case_in_patient.name)
     self.assertEqual("a new name", new_update_action["name"])        
     self.assertEqual(UPDATE_DATE, case_in_patient.opened_on)
     self.assertEqual(UPDATE_DATE, new_update_action["opened_on"])
     
     # case should have a new modified date
     self.assertEqual(MODIFY_DATE, case.modified_on)
Exemple #16
0
def fuzzy_match(request):
    # TODO this currently always returns nothing
    fname = request.POST.get('fname')
    lname = request.POST.get('lname')
    gender = request.POST.get('sex')
    dob = request.POST.get('dob')
    def prep(val):
        return val.strip().lower() if val and isinstance(val, basestring) else val
    
    startkey = map(prep, [gender, lname, fname, dob])
    endkey = map(prep, [gender, lname, fname, dob, {}])
    pats = CPatient.view(VIEW_PATIENT_FUZZY_SEARCH, startkey=startkey,
                         endkey=endkey, reduce=False, include_docs=True).all()
    return _patient_list_response(pats)
Exemple #17
0
def insert_zscores(sender, form, **kwargs):
    """For Under5, hook up zscore calculated"""
    from bhoma.apps.zscore.models import Zscore
    from bhoma.apps.patient.models import CPatient
    
    patient_id = form.xpath("case/patient_id")
    
    if not patient_id or not get_db().doc_exist(patient_id):  
        return
    
    patient = CPatient.get(patient_id)
    if form["#type"] == "underfive" and patient.age_in_months <= 60:
        
        form.zscore_calc_good = []
        try:
            zscore = Zscore.objects.get(gender=patient.gender, age=patient.age_in_months)
        except Zscore.DoesNotExist:
            # how is this possible?
            zscore = None
            
        if zscore and form.xpath("nutrition/weight_for_age") and form.xpath("vitals/weight"):
            def calculate_zscore(l_value,m_value,s_value,x_value):
                #for L != 0, Z = (((X/M)^L)-1)/(L*S)
                eval_power = pow((float(x_value) / m_value),l_value)
                return ((eval_power - 1) / (l_value * s_value))
            
            def compare_sd(zscore_value):
                if zscore_value >= 0: 
                    return "0"
                elif 0 > zscore_value and zscore_value >= -2: 
                    return "-2"
                elif -2 > zscore_value and zscore_value >= -3: 
                    return "-3"
                elif -3 > zscore_value:
                    return "below -3"
            
            zscore_num = calculate_zscore(zscore.l_value, zscore.m_value, zscore.s_value, form["vitals"]["weight"])
            sd_num = compare_sd(zscore_num)
            
            if form.xpath("nutrition/weight_for_age") == sd_num:
                form.zscore_calc_good = "true"
            else:
                form.zscore_calc_good = "false"
        
        else:
            form.zscore_calc_good = "unable_to_calc"
        
        form.save()
Exemple #18
0
def close_ltfu_cases(sender, patient_id, **kwargs):
    """
    Checks if any open cases in the patient are passed the LTFU date
    and if they are closes them with status lost to followup.
    """
    from bhoma.apps.patient.models import CPatient
    from bhoma.apps.case.bhomacaselogic.ltfu import close_as_lost
    patient = CPatient.get(patient_id)
    save_pat = False
    for case in patient.cases:
        today = datetime.utcnow().date()
        if not case.closed and case.ltfu_date and case.ltfu_date < today:
            close_as_lost(case)
            save_pat = True
    if save_pat:
        patient.save()
Exemple #19
0
def update_pregnancy_report_data(sender, patient_id, **kwargs):
    """
    Update pregnancies of a patient.
    """
    from bhoma.apps.reports.calc.pregnancy import PregnancyReportData
    from bhoma.apps.reports.models import PregnancyReportRecord
    from bhoma.apps.patient.models import CPatient
    
    patient = CPatient.get(patient_id)
    # manually remove old pregnancies, since all pregnancy data is dynamically generated
    for old_preg in PregnancyReportRecord.view("reports/pregnancies_for_patient", key=patient_id, include_docs=True).all():
        old_preg.delete() 
    for preg in patient.pregnancies:
        preg_report_data = PregnancyReportData(patient, preg)
        couch_pregnancy = preg_report_data.to_couch_object()
        couch_pregnancy.save()
Exemple #20
0
def new_form_received(patient_id, form):
    """
    A new form was received for a patient.  This usually just adds the form
    to the patient object, but will fully reprocess the patient data if the
    form is from the past, so that previously-entered but later-occurring 
    changes can be applied to the data
    """
    patient = CPatient.get(patient_id)
    encounter_date = Encounter.get_visit_date(form)
    full_reprocess = False
    for encounter in patient.encounters:
        if encounter.visit_date > encounter_date:
            full_reprocess = True
            break
    
    if full_reprocess:
        reprocess(patient_id)
    else:
        add_form_to_patient(patient_id, form)
Exemple #21
0
def update_patient_deceased_status(sender, patient_id, **kwargs):
    """
    Check if any of the cases are resolved with type death and
    if so, mark the patient as deceased.  
    """
    from bhoma.apps.patient.models import CPatient
    patient = CPatient.get(patient_id)
    if not patient.is_deceased:
        for case in patient.cases:
            if case.outcome == Outcome.PATIENT_DIED:
                patient.handle_died()
                patient.save()
    else:
        save_pat = False
        for case in patient.cases:
            if not case.closed:
                case.manual_close(Outcome.PATIENT_DIED, datetime.utcnow())
                save_pat = True
        if save_pat:
            patient.save()
Exemple #22
0
 def testLifeThreatening(self):
     folder_name = os.path.join(os.path.dirname(__file__), "data", "chw")
     patient = export.import_patient_json_file(os.path.join(folder_name, "patient.json"))
     self.assertEqual(0, len(patient.encounters))
     self.assertEqual(0, len(patient.cases))
     add_form_with_date_offset\
             (None, os.path.join(folder_name, "life_threatening_referral.xml"),
              days_from_today=0)
     patient = CPatient.get(patient.get_id)
     self.assertEqual(1, len(patient.encounters))
     [case] = patient.cases
     [ccase] = case.commcare_cases
     self.assertFalse(ccase.closed)
     visit_date = datetime.utcnow().date()
     self.assertEqual("referral_no_show", ccase.followup_type)
     self.assertFalse(ccase.closed)
     self.assertEqual(visit_date + timedelta(days=3), ccase.start_date)
     self.assertEqual(visit_date + timedelta(days=3), ccase.activation_date)
     self.assertEqual(visit_date + timedelta(days=3), ccase.due_date)
     self.assertEqual(visit_date + timedelta(days=42), case.ltfu_date)
     self.assertEqual("new_clinic_referral|fever headache", ccase.name)
Exemple #23
0
def add_form_to_patient(patient_id, form):
    """
    Adds a clinic form to a patient, including all processing necessary.
    """
    
    patient = CPatient.get(patient_id)
    new_encounter = Encounter.from_xform(form)
    patient.encounters.append(new_encounter)
    
    encounter_info = ENCOUNTERS_BY_XMLNS.get(form.namespace)
    if not encounter_info:
        raise Exception("Attempt to add unknown form type: %s to patient %s!" % \
                        (form.namespace, patient_id))
    
    if encounter_info.classification == CLASSIFICATION_CLINIC:
        case = get_or_update_bhoma_case(form, new_encounter)
        if case:
            patient.cases.append(case)
        
        if is_pregnancy_encounter(new_encounter):
            update_pregnancies(patient, new_encounter)

        if is_delivery_encounter(new_encounter):
            update_deliveries(patient, new_encounter)

    elif encounter_info.classification == CLASSIFICATION_PHONE:
        # process phone form
        process_phone_form(patient, new_encounter)
    else:
        logging.error("Unknown classification %s for encounter: %s" % \
                      (encounter_info.classification, form.get_id))
    
    # finally close any previous cases we had open, according
    # to the complicated rules
    close_previous_cases_from_new_form(patient, form, new_encounter)
    patient.save()
Exemple #24
0
def new_encounter(request, patient_id, encounter_slug):
    """A new encounter for a patient"""
    encounter_info = CLINIC_ENCOUNTERS[encounter_slug]
    
    def callback(xform, doc):
        if doc:
            new_form_workflow(doc, SENDER_CLINIC, patient_id)
        return HttpResponseRedirect(reverse("single_patient", args=(patient_id,)))  

    patient = CPatient.get(patient_id)

    xform = encounter_info.get_xform()
    # TODO: generalize this better
    preloader_tags = {"case": {"patient_id" : patient_id,
                               "age_years" : str(patient.age) if patient.age != None else '',
                               "dob": patient.birthdate.strftime('%Y-%m-%d') if patient.birthdate else '',
                               "gender" : patient.gender,
                               "bhoma_case_id" : "<uid>",
                               "case_id" : "<uid>"},
                      "meta": {"clinic_id": settings.BHOMA_CLINIC_ID,
                               "user_id":   request.user.get_profile()._id,
                               "username":  request.user.username}}
                               
    return xforms_views.play(request, xform.id, callback, preloader_tags)
Exemple #25
0
def delete_all_patients():
    for pat in CPatient.view(const.VIEW_PATIENT_BY_BHOMA_ID, reduce=False, include_docs=True).all():
        pat.delete()