def test_custom_action(self): rule = create_empty_rule( self.domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, case_type="circus", ) case1 = CaseFactory(self.domain).create_case( case_type="circus", update={ "all_activity_complete_date": "2021-06-31", }, ) case2 = CaseFactory(self.domain).create_case( case_type="circus", update={ "size": "big", }, ) set_all_activity_complete_date_to_today(case1, rule) set_all_activity_complete_date_to_today(case2, rule) today = datetime.today().strftime(ISO_DATE_FORMAT) case1 = CommCareCase.objects.get_case(case1.case_id) case2 = CommCareCase.objects.get_case(case2.case_id) self.assertEqual(case1.get_case_property("all_activity_complete_date"), "2021-06-31") self.assertEqual(case2.get_case_property("all_activity_complete_date"), today) self.assertFalse(case1.closed) self.assertFalse(case2.closed)
def test_run_messaging_rule(self, task_patch): schedule = AlertSchedule.create_simple_alert( self.domain, SMSContent(message={'en': 'Hello'}) ) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_action( CreateScheduleInstanceActionDefinition, alert_schedule_id=schedule.schedule_id, recipients=(('Self', None),), ) AutomaticUpdateRule.clear_caches(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) with create_case(self.domain, 'person') as case1, create_case(self.domain, 'person') as case2: run_messaging_rule(self.domain, rule.pk) self.assertEqual(task_patch.call_count, 2) task_patch.assert_has_calls( [ call(self.domain, case1.case_id, rule.pk), call(self.domain, case2.case_id, rule.pk), ], any_order=True )
def create_conditional_alert(self, domain, content): schedule = AlertSchedule.create_simple_alert(domain, content) rule = create_empty_rule(domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) rule.add_action( CreateScheduleInstanceActionDefinition, alert_schedule_id=schedule.schedule_id, recipients=[['CommCareUser', uuid.uuid4().hex]], ) return rule
def test_timed_schedule_instance_creation(self, utcnow_patch): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, TimedEvent(time=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_domain_has_conditional_alerts(self): self.assertFalse( AutomaticUpdateRule.domain_has_conditional_alerts(self.domain)) self.assertFalse(domain_has_reminders(self.domain)) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) self.addCleanup(rule.delete) self.assertTrue( AutomaticUpdateRule.domain_has_conditional_alerts(self.domain)) self.assertTrue(domain_has_reminders(self.domain))
def _add_rule(self, alert_schedule_id=None, timed_schedule_id=None): assert(alert_schedule_id or timed_schedule_id) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) self.addCleanup(rule.delete) rule.add_action( CreateScheduleInstanceActionDefinition, recipients=(('CommCareUser', self.user.get_id),), alert_schedule_id=alert_schedule_id, timed_schedule_id=timed_schedule_id, ) rule.save() return rule
def test_no_further_escalation(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': 'state'}, ) as tech_issue: result = escalate_tech_issue(tech_issue, rule) self.assertEqual(result.num_updates, 0) self.assertEqual(result.num_creates, 0)
def test_custom_action(self): checkin_case = self.make_checkin_case() rule = create_empty_rule( self.domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, case_type="checkin", ) case_properties = { "assigned_to_primary_checkin_case_id": checkin_case.case_id, "is_assigned_primary": "foo", "assigned_to_primary_name": "bar", "assigned_to_primary_username": "******", } patient_case = CaseFactory(self.domain).create_case( case_type="patient", owner_id=self.mobile_worker.get_id, update=case_properties, ) other_patient_case = CaseFactory(self.domain).create_case( case_type="patient", owner_id=self.mobile_worker.get_id, update={"assigned_to_primary_checkin_case_id": "123"}, ) other_case = CaseFactory(self.domain).create_case( case_type="other", owner_id=self.mobile_worker.get_id, update={"assigned_to_primary_checkin_case_id": checkin_case.case_id}, ) for case in [patient_case, other_patient_case, other_case]: send_to_elasticsearch("case_search", transform_case_for_elasticsearch(case.to_json())) self.es.indices.refresh(CASE_SEARCH_INDEX_INFO.index) close_cases_assigned_to_checkin(checkin_case, rule) self.assertTrue(CommCareCase.objects.get_case(checkin_case.case_id).closed, self.domain) patient_case = CommCareCase.objects.get_case(patient_case.case_id, self.domain) self.assertFalse(patient_case.closed) for prop in case_properties: self.assertEqual(patient_case.get_case_property(prop), "") other_case = CommCareCase.objects.get_case(other_case.case_id, self.domain) self.assertFalse(other_case.closed) self.assertEqual( other_case.get_case_property("assigned_to_primary_checkin_case_id"), checkin_case.case_id, ) other_patient_case = CommCareCase.objects.get_case(other_patient_case.case_id, self.domain) self.assertFalse(other_patient_case.closed) self.assertEqual( other_patient_case.get_case_property("assigned_to_primary_checkin_case_id"), "123", )
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 _add_rule(self, content): schedule = TimedSchedule.create_simple_daily_schedule( self.domain, TimedEvent(time=time(9, 0)), content) rule = create_empty_rule(self.domain, AutomaticUpdateRule.WORKFLOW_SCHEDULING) self.addCleanup(rule.delete) rule.add_action(CreateScheduleInstanceActionDefinition, timed_schedule_id=schedule.schedule_id, recipients=(('CommCareUser', self.user.get_id), )) rule.save() return rule
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_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_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_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_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)