def setUp(self): self.domain = 'auto-update-test' self.case_db = CaseAccessors(self.domain) self.factory = CaseFactory(self.domain) self.rule = AutomaticUpdateRule( domain=self.domain, name='test-rule', case_type='test-case-type', active=True, server_modified_boundary=30, ) self.rule.save() self.rule.automaticupdaterulecriteria_set = [ AutomaticUpdateRuleCriteria( property_name='last_visit_date', property_value='30', match_type=AutomaticUpdateRuleCriteria.MATCH_DAYS_SINCE, ), ] self.rule.automaticupdateaction_set = [ AutomaticUpdateAction( action=AutomaticUpdateAction.ACTION_UPDATE, property_name='update_flag', property_value='Y', ), AutomaticUpdateAction(action=AutomaticUpdateAction.ACTION_CLOSE, ), ] self.rule2 = AutomaticUpdateRule( domain=self.domain, name='test-rule-2', case_type='test-case-type-2', active=True, server_modified_boundary=30, ) self.rule2.save() self.rule2.automaticupdateaction_set = [ AutomaticUpdateAction(action=AutomaticUpdateAction.ACTION_CLOSE, ), ] self.rule3 = AutomaticUpdateRule( domain=self.domain, name='test-rule-3', case_type='test-case-type-2', active=True, server_modified_boundary=50, ) self.rule3.save() self.rule3.automaticupdateaction_set = [ AutomaticUpdateAction(action=AutomaticUpdateAction.ACTION_CLOSE, ), ] with drop_connected_signals(case_post_save): case = self.factory.create_case(case_type='test-case-type')
def post(self, request, *args, **kwargs): rule_form_valid = self.rule_form.is_valid() criteria_form_valid = self.criteria_form.is_valid() actions_form_valid = self.actions_form.is_valid() if self.read_only_mode: # Don't allow making changes to rules that have custom # criteria/actions unless the user has permission to return HttpResponseBadRequest() if rule_form_valid and criteria_form_valid and actions_form_valid: if not self.is_system_admin and ( self.criteria_form.requires_system_admin_to_save or self.actions_form.requires_system_admin_to_save ): # Don't allow adding custom criteria/actions to rules # unless the user has permission to return HttpResponseBadRequest() with transaction.atomic(): if self.initial_rule: rule = self.initial_rule else: rule = AutomaticUpdateRule( domain=self.domain, active=True, workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, ) rule.name = self.rule_form.cleaned_data['name'] self.criteria_form.save_criteria(rule) self.actions_form.save_actions(rule) return HttpResponseRedirect(reverse(AutomaticUpdateRuleListView.urlname, args=[self.domain])) return self.get(request, *args, **kwargs)
def test_parent_cases(self): with _with_case(self.domain, 'test-child-case-type', datetime(2016, 1, 1)) as child, \ _with_case(self.domain, 'test-parent-case-type', datetime(2016, 1, 1), case_name='abc') as parent: # Set the parent case relationship child = set_parent_case(self.domain, child, parent) # Create a rule that references parent/name which should match rule = AutomaticUpdateRule( domain=self.domain, name='test-parent-rule', case_type='test-child-case-type', active=True, server_modified_boundary=30, ) rule.save() self.addCleanup(rule.delete) AutomaticUpdateRuleCriteria.objects.create( property_name='parent/name', property_value='abc', match_type=AutomaticUpdateRuleCriteria.MATCH_EQUAL, rule=rule, ) AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_UPDATE, property_name='parent/update_flag', property_value='P', rule=rule, ) AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_UPDATE, property_name='parent_name', property_value='parent/name', property_value_type=AutomaticUpdateAction.CASE_PROPERTY, rule=rule, ) # rule should match on parent case property and update parent case rule.apply_rule(child, datetime(2016, 3, 1)) updated_parent = self.case_db.get_case(parent.case_id) updated_child = self.case_db.get_case(child.case_id) self.assertEqual(updated_parent.get_case_property('update_flag'), 'P') self.assertEqual(updated_child.get_case_property('parent_name'), 'abc') # Update the rule to match on a different name and now it shouldn't match rule.automaticupdaterulecriteria_set.all().delete() AutomaticUpdateRuleCriteria.objects.create( property_name='parent/name', property_value='def', match_type=AutomaticUpdateRuleCriteria.MATCH_EQUAL, rule=rule, ) self.assertFalse( rule.rule_matches_case(child, datetime(2016, 3, 1)))
def post(self, request, *args, **kwargs): if self.async_response is not None: return self.async_response basic_info_form_valid = self.basic_info_form.is_valid() criteria_form_valid = self.criteria_form.is_valid() schedule_form_valid = self.schedule_form.is_valid() if self.read_only_mode: # Don't allow making changes to rules that have custom # criteria/actions unless the user has permission to return HttpResponseBadRequest() if basic_info_form_valid and criteria_form_valid and schedule_form_valid: if not self.is_system_admin and ( self.criteria_form.requires_system_admin_to_save or self.schedule_form.requires_system_admin_to_save ): # Don't allow adding custom criteria/actions to rules # unless the user has permission to return HttpResponseBadRequest() if not self.can_use_inbound_sms and self.schedule_form.uses_sms_survey: return HttpResponseBadRequest( "Cannot create or edit survey reminders because subscription " "does not have access to inbound SMS" ) with transaction.atomic(): if self.rule: rule = self.rule else: rule = AutomaticUpdateRule( domain=self.domain, active=True, workflow=AutomaticUpdateRule.WORKFLOW_SCHEDULING, ) rule.name = self.basic_info_form.cleaned_data['name'] self.criteria_form.save_criteria(rule) self.schedule_form.save_rule_action_and_schedule(rule) if not ( self.new_reminders_migrator and self.schedule_form.cleaned_data['skip_running_rule_post_save'] ): initiate_messaging_rule_run(rule.domain, rule.pk) return HttpResponseRedirect(reverse(ConditionalAlertListView.urlname, args=[self.domain])) return self.get(request, *args, **kwargs)
def test_auto_case_update_rules(self): from corehq.apps.data_interfaces.models import ( AutomaticUpdateRule, AutomaticUpdateRuleCriteria, AutomaticUpdateAction) expected_object_counts = Counter({ AutomaticUpdateRule: 1, AutomaticUpdateRuleCriteria: 1, AutomaticUpdateAction: 2, }) register_cleanup(self, list(expected_object_counts), self.domain_name) pre_rule = AutomaticUpdateRule( domain=self.domain_name, name='test-rule', case_type='test-case-type', active=True, server_modified_boundary=30, ) pre_rule.save() pre_criteria = AutomaticUpdateRuleCriteria.objects.create( property_name='last_visit_date', property_value='30', match_type=AutomaticUpdateRuleCriteria.MATCH_DAYS_AFTER, rule=pre_rule, ) pre_action_update = AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_UPDATE, property_name='update_flag', property_value='Y', rule=pre_rule, ) pre_action_close = AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_CLOSE, rule=pre_rule, ) self._dump_and_load(expected_object_counts) post_rule = AutomaticUpdateRule.objects.get(pk=pre_rule.pk) post_criteria = AutomaticUpdateRuleCriteria.objects.get( pk=pre_criteria.pk) post_action_update = AutomaticUpdateAction.objects.get( pk=pre_action_update.pk) post_action_close = AutomaticUpdateAction.objects.get( pk=pre_action_close.pk) self.assertModelsEqual( [pre_rule, pre_criteria, pre_action_update, pre_action_close], [post_rule, post_criteria, post_action_update, post_action_close])
def test_parent_case_lookup(self): with _with_case(self.domain, 'test-child-case-type', datetime(2016, 1, 1)) as child, \ _with_case(self.domain, 'test-parent-case-type', datetime(2016, 1, 1), case_name='abc') as parent: # Set the parent case relationship child = set_parent_case(self.domain, child, parent) # Create a rule that references parent/name which should match rule = AutomaticUpdateRule( domain=self.domain, name='test-parent-rule', case_type='test-child-case-type', active=True, server_modified_boundary=30, ) rule.save() self.addCleanup(rule.delete) rule.automaticupdaterulecriteria_set = [ AutomaticUpdateRuleCriteria( property_name='parent/name', property_value='abc', match_type=AutomaticUpdateRuleCriteria.MATCH_EQUAL, ), ] self.assertTrue(rule.rule_matches_case(child, datetime(2016, 3, 1))) # Update the rule to match on a different name and now it shouldn't match rule.automaticupdaterulecriteria_set.all().delete() rule.automaticupdaterulecriteria_set = [ AutomaticUpdateRuleCriteria( property_name='parent/name', property_value='def', match_type=AutomaticUpdateRuleCriteria.MATCH_EQUAL, ), ] self.assertFalse( rule.rule_matches_case(child, datetime(2016, 3, 1)))
def setUp(self): test_rules = [ AutomaticUpdateRule( domain=self.domain, active=True, workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, name="Norway rule", case_type="person", filter_on_server_modified=True, server_modified_boundary=None), AutomaticUpdateRule( domain=self.domain, active=True, workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, name="Is it hot enough?", case_type="person", filter_on_server_modified=False, server_modified_boundary=2), AutomaticUpdateRule( domain=self.domain, active=False, workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, name="Closed parent case", case_type="family_member", filter_on_server_modified=True, server_modified_boundary=None), ] test_rules[0].save() test_rules[1].save() test_rules[2].save() # Create test rule criterias definition = MatchPropertyDefinition.objects.create( property_name="place", property_value="Norway", match_type=MatchPropertyDefinition.MATCH_EQUAL, ) criteria = CaseRuleCriteria(rule=test_rules[0]) criteria.definition = definition criteria.save() definition = MatchPropertyDefinition.objects.create( property_name="temperature", property_value="96", match_type=MatchPropertyDefinition.MATCH_EQUAL, ) criteria = CaseRuleCriteria(rule=test_rules[1]) criteria.definition = definition criteria.save() definition = CustomMatchDefinition.objects.create( name="COVID_US_ASSOCIATED_USER_CASES", ) criteria = CaseRuleCriteria(rule=test_rules[0]) criteria.definition = definition criteria.save() definition = ClosedParentDefinition.objects.create() criteria = CaseRuleCriteria(rule=test_rules[2]) criteria.definition = definition criteria.save() # Create test rule actions definition = UpdateCaseDefinition(close_case=True) definition.save() action = CaseRuleAction(rule=test_rules[0]) action.definition = definition action.save() definition = UpdateCaseDefinition(close_case=False) test_properties = [] test_properties.append( UpdateCaseDefinition.PropertyDefinition( name="hot_enough", value_type="EXACT", value="true", )) test_properties.append( UpdateCaseDefinition.PropertyDefinition( name="territory_hot_enough", value_type="CASE_PROPERTY", value="current_territory", )) definition.set_properties_to_update(test_properties) definition.save() action = CaseRuleAction(rule=test_rules[1]) action.definition = definition action.save() definition = CustomActionDefinition.objects.create( name="COVID_US_CLOSE_CASES_ASSIGNED_CHECKIN", ) action = CaseRuleAction(rule=test_rules[1]) action.definition = definition action.save()
def update_auto_update_rules(domain_link): if domain_link.is_remote: upstream_rules = remote_get_auto_update_rules(domain_link) else: upstream_rules = local_get_auto_update_rules(domain_link.master_domain) downstream_rules = AutomaticUpdateRule.by_domain( domain_link.linked_domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, active_only=False ) for upstream_rule_def in upstream_rules: # Grab local rule by upstream ID (preferred) or by name try: downstream_rule = downstream_rules.get(upstream_id=upstream_rule_def['rule']['id']) except AutomaticUpdateRule.DoesNotExist: try: downstream_rule = downstream_rules.get(name=upstream_rule_def['rule']['name']) except AutomaticUpdateRule.MultipleObjectsReturned: # If there are multiple rules with the same name, overwrite the first. downstream_rule = downstream_rules.filter(name=upstream_rule_def['rule']['name']).first() except AutomaticUpdateRule.DoesNotExist: downstream_rule = None # If no corresponding local rule, make a new rule if not downstream_rule: downstream_rule = AutomaticUpdateRule( domain=domain_link.linked_domain, active=upstream_rule_def['rule']['active'], workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE, upstream_id=upstream_rule_def['rule']['id'] ) # Copy all the contents from old rule to new rule with transaction.atomic(): downstream_rule.name = upstream_rule_def['rule']['name'] downstream_rule.case_type = upstream_rule_def['rule']['case_type'] downstream_rule.filter_on_server_modified = upstream_rule_def['rule']['filter_on_server_modified'] downstream_rule.server_modified_boundary = upstream_rule_def['rule']['server_modified_boundary'] downstream_rule.active = upstream_rule_def['rule']['active'] downstream_rule.save() downstream_rule.delete_criteria() downstream_rule.delete_actions() # Largely from data_interfaces/forms.py - save_criteria() for criteria in upstream_rule_def['criteria']: definition = None if criteria['match_property_definition']: definition = MatchPropertyDefinition.objects.create( property_name=criteria['match_property_definition']['property_name'], property_value=criteria['match_property_definition']['property_value'], match_type=criteria['match_property_definition']['match_type'], ) elif criteria['custom_match_definition']: definition = CustomMatchDefinition.objects.create( name=criteria['custom_match_definition']['name'], ) elif criteria['closed_parent_definition']: definition = ClosedParentDefinition.objects.create() new_criteria = CaseRuleCriteria(rule=downstream_rule) new_criteria.definition = definition new_criteria.save() # Largely from data_interfacees/forms.py - save_actions() for action in upstream_rule_def['actions']: definition = None if action['update_case_definition']: definition = UpdateCaseDefinition(close_case=action['update_case_definition']['close_case']) properties = [] for propertyItem in action['update_case_definition']['properties_to_update']: properties.append( UpdateCaseDefinition.PropertyDefinition( name=propertyItem['name'], value_type=propertyItem['value_type'], value=propertyItem['value'], ) ) definition.set_properties_to_update(properties) definition.save() elif action['custom_action_definition']: definition = CustomActionDefinition.objects.create( name=action['custom_action_definition']['name'], ) action = CaseRuleAction(rule=downstream_rule) action.definition = definition action.save()
def setUp(self): super(AutomaticCaseUpdateTest, self).setUp() self.domain = 'auto-update-test' update_toggle_cache(AUTO_CASE_UPDATE_ENHANCEMENTS.slug, self.domain, True, NAMESPACE_DOMAIN) update_toggle_cache(RUN_AUTO_CASE_UPDATES_ON_SAVE.slug, self.domain, True, NAMESPACE_DOMAIN) self.case_db = CaseAccessors(self.domain) self.factory = CaseFactory(self.domain) self.rule = AutomaticUpdateRule( domain=self.domain, name='test-rule', case_type='test-case-type', active=True, server_modified_boundary=30, ) self.rule.save() AutomaticUpdateRuleCriteria.objects.create( property_name='last_visit_date', property_value='30', match_type=AutomaticUpdateRuleCriteria.MATCH_DAYS_AFTER, rule=self.rule, ) AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_UPDATE, property_name='update_flag', property_value='Y', rule=self.rule, ) self.rule2 = AutomaticUpdateRule( domain=self.domain, name='test-rule-2', case_type='test-case-type-2', active=True, server_modified_boundary=30, ) self.rule2.save() AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_CLOSE, rule=self.rule2, ) self.rule3 = AutomaticUpdateRule( domain=self.domain, name='test-rule-3', case_type='test-case-type-2', active=True, server_modified_boundary=50, ) self.rule3.save() AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_CLOSE, rule=self.rule3, ) self.rule4 = AutomaticUpdateRule( domain=self.domain, name='test-rule-4', case_type='test-case-type', active=True, server_modified_boundary=30, ) self.rule4.save() AutomaticUpdateRuleCriteria.objects.create( property_name='last_visit_date', property_value='40', match_type=AutomaticUpdateRuleCriteria.MATCH_DAYS_AFTER, rule=self.rule4, ) AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_UPDATE, property_name='update_flag', property_value='C', rule=self.rule4, ) AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_CLOSE, rule=self.rule4, ) self.rule5 = AutomaticUpdateRule(domain=self.domain, name='test-rule-5', case_type='test-case-type-3', active=True, filter_on_server_modified=False) self.rule5.save() AutomaticUpdateRuleCriteria.objects.create( property_name='name', property_value='signal', match_type=AutomaticUpdateRuleCriteria.MATCH_EQUAL, rule=self.rule5, ) AutomaticUpdateAction.objects.create( action=AutomaticUpdateAction.ACTION_UPDATE, property_name='after_save', property_value='updated', rule=self.rule5, ) with drop_connected_signals(case_post_save): case = self.factory.create_case(case_type='test-case-type')