class Meta: validators = [ RulesBasedValidator( ValidationRule( 'invalid_required_checks_conducted_on', IsFieldBeingUpdatedAndIsNotBlankRule( 'required_checks_conducted_on', ), when=AndRule( IsFieldBeingUpdatedRule('required_checks_conducted', ), InRule( 'required_checks_conducted', REQUIRED_CHECKS_THAT_NEED_ADDITIONAL_INFORMATION, ), ), ), ValidationRule( 'invalid_required_checks_conducted_by', IsFieldBeingUpdatedAndIsNotBlankRule( 'required_checks_conducted_by', ), when=AndRule( IsFieldBeingUpdatedRule('required_checks_conducted', ), InRule( 'required_checks_conducted', REQUIRED_CHECKS_THAT_NEED_ADDITIONAL_INFORMATION, ), ), ), ValidationRule( 'required_checks_conducted_value', OperatorRule( 'required_checks_conducted', is_not_blank, ), when=AnyIsNotBlankRule( 'required_checks_conducted_by', 'required_checks_conducted_on', ), ), ValidationRule( 'invalid_required_checks_conducted_on_must_be_within_12_months', IsFieldRule( 'required_checks_conducted_on', is_provided_and_is_date_less_than_a_year_ago, ), when=AndRule( IsFieldBeingUpdatedRule( 'required_checks_conducted_on', ), InRule( 'required_checks_conducted', REQUIRED_CHECKS_THAT_NEED_ADDITIONAL_INFORMATION, ), ), ), ), ]
def test_and_rule_combines_other_rules(subrule1_res, subrule2_res): """Test that AndRule combines sub-rules using the AND operator.""" rule = AndRule( _make_stub_rule('field1', subrule1_res), _make_stub_rule('field2', subrule2_res), ) combiner = Mock(spec_set=DataCombiner) assert rule(combiner) == (subrule1_res and subrule2_res)
class Meta: model = Interaction extra_kwargs = { # Date is a datetime in the model, but only the date component is used # (at present). Setting the formats as below effectively makes the field # behave like a date field without changing the schema and breaking the # v1 API. 'date': { 'format': '%Y-%m-%d', 'input_formats': ['%Y-%m-%d'] }, 'grant_amount_offered': { 'min_value': 0 }, 'net_company_receipt': { 'min_value': 0 }, 'status': { 'default': Interaction.STATUSES.complete, 'allow_null': False }, 'location': { 'default': '' }, 'theme': { 'allow_blank': False, 'default': None, }, } fields = ( 'id', 'company', 'contacts', 'created_on', 'created_by', 'event', 'is_event', 'status', 'kind', 'modified_by', 'modified_on', 'date', 'dit_adviser', 'dit_participants', 'dit_team', 'communication_channel', 'grant_amount_offered', 'investment_project', 'net_company_receipt', 'service', 'service_delivery_status', 'subject', 'theme', 'notes', 'archived_documents_url_path', 'policy_areas', 'policy_feedback_notes', 'policy_issue_types', 'was_policy_feedback_provided', 'location', 'archived', 'archived_by', 'archived_on', 'archived_reason', ) read_only_fields = ( 'archived_documents_url_path', 'archived', 'archived_by', 'archived_on', 'archived_reason', ) validators = [ HasAssociatedInvestmentProjectValidator(), ContactsBelongToCompanyValidator(), StatusChangeValidator(), RulesBasedValidator( # If dit_adviser and dit_team are *omitted* (note that they already have # allow_null=False) we assume that dit_participants is being used, and return an # error if it is empty. # TODO: Remove once dit_adviser and dit_team have been removed. ValidationRule( 'required', OperatorRule('dit_participants', bool), when=AllIsBlankRule('dit_adviser', 'dit_team'), ), # If dit_adviser has been provided, double-check that dit_team is also set. # TODO: Remove once dit_adviser and dit_team have been removed. ValidationRule( 'required', OperatorRule('dit_adviser', bool), when=AndRule( OperatorRule('dit_team', bool), OperatorRule('dit_participants', not_), ), ), # If dit_team has been provided, double-check that dit_adviser is also set. # TODO: Remove once dit_adviser and dit_team have been removed. ValidationRule( 'required', OperatorRule('dit_team', bool), when=AndRule( OperatorRule('dit_adviser', bool), OperatorRule('dit_participants', not_), ), ), ValidationRule( 'required', OperatorRule('communication_channel', bool), when=AndRule( EqualsRule('kind', Interaction.KINDS.interaction), EqualsRule('status', Interaction.STATUSES.complete), ), ), ValidationRule( 'required', OperatorRule('service', bool), when=EqualsRule('status', Interaction.STATUSES.complete), ), ValidationRule( 'invalid_for_non_interaction', OperatorRule('investment_project', not_), when=EqualsRule('kind', Interaction.KINDS.service_delivery), ), ValidationRule( 'invalid_for_service_delivery', OperatorRule('communication_channel', not_), when=EqualsRule('kind', Interaction.KINDS.service_delivery), ), ValidationRule( 'invalid_for_non_service_delivery', OperatorRule('is_event', is_blank), OperatorRule('event', is_blank), OperatorRule('service_delivery_status', is_blank), OperatorRule('grant_amount_offered', is_blank), OperatorRule('net_company_receipt', is_blank), when=EqualsRule('kind', Interaction.KINDS.interaction), ), ValidationRule( 'invalid_when_no_policy_feedback', OperatorRule('policy_issue_types', not_), OperatorRule('policy_areas', not_), OperatorRule('policy_feedback_notes', not_), when=OperatorRule('was_policy_feedback_provided', not_), ), ValidationRule( 'required', OperatorRule('policy_areas', bool), OperatorRule('policy_issue_types', bool), OperatorRule('policy_feedback_notes', is_not_blank), when=OperatorRule('was_policy_feedback_provided', bool), ), ValidationRule( 'required', OperatorRule('is_event', is_not_blank), when=EqualsRule('kind', Interaction.KINDS.service_delivery), ), ValidationRule( 'required', OperatorRule('event', bool), when=OperatorRule('is_event', bool), ), ValidationRule( 'too_many_contacts_for_event_service_delivery', OperatorRule('contacts', lambda value: len(value) <= 1), when=OperatorRule('is_event', bool), ), ValidationRule( 'invalid_for_non_event', OperatorRule('event', not_), when=OperatorRule('is_event', not_), ), ), ]
class Meta: model = Interaction extra_kwargs = { # Date is a datetime in the model, but only the date component is used # (at present). Setting the formats as below effectively makes the field # behave like a date field without changing the schema and breaking the # v1 API. 'date': {'format': '%Y-%m-%d', 'input_formats': ['%Y-%m-%d']}, 'grant_amount_offered': {'min_value': 0}, 'net_company_receipt': {'min_value': 0}, 'status': {'default': Interaction.Status.COMPLETE}, 'theme': { 'allow_blank': False, 'default': None, }, } fields = ( 'id', 'company', 'contacts', 'created_on', 'created_by', 'event', 'is_event', 'status', 'kind', 'modified_by', 'modified_on', 'date', 'dit_participants', 'communication_channel', 'grant_amount_offered', 'investment_project', 'net_company_receipt', 'service', 'service_answers', 'service_delivery_status', 'subject', 'theme', 'notes', 'archived_documents_url_path', 'policy_areas', 'policy_feedback_notes', 'policy_issue_types', 'was_policy_feedback_provided', 'were_countries_discussed', 'export_countries', 'archived', 'archived_by', 'archived_on', 'archived_reason', 'company_referral', ) read_only_fields = ( 'archived_documents_url_path', 'archived', 'archived_by', 'archived_on', 'archived_reason', ) # Note: These validators are also used by the admin site import interactions tool # (see the admin_csv_import sub-package) validators = [ HasAssociatedInvestmentProjectValidator(), ContactsBelongToCompanyValidator(), StatusChangeValidator(), ServiceAnswersValidator(), DuplicateExportCountryValidator(), RulesBasedValidator( ValidationRule( 'required', OperatorRule('communication_channel', bool), when=AndRule( EqualsRule('kind', Interaction.Kind.INTERACTION), EqualsRule('status', Interaction.Status.COMPLETE), ), ), ValidationRule( 'required', OperatorRule('service', bool), when=EqualsRule('status', Interaction.Status.COMPLETE), ), ValidationRule( 'invalid_for_investment', EqualsRule('kind', Interaction.Kind.INTERACTION), when=EqualsRule('theme', Interaction.Theme.INVESTMENT), ), ValidationRule( 'invalid_for_non_interaction', OperatorRule('investment_project', not_), when=EqualsRule('kind', Interaction.Kind.SERVICE_DELIVERY), ), ValidationRule( 'invalid_for_service_delivery', OperatorRule('communication_channel', not_), when=EqualsRule('kind', Interaction.Kind.SERVICE_DELIVERY), ), ValidationRule( 'invalid_for_non_service_delivery', OperatorRule('is_event', is_blank), OperatorRule('event', is_blank), OperatorRule('service_delivery_status', is_blank), when=EqualsRule('kind', Interaction.Kind.INTERACTION), ), ValidationRule( 'invalid_when_no_policy_feedback', OperatorRule('policy_issue_types', not_), OperatorRule('policy_areas', not_), OperatorRule('policy_feedback_notes', not_), when=OperatorRule('was_policy_feedback_provided', not_), ), ValidationRule( 'required', OperatorRule('policy_areas', bool), OperatorRule('policy_issue_types', bool), OperatorRule('policy_feedback_notes', is_not_blank), when=OperatorRule('was_policy_feedback_provided', bool), ), ValidationRule( 'required', OperatorRule('is_event', is_not_blank), when=EqualsRule('kind', Interaction.Kind.SERVICE_DELIVERY), ), ValidationRule( 'too_many_contacts_for_event_service_delivery', OperatorRule('contacts', lambda value: len(value) <= 1), when=OperatorRule('is_event', bool), ), ValidationRule( 'invalid_for_investment', OperatorRule('were_countries_discussed', not_), OperatorRule('export_countries', not_), when=EqualsRule('theme', Interaction.Theme.INVESTMENT), ), ValidationRule( 'required', OperatorRule('were_countries_discussed', is_not_blank), when=AndRule( IsObjectBeingCreated(), InRule( 'theme', [Interaction.Theme.EXPORT, Interaction.Theme.OTHER], ), ), ), ValidationRule( 'required', OperatorRule('export_countries', is_not_blank), when=AndRule( OperatorRule('were_countries_discussed', bool), InRule( 'theme', [Interaction.Theme.EXPORT, Interaction.Theme.OTHER], ), ), ), ValidationRule( 'invalid_when_no_countries_discussed', OperatorRule('export_countries', is_blank), when=AndRule( IsObjectBeingCreated(), OperatorRule('were_countries_discussed', not_), InRule( 'theme', [Interaction.Theme.EXPORT, Interaction.Theme.OTHER], ), ), ), # These two rules are only checked for service deliveries as there's a separate # check that event is blank for interactions above which takes precedence (to # avoid duplicate or contradictory error messages) ValidationRule( 'required', OperatorRule('event', bool), when=AndRule( OperatorRule('is_event', bool), EqualsRule('kind', Interaction.Kind.SERVICE_DELIVERY), ), ), ValidationRule( 'invalid_for_non_event', OperatorRule('event', not_), when=AndRule( OperatorRule('is_event', not_), EqualsRule('kind', Interaction.Kind.SERVICE_DELIVERY), ), ), ), ]