예제 #1
0
 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'),
         ''
     )
예제 #2
0
 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'])
     )
예제 #3
0
    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)
예제 #4
0
    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')
예제 #5
0
    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
        )
예제 #6
0
 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')
예제 #7
0
 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'])
     )
예제 #8
0
    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)
예제 #9
0
 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'
     )
예제 #10
0
 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'})
예제 #11
0
 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'])
     )
예제 #12
0
 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'),
         ''
     )
예제 #13
0
    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')
예제 #14
0
    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')
예제 #15
0
    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),
        ])
예제 #16
0
    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')
예제 #17
0
    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:]}
            )
예제 #18
0
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)