def test_prevent_quota_definition_deletion( unapproved_transaction, date_ranges, date_range, update_type, error_expected, ): """ QAM does not like handling deletions of active Quota Definitions. Ensure an active Quota Definition cannot be deleted. """ quota_definition = factories.QuotaDefinitionFactory.create( valid_between=getattr(date_ranges, date_range), ) deleted = quota_definition.new_version( workbasket=unapproved_transaction.workbasket, transaction=unapproved_transaction, update_type=update_type, ) error_expected = error_expected and (update_type == UpdateType.DELETE) with raises_if(BusinessRuleViolation, error_expected): business_rules.PreventQuotaDefinitionDeletion( deleted.transaction).validate(deleted, )
def test_GA13(area_code, expect_error): """The referenced geographical area id (member) can only be linked to a country or region.""" membership = factories.GeographicalMembershipFactory.create( member__area_code=area_code, ) with raises_if(BusinessRuleViolation, expect_error): business_rules.GA13(membership.transaction).validate(membership)
def test_ACN2_allowed_application_codes(app_code, expect_error): """The referenced additional code type must have as application code "non- Meursing" or "Export Refund for Processed Agricultural Goods”.""" additional_code = factories.AdditionalCodeFactory.create( type__application_code=app_code, ) with raises_if(BusinessRuleViolation, expect_error): business_rules.ACN2( additional_code.transaction).validate(additional_code)
def test_blocking_of_fcfs_quotas_only(mechanism, error_expected): """Blocking periods are only applicable to FCFS quotas.""" blocking = factories.QuotaBlockingFactory.create( quota_definition__order_number__mechanism=mechanism, ) with raises_if(BusinessRuleViolation, error_expected): business_rules.BlockingOnlyOfFCFSQuotas( blocking.transaction).validate(blocking)
def do_assert( factory: Type[factories.TrackedModelMixin], business_rule: Type[BusinessRule], identifying_fields: Optional[Dict[str, Any]] = None, ): make_record, error_expected = request.param duplicate = make_record(factory, identifying_fields) with raises_if(BusinessRuleViolation, error_expected): business_rule(duplicate.transaction).validate(duplicate)
def test_suspension_of_fcfs_quotas_only(mechanism, error_expected): """Quota suspensions are only applicable to First Come First Served quotas.""" suspension = factories.QuotaSuspensionFactory.create( quota_definition__order_number__mechanism=mechanism, ) with raises_if(BusinessRuleViolation, error_expected): business_rules.SuspensionsOnlyToFCFSQuotas( suspension.transaction).validate(suspension, )
def test_GA16(date_ranges, group_validity, membership_validity, expect_error): """The validity period of the geographical area group must span all membership periods of its members.""" membership = factories.GeographicalMembershipFactory.create( geo_group__valid_between=getattr(date_ranges, group_validity), valid_between=getattr(date_ranges, membership_validity), ) with raises_if(BusinessRuleViolation, expect_error): business_rules.GA16(membership.transaction).validate(membership)
def test_duties_validator( duties, error_expected, date_ranges, duty_sentence_parser, ): # duty_sentence_parser populates data needed by the DutySentenceParser # removing it will cause the test to fail. with raises_if(ValidationError, error_expected): validate_duties(duties, date_ranges.normal)
def check(factory): first_instance = factory.create() instance = factory.create( update_type=update_type, version_group=first_instance.version_group, ) with raises_if(UpdateValidity.Violation, expected_error): UpdateValidity(instance.transaction).validate(instance) return True
def test_ON13(area_code, expect_error): """An exclusion can only be entered if the order number origin is a geographical area group (area code = 1). """ origin = factories.QuotaOrderNumberOriginFactory.create( geographical_area__area_code=area_code, ) exclusion = factories.QuotaOrderNumberOriginExclusionFactory.create( origin=origin) with raises_if(BusinessRuleViolation, expect_error): business_rules.ON13(exclusion.transaction).validate(exclusion)
def test_NIG10(date_ranges, valid_between, expect_error): """The successor must be applicable the day after the end date of the old code.""" successor = factories.GoodsNomenclatureSuccessorFactory.create( absorbed_into_goods_nomenclature__valid_between=date_ranges.normal, replaced_goods_nomenclature__valid_between=getattr( date_ranges, valid_between, ), ) with raises_if(BusinessRuleViolation, expect_error): business_rules.NIG10(successor.transaction).validate(successor)
def test_QA6(existing_relation, new_relation, error_expected): """Sub-quotas associated with the same main quota must have the same relation type.""" existing = factories.QuotaAssociationFactory.create( sub_quota_relation_type=existing_relation, ) assoc = factories.QuotaAssociationFactory.create( main_quota=existing.main_quota, sub_quota_relation_type=new_relation, ) with raises_if(BusinessRuleViolation, error_expected): business_rules.QA6(assoc.transaction).validate(assoc)
def test_NIG18_NIG19(application_code, item_id, error_expected): """Footnotes with a footnote type for which the application type = "CN footnotes" must be linked to CN lines (all codes up to 8 digits). Footnotes with a footnote type for which the application type = "TARIC footnotes" can be associated at any level.""" assoc = factories.FootnoteAssociationGoodsNomenclatureFactory.create( associated_footnote__footnote_type__application_code=application_code, goods_nomenclature__item_id=item_id, ) with raises_if(BusinessRuleViolation, error_expected): business_rules.NIG18(assoc.transaction).validate(assoc)
def test_NIG7(date_ranges, valid_between, expect_error): """The origin must be applicable the day before the start date of the new code entered.""" origin = factories.GoodsNomenclatureOriginFactory.create( derived_from_goods_nomenclature__valid_between=date_ranges.normal, new_goods_nomenclature__valid_between=getattr( date_ranges, valid_between, ), ) with raises_if(BusinessRuleViolation, expect_error): business_rules.NIG7(origin.transaction).validate(origin)
def test_ON2(date_ranges, existing_range, new_range, ranges_overlap): """There may be no overlap in time of two quota order numbers with the same quota order number id.""" existing = factories.QuotaOrderNumberFactory.create(valid_between=getattr( date_ranges, existing_range), ) order_number = factories.QuotaOrderNumberFactory.create( order_number=existing.order_number, valid_between=getattr(date_ranges, new_range), ) with raises_if(BusinessRuleViolation, ranges_overlap): business_rules.ON2(order_number.transaction).validate(order_number)
def test_NIG24(date_ranges, valid_between, expect_error): """When the same footnote is associated more than once with the same nomenclature then there may be no overlap in their association periods.""" existing = factories.FootnoteAssociationGoodsNomenclatureFactory.create( valid_between=date_ranges.normal, ) association = factories.FootnoteAssociationGoodsNomenclatureFactory.create( associated_footnote=existing.associated_footnote, goods_nomenclature=existing.goods_nomenclature, valid_between=getattr(date_ranges, valid_between), ) with raises_if(BusinessRuleViolation, expect_error): business_rules.NIG24(association.transaction).validate(association)
def check(factory): instance = factory.create(update_type=update_type) # Create a future instance – the business rule should ignore this # but the test for CREATE will fail if it does not. factory.create( update_type=UpdateType.UPDATE, transaction__workbasket=instance.transaction.workbasket, transaction__order=instance.transaction.order + 1, ) with raises_if(UpdateValidity.Violation, expected_error): UpdateValidity(instance.transaction).validate(instance) return True
def check( factory: Type[DjangoModelFactory], business_rule: Type[ValidityPeriodContained], **factory_kwargs, ): container_validity, contained_validity, fully_spanned = spanning_dates contained = getattr(business_rule, "contained_field_name") or "" container = getattr(business_rule, "container_field_name") or "" # If the test is checking an UPDATE or a DELETE, set the dates to be # valid on the original version so that we can tell if it is # successfully checking the later version. validity_on_contained = (container_validity if update_type != UpdateType.CREATE else contained_validity) object = factory.create( **factory_kwargs, **{ f"{contained}{'__' if contained else ''}valid_between": validity_on_contained, f"{contained}{'__' if contained else ''}update_type": UpdateType.CREATE, f"{container}{'__' if container else ''}valid_between": container_validity, }, ) workbasket = object.transaction.workbasket if update_type != UpdateType.CREATE: # Make a new version of the contained model with the actual dates we # are testing, first finding the correct contained model to use. contained_obj = object if contained: with override_current_transaction( workbasket.current_transaction): contained_obj = (object.get_versions().current(). follow_path(contained).get()) contained_obj.new_version( workbasket, valid_between=contained_validity, update_type=update_type, ) error_expected = update_type != UpdateType.DELETE and not fully_spanned with raises_if(business_rule.Violation, error_expected): business_rule(workbasket.current_transaction).validate(object)
def test_QA4(coefficient, expect_error): """ Whenever a sub-quota receives a coefficient, this has to be a strictly positive decimal number. When it is not specified a value of 1 is always assumed """ kwargs = {} if coefficient is not None: kwargs["coefficient"] = coefficient assoc = factories.QuotaAssociationFactory.create(**kwargs) with raises_if(BusinessRuleViolation, expect_error): business_rules.QA4(assoc.transaction).validate(assoc)
def test_QA3(main_volume, main_unit, sub_volume, sub_unit, expect_error): """When converted to the measurement unit of the main quota, the volume of a sub-quota must always be lower than or equal to the volume of the main quota.""" units = defaultdict(factories.MeasurementUnitFactory) assoc = factories.QuotaAssociationFactory( main_quota__volume=main_volume, main_quota__measurement_unit=units[main_unit], sub_quota__volume=sub_volume, sub_quota__measurement_unit=units[sub_unit], ) with raises_if(BusinessRuleViolation, expect_error): business_rules.QA3(assoc.transaction).validate(assoc)
def test_footnote_update(new_data, expected_valid, use_update_form): """ Tests that footnote update view allows an empty dict and that it is possible to update the end date day, month, and year to an earlier date. We expect a later end date to fail because the validity period extends beyond that of the footnote type. We test end date, rather than start_date because it is not possible to edit the start date through the view without separately updating the description start date beforehand. """ with raises_if(ValidationError, not expected_valid): use_update_form( factories.FootnoteFactory( valid_between=factories.date_ranges("big"), footnote_type__valid_between=factories.date_ranges("big"), ), new_data, )
def test_ROIMB46(regulation_id, role_type, expect_error, delete_record): """A base regulation cannot be deleted if it is used as a justification regulation, except for ‘C’ regulations used only in measures as both measure-generating regulation and justification regulation.""" # We should not be deleting base regulations. Also, we will not be using the # justification regulation field, though there will be a lot of EU regulations where # the justification regulation field is set. regulation = factories.RegulationFactory.create( regulation_id=regulation_id, role_type=role_type, ) measure = factories.MeasureFactory.create( valid_between=factories.date_ranges("normal"), generating_regulation=regulation, terminating_regulation=regulation, ) assert measure.terminating_regulation == regulation deleted = delete_record(regulation) with raises_if(BusinessRuleViolation, expect_error): business_rules.ROIMB46(deleted.transaction).validate(deleted)
def test_QA5(existing_volume, new_volume, coeff, type, error_expected): """ Whenever a sub-quota is defined with the ‘equivalent’ type, it must have the same volume as the other sub-quotas associated with the parent quota. Moreover it must be defined with a coefficient not equal to 1. A sub-quota defined with the 'normal' type must have a coefficient of 1. """ existing = factories.QuotaAssociationFactory.create( sub_quota__volume=Decimal(existing_volume), sub_quota_relation_type=type, ) assoc = factories.QuotaAssociationFactory.create( main_quota=existing.main_quota, sub_quota__volume=Decimal(new_volume), sub_quota_relation_type=type, coefficient=Decimal(coeff), ) with raises_if(BusinessRuleViolation, error_expected): business_rules.QA5(assoc.transaction).validate(assoc)
def test_NIG2( date_ranges, parent_validity, self_validity, child_validity, expect_error, ): """ The validity period of the goods nomenclature must be within the validity period of the product line above in the hierarchy. Also covers NIG3 """ parent = factories.GoodsNomenclatureIndentFactory.create( indented_goods_nomenclature__valid_between=getattr( date_ranges, parent_validity, ), indented_goods_nomenclature__item_id="2901000000", indent=0, ) self = factories.GoodsNomenclatureIndentFactory.create( indented_goods_nomenclature__valid_between=getattr(date_ranges, self_validity), indented_goods_nomenclature__item_id="2901210000", indent=1, ) child = factories.GoodsNomenclatureIndentFactory.create( indented_goods_nomenclature__item_id="2901290000", indented_goods_nomenclature__valid_between=getattr(date_ranges, child_validity), indent=2, ) # Running against a lone code should never error business_rules.NIG2(parent.transaction).validate(parent) with raises_if(BusinessRuleViolation, expect_error): business_rules.NIG2(type(child.transaction).objects.last()).validate(self)
def test_quota_definition_must_have_one_unit(has_unit, has_currency, error_expected): with raises_if(IntegrityError, error_expected): factories.QuotaDefinitionFactory.create( is_monetary=has_currency, is_physical=has_unit, )
def test_regulation_update(new_data, expected_valid, use_update_form): with raises_if(ValidationError, not expected_valid): use_update_form(factories.UIRegulationFactory(), new_data)
def test_footnote_create_form(use_create_form, new_data, expected_valid): with raises_if(ValidationError, not expected_valid): use_create_form(models.Footnote, new_data)
def test_no_blank_descriptions(description, error_expected): description = factories.TestModelDescription1Factory( description=description) with raises_if(BusinessRuleViolation, error_expected): NoBlankDescription(description.transaction).validate(description)
def test_footnote_description_update(new_data, expected_valid, use_update_form): with raises_if(ValidationError, not expected_valid): use_update_form(factories.FootnoteDescriptionFactory(), new_data)
def test_additional_code_create_form(use_create_form, new_data, expected_valid): with raises_if(ValidationError, not expected_valid): use_create_form(AdditionalCode, new_data)