Ejemplo n.º 1
0
    def parse(cls: Type[Sscc], value: str) -> Sscc:
        """Parse the given value into a :class:`Sscc` object.

        Args:
            value: The value to parse.

        Returns:
            SSCC data structure with the successfully extracted data.
            The checksum is guaranteed to be valid if an SSCC object is returned.

        Raises:
            ParseError: If the parsing fails.
        """
        value = value.strip()

        if len(value) != 18:
            raise ParseError(f"Failed to parse {value!r} as SSCC: "
                             f"Expected 18 digits, got {len(value)}.")

        if not value.isnumeric():
            raise ParseError(
                f"Failed to parse {value!r} as SSCC: Expected a numerical value."
            )

        value_without_extension_digit = value[1:]
        prefix = GS1Prefix.extract(value_without_extension_digit)
        extension_digit = int(value[0])
        payload = value[:-1]
        check_digit = int(value[-1])

        calculated_check_digit = numeric_check_digit(payload)
        if check_digit != calculated_check_digit:
            raise ParseError(
                f"Invalid SSCC check digit for {value!r}: "
                f"Expected {calculated_check_digit!r}, got {check_digit!r}.")

        return cls(
            value=value,
            prefix=prefix,
            extension_digit=extension_digit,
            payload=payload,
            check_digit=check_digit,
        )
Ejemplo n.º 2
0
    def parse(
        cls: Type[Gtin], value: str, *, rcn_region: Optional[RcnRegion] = None
    ) -> Gtin:
        """Parse the given value into a :class:`Gtin` object.

        Both GTIN-8, GTIN-12, GTIN-13, and GTIN-14 are supported.

        Args:
            value: The value to parse.
            rcn_region: The geographical region whose rules should be used to
                interpret Restricted Circulation Numbers (RCN).
                Needed to extract e.g. variable weight/price from GTIN.

        Returns:
            GTIN data structure with the successfully extracted data.
            The checksum is guaranteed to be valid if a GTIN object is returned.

        Raises:
            ParseError: If the parsing fails.
        """
        from biip.gtin import Rcn

        value = value.strip()

        if len(value) not in (8, 12, 13, 14):
            raise ParseError(
                f"Failed to parse {value!r} as GTIN: "
                f"Expected 8, 12, 13, or 14 digits, got {len(value)}."
            )

        if not value.isnumeric():
            raise ParseError(
                f"Failed to parse {value!r} as GTIN: Expected a numerical value."
            )

        stripped_value = _strip_leading_zeros(value)
        assert len(stripped_value) in (8, 12, 13, 14)

        num_significant_digits = len(stripped_value)
        gtin_format = GtinFormat(num_significant_digits)

        payload = stripped_value[:-1]
        check_digit = int(stripped_value[-1])

        packaging_level: Optional[int] = None
        if gtin_format == GtinFormat.GTIN_14:
            packaging_level = int(stripped_value[0])
            value_without_packaging_level = stripped_value[1:]
            prefix = GS1Prefix.extract(value_without_packaging_level)
        elif gtin_format == GtinFormat.GTIN_12:
            # Add a zero to convert U.P.C. Company Prefix to GS1 Company Prefix
            prefix = GS1Prefix.extract(stripped_value.zfill(13))
        elif gtin_format == GtinFormat.GTIN_8:
            prefix = GS1Prefix.extract(stripped_value.zfill(12))
        else:
            prefix = GS1Prefix.extract(stripped_value)

        calculated_check_digit = numeric_check_digit(payload)
        if check_digit != calculated_check_digit:
            raise ParseError(
                f"Invalid GTIN check digit for {value!r}: "
                f"Expected {calculated_check_digit!r}, got {check_digit!r}."
            )

        gtin_type: Type[Union[Gtin, Rcn]]
        if "Restricted Circulation Number" in prefix.usage:
            gtin_type = Rcn
        else:
            gtin_type = Gtin

        gtin = gtin_type(
            value=value,
            format=gtin_format,
            prefix=prefix,
            payload=payload,
            check_digit=check_digit,
            packaging_level=packaging_level,
        )

        if isinstance(gtin, Rcn) and rcn_region is not None:
            gtin._parse_with_regional_rules(rcn_region)

        return gtin
Ejemplo n.º 3
0
def test_is_hashable() -> None:
    prefix = GS1Prefix.extract("978")

    assert hash(prefix) is not None
Ejemplo n.º 4
0
def test_invalid_gs1_prefix(bad_value: str) -> None:
    with pytest.raises(ParseError) as exc_info:
        GS1Prefix.extract(bad_value)

    assert str(exc_info.value) == f"Failed to get GS1 Prefix from {bad_value!r}."
Ejemplo n.º 5
0
def test_gs1_prefix(value: str, expected: GS1Prefix) -> None:
    assert GS1Prefix.extract(value) == expected