Beispiel #1
0
    def verify_check_digit(self, rcn: Rcn) -> None:
        if self.check_digit_slice is None:
            return None

        value = rcn.value[self.value_slice]
        check_digit = int(rcn.value[self.check_digit_slice])
        calculated_check_digit = checksums.price_check_digit(value)

        if check_digit != calculated_check_digit:
            raise ParseError(
                f"Invalid check digit for variable measure value {value!r} "
                f"in RCN {rcn.value!r}: "
                f"Expected {calculated_check_digit!r}, got {check_digit!r}.")
Beispiel #2
0
    def _parse_using_british_price_rules(self: Rcn) -> None:
        # References:
        #   https://www.gs1uk.org/how-to-barcode-variable-measure-items

        if self.payload[:2] not in ("20", ):
            return

        check_digit = int(self.payload[-5])
        value = self.payload[-4:]

        calculated_check_digit = checksums.price_check_digit(value)
        if check_digit != calculated_check_digit:
            raise ParseError(
                f"Invalid price check digit for price data {value!r} "
                f"in RCN {self.value!r}: "
                f"Expected {calculated_check_digit!r}, got {check_digit!r}.")

        pounds_sterling = Decimal(value)
        self.price = pounds_sterling / 100
Beispiel #3
0
    def without_variable_measure(self, rcn: Rcn) -> Gtin:
        # Zero out the variable measure part of the payload, and recalculate both
        # the GTIN check digit and the variable measure's check digit digit, if any.

        rcn_13 = rcn.as_gtin_13()
        zeroed_value = "0" * len(rcn_13[self.value_slice])

        digits = list(self.pattern)
        digits[self.prefix_slice] = list(rcn_13[self.prefix_slice])
        digits[self.value_slice] = list(zeroed_value)
        if self.check_digit_slice is not None:
            digits[self.check_digit_slice] = [
                str(checksums.price_check_digit(zeroed_value))
            ]

        gtin_payload = "".join(digits)
        gtin_check_digit = checksums.numeric_check_digit(gtin_payload)
        gtin = f"{gtin_payload}{gtin_check_digit}"
        return Gtin.parse(gtin, rcn_region=rcn.region)
Beispiel #4
0
    def without_variable_measure(self: Rcn) -> Gtin:
        """Create a new RCN where the variable measure is zeroed out.

        This provides us with a number which still includes the item
        reference, but does not vary with weight/price, and can thus be used
        to lookup the relevant trade item in a database or similar.

        This has no effect on RCNs intended for use within a company, as
        the semantics of those numbers vary from company to company.

        Returns:
            A new RCN instance with zeros in the variable measure places.

        Raises:
            EncodeError: If the rules for variable measures in the region are unknown.
        """
        if self.usage == RcnUsage.COMPANY:
            return self

        if self.region in (
                RcnRegion.BALTICS,
                RcnRegion.NORWAY,
                RcnRegion.SWEDEN,
        ):
            measure = "0000"
            payload = f"{self.value[:-5]}{measure}"
            check_digit = checksums.numeric_check_digit(payload)
            value = f"{payload}{check_digit}"
            return Gtin.parse(value, rcn_region=self.region)
        elif self.region in (RcnRegion.GREAT_BRITAIN, ):
            measure = "0000"
            price_check_digit = checksums.price_check_digit(measure)
            payload = f"{self.value[:-6]}{price_check_digit}{measure}"
            check_digit = checksums.numeric_check_digit(payload)
            value = f"{payload}{check_digit}"
            return Gtin.parse(value, rcn_region=self.region)
        else:
            raise EncodeError(
                f"Cannot zero out the variable measure part of {self.value!r} as the "
                f"RCN rules for the geographical region {self.region!r} are unknown."
            )
Beispiel #5
0
def test_price_check_digit(value: str, expected: int) -> None:
    assert price_check_digit(value) == expected
Beispiel #6
0
def test_price_check_digit_on_values_with_wrong_length(value: str) -> None:
    with pytest.raises(ValueError) as exc_info:
        price_check_digit(value)

    assert str(
        exc_info.value) == f"Expected input of length 4 or 5, got {value!r}."
Beispiel #7
0
def test_price_check_digit_with_nonnumeric_value(value: str) -> None:
    with pytest.raises(ValueError) as exc_info:
        price_check_digit(value)

    assert str(exc_info.value) == f"Expected numeric value, got {value!r}."