Пример #1
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))
Пример #2
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
Пример #3
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})
Пример #4
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)
Пример #5
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()})
Пример #6
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"))
Пример #7
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})
Пример #8
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
Пример #9
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)
Пример #10
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()
Пример #11
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()
Пример #12
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()
Пример #13
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)
Пример #14
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()
Пример #15
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)
Пример #16
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()
Пример #17
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)