def test_handle_success(self): cases = self.create_case_structure() cases[self.person_id] = self.assign_person_to_location(self.phi.location_id) payload_generator = RegisterPatientPayloadGenerator(None) payload_generator.handle_success(MockResponse(201, {"success": "hooray"}), cases[self.episode_id], None) updated_episode_case = CaseAccessors(self.domain).get_case(self.episode_id) self.assertEqual( updated_episode_case.dynamic_case_properties().get('dots_99_registered'), 'true' ) self.assertEqual( updated_episode_case.dynamic_case_properties().get('dots_99_error'), '' )
def test_handle_failure(self): payload_generator = RegisterPatientPayloadGenerator(None) error = { "error": "Something went terribly wrong", } payload_generator.handle_failure(MockResponse(400, error), self.cases[self.episode_id]) updated_episode_case = CaseAccessors(self.domain).get_case(self.episode_id) self.assertEqual( updated_episode_case.dynamic_case_properties().get('dots_99_registered'), 'false' ) self.assertEqual( updated_episode_case.dynamic_case_properties().get('dots_99_error'), "400: {}".format(error['error']) )
def testCreateThenUpdateInSeparateForms(self): # recycle our previous test's form xform1, original_case = bootstrap_case_from_xml(self, "create_update.xml") self.assertEqual(original_case.type, "test_case_type") self.assertEqual(original_case.name, "test case name") # we don't need to bother checking all the properties because this is # the exact same workflow as above. xform2, case = bootstrap_case_from_xml(self, "update.xml", original_case.case_id) # fetch the case from the DB to ensure it is property wrapped case = CaseAccessors().get_case(case.case_id) self.assertEqual(False, case.closed) if getattr(settings, 'TESTS_SHOULD_USE_SQL_BACKEND', False): self._check_transactions(case, [xform1, xform2]) self.assertTrue(case.transactions[0].is_case_create) else: self.assertEqual(3, len(case.actions)) new_update_action = case.actions[2] self.assertEqual(const.CASE_ACTION_UPDATE, new_update_action.action_type) self.assertEqual("http://openrosa.org/case/test/update", new_update_action.xform_xmlns) self.assertEqual("", new_update_action.xform_name) # updated prop self.assertEqual("abcd", new_update_action.updated_unknown_properties["someprop"]) # new prop self.assertEqual("efgh", new_update_action.updated_unknown_properties["somenewprop"]) # update original case fields self.assertEqual("a_new_type", new_update_action.updated_known_properties["type"]) self.assertEqual("a new name", new_update_action.updated_known_properties["name"]) self.assertEqual(UPDATE_DATE, new_update_action.updated_known_properties["opened_on"]) # some properties didn't change self.assertEqual("123", str(case.dynamic_case_properties()['someotherprop'])) # but some should have self.assertEqual("abcd", case.dynamic_case_properties()["someprop"]) # and there are new ones self.assertEqual("efgh", case.dynamic_case_properties()["somenewprop"]) # we also changed everything originally in the case self.assertEqual("a_new_type", case.type) self.assertEqual("a new name", case.name) self.assertEqual(coerce_to_datetime(UPDATE_DATE), coerce_to_datetime(case.opened_on)) # case should have a new modified date self.assertEqual(MODIFY_DATE, case.modified_on)
def test_update_and_reactivate_in_one_save(self): """ Confirm that a usercase can be updated and reactived in a single save of the user model """ """ Confirm that updating a deactivated user also updates the user case. """ self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id( self.user._id, USERCASE_TYPE) self.assertIsNotNone(user_case) self.user.is_active = False self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id( self.user._id, USERCASE_TYPE) self.assertTrue(user_case.closed) self.user.user_data = {'foo': 'bar'} self.user.is_active = True self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id( self.user._id, USERCASE_TYPE) self.assertFalse(user_case.closed) self.assertEqual(user_case.dynamic_case_properties()['foo'], 'bar')
def test_update_by_person(self): expected_update = { 'aggregated_score_date_calculated': datetime.date(2016, 1, 16), 'expected_doses_taken': 0, 'aggregated_score_count_taken': 0, # 1 day before should be adherence_schedule_date_start, 'adherence_latest_date_recorded': datetime.date(2016, 1, 16), 'adherence_total_doses_taken': 0 } episode = self.create_episode_case(datetime.date(2016, 1, 15), datetime.date(2016, 1, 17), 'schedule1', []) update_episode_adherence_properties(self.domain, self.person_id) episode = CaseAccessors(self.domain).get_case(episode.case_id) self.assertDictEqual( { key: episode.dynamic_case_properties()[key] for key in expected_update }, {key: str(val) for key, val in expected_update.iteritems() } # convert values to strings )
def test_sync_usercase_custom_user_data_on_create(self): """ Custom user data should be synced when the user is created """ self.user.user_data = { 'completed_training': 'yes', } self.user.save() case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertIsNotNone(case) self.assertEquals(case.dynamic_case_properties()['completed_training'], 'yes')
def test_handle_failure(self): cases = self.create_case_structure() payload_generator = UpdatePatientPayloadGenerator(None) error = { "error": "Something went terribly wrong", } payload_generator.handle_failure(MockResponse(400, error), cases[self.person_id], None) updated_episode_case = CaseAccessors(self.domain).get_case(self.episode_id) self.assertEqual( updated_episode_case.dynamic_case_properties().get('dots_99_error'), "400: {}".format(error['error']) )
def test_mandatory_field_smear_result(self): update_case(self.domain, self.test_id, {"result_grade": "scanty"}) test_case = CaseAccessors(self.domain).get_case(self.test_id) with self.assertRaisesMessage( NikshayRequiredValueMissing, "Mandatory value missing in one of the following LabSerialNo: {lsn}, ResultGrade: {rg}".format( lsn=test_case.dynamic_case_properties().get('lab_serial_number'), rg="scanty") ): NikshayFollowupPayloadGenerator(None).get_payload(self.repeat_record, test_case) update_case(self.domain, self.test_id, {"result_grade": "scanty", "max_bacilli_count": "10"}) test_case = CaseAccessors(self.domain).get_case(self.test_id) with self.assertRaisesMessage( NikshayRequiredValueMissing, "Mandatory value missing in one of the following LabSerialNo: {lsn}, ResultGrade: {rg}".format( lsn=test_case.dynamic_case_properties().get('lab_serial_number'), rg="scanty") ): NikshayFollowupPayloadGenerator(None).get_payload(self.repeat_record, test_case) update_case(self.domain, self.test_id, {"result_grade": "5+"}) test_case = CaseAccessors(self.domain).get_case(self.test_id) with self.assertRaisesMessage( NikshayRequiredValueMissing, "Mandatory value missing in one of the following LabSerialNo: {lsn}, ResultGrade: {rg}".format( lsn=test_case.dynamic_case_properties().get('lab_serial_number'), rg="5+") ): NikshayFollowupPayloadGenerator(None).get_payload(self.repeat_record, test_case) update_case(self.domain, self.test_id, {"result_grade": "1+"}) test_case = CaseAccessors(self.domain).get_case(self.test_id) NikshayFollowupPayloadGenerator(None).get_payload(self.repeat_record, test_case) update_case(self.domain, self.test_id, {"result_grade": "scanty", "max_bacilli_count": "1"}) test_case = CaseAccessors(self.domain).get_case(self.test_id) NikshayFollowupPayloadGenerator(None).get_payload(self.repeat_record, test_case)
def test_handle_success(self): date = datetime(2017, 2, 20) cases = self.create_case_structure() cases['adherence'] = self.create_adherence_cases([date])[0] adherence_id = cases['adherence'].case_id self.factory.create_or_update_case(CaseStructure( case_id=adherence_id, attrs={ 'create': False, 'update': {'dots_99_error': 'bad things'}, }, )) payload_generator = AdherencePayloadGenerator(None) payload_generator.handle_success(MockResponse(200, {"success": "hooray"}), cases['adherence'], None) updated_adherence_case = CaseAccessors(self.domain).get_case(adherence_id) self.assertEqual( updated_adherence_case.dynamic_case_properties().get('dots_99_error'), '' ) self.assertEqual( updated_adherence_case.dynamic_case_properties().get('dots_99_updated'), 'true' )
def test_sync_usercase_custom_user_data_on_update(self): """ Custom user data should be synced when the user is updated """ self.user.user_data = { 'completed_training': 'no', } self.user.save() self.user.user_data = { 'completed_training': 'yes', } sync_usercase(self.user) case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertEqual(case.dynamic_case_properties()['completed_training'], 'yes') self._check_update_matches(case, {'completed_training': 'yes'})
def test_handle_failure(self): date = datetime(2017, 2, 20) cases = self.create_case_structure() cases['adherence'] = self.create_adherence_cases([date])[0] adherence_id = cases['adherence'].case_id payload_generator = AdherencePayloadGenerator(None) error = { "error": "Something went terribly wrong", } payload_generator.handle_failure(MockResponse(400, error), cases['adherence'], None) updated_adherence_case = CaseAccessors(self.domain).get_case(adherence_id) self.assertEqual( updated_adherence_case.dynamic_case_properties().get('dots_99_error'), "400: {}".format(error['error']) )
def test_handle_success(self): cases = self.create_case_structure() self.factory.create_or_update_case(CaseStructure( case_id=self.episode_id, attrs={ 'create': False, 'update': {'dots_99_error': 'bad things'}, }, )) payload_generator = UpdatePatientPayloadGenerator(None) payload_generator.handle_success(MockResponse(200, {"success": "hooray"}), cases[self.person_id], None) updated_episode_case = CaseAccessors(self.domain).get_case(self.episode_id) self.assertEqual( updated_episode_case.dynamic_case_properties().get('dots_99_error'), '' )
def test_update_deactivated_user(self): """ Confirm that updating a deactivated user also updates the user case. """ self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertIsNotNone(user_case) self.user.is_active = False self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertTrue(user_case.closed) self.user.user_data = {'foo': 'bar'} self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertTrue(user_case.closed) self.assertEquals(user_case.dynamic_case_properties()['foo'], 'bar')
def test_update_deactivated_user(self): """ Confirm that updating a deactivated user also updates the user case. """ self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id( self.user._id, USERCASE_TYPE) self.assertIsNotNone(user_case) self.user.is_active = False self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id( self.user._id, USERCASE_TYPE) self.assertTrue(user_case.closed) self.user.update_metadata({'foo': 'bar'}) self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id( self.user._id, USERCASE_TYPE) self.assertTrue(user_case.closed) self.assertEqual(user_case.dynamic_case_properties()['foo'], 'bar')
def test_ledger_update_with_case_update(self): from corehq.apps.commtrack.tests.util import get_single_balance_block submit_case_blocks([ CaseBlock(case_id=self.case.case_id, update={'a': "1"}).as_string(), get_single_balance_block(self.case.case_id, self.product_a._id, 100)], DOMAIN ) self._assert_ledger_state(100) case = CaseAccessors(DOMAIN).get_case(self.case.case_id) self.assertEqual("1", case.dynamic_case_properties()['a']) if settings.TESTS_SHOULD_USE_SQL_BACKEND: transactions = CaseAccessorSQL.get_transactions(self.case.case_id) self.assertEqual(2, len(transactions)) self.assertTrue(transactions[0].is_form_transaction) # ordering not guaranteed since they have the same date self.assertTrue(transactions[1].is_form_transaction) self.assertTrue(transactions[1].is_ledger_transaction) self._assert_transactions([ self._expected_val(100, 100), ])
def test_update_and_reactivate_in_one_save(self): """ Confirm that a usercase can be updated and reactived in a single save of the user model """ """ Confirm that updating a deactivated user also updates the user case. """ self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertIsNotNone(user_case) self.user.is_active = False self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertTrue(user_case.closed) self.user.user_data = {'foo': 'bar'} self.user.is_active = True self.user.save() user_case = CaseAccessors(TEST_DOMAIN).get_case_by_domain_hq_user_id(self.user._id, USERCASE_TYPE) self.assertFalse(user_case.closed) self.assertEqual(user_case.dynamic_case_properties()['foo'], 'bar')
def test_ledger_update_with_case_update(self): submit_case_blocks([ CaseBlock(case_id=self.case.case_id, update={'a': "1"}).as_string(), BALANCE_BLOCK.format( case_id=self.case.case_id, product_id=self.product_a._id, quantity=100 )], DOMAIN ) self._assert_ledger_state(100) case = CaseAccessors(DOMAIN).get_case(self.case.case_id) self.assertEqual("1", case.dynamic_case_properties()['a']) if settings.TESTS_SHOULD_USE_SQL_BACKEND: transactions = CaseAccessorSQL.get_transactions(self.case.case_id) self.assertEqual(3, len(transactions)) self.assertEqual(CaseTransaction.TYPE_FORM, transactions[0].type) # ordering not guaranteed since they have the same date self.assertEqual( {CaseTransaction.TYPE_FORM, CaseTransaction.TYPE_LEDGER}, {t.type for t in transactions[1:]} )
class HistoricalAdherenceReport(EnikshayReport): name = ugettext_lazy('Historical Adherence') report_title = ugettext_lazy('Historical Adherence') slug = 'historical_adherence' use_datatables = False report_template_path = 'enikshay/historical_adherence.html' print_override_template = "enikshay/print_report.html" fields = (DatespanFilter, EpisodeFilter) emailable = False exportable = False printable = True def __init__(self, *args, **kwargs): super(HistoricalAdherenceReport, self).__init__(*args, **kwargs) try: self.episode = CaseAccessors(self.domain).get_case( self.episode_case_id) except CaseNotFound: raise BadRequestError() self.episode_properties = self.episode.dynamic_case_properties() self.person = get_person_case_from_episode(self.domain, self.episode_case_id) @classmethod def show_in_navigation(cls, domain=None, project=None, user=None): return False @classmethod def show_in_user_roles(cls, domain=None, project=None, user=None): return True @property def episode_case_id(self): return self.request.GET.get("episode_id") def decorator_dispatcher(self, request, *args, **kwargs): response = super(HistoricalAdherenceReport, self).decorator_dispatcher(request, *args, **kwargs) if not user_can_access_location_id( self.domain, self.request.couch_user, self.person.owner_id): raise location_restricted_exception(request) return response @property def headers(self): return DataTablesHeader() @property def rows(self): return [] @property def default_datespan(self): start = self.adherence_schedule_date_start utc_now = datetime.datetime.now(pytz.utc) india_now = utc_now.astimezone(india_timezone) end = india_now.date() datespan = DateSpan(start, end, timezone=india_timezone, inclusive=self.inclusive) datespan.max_days = self.datespan_max_days datespan.is_default = True return datespan @property def report_context(self): report_context = super(HistoricalAdherenceReport, self).report_context report_context['weeks'] = self.get_calendar() report_context['patient_name'] = self.person.name report_context['treatment_phase'] = self.get_treatment_phase() report_context['doses'] = self.get_doses() report_context['adherence_schedule'] = self.get_adherence_schedule( ).title report_context['patient_type'] = self.get_patient_type() return report_context def get_doses(self): adherence_cases = [] for day, cases in self.get_adherence_cases_dict().iteritems(): adherence_cases.extend(cases) doses_taken_by_date = EpisodeAdherenceUpdate.calculate_doses_taken_by_day( [c.to_json() for c in adherence_cases]) return EpisodeAdherenceUpdate.count_doses_taken(doses_taken_by_date) def get_treatment_phase(self): if self.episode_properties.get("treatment_initiated", False) in ("yes_phi", "yes_private"): if self.episode_properties.get("cp_initiated", False) == "yes": return "CP" return "IP" return "" def get_patient_type(self): type_ = self.episode_properties.get("patient_type_choice", None) return { "new": "New", "recurrent": "Recurrent", "treatment_after_failure": "Treatment after failure", "treatment_after_lfu": "Treatment after loss to follow up (LFU)", "other_previously_treated": "Other previously treated", }.get(type_, None) def get_adherence_schedule(self): schedule_id = self.episode_properties.get("adherence_schedule_id", "schedule_daily") # Note: This configuration is stored in the "adherence_schedules" fixture, but reproducing it here to avoid # extra db lookups, and because this information should be pretty static. return { # 0 is monday "schedule_daily": Schedule([0, 1, 2, 3, 4, 5, 6], False, 'Daily'), "schedule_trs": Schedule([1, 3, 5], True, 'Intermittent (TTS)'), "schedule_mwf": Schedule([0, 2, 4], True, 'Intermittent (MWF)'), }[schedule_id] @property def mark_expected(self): return self.get_adherence_schedule().mark_expected @property def expected_days(self): return self.get_adherence_schedule().days_dose_expected @property def adherence_schedule_date_start(self): day = self.episode_properties.get('adherence_schedule_date_start') if not day: day = self.episode_properties.get(TREATMENT_START_DATE) return parse(day).date() @memoized def get_adherence_cases_dict(self): return get_adherence_cases_by_day(self.domain, self.episode_case_id) def _get_first_sunday_before_or_equal_to(self, date): day = datetime.date(date.year, date.month, date.day) while day.weekday() != 6: # 6 is sunday day -= datetime.timedelta(days=1) return day def get_calendar(self): """ Return a list of Week objects """ adherence_cases_dict = self.get_adherence_cases_dict() first_date, last_date = self._get_date_range() assert first_date <= last_date calendar = [] # A list of Weeks sunday = self._get_first_sunday_before_or_equal_to(first_date) while sunday <= self._get_first_sunday_before_or_equal_to(last_date): days = [] for i in range(7): date = sunday + datetime.timedelta(days=i) if date >= first_date and date <= last_date: cases_for_date = adherence_cases_dict.get(date, []) days.append( Day( date, self.get_adherence_image_key(cases_for_date, date), self.show_unexpected_image(cases_for_date, date), len(cases_for_date) > 1, force_month_label=date == first_date, )) else: # The day won't be rendered on the screen, but a placeholder will appear days.append(None) calendar.append(Week(days)) sunday += datetime.timedelta(days=7) return calendar def _get_date_range(self): first_date = self.datespan.startdate last_date = self.datespan.enddate # Sometimes the report dispatcher sets the request.datespan dates to be datetimes :( try: first_date = first_date.date() except AttributeError: pass try: last_date = last_date.date() except AttributeError: pass return first_date, last_date def get_primary_adherence_case(self, adherence_cases): """ Return the case who's adherence value should be used. Cases with adherence_source == enikshay take precedence over other sources Then open cases tak precedence over other cases Then cases with a later modified_on take precedence over earlier cases Then cases with a later opened_on take precedence over earlier cases """ if not adherence_cases: return None def _source_is_enikshay(case): return case.dynamic_case_properties().get('adherence_source') in ( 'enikshay', '') return sorted(adherence_cases, key=lambda c: (_source_is_enikshay(c), not c.closed, c. modified_on, c.opened_on))[-1] def get_adherence_value(self, primary_adherence_case): if not primary_adherence_case: return None return primary_adherence_case.dynamic_case_properties().get( 'adherence_value') def get_adherence_source(self, primary_adherence_case): if not primary_adherence_case: return None return primary_adherence_case.dynamic_case_properties().get( 'adherence_source') def get_adherence_image_key(self, adherence_cases, date): primary_adherence_case = self.get_primary_adherence_case( adherence_cases) adherence_value = self.get_adherence_value(primary_adherence_case) if len(adherence_cases) == 0 or adherence_value == "missing_data": return self.unknown_img_holder(date) if adherence_value == "unobserved_dose": if self.get_adherence_source(primary_adherence_case) == "99DOTS": return "unobserved_dose_dot" return "unobserved_dose" if adherence_value not in ("dose_unknown_expected", "unobserved_dose_dot", "self_administered_dose", "unobserved_dose", "missed_dose", "directly_observed_dose", None, ""): assert_ = soft_assert(to='ncarnahan' + '@' + 'dimagi' + '.com') assert_( False, "Got an unexpected adherence_value of {} for case {}".format( adherence_value, primary_adherence_case.case_id)) return adherence_value def unknown_img_holder(self, date): if (self.mark_expected and self.adherence_schedule_date_start < date and date.weekday() in self.expected_days): return "dose_unknown_expected" def show_unexpected_image(self, adherence_cases, date): adherence_value = self.get_adherence_value( self.get_primary_adherence_case(adherence_cases)) return ((self.mark_expected and self.adherence_schedule_date_start < date) and len(adherence_cases) > 0 and adherence_value not in ("missed_dose", "missing_data") and date.weekday() not in self.expected_days)