Пример #1
0
def test_ON10_multiple_active_origins():
    """Tests that it is possible to create multiple quota origins, as long as a
    measure with a quota is covered by at least one of these origins."""
    valid_between = TaricDateRange(date(2020, 1, 1), date(2020, 1, 31))
    measure = factories.MeasureWithQuotaFactory.create(
        order_number__origin__valid_between=valid_between,
        valid_between=valid_between,
    )
    later_origin = factories.QuotaOrderNumberOriginFactory.create(
        order_number=measure.order_number,
        valid_between=TaricDateRange(date(2021, 1, 1), date(2021, 1, 31)),
    )

    business_rules.ON10(later_origin.transaction).validate(later_origin)
Пример #2
0
    def terminate(self, workbasket, when: date):
        """
        Returns a new version of the measure updated to end on the specified
        date.

        If the measure would not have started on that date, the measure is
        deleted instead. If the measure will already have ended by this date,
        then does nothing.
        """
        starts_after_date = self.valid_between.lower >= when
        ends_before_date = (
            not self.valid_between.upper_inf and self.valid_between.upper < when
        )

        if ends_before_date:
            return self

        update_params = {}
        if starts_after_date:
            update_params["update_type"] = UpdateType.DELETE
        else:
            update_params["update_type"] = UpdateType.UPDATE
            update_params["valid_between"] = TaricDateRange(
                lower=self.valid_between.lower,
                upper=when,
            )
            if not self.terminating_regulation:
                update_params["terminating_regulation"] = self.generating_regulation

        return self.new_draft(workbasket, **update_params)
Пример #3
0
def test_form_save_creates_new_footnote_id_and_footnote_type_id_combo(
    session_with_workbasket, ):
    """Tests that when two non-overlapping footnotes of the same type are
    created that these are created with a different footnote_id, to avoid
    duplication of footnote_id and footnote_type_id combination e.g. TN001."""
    footnote_type = factories.FootnoteTypeFactory.create()
    valid_between = TaricDateRange(
        datetime.date(2021, 1, 1),
        datetime.date(2021, 12, 1),
    )
    earlier = factories.FootnoteFactory.create(
        footnote_type=footnote_type,
        valid_between=valid_between,
        footnote_id="001",
    )

    data = {
        "footnote_type": footnote_type.pk,
        "start_date_0": 2,
        "start_date_1": 2,
        "start_date_2": 2022,
        "description": "A note on feet",
    }
    form = forms.FootnoteCreateForm(data=data, request=session_with_workbasket)
    new_footnote = form.save(commit=False)

    assert earlier.footnote_id != new_footnote.footnote_id
Пример #4
0
def test_form_save_creates_new_certificate(session_with_workbasket, ):
    """Tests that the certificate create form creates a new certificate, and
    that two certificates of the same type are created with different sid's."""

    certificate_type = factories.CertificateTypeFactory.create()
    valid_between = TaricDateRange(
        datetime.date(2021, 1, 1),
        datetime.date(2021, 12, 1),
    )
    certificate_a = factories.CertificateFactory.create(
        certificate_type=certificate_type,
        valid_between=valid_between,
        sid="001",
    )

    certificate_b_data = {
        "certificate_type": certificate_type.pk,
        "start_date_0": 2,
        "start_date_1": 2,
        "start_date_2": 2022,
        "description": "A participation certificate",
    }
    form = forms.CertificateCreateForm(
        data=certificate_b_data,
        request=session_with_workbasket,
    )
    certificate_b = form.save(commit=False)

    assert certificate_a.certificate_type == certificate_b.certificate_type
    assert certificate_a.sid != certificate_b.sid
    assert certificate_b.sid == "002"
Пример #5
0
    def clean(self):
        cleaned_data = super().clean()

        # extract sid from code
        cleaned_data["sid"] = cleaned_data.pop("code", "")[1:]

        if not cleaned_data["sid"] and self.instance and self.instance.sid:
            cleaned_data["sid"] = self.instance.sid

        if not cleaned_data["sid"]:
            raise ValidationError({"code": "Certificate code is required"})

        # get type from instance if not submitted
        ctype = cleaned_data.get("certificate_type")

        if not ctype and self.instance and self.instance.certificate_type:
            ctype = self.instance.certificate_type

        if not ctype:
            raise ValidationError(
                {"certificate_type": "Certificate type is required"})

        # combine start and end dates into date range
        start_date = cleaned_data.pop("start_date", None)
        end_date = cleaned_data.pop("end_date", None)
        cleaned_data["valid_between"] = TaricDateRange(start_date, end_date)

        return cleaned_data
Пример #6
0
    def terminate(self: Self, workbasket, when: date) -> Self:
        """
        Returns a new version of the object updated to end on the specified
        date.

        If the object would not have started on that date, the object is deleted
        instead. If the object will already have ended by this date, then does
        nothing.

        Any keyword arguments passed will be applied in the case of an update
        and are ignored for a delete or no change.
        """
        starts_after_date = (
            not self.valid_between.lower_inf and self.valid_between.lower >= when
        )
        ends_before_date = (
            not self.valid_between.upper_inf and self.valid_between.upper < when
        )

        if ends_before_date:
            return self

        update_params = {}
        if starts_after_date:
            update_params["update_type"] = UpdateType.DELETE
        else:
            update_params["update_type"] = UpdateType.UPDATE
            update_params["valid_between"] = TaricDateRange(
                lower=self.valid_between.lower,
                upper=when,
            )

        return self.new_version(workbasket, **update_params)
Пример #7
0
def test_goods_nomenclature_indent_importer_update_multiple_parents(
    valid_user,
    date_ranges,
    update_type,
):
    parent_indent = factories.SimpleGoodsNomenclatureIndentFactory.create(
        valid_between=TaricDateRange(date(2020, 1, 1), date(2020, 12, 1)),
        indented_goods_nomenclature__valid_between=TaricDateRange(
            date(2020, 1, 1),
            date(2020, 12, 1),
        ),
        indented_goods_nomenclature__item_id="1300000000",
    )
    parent1 = factories.GoodsNomenclatureIndentNodeFactory.create(
        valid_between=TaricDateRange(date(2020, 1, 1), date(2020, 4, 1)),
        indent=parent_indent,
    )
    parent2 = factories.GoodsNomenclatureIndentNodeFactory.create(
        valid_between=TaricDateRange(date(2020, 4, 2), date(2020, 8, 1)),
        indent=parent_indent,
    )
    parent3 = factories.GoodsNomenclatureIndentNodeFactory.create(
        valid_between=TaricDateRange(date(2020, 8, 2), date(2020, 12, 1)),
        indent=parent_indent,
    )

    indent = factories.GoodsNomenclatureIndentFactory.build(
        indented_goods_nomenclature=factories.SimpleGoodsNomenclatureFactory.create(
            item_id="1301000000",
            valid_between=TaricDateRange(date(2020, 1, 1), date(2020, 12, 1)),
        ),
        valid_between=TaricDateRange(date(2020, 1, 1), date(2020, 6, 1)),
    )

    first_indent = make_and_get_indent(indent, valid_user, depth=0)
    first_parents = [node.get_parent() for node in first_indent.nodes.all()]

    assert set(first_parents) == {parent1, parent2, parent3}

    updated_indent = factories.GoodsNomenclatureIndentFactory.build(
        sid=first_indent.sid,
        indented_goods_nomenclature=indent.indented_goods_nomenclature,
        valid_between=TaricDateRange(date(2020, 6, 2), date(2020, 12, 1)),
        update_type=update_type,
    )
    second_indent = make_and_get_indent(updated_indent, valid_user, depth=0)
    second_parents = [node.get_parent() for node in second_indent.nodes.all()]

    assert second_indent.sid == first_indent.sid
    assert second_indent.indent == 0
    assert len(second_parents) == 2
    assert set(second_parents) == {parent2, parent3}
    assert (
        second_indent.indented_goods_nomenclature.sid
        == indent.indented_goods_nomenclature.sid
    )
    assert second_indent.valid_between.lower == updated_indent.valid_between.lower
Пример #8
0
 def __getattr__(self, name):
     if name in self.deltas:
         start, end = self.deltas[name]
         start = self.now + start
         if end is not None:
             end = self.now + end
         return TaricDateRange(start, end)
     raise AttributeError(name)
Пример #9
0
def validity_range(request):
    start, end, expect_error = request.param
    return (
        TaricDateRange(
            date.fromisoformat(start),
            date.fromisoformat(end),
        ),
        expect_error,
    )
Пример #10
0
    def clean(self):
        cleaned_data = super().clean()

        start_date = cleaned_data.pop("start_date", None)
        cleaned_data["valid_between"] = TaricDateRange(
            start_date,
            self.instance.valid_between.upper,
        )

        return cleaned_data
Пример #11
0
def test_goods_nomenclature_indent_importer_create_multiple_parents(
    valid_user,
    date_ranges,
):
    """
    In some cases there is an indent which is created which already expects to
    have multiple parents over its lifetime.

    Assert multiple indent nodes are generated in this scenario.
    """

    indent_validity = TaricDateRange(
        date_ranges.adjacent_earlier.lower,
        date_ranges.adjacent_later.upper,
    )
    parent_indent = factories.SimpleGoodsNomenclatureIndentFactory.create(
        valid_between=indent_validity,
        indented_goods_nomenclature__valid_between=indent_validity,
        indented_goods_nomenclature__item_id="1300000000",
    )
    parent_nodes = {
        factories.GoodsNomenclatureIndentNodeFactory.create(
            valid_between=date_ranges.adjacent_earlier,
            indent=parent_indent,
        ),
        factories.GoodsNomenclatureIndentNodeFactory.create(
            valid_between=date_ranges.normal,
            indent=parent_indent,
        ),
        factories.GoodsNomenclatureIndentNodeFactory.create(
            valid_between=date_ranges.adjacent_later,
            indent=parent_indent,
        ),
    }

    indent = factories.GoodsNomenclatureIndentFactory.build(
        update_type=UpdateType.CREATE.value,
        indented_goods_nomenclature=factories.SimpleGoodsNomenclatureFactory.create(
            item_id="1301000000",
            valid_between=indent_validity,
        ),
        valid_between=indent_validity,
    )

    db_indent = make_and_get_indent(indent, valid_user, depth=0)

    assert db_indent.sid == indent.sid
    assert db_indent.indent == 0
    assert db_indent.nodes.count() == 3
    assert all(node.get_parent() in parent_nodes for node in db_indent.nodes.all())
    assert (
        db_indent.indented_goods_nomenclature.sid
        == indent.indented_goods_nomenclature.sid
    )
    assert db_indent.valid_between.lower == indent.valid_between.lower
Пример #12
0
    def filter_active_state(self, queryset, name, value):
        active_status_filter = Q()
        current_date = TaricDateRange(date.today(), date.today())
        if value == ["active"]:
            active_status_filter = Q(valid_between__upper_inf=True) | Q(
                valid_between__contains=current_date,
            )
        if value == ["terminated"]:
            active_status_filter = Q(valid_between__fully_lt=current_date)

        return queryset.filter(active_status_filter)
Пример #13
0
    def _get_restricted_valid_between(
        self,
        valid_between: TaricDateRange,
    ) -> TaricDateRange:
        new_valid_between = self.valid_between
        if not new_valid_between.lower or (
                valid_between.lower
                and new_valid_between.lower < valid_between.lower):
            new_valid_between = TaricDateRange(
                valid_between.lower,
                new_valid_between.upper,
            )
        if not new_valid_between.upper or (
                valid_between.upper
                and new_valid_between.upper > valid_between.upper):
            new_valid_between = TaricDateRange(
                new_valid_between.lower,
                valid_between.upper,
            )

        return new_valid_between
Пример #14
0
def test_starts_on_minimum_date(
    measure_data,
    date_ranges: Dates,
    measure_creation_pattern: MeasureCreationPattern,
):
    measure_data["validity_start"] = date_ranges.no_end_before(
        date_ranges.now).lower
    measure_data["goods_nomenclature"] = factories.GoodsNomenclatureFactory(
        valid_between=TaricDateRange(date_ranges.now, None), )

    measure = measure_creation_pattern.create(**measure_data)
    assert measure.valid_between.lower == date_ranges.now
Пример #15
0
    def suspend(
            self,
            code: GoodsNomenclature,
            duty: str,
            validity_start: date,
            validity_end: Optional[date],
            footnotes=frozenset(),
            copy_from: Optional[Measure] = None,
    ):
        """Implement a new suspension on tariffs on the passed code down to the
        given duty rate between the two validity dates."""
        if not copy_from:
            # If there is no MFN measure we have a problem because we don't know what
            # rate to use on the subsequent measure, so just skip that.
            existing_measures = self.get_mfn_measures(code, validity_start)
            if not existing_measures.exists():
                self.logger.warning(
                    "No MFN found on code %s at %s. Resulting suspension will not have MFN rate.",
                    code,
                    validity_start,
                )

            # If the MFN measure does not have an additional code, remove it.
            # If not, keep it because the other suspension still needs it.
            if (existing_measures.count() == 1
                    and existing_measures.get().additional_code is None):
                deleted_mfn_measure = existing_measures.get().terminate(
                    self.workbasket,
                    validity_start - timedelta(days=1),
                )
                self._log("Terminated", deleted_mfn_measure)

        # Now create the new MFN measure.
        maybe_mfn = self.get_suspended_mfn_measure(code, validity_start)
        if not maybe_mfn.exists():
            mfn_measure = (copy_from or existing_measures.last()).copy(
                goods_nomenclature=code,
                additional_code=self.mfn_additional_code,
                generating_regulation=self.mfn_regulation,
                valid_between=TaricDateRange(validity_start, validity_end),
                transaction=self.workbasket.new_transaction(),
            )
            self._log("Created MFN measure", mfn_measure)

        # Now create the suspended measure.
        return self.create_suspension(
            code,
            duty,
            validity_start,
            validity_end,
            footnotes,
        )
Пример #16
0
    def from_db_value(self, value: Union[DateRange, TaricDateRange], *_args,
                      **_kwargs) -> TaricDateRange:
        """
        By default Django ignores the range_type and just returns a Psycopg2
        DateRange.

        This method forces the conversion to a TaricDateRange and shifts the
        upper date to be inclusive (it is exclusive by default).
        """
        if not isinstance(value, DateRange):
            return value
        lower = value.lower
        upper = value.upper
        if not value.upper_inc and not value.upper_inf:
            upper = upper - relativedelta(days=1)
        return TaricDateRange(lower=lower, upper=upper)
Пример #17
0
def test_goods_nomenclature_indent_importer_with_overlapping_branch_shift(
    make_inappropriate_family,
    valid_user,
    date_ranges,
):
    """
    In some scenarios a new indent can step in between an existing Goods
    Nomenclature and its parent. In more extreme cases when this happens the
    dates could overlap so that the child needs to belong to both parents.

    Ensure when this happens the child is split between both parents.
    """
    bad_parent, child_indent = make_inappropriate_family("46")

    child_nodes = models.GoodsNomenclatureIndentNode.objects.filter(indent=child_indent)
    assert child_nodes.count() > 0
    for node in child_nodes:
        assert node.get_parent() == bad_parent.nodes.first()

    new_parent = make_and_get_indent(
        factories.GoodsNomenclatureIndentFactory.build(
            indented_goods_nomenclature=factories.GoodsNomenclatureFactory.create(
                item_id="4602000000",
                valid_between=date_ranges.adjacent_no_end,
            ),
            valid_between=date_ranges.adjacent_no_end,
            update_type=UpdateType.CREATE,
        ),
        valid_user,
        depth=0,
    )

    child_nodes = models.GoodsNomenclatureIndentNode.objects.filter(indent=child_indent)

    assert child_nodes.count() == 2
    nodes = {node.get_parent().indent: node for node in child_nodes}

    assert bad_parent in nodes
    assert nodes[bad_parent].valid_between == TaricDateRange(
        date_ranges.no_end.lower,
        date_ranges.adjacent_no_end.lower - relativedelta(days=1),
    )

    assert new_parent in nodes
    assert nodes[new_parent].valid_between == date_ranges.adjacent_no_end
Пример #18
0
    def unsuspend(
        self,
        code: GoodsNomenclature,
        validity_start: date,
        validity_end: Optional[date],
        replace_onto: Optional[GoodsNomenclature] = None,
    ):
        """End the suspension on tariffs on the passed code as of the passed
        validity dates."""
        if not replace_onto:
            replace_onto = code

        # Find the existing suspension measures and terminate them.
        terminated_suspension = self.get_suspension_measure(
            code, validity_start).get()
        self._log(
            "Terminated",
            terminated_suspension.terminate(
                self.workbasket,
                validity_start - timedelta(days=1),
            ),
        )

        terminated_mfn = self.get_suspended_mfn_measure(code,
                                                        validity_start).get()
        self._log(
            "Terminated",
            terminated_mfn.terminate(
                self.workbasket,
                validity_start - timedelta(days=1),
            ),
        )

        # If there are any other codes left, we don't need to recreate the MFN
        # Else, set up a new MFN measure
        if not self.get_mfn_measures(code, validity_start).exists():
            new_mfn = terminated_mfn.copy(
                goods_nomenclature=replace_onto,
                generating_regulation=self.mfn_regulation,
                additional_code=None,
                valid_between=TaricDateRange(validity_start, validity_end),
                transaction=self.workbasket.new_transaction(
                ),  # TODO footnotes
            )
            self._log("Created plain MFN", new_mfn)
Пример #19
0
    def filter_active_state(self, queryset, name, value):
        """
        Filter the given queryset to those which have the specified active
        state.

        :param queryset: The queryset to filter
        :param name: The name of the field
        :param value: The value of the field
        """
        active_status_filter = Q()
        current_date = TaricDateRange(date.today(), date.today())
        if value == ["active"]:
            active_status_filter = Q(valid_between__upper_inf=True) | Q(
                valid_between__contains=current_date,
            )
        if value == ["terminated"]:
            active_status_filter = Q(valid_between__fully_lt=current_date)

        return queryset.filter(active_status_filter)
Пример #20
0
    def validate(self, measure):
        generating = measure.generating_regulation
        terminating = measure.terminating_regulation

        if terminating is None:
            return

        # TODO: Verify this is needed
        # if generating.approved and not terminating.approved:
        #     raise self.violation(
        #         measure,
        #         "If the measure's measure-generating regulation is 'approved', then so "
        #         "must be the justification regulation.",
        #     )

        if (terminating.regulation_id == generating.regulation_id
                and terminating.role_type == generating.role_type):
            return

        # TODO: verify this day (should be 2004-01-01 really, except for measure 2700491 (at least), and 2939413))
        # TODO: And carrying on past 2020 with 3784976
        if 1 or measure.valid_between.lower < date(2007, 7, 1):
            return

        valid_day = measure.effective_end_date + relativedelta(days=1)
        if valid_day not in terminating.valid_between:
            amends = terminating.amends.first()
            if amends and valid_day in TaricDateRange(
                    amends.valid_between.lower,
                    terminating.valid_between.upper,
            ):
                return

            raise self.violation(
                measure,
                "The justification regulation must be either the measure's measure-generating "
                "regulation, or a measure-generating regulation valid on the day after the "
                "measure's end date.",
            )
Пример #21
0
    def clean(self):
        cleaned_data = super().clean()

        if self.instance and self.instance.footnote_id:
            cleaned_data["footnote_id"] = self.instance.footnote_id

        # get type from instance if not submitted
        footnote_type = cleaned_data.get("footnote_type")

        if not footnote_type and self.instance and self.instance.footnote_type:
            footnote_type = self.instance.footnote_type

        if not footnote_type:
            raise ValidationError(
                {"footnote_type": "Footnote type is required"})

        # combine start and end dates into date range
        start_date = cleaned_data.pop("start_date", None)
        end_date = cleaned_data.pop("end_date", None)
        cleaned_data["valid_between"] = TaricDateRange(start_date, end_date)

        return cleaned_data
Пример #22
0
    def clean(self):
        cleaned_data = super().clean()

        start_date = cleaned_data.pop("start_date", None)
        end_date = cleaned_data.pop("end_date", None)

        # Data may not be present, e.g. if the user skips ahead in the sidebar
        valid_between = self.initial.get("valid_between")
        if valid_between and end_date and start_date and end_date < start_date:
            if start_date != valid_between.lower:
                self.add_error(
                    "start_date",
                    "The start date must be the same as or before the end date.",
                )
            if end_date != self.initial["valid_between"].upper:
                self.add_error(
                    "end_date",
                    "The end date must be the same as or after the start date.",
                )
        cleaned_data["valid_between"] = TaricDateRange(start_date, end_date)

        if start_date:
            day, month, year = (start_date.day, start_date.month,
                                start_date.year)
            self.fields["start_date"].initial = date(
                day=int(day),
                month=int(month),
                year=int(year),
            )

        if end_date:
            day, month, year = (end_date.day, end_date.month, end_date.year)
            self.fields["end_date"].initial = date(
                day=int(day),
                month=int(month),
                year=int(year),
            )

        return cleaned_data
Пример #23
0
    def validate(self, measure):
        if (not measure.effective_valid_between.upper_inf
                and measure.effective_valid_between.upper < date(2008, 1, 1)):
            # Exclude measure ending before 2008 - ME87 only counts from 2008 onwards.
            return

        regulation_validity = measure.generating_regulation.valid_between
        effective_end_date = measure.generating_regulation.effective_end_date

        if effective_end_date:
            regulation_validity = TaricDateRange(
                regulation_validity.lower,
                date(
                    year=effective_end_date.year,
                    month=effective_end_date.month,
                    day=effective_end_date.day,
                ),
            )

        if not validity_range_contains_range(
                regulation_validity,
                measure.effective_valid_between,
        ):
            raise self.violation(measure)
Пример #24
0
 def short_before(cls, dt):
     return TaricDateRange(
         dt + relativedelta(months=-1),
         dt + relativedelta(days=-14),
     )
Пример #25
0
 def short_after(cls, dt):
     return TaricDateRange(
         dt + relativedelta(days=+14),
         dt + relativedelta(months=+1),
     )
Пример #26
0
 def short_overlap(cls, dt):
     return TaricDateRange(
         dt + relativedelta(months=-1),
         dt + relativedelta(months=+1),
     )
Пример #27
0
 def no_end_before(cls, dt):
     return TaricDateRange(
         dt + relativedelta(months=-1),
         None,
     )
Пример #28
0
def measure_type():
    return factories.MeasureTypeFactory.create(valid_between=TaricDateRange(
        datetime.date(2020, 1, 1), None, "[)"), )
Пример #29
0
    def create(
        self,
        duty_sentence: str,
        geographical_area: GeographicalArea,
        goods_nomenclature: GoodsNomenclature,
        measure_type: MeasureType,
        validity_start: date,
        validity_end: date,
        exclusions: Sequence[GeographicalArea] = [],
        order_number: Optional[QuotaOrderNumber] = None,
        authorised_use: bool = False,
        additional_code: AdditionalCode = None,
        footnotes: Sequence[Footnote] = [],
        proofs_of_origin: Sequence[Certificate] = [],
        condition_sentence: Optional[str] = None,
    ) -> Iterator[TrackedModel]:
        """
        Create a new measure linking the passed data and any defaults. The
        measure is saved as part of a single transaction.

        If `exclusions` are passed, measure exclusions will be created for those
        geographical areas on the created measures. If a group is passed as an
        exclusion, all of its members at of the start date of the measure will
        be excluded.

        If `authorised_use` is `True`, measure conditions requiring the N990
        authorised use certificate will be added to the measure.

        If `footnotes` are passed, footnote associations will be added to the
        measure.

        If `proofs_of_origin` are passed, measure conditions requiring the
        proofs will be added to the measure.
        """

        assert goods_nomenclature.suffix == "80", "ME7 – must be declarable"

        actual_start = maybe_max(validity_start,
                                 goods_nomenclature.valid_between.lower)
        actual_end = maybe_min(goods_nomenclature.valid_between.upper,
                               validity_end)

        new_measure_sid = self.measure_sid_counter()

        if actual_end != validity_end:
            logger.warning(
                "Measure {} end date capped by {} end date: {:%Y-%m-%d}".
                format(
                    new_measure_sid,
                    goods_nomenclature.item_id,
                    actual_end,
                ), )

        measure_data: Dict[str, Any] = {
            "update_type": UpdateType.CREATE,
            "transaction": self.workbasket.new_transaction(),
            **self.defaults,
            **{
                "sid":
                new_measure_sid,
                "measure_type":
                measure_type,
                "geographical_area":
                geographical_area,
                "goods_nomenclature":
                goods_nomenclature,
                "order_number":
                order_number or self.defaults.get("order_number"),
                "additional_code":
                additional_code or self.defaults.get("additional_code"),
                "valid_between":
                TaricDateRange(actual_start, actual_end),
            },
        }

        if actual_end is not None:
            measure_data["terminating_regulation"] = measure_data[
                "generating_regulation"]

        new_measure = Measure.objects.create(**measure_data)
        yield new_measure

        # If there are any geographical exclusions, output them attached to
        # the measure. If a group is passed as an exclusion, the members of
        # that group will be excluded instead.
        # TODO: create multiple measures if memberships come to an end.
        for exclusion in exclusions:
            yield from self.get_measure_excluded_geographical_areas(
                new_measure,
                exclusion,
            )

        # Output any footnote associations required.
        yield from self.get_measure_footnotes(new_measure, footnotes)

        # If this is a measure under authorised use, we need to add
        # some measure conditions with the N990 certificate.
        if authorised_use:
            yield from self.get_authorised_use_measure_conditions(new_measure)

        # If this is a measure for an origin quota, we need to add
        # some measure conditions with the passed proof of origin.
        if any(proofs_of_origin):
            yield from self.get_proof_of_origin_condition(
                new_measure, proofs_of_origin)

        # If we have a condition sentence, parse and add to the measure.
        if condition_sentence:
            yield from self.get_conditions(new_measure, condition_sentence)

        # Now generate the duty components for the passed duty rate.
        yield from self.get_measure_components_from_duty_rate(
            new_measure,
            duty_sentence,
        )
Пример #30
0
 def medium_before(cls, dt):
     return TaricDateRange(
         dt + relativedelta(months=-1),
         dt + relativedelta(days=-1),
     )