Example #1
0
def create_aww_indicator_3(domain):
    with transaction.atomic():
        schedule = TimedSchedule.create_simple_daily_schedule(
            domain,
            TimedEvent(time=time(9, 0)),
            CustomContent(custom_content_id='ICDS_MISSED_CF_VISIT_TO_AWW'),
            total_iterations=1,
            start_offset=1,
        )
        schedule.default_language_code = 'hin'
        schedule.custom_metadata = {'icds_indicator': 'aww_3'}
        schedule.save()
        rule = AutomaticUpdateRule.objects.create(
            domain=domain,
            name="AWW #3: Missed CF #1",
            case_type='ccs_record',
            active=True,
            deleted=False,
            filter_on_server_modified=False,
            server_modified_boundary=None,
            migrated=True,
            workflow=AutomaticUpdateRule.WORKFLOW_SCHEDULING,
        )
        rule.add_criteria(
            MatchPropertyDefinition,
            property_name='cf1_date',
            match_type=MatchPropertyDefinition.MATCH_HAS_NO_VALUE,
        )
        rule.add_action(
            CreateScheduleInstanceActionDefinition,
            timed_schedule_id=schedule.schedule_id,
            recipients=(('Owner', None),),
            scheduler_module_info=CreateScheduleInstanceActionDefinition.SchedulerModuleInfo(
                enabled=True,
                app_id='48cc1709b7f62ffea24cc6634a004745',
                form_unique_id='84ea09b6aa5aba125ec82bf2bb8dfa44cc5ea150',
                visit_number=0,
                window_position=VISIT_WINDOW_END,
            ),
        )
Example #2
0
def _create_ls_indicator_5(domain, visit_num):
    with transaction.atomic():
        schedule = TimedSchedule.create_simple_daily_schedule(
            domain,
            TimedEvent(time=time(9, 0)),
            CustomContent(custom_content_id='ICDS_MISSED_PNC_VISIT_TO_LS'),
            total_iterations=1,
            start_offset=1,
        )
        schedule.default_language_code = 'hin'
        schedule.custom_metadata = {'icds_indicator': 'ls_5'}
        schedule.save()
        rule = AutomaticUpdateRule.objects.create(
            domain=domain,
            name="LS #5: Missed PNC #%s" % visit_num,
            case_type='ccs_record',
            active=True,
            deleted=False,
            filter_on_server_modified=False,
            server_modified_boundary=None,
            migrated=True,
            workflow=AutomaticUpdateRule.WORKFLOW_SCHEDULING,
        )
        rule.add_criteria(
            MatchPropertyDefinition,
            property_name='pnc%s_date' % visit_num,
            match_type=MatchPropertyDefinition.MATCH_HAS_NO_VALUE,
        )
        rule.add_action(
            CreateScheduleInstanceActionDefinition,
            timed_schedule_id=schedule.schedule_id,
            recipients=(('CustomRecipient', 'ICDS_SUPERVISOR_FROM_AWC_OWNER'),),
            scheduler_module_info=CreateScheduleInstanceActionDefinition.SchedulerModuleInfo(
                enabled=True,
                app_id='48cc1709b7f62ffea24cc6634a004745',
                form_unique_id='f55da33c32fb41489d5082b7b3acfe43c739e988',
                visit_number=visit_num - 1,
                window_position=VISIT_WINDOW_END,
            ),
        )
    def get_json_rule(self, rule):
        json_rule = SimpleSchedulingRule(
            name=rule.name,
            case_type=rule.case_type,
        )

        for criterion in rule.memoized_criteria:
            definition = criterion.definition
            if not isinstance(definition, MatchPropertyDefinition):
                raise CommandError(
                    "Rule %s references currently unsupported criterion definition for export. "
                    "Either add support to this script for unsupported criteria or exclude rule "
                    "from export." % rule.pk
                )

            json_rule.criteria.append(MatchPropertyCriterion(
                property_name=definition.property_name,
                property_value=definition.property_value,
                match_type=definition.match_type,
            ))

        if len(rule.memoized_actions) != 1:
            raise CommandError(
                "Expected exactly one action for rule %s. This is an unexpected configuration. "
                "Was this rule created with the UI?" % rule.pk
            )

        action = rule.memoized_actions[0].definition
        if not isinstance(action, CreateScheduleInstanceActionDefinition):
            raise CommandError(
                "Expected CreateScheduleInstanceActionDefinition for rule %s. This is an unexpected "
                "configuration. Was this rule created with the UI?" % rule.pk
            )

        for recipient_type, recipient_id in action.recipients:
            if recipient_type not in (
                CaseScheduleInstanceMixin.RECIPIENT_TYPE_SELF,
                CaseScheduleInstanceMixin.RECIPIENT_TYPE_CASE_OWNER,
                CaseScheduleInstanceMixin.RECIPIENT_TYPE_LAST_SUBMITTING_USER,
                CaseScheduleInstanceMixin.RECIPIENT_TYPE_PARENT_CASE,
                CaseScheduleInstanceMixin.RECIPIENT_TYPE_CUSTOM,
            ):
                raise CommandError(
                    "Unsupported recipient_type %s referenced in rule %s. That's probably because the "
                    "recipient type references a specific object like a user or location whose id cannot "
                    "be guaranteed to be the same in the imported project. This rule must be excluded "
                    "from export" % (recipient_type, rule.pk)
                )

        if action.get_scheduler_module_info().enabled:
            raise CommandError(
                "Scheduler module integration is not supported for export because it references "
                "a form whose unique id is not guaranteed to be the same in the imported project. Please "
                "exclude rule %s from export." % rule.pk
            )

        json_rule.recipients = copy.deepcopy(action.recipients)
        json_rule.reset_case_property_name = action.reset_case_property_name
        json_rule.start_date_case_property = action.start_date_case_property
        json_rule.specific_start_date = action.specific_start_date
        json_rule.scheduler_module_info = CreateScheduleInstanceActionDefinition.SchedulerModuleInfo(enabled=False)

        return json_rule
    def test_visit_scheduler_integration(self, utcnow_patch, module_and_form_patch):
        schedule = TimedSchedule.create_simple_daily_schedule(
            self.domain,
            TimedEvent(time=time(9, 0)),
            SMSContent(message={'en': 'Hello'}),
            total_iterations=1,
        )

        rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING)

        _, definition = rule.add_action(
            CreateScheduleInstanceActionDefinition,
            timed_schedule_id=schedule.schedule_id,
            recipients=(('CommCareUser', self.user.get_id),)
        )

        module, form = get_visit_scheduler_module_and_form_for_test()

        definition.set_scheduler_module_info(CreateScheduleInstanceActionDefinition.SchedulerModuleInfo(
            enabled=True,
            app_id='n/a for test',
            form_unique_id=form.unique_id,
            visit_number=1,
            window_position=VISIT_WINDOW_START,
        ))

        definition.save()

        AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING)

        utcnow_patch.return_value = datetime(2017, 8, 1, 7, 0)
        module_and_form_patch.return_value = module, form

        with create_case(self.domain, 'person') as case:
            # Schedule phase does not match, nothing is scheduled
            instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule)
            self.assertEqual(instances.count(), 0)

            update_case(self.domain, case.case_id,
                case_properties={'add': '2017-08-01', 'current_schedule_phase': '2'})

            instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule)
            self.assertEqual(instances.count(), 1)

            self.assertEqual(instances[0].case_id, case.case_id)
            self.assertEqual(instances[0].rule_id, rule.pk)
            self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id)
            self.assertEqual(instances[0].start_date, date(2017, 8, 6))
            self.assertEqual(instances[0].domain, self.domain)
            self.assertEqual(instances[0].recipient_type, 'CommCareUser')
            self.assertEqual(instances[0].recipient_id, self.user.get_id)
            self.assertEqual(instances[0].current_event_num, 0)
            self.assertEqual(instances[0].schedule_iteration_num, 1)
            self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0))
            self.assertTrue(instances[0].active)

            # If the anchor date gets updated (due to correction, for example), the schedule recalculates
            update_case(self.domain, case.case_id, case_properties={'add': '2017-08-10'})
            instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule)
            self.assertEqual(instances.count(), 1)

            self.assertEqual(instances[0].case_id, case.case_id)
            self.assertEqual(instances[0].rule_id, rule.pk)
            self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id)
            self.assertEqual(instances[0].start_date, date(2017, 8, 15))
            self.assertEqual(instances[0].domain, self.domain)
            self.assertEqual(instances[0].recipient_type, 'CommCareUser')
            self.assertEqual(instances[0].recipient_id, self.user.get_id)
            self.assertEqual(instances[0].current_event_num, 0)
            self.assertEqual(instances[0].schedule_iteration_num, 1)
            self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 15, 13, 0))
            self.assertTrue(instances[0].active)

            # If the anchor date is in the past, the schedule instance is deactivated
            update_case(self.domain, case.case_id, case_properties={'add': '2017-07-01'})
            instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule)
            self.assertEqual(instances.count(), 1)

            self.assertEqual(instances[0].case_id, case.case_id)
            self.assertEqual(instances[0].rule_id, rule.pk)
            self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id)
            self.assertEqual(instances[0].start_date, date(2017, 7, 6))
            self.assertEqual(instances[0].domain, self.domain)
            self.assertEqual(instances[0].recipient_type, 'CommCareUser')
            self.assertEqual(instances[0].recipient_id, self.user.get_id)
            self.assertEqual(instances[0].current_event_num, 0)
            self.assertEqual(instances[0].schedule_iteration_num, 2)
            self.assertEqual(instances[0].next_event_due, datetime(2017, 7, 7, 13, 0))
            self.assertFalse(instances[0].active)

            # If the anchor date is reset, the schedule instance is reactivated
            update_case(self.domain, case.case_id, case_properties={'add': '2017-08-01'})
            instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule)
            self.assertEqual(instances.count(), 1)

            self.assertEqual(instances[0].case_id, case.case_id)
            self.assertEqual(instances[0].rule_id, rule.pk)
            self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id)
            self.assertEqual(instances[0].start_date, date(2017, 8, 6))
            self.assertEqual(instances[0].domain, self.domain)
            self.assertEqual(instances[0].recipient_type, 'CommCareUser')
            self.assertEqual(instances[0].recipient_id, self.user.get_id)
            self.assertEqual(instances[0].current_event_num, 0)
            self.assertEqual(instances[0].schedule_iteration_num, 1)
            self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0))
            self.assertTrue(instances[0].active)

            # Making an arbitrary update doesn't cause any recalculating to happen
            with patch('corehq.messaging.scheduling.scheduling_partitioned.models.AbstractTimedScheduleInstance.recalculate_schedule') as recalculate_patch:
                update_case(self.domain, case.case_id, case_properties={'new_property': 'new value'})
                self.assertEqual(recalculate_patch.call_count, 0)

            instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule)
            self.assertEqual(instances.count(), 1)

            self.assertEqual(instances[0].case_id, case.case_id)
            self.assertEqual(instances[0].rule_id, rule.pk)
            self.assertEqual(instances[0].timed_schedule_id, schedule.schedule_id)
            self.assertEqual(instances[0].start_date, date(2017, 8, 6))
            self.assertEqual(instances[0].domain, self.domain)
            self.assertEqual(instances[0].recipient_type, 'CommCareUser')
            self.assertEqual(instances[0].recipient_id, self.user.get_id)
            self.assertEqual(instances[0].current_event_num, 0)
            self.assertEqual(instances[0].schedule_iteration_num, 1)
            self.assertEqual(instances[0].next_event_due, datetime(2017, 8, 6, 13, 0))
            self.assertTrue(instances[0].active)

            # Terminate the schedule, no more schedule instances should be scheduled
            update_case(self.domain, case.case_id, case_properties={'current_schedule_phase': '-1'})
            instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule)
            self.assertEqual(instances.count(), 0)
class VisitSchedulerIntegrationHelperTestCase(TestCase):
    domain = 'visit-scheduler-integration-helper'

    @classmethod
    def setUpClass(cls):
        cls.module, cls.form = get_visit_scheduler_module_and_form_for_test()
        super(VisitSchedulerIntegrationHelperTestCase, cls).setUpClass()

    def get_helper(self, case, visit_number=2, window_position=VISIT_WINDOW_START):
        return VisitSchedulerIntegrationHelper(
            case,
            CreateScheduleInstanceActionDefinition.SchedulerModuleInfo(
                enabled=True,
                app_id='n/a for test',
                form_unique_id=self.form.unique_id,
                visit_number=visit_number,
                window_position=window_position,
            )
        )

    def test_get_visit_scheduler_form_phase(self):
        with create_case(self.domain, 'person') as case:
            phase_num, phase = self.get_helper(case).get_visit_scheduler_form_phase(self.module)
            self.assertEqual(phase_num, 2)
            self.assertEqual(phase.to_json(), self.module.schedule_phases[1].to_json())

    def test_calculate_window_date(self):
        with create_case(self.domain, 'person') as case:
            helper = self.get_helper(case, window_position=VISIT_WINDOW_START)
            self.assertEqual(