def get_open_cases_to_send(clinic_id, zone, last_sync): """ Given a list of patients, get the open/updated cases since the last sync operation. This returns tuples phone_case objects, and flags that say whether or not they should be created """ to_return = [] case_ids = [] # find all relevant cases for the CHW and send them to the phone, unless # they have already been sent and haven't changed. potential_case_list = PatientCase.view_with_patient("case/open_for_chw_for_phone", key=[clinic_id, zone]) last_sync_date = datetime.min if not last_sync else last_sync.date for case in potential_case_list: # keep a running list of case ids sent down because the phone doesn't # deal well with duplicates. There shouldn't be duplicates, but they # can come up with bugs, so arbitrarily only send down the first case # if there are any duplicates if case.get_id not in case_ids: phone_case = PhoneCase.from_bhoma_case(case) if phone_case is None: # we don't expect to get into this scenario, but it can happen # don't fail hard with null reference below continue previously_synced = case_previously_synced(phone_case.case_id, last_sync) if phone_case and phone_case.is_started() and not phone_case.is_over(): # this is an active case, so send it unless it's a duplicate # or was already synced if phone_case.case_id in case_ids: logging.warning("Found a duplicate case for %s. Will not be sent to phone." % phone_case.case_id) elif previously_synced and phone_case.date_modified < last_sync_date: logging.debug("Case %s already sent to phone and no changes. Won't be sent again" % phone_case.case_id) else: case_ids.append(phone_case.case_id) to_return.append((phone_case, not previously_synced)) return to_return
def get_healthy_pregnancy_case(pregnancy, encounter): # Any pregnancy case that is created that hasn't been closed by a delivery # gets a followup. The followups become active at week 42 and expires in # week 46 of the pregnancy # The CHW should track the delivery and give an outcome to the pregnancy. lmp = pregnancy.lmp # TODO: is this check/logic necessary? if lmp: send_to_phone = True reason = "pregnancy_expecting_outcome" else: send_to_phone = False reason = "unknown_lmp" ltfu_date = lmp + timedelta(days=46*7) if lmp else None bhoma_case = PatientCase(_id=get_bhoma_case_id_from_pregnancy(pregnancy), opened_on=datetime.combine(encounter.visit_date, time()), modified_on=datetime.utcnow(), type=const.CASE_TYPE_PREGNANCY, encounter_id=encounter.get_id, patient_id=get_patient_id_from_form(encounter.get_xform()), ltfu_date=ltfu_date, outcome=pregnancy.outcome, closed=pregnancy.closed, closed_on=pregnancy.closed_on, send_to_phone=send_to_phone, send_to_phone_reason=reason) bhoma_case.status = "pending outcome" if send_to_phone and not bhoma_case.closed: cccase = get_first_commcare_case(encounter, bhoma_case=bhoma_case, case_id=get_commcare_case_id_from_block(encounter,bhoma_case)) cccase.followup_type = const.PHONE_FOLLOWUP_TYPE_PREGNANCY # starts and becomes active the same day, 42 weeks from LMP bhoma_case.lmp = lmp cccase.start_date = lmp + timedelta(days= 7 * 42) cccase.missed_appointment_date = cccase.start_date cccase.activation_date = cccase.start_date cccase.due_date = cccase.activation_date + timedelta(days=DAYS_AFTER_PREGNANCY_ACTIVE_DUE) bhoma_case.commcare_cases = [cccase] return bhoma_case
def duplicate_details(request, case_id): case_details = PatientCase.view("case/all_and_patient", key=case_id) return render_to_response('case/details.html', {"case_id": case_id, "cases" : case_details}, context_instance=RequestContext(request))
def get_delivery_case(patient, encounter, delivery): # All deliveries get two follow ups. if delivery.date: send_to_phone = True reason = "delivery_needing_followup" else: send_to_phone = False reason = "unknown_delivery_date" # todo proper ltfu date ltfu_date = delivery.date + timedelta(days=7*42) bhoma_case = PatientCase( _id=get_bhoma_case_id_from_delivery(delivery), opened_on=datetime.combine(encounter.visit_date, time()), modified_on=datetime.utcnow(), type=const.CASE_TYPE_DELIVERY, encounter_id=encounter.get_id, patient_id=patient._id, ltfu_date=ltfu_date, status="pending outcome", outcome=delivery.outcome, closed=delivery.closed, closed_on=delivery.closed_on, send_to_phone=send_to_phone, send_to_phone_reason=reason, ) if send_to_phone and not bhoma_case.closed: # we'll generate two commcare cases immedieately ccfu1 = get_first_commcare_case( encounter, bhoma_case=bhoma_case, case_id=get_commcare_case_id_from_delivery(delivery, 1) ) ccfu1.followup_type = const.PHONE_FOLLOWUP_TYPE_DELIVERY # starts after 4 days, active after 6 days ccfu1.start_date = delivery.date + timedelta(days=1) ccfu1.orig_visit_date = delivery.date ccfu1.missed_appointment_date = None # TODO: do we need to change this so the phone can use it? ccfu1.activation_date = delivery.date + timedelta(days=2) ccfu1.due_date = ccfu1.activation_date + timedelta(days=14) ccfu1.ltfu_date = ccfu1.activation_date + timedelta(days=24) ccfu1.visit_number = '1' ccfu2 = get_first_commcare_case( encounter, bhoma_case=bhoma_case, case_id=get_commcare_case_id_from_delivery(delivery, 2) ) ccfu2.followup_type = const.PHONE_FOLLOWUP_TYPE_DELIVERY # starts after 23 days, active after 28 days, due in 5, ltfu after 42 ccfu2.start_date = delivery.date + timedelta(days=23) ccfu2.orig_visit_date = delivery.date ccfu2.missed_appointment_date = None # TODO: do we need to change this so the phone can use it? ccfu2.activation_date = delivery.date + timedelta(days=28) ccfu2.due_date = ccfu2.activation_date + timedelta(days=5) ccfu2.ltfu_date = ccfu2.activation_date + timedelta(days=42) ccfu2.visit_number = '2' bhoma_case.commcare_cases = [ccfu1, ccfu2] return bhoma_case
def process_followup(patient, new_encounter): form = new_encounter.get_xform() assert form.namespace == config.CHW_FOLLOWUP_NAMESPACE caseblocks = extract_case_blocks(form) for caseblock in caseblocks: case_id = caseblock[const.CASE_TAG_ID] # find bhoma case try: results = get_db().view("case/bhoma_case_lookup", key=case_id, reduce=False).one() except MultipleResultsFound: logging.error("Found duplicate cases in a patient: patient_id: %s, case_id: %s" % (patient.get_id, case_id)) results = None if results: raw_data = results["value"] bhoma_case = PatientCase.wrap(raw_data) for case in bhoma_case.commcare_cases: if case.case_id == case_id: # apply generic commcare update to the case case.update_from_block(caseblock, new_encounter.visit_date) # apply custom updates to bhoma case bhoma_case_close_value = case.all_properties().get(const.CASE_TAG_BHOMA_CLOSE, None) bhoma_case_outcome_value = case.all_properties().get(const.CASE_TAG_BHOMA_OUTCOME, "") if bhoma_case_close_value and int(bhoma_case_close_value): # bhoma case should be closed if bhoma_case.closed: logging.warn("Tried to close case %s from phone but it was already closed! Ignoring." % bhoma_case.get_id) else: bhoma_case.closed = True bhoma_case.outcome = bhoma_case_outcome_value bhoma_case.closed_on = datetime.combine(new_encounter.visit_date, time()) else: # we didn't close the bhoma case, check if we need to # create any new commcare cases # referred back: create an appointment if bhoma_case_outcome_value == const.Outcome.REFERRED_BACK_TO_CLINIC: appt_date_string = form.xpath("met/followup/refer_when") if appt_date_string: new_case = new_commcare_case(case_id=get_commcare_case_id_from_block(new_encounter, bhoma_case), name=get_commcare_case_name(new_encounter, bhoma_case), type=bhoma_case.type, opened_on=datetime.combine(new_encounter.visit_date, time()), modified_on=datetime.utcnow(), user_id=get_user_id(new_encounter), encounter_id=new_encounter.get_id, bhoma_case_id=bhoma_case.get_id) new_case.followup_type = const.PHONE_FOLLOWUP_TYPE_MISSED_APPT appt_date = string_to_datetime(appt_date_string).date() add_missed_appt_dates(new_case, appt_date) bhoma_case.status = const.Status.RETURN_TO_CLINIC bhoma_case.commcare_cases.append(new_case) elif bhoma_case_outcome_value == const.Outcome.ACTUALLY_WENT_TO_CLINIC: bhoma_case.status = const.STATUS_WENT_BACK_TO_CLINIC elif bhoma_case_outcome_value == const.Outcome.PENDING_PATIENT_MEETING: bhoma_case.status = const.STATUS_PENDING_CHW_MEETING if is_delivery(bhoma_case): custom_process_delivery_case(bhoma_case, new_encounter) patient.update_cases([bhoma_case]) else: logging.error(("No case in patient %s with id %s found. " "If you are not debugging then this is a weird error.") % (patient.get_id, case_id))
def cases_for_patient(patient_id): """ Get the list of open cases for a particular patient """ return PatientCase.view_with_patient("case/open_for_patient", key=patient_id).all()
def cases_for_chw(chw): """ From chw clinic zone, get the list of open cases """ key = [chw.current_clinic_id, chw.current_clinic_zone] return PatientCase.view_with_patient("case/open_for_chw", key=key).all()