def test_supervisor_from_awc_owner(self): for cls in (CaseAlertScheduleInstance, CaseTimedScheduleInstance): with create_case(self.domain, 'person', owner_id=self.awc1.location_id) as case: self.assertEqual( cls( domain=self.domain, case_id=case.case_id, recipient_type='CustomRecipient', recipient_id='ICDS_SUPERVISOR_FROM_AWC_OWNER' ).recipient, self.ls1 ) with create_case(self.domain, 'person', owner_id=self.awc2.location_id) as case: self.assertIsNone( cls( domain=self.domain, case_id=case.case_id, recipient_type='CustomRecipient', recipient_id='ICDS_SUPERVISOR_FROM_AWC_OWNER' ).recipient ) with create_case(self.domain, 'person') as case: self.assertIsNone( cls( domain=self.domain, case_id=case.case_id, recipient_type='CustomRecipient', recipient_id='ICDS_SUPERVISOR_FROM_AWC_OWNER' ).recipient )
def test_parent_case_recipient(self): with create_case(self.domain, 'person') as child, create_case(self.domain, 'person') as parent: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=child.case_id, recipient_type=CaseScheduleInstanceMixin.RECIPIENT_TYPE_PARENT_CASE) self.assertIsNone(instance.recipient) set_parent_case(self.domain, child, parent, relationship='child', identifier='parent') instance = CaseTimedScheduleInstance(domain=self.domain, case_id=child.case_id, recipient_type=CaseScheduleInstanceMixin.RECIPIENT_TYPE_PARENT_CASE) self.assertEqual(instance.recipient.case_id, parent.case_id)
def test_case_group_recipient_with_user_data_filter(self): # The user data filter should have no effect here because all # the recipients are cases. schedule = TimedSchedule.create_simple_daily_schedule( self.domain, TimedEvent(time=time(9, 0)), SMSContent(message={'en': 'Hello'}) ) schedule.user_data_filter = {'role': ['nurse']} schedule.save() with create_case(self.domain, 'person') as case: case_group = CommCareCaseGroup(domain=self.domain, cases=[case.case_id]) case_group.save() self.addCleanup(case_group.delete) instance = CaseTimedScheduleInstance( domain=self.domain, timed_schedule_id=schedule.schedule_id, recipient_type=ScheduleInstance.RECIPIENT_TYPE_CASE_GROUP, recipient_id=case_group.get_id, ) recipients = list(instance.expand_recipients()) self.assertEqual(len(recipients), 1) self.assertEqual(recipients[0].case_id, case.case_id)
def test_child_case_recipient(self): with create_case(self.domain, 'person') as child_1, \ create_case(self.domain, 'person') as child_2, \ create_case(self.domain, 'person') as parent: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=parent.case_id, recipient_type=CaseScheduleInstanceMixin.RECIPIENT_TYPE_ALL_CHILD_CASES) self.assertIsInstance(instance.recipient, list) self.assertEqual(len(instance.recipient), 0) set_parent_case(self.domain, child_1, parent, relationship='child', identifier='parent') set_parent_case(self.domain, child_2, parent, relationship='child', identifier='parent') instance = CaseTimedScheduleInstance(domain=self.domain, case_id=parent.case_id, recipient_type=CaseScheduleInstanceMixin.RECIPIENT_TYPE_ALL_CHILD_CASES) self.assertIsInstance(instance.recipient, list) self.assertEqual(len(instance.recipient), 2) self.assertItemsEqual([c.case_id for c in instance.recipient], [child_1.case_id, child_2.case_id])
def create_user_case(user): """ Returns a context manager that yields the user case and deletes it on exit. """ return create_case( user.domain, USERCASE_TYPE, owner_id=user.get_id, external_id=user.get_id, update={'hq_user_id': user.get_id}, )
def test_get_anchor_date(self): with create_case(self.domain, 'person') as case: helper = self.get_helper(case) with self.assertRaises(VisitSchedulerIntegrationHelper. VisitSchedulerIntegrationException): helper.get_anchor_date('add') update_case(self.domain, case.case_id, case_properties={'add': '2017-08-01'}) case = CaseAccessors(self.domain).get_case(case.case_id) helper = self.get_helper(case) self.assertEqual(helper.get_anchor_date('add'), date(2017, 8, 1))
def test_username_case_property_recipient(self): # test valid username with create_case(self.domain, 'person', owner_id=self.city_location.location_id, update={'recipient': 'mobile'}) as case: instance = CaseTimedScheduleInstance( domain=self.domain, case_id=case.case_id, recipient_type=CaseScheduleInstanceMixin. RECIPIENT_TYPE_CASE_PROPERTY_USER, recipient_id='recipient') self.assertEqual(instance.recipient.get_id, self.full_mobile_user.get_id) # test invalid username with create_case(self.domain, 'person', owner_id=self.city_location.location_id, update={'recipient': 'mobile10'}) as case: instance = CaseTimedScheduleInstance( domain=self.domain, case_id=case.case_id, recipient_type=CaseScheduleInstanceMixin. RECIPIENT_TYPE_CASE_PROPERTY_USER, recipient_id='recipient') self.assertIsNone(instance.recipient) # test no username with create_case(self.domain, 'person', owner_id=self.city_location.location_id) as case: instance = CaseTimedScheduleInstance( domain=self.domain, case_id=case.case_id, recipient_type=CaseScheduleInstanceMixin. RECIPIENT_TYPE_CASE_PROPERTY_USER, recipient_id='recipient') self.assertIsNone(instance.recipient)
def test_email_case_property_recipient(self): with create_case(self.domain, 'person', owner_id=self.city_location.location_id, update={'recipient': '*****@*****.**'}) as case: instance = CaseTimedScheduleInstance( domain=self.domain, case_id=case.case_id, recipient_type=CaseScheduleInstanceMixin. RECIPIENT_TYPE_CASE_PROPERTY_EMAIL, recipient_id='recipient') self.assertEqual(instance.recipient.get_email(), '*****@*****.**') with create_case(self.domain, 'person', owner_id=self.city_location.location_id) as case: instance = CaseTimedScheduleInstance( domain=self.domain, case_id=case.case_id, recipient_type=CaseScheduleInstanceMixin. RECIPIENT_TYPE_CASE_PROPERTY_EMAIL, recipient_id='recipient') self.assertIsNone(instance.recipient.get_email())
def test_when_delegate_exists(self): rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE) rule.add_action(CustomActionDefinition, name='ICDS_ESCALATE_TECH_ISSUE') with create_case( self.domain, 'tech_issue', case_name='New Issue', update={ 'ticket_level': 'block', 'touch_case_date': '2017-06-01', 'block_location_id': 'block_id', 'district_location_id': 'district_id', 'state_location_id': 'state_id', }, ) as tech_issue: result = rule.run_actions_when_case_matches(tech_issue) self.assertEqual(result.num_updates, 1) self.assertEqual(result.num_creates, 1) self.assertEqual(result.num_related_updates, 0) tech_issue = CaseAccessors(self.domain).get_case( tech_issue.case_id) subcases = tech_issue.get_subcases(index_identifier='parent') self.assertEqual(len(subcases), 1) [tech_issue_delegate] = subcases self.assertEqual( tech_issue_delegate.get_case_property('change_in_level'), '1') update_case(self.domain, tech_issue.case_id, case_properties={'ticket_level': 'block'}) tech_issue = CaseAccessors(self.domain).get_case( tech_issue.case_id) result = rule.run_actions_when_case_matches(tech_issue) self.assertEqual(result.num_updates, 1) self.assertEqual(result.num_creates, 0) self.assertEqual(result.num_related_updates, 1) tech_issue = CaseAccessors(self.domain).get_case( tech_issue.case_id) subcases = tech_issue.get_subcases(index_identifier='parent') self.assertEqual(len(subcases), 1) [tech_issue_delegate] = subcases self.assertEqual( tech_issue_delegate.get_case_property('change_in_level'), '2')
def test_specific_case_recipient(self): with create_case(self.domain, 'person') as case: instance = ScheduleInstance( domain=self.domain, recipient_type=ScheduleInstance.RECIPIENT_TYPE_CASE, recipient_id=case.case_id, ) self.assertEqual(instance.recipient.case_id, case.case_id) instance = ScheduleInstance( domain=self.domain, recipient_type=ScheduleInstance.RECIPIENT_TYPE_CASE, recipient_id='id-does-not-exist', ) self.assertIsNone(instance.recipient)
def test_no_further_escalation(self): rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE) rule.add_action(CustomActionDefinition, name='ICDS_ESCALATE_TECH_ISSUE') with create_case( self.domain, 'tech_issue', case_name='New Issue', update={'ticket_level': 'state'}, ) as tech_issue: result = rule.run_actions_when_case_matches(tech_issue) self.assertEqual(result.num_updates, 0) self.assertEqual(result.num_creates, 0)
def test_specific_case_recipient(self): with create_case(self.domain, 'person') as case: instance = ScheduleInstance( domain=self.domain, recipient_type=ScheduleInstance.RECIPIENT_TYPE_CASE, recipient_id=case.case_id, ) self.assertEqual(instance.recipient.case_id, case.case_id) instance = ScheduleInstance( domain=self.domain, recipient_type=ScheduleInstance.RECIPIENT_TYPE_CASE, recipient_id='id-does-not-exist', ) self.assertIsNone(instance.recipient)
def test_owner_recipient(self): with create_case(self.domain, 'person', owner_id=self.city_location.location_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, SQLLocation)) self.assertEqual(instance.recipient.location_id, self.city_location.location_id) with create_case(self.domain, 'person', owner_id=self.group.get_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, Group)) self.assertEqual(instance.recipient.get_id, self.group.get_id) with create_case(self.domain, 'person', owner_id=self.mobile_user.get_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, CommCareUser)) self.assertEqual(instance.recipient.get_id, self.mobile_user.get_id) with create_case(self.domain, 'person', owner_id=self.web_user.get_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, WebUser)) self.assertEqual(instance.recipient.get_id, self.web_user.get_id) with create_case(self.domain, 'person') as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertIsNone(instance.recipient)
def test_owner_recipient(self): with create_case(self.domain, 'person', owner_id=self.city_location.location_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, SQLLocation)) self.assertEqual(instance.recipient.location_id, self.city_location.location_id) with create_case(self.domain, 'person', owner_id=self.group.get_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, Group)) self.assertEqual(instance.recipient.get_id, self.group.get_id) with create_case(self.domain, 'person', owner_id=self.mobile_user.get_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, CommCareUser)) self.assertEqual(instance.recipient.get_id, self.mobile_user.get_id) with create_case(self.domain, 'person', owner_id=self.web_user.get_id) as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertTrue(isinstance(instance.recipient, WebUser)) self.assertEqual(instance.recipient.get_id, self.web_user.get_id) with create_case(self.domain, 'person') as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Owner') self.assertIsNone(instance.recipient)
def test_get_visit(self): with create_case(self.domain, 'person') as case: helper = self.get_helper(case, visit_number=1) self.assertEqual( helper.get_visit(self.form).to_json(), self.form.schedule.visits[1].to_json() ) # Repeat visits aren't supported helper = self.get_helper(case, visit_number=2) with self.assertRaises(VisitSchedulerIntegrationHelper.VisitSchedulerIntegrationException): helper.get_visit(self.form) # Index out of range helper = self.get_helper(case, visit_number=999) with self.assertRaises(VisitSchedulerIntegrationHelper.VisitSchedulerIntegrationException): helper.get_visit(self.form)
def _test_auto_escalation(self, from_level, to_level): rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE) rule.add_action(CustomActionDefinition, name='ICDS_ESCALATE_TECH_ISSUE') with create_case( self.domain, 'tech_issue', case_name='New Issue', update={ 'ticket_level': from_level, 'touch_case_date': '2017-06-01', 'block_location_id': 'block_id', 'district_location_id': 'district_id', 'state_location_id': 'state_id', }, ) as tech_issue: properties = tech_issue.to_json() self.assertEqual(properties.get('ticket_level'), from_level) self.assertEqual(properties.get('touch_case_date'), '2017-06-01') self.assertIsNone(properties.get('change_in_level')) result = rule.run_actions_when_case_matches(tech_issue) self.assertEqual(result.num_updates, 1) self.assertEqual(result.num_creates, 1) tech_issue = CaseAccessors(self.domain).get_case( tech_issue.case_id) properties = tech_issue.to_json() self.assertEqual(properties.get('ticket_level'), to_level) self.assertEqual(properties.get('touch_case_date'), self.todays_date) self.assertEqual(properties.get('change_in_level'), '1') subcases = tech_issue.get_subcases(index_identifier='parent') self.assertEqual(len(subcases), 1) [tech_issue_delegate] = subcases self.assertEqual(tech_issue_delegate.type, 'tech_issue_delegate') self.assertEqual(tech_issue_delegate.name, tech_issue.name) self.assertEqual( tech_issue_delegate.owner_id, tech_issue.get_case_property('%s_location_id' % to_level)) self.assertEqual( tech_issue_delegate.get_case_property('change_in_level'), '1')
def test_when_delegate_exists(self): rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE) with create_case( self.domain, 'tech_issue', case_name='New Issue', update={ 'ticket_level': 'block', 'touch_case_date': '2017-06-01', 'block_location_id': 'block_id', 'district_location_id': 'district_id', 'state_location_id': 'state_id', }, ) as tech_issue: result = escalate_tech_issue(tech_issue, rule) self.assertEqual(result.num_updates, 1) self.assertEqual(result.num_creates, 1) self.assertEqual(result.num_related_updates, 0) tech_issue = CaseAccessors(self.domain).get_case( tech_issue.case_id) subcases = tech_issue.get_subcases(index_identifier='parent') self.assertEqual(len(subcases), 1) [tech_issue_delegate] = subcases self.assertEqual( tech_issue_delegate.get_case_property('change_in_level'), '1') self.assertEqual(tech_issue_delegate.owner_id, 'district_id') tech_issue = CaseAccessors(self.domain).get_case( tech_issue.case_id) result = escalate_tech_issue(tech_issue, rule) self.assertEqual(result.num_updates, 1) self.assertEqual(result.num_creates, 0) self.assertEqual(result.num_related_updates, 1) tech_issue = CaseAccessors(self.domain).get_case( tech_issue.case_id) subcases = tech_issue.get_subcases(index_identifier='parent') self.assertEqual(len(subcases), 1) [tech_issue_delegate] = subcases self.assertEqual( tech_issue_delegate.get_case_property('change_in_level'), '2') self.assertEqual(tech_issue_delegate.owner_id, 'state_id')
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( helper.calculate_window_date(self.form.schedule.visits[1], date(2017, 8, 1)), date(2017, 7, 30) ) helper = self.get_helper(case, window_position=VISIT_WINDOW_DUE_DATE) self.assertEqual( helper.calculate_window_date(self.form.schedule.visits[1], date(2017, 8, 1)), date(2017, 8, 1) ) helper = self.get_helper(case, window_position=VISIT_WINDOW_END) self.assertEqual( helper.calculate_window_date(self.form.schedule.visits[1], date(2017, 8, 1)), date(2017, 8, 4) )
def test_ignoring_entries(self): with create_case(self.domain, 'person') as case: update_case(self.domain, case.case_id, case_properties={'contact_phone_number': '12345', 'contact_phone_number_is_verified': '1'}) self.assertPhoneEntryCount(1) self.assertPhoneEntryCount(1, only_count_two_way=True) with patch('corehq.apps.sms.tasks.use_phone_entries') as patch1, \ patch('corehq.messaging.tasks.use_phone_entries') as patch2, \ patch('corehq.messaging.scheduling.models.abstract.use_phone_entries') as patch3: patch1.return_value = patch2.return_value = patch3.return_value = False update_case(self.domain, case.case_id, case_properties={'contact_phone_number': '23456'}) case = CaseAccessors(self.domain).get_case(case.case_id) self.assertPhoneEntryCount(1) self.assertPhoneEntryCount(1, only_count_two_way=True) self.assertTwoWayEntry(PhoneNumber.objects.get(owner_id=case.case_id), '12345') self.assertEqual(Content.get_two_way_entry_or_phone_number(case), '23456')
def test_ignoring_entries(self): with create_case(self.domain, 'person') as case: update_case(self.domain, case.case_id, case_properties={'contact_phone_number': '12345', 'contact_phone_number_is_verified': '1'}) self.assertPhoneEntryCount(1) self.assertPhoneEntryCount(1, only_count_two_way=True) with patch('corehq.apps.sms.tasks.use_phone_entries') as patch1, \ patch('corehq.messaging.tasks.use_phone_entries') as patch2, \ patch('corehq.messaging.scheduling.models.abstract.use_phone_entries') as patch3: patch1.return_value = patch2.return_value = patch3.return_value = False update_case(self.domain, case.case_id, case_properties={'contact_phone_number': '23456'}) case = CaseAccessors(self.domain).get_case(case.case_id) self.assertPhoneEntryCount(1) self.assertPhoneEntryCount(1, only_count_two_way=True) self.assertTwoWayEntry(PhoneNumber.objects.get(owner_id=case.case_id), '12345') self.assertEqual(Content.get_two_way_entry_or_phone_number(case), '23456')
def test_ignoring_entries(self): with create_case(self.domain, 'person') as case: update_case(self.domain, case.case_id, case_properties={ 'contact_phone_number': '12345', 'contact_phone_number_is_verified': '1' }) self.assertPhoneEntryCount(1) self.assertPhoneEntryCount(1, only_count_two_way=True) with override_settings(USE_PHONE_ENTRIES=False): update_case(self.domain, case.case_id, case_properties={'contact_phone_number': '23456'}) case = CaseAccessors(self.domain).get_case(case.case_id) self.assertPhoneEntryCount(1) self.assertPhoneEntryCount(1, only_count_two_way=True) self.assertTwoWayEntry( PhoneNumber.objects.get(owner_id=case.case_id), '12345') self.assertEqual( Content.get_two_way_entry_or_phone_number(case), '23456')
def create_user_case(self, user): create_case_kwargs = { 'external_id': user.get_id, 'update': {'hq_user_id': user.get_id}, } return create_case(self.domain, 'commcare-user', **create_case_kwargs)
def create_user_case(self, user): create_case_kwargs = { 'external_id': user.get_id, 'update': {'hq_user_id': user.get_id}, } return create_case(self.domain, 'commcare-user', **create_case_kwargs)
def test_case_recipient(self): with create_case(self.domain, 'person') as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Self') self.assertTrue(is_commcarecase(instance.recipient)) self.assertEqual(instance.recipient.case_id, case.case_id)
def test_timed_schedule_instance_creation(self, utcnow_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, time(9, 0), SMSContent(message={'en': 'Hello'})) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_criteria( MatchPropertyDefinition, property_name='start_sending', property_value='Y', match_type=MatchPropertyDefinition.MATCH_EQUAL, ) rule.add_action(CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id), )) AutomaticUpdateRule.clear_caches( self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 5, 1, 7, 0) with create_case(self.domain, 'person') as case: # Rule does not match, no instances created instances = get_case_timed_schedule_instances_for_schedule( case.case_id, schedule) self.assertEqual(instances.count(), 0) # Make the rule match. On the first iteration, the instance is created. On the second, # no new instance is created since it already exists. for minute in [1, 2]: utcnow_patch.return_value = datetime(2017, 5, 1, 7, minute) update_case(self.domain, case.case_id, case_properties={'start_sending': 'Y'}) 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, 5, 1)) 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, 5, 1, 13, 0)) self.assertTrue(instances[0].active) # Make the rule not match. Instance should no longer exist. utcnow_patch.return_value = datetime(2017, 5, 1, 7, 3) update_case(self.domain, case.case_id, case_properties={'start_sending': 'N'}) instances = get_case_timed_schedule_instances_for_schedule( case.case_id, schedule) self.assertEqual(instances.count(), 0)
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)
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_alert_schedule_reset(self, utcnow_patch): schedule = AlertSchedule.create_simple_alert( self.domain, SMSContent(message={'en': 'Hello'}) ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_criteria( MatchPropertyDefinition, property_name='start_sending', property_value='Y', match_type=MatchPropertyDefinition.MATCH_EQUAL, ) rule.add_action( CreateScheduleInstanceActionDefinition, alert_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),), reset_case_property_name='reset_property', ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 5, 1, 7, 0) with create_case(self.domain, 'person') as case: # Rule does not match, no instances created instances = get_case_alert_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0) # Make the rule match. On the first iteration, the instance is created. On the second, # nothing is changed. for minute in (1, 2): utcnow_patch.return_value = datetime(2017, 5, 1, 7, minute) update_case(self.domain, case.case_id, case_properties={'start_sending': 'Y', 'reset_property': 'a'}) instances = get_case_alert_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].alert_schedule_id, schedule.schedule_id) 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, 5, 1, 7, 1)) self.assertEqual(instances[0].last_reset_case_property_value, 'a') self.assertTrue(instances[0].active) # Update the reset property, and the instance is reset. utcnow_patch.return_value = datetime(2017, 6, 1, 7, 0) update_case(self.domain, case.case_id, case_properties={'reset_property': 'b'}) instances = get_case_alert_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].alert_schedule_id, schedule.schedule_id) 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, 6, 1, 7, 0)) self.assertEqual(instances[0].last_reset_case_property_value, 'b') self.assertTrue(instances[0].active)
def test_timed_schedule_case_property_timed_event(self, utcnow_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, CasePropertyTimedEvent(case_property_name='reminder_time'), SMSContent(message={'en': 'Hello'}) ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_criteria( MatchPropertyDefinition, property_name='start_sending', property_value='Y', match_type=MatchPropertyDefinition.MATCH_EQUAL, ) rule.add_action( CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),), ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 5, 1, 7, 0) with create_case(self.domain, 'person') as case: # Rule does not match, no instances created instances = get_case_timed_schedule_instances_for_schedule(case.case_id, schedule) self.assertEqual(instances.count(), 0) # Make the rule match, but don't give a preferred time. Default scheduling time is used. update_case(self.domain, case.case_id, case_properties={'start_sending': 'Y'}) 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, 5, 1)) 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, 5, 1, 16, 0)) self.assertTrue(instances[0].active) # Update the preferred time, and the schedule should recalculate update_case(self.domain, case.case_id, case_properties={'reminder_time': '09:00'}) 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, 5, 1)) 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, 5, 1, 13, 0)) self.assertTrue(instances[0].active) # Update the preferred time to a bad value and the default time is used again. update_case(self.domain, case.case_id, case_properties={'reminder_time': 'x'}) 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, 5, 1)) 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, 5, 1, 16, 0)) self.assertTrue(instances[0].active)
def test_case_recipient(self): with create_case(self.domain, 'person') as case: instance = CaseTimedScheduleInstance(domain=self.domain, case_id=case.case_id, recipient_type='Self') self.assertTrue(is_commcarecase(instance.recipient)) self.assertEqual(instance.recipient.case_id, case.case_id)
def test_start_offset(self, utcnow_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, TimedEvent(time=time(9, 0)), SMSContent(message={'en': 'Hello'}), start_offset=2, ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_action( CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id),), ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) utcnow_patch.return_value = datetime(2017, 8, 1, 15, 0) with create_case(self.domain, 'person') as case: 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, 1)) 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, 3, 13, 0)) self.assertEqual(instances[0].schedule_revision, schedule.get_schedule_revision()) self.assertTrue(instances[0].active) # Change the schedule's start offset and force a case update to reprocess the schedule instance. # The start date should not change, but the schedule instance should respond to the new start offset # by calculating a new next_event_due timestamp. schedule.start_offset = 5 schedule.save() schedule = TimedSchedule.objects.get(schedule_id=schedule.schedule_id) utcnow_patch.return_value = datetime(2017, 8, 4, 7, 0) update_case(self.domain, case.case_id, case_properties={'new_property': 'new value'}) 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, 1)) 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.assertEqual(instances[0].schedule_revision, schedule.get_schedule_revision()) self.assertTrue(instances[0].active) # Making another 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 2'}) 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, 1)) 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.assertEqual(instances[0].schedule_revision, schedule.get_schedule_revision()) self.assertTrue(instances[0].active)