Exemple #1
0
def test_parse_gtin_8(value: str) -> None:
    assert Gtin.parse(value) == Gtin(
        value=value,
        format=GtinFormat.GTIN_8,
        prefix=GS1Prefix(value="00009", usage="GS1 US"),
        payload="9638507",
        check_digit=4,
    )
Exemple #2
0
def test_parse_gtin_12_without_leading_zero(value: str) -> None:
    assert Gtin.parse(value) == Gtin(
        value=value,
        format=GtinFormat.GTIN_12,
        prefix=GS1Prefix(value="061", usage="GS1 US"),
        payload="61414100003",
        check_digit=6,
    )
Exemple #3
0
def test_parse_gtin_13(value: str) -> None:
    assert Gtin.parse(value) == Gtin(
        value=value,
        format=GtinFormat.GTIN_13,
        prefix=GS1Prefix(value="590", usage="GS1 Poland"),
        payload="590123412345",
        check_digit=7,
    )
Exemple #4
0
def test_parse_gtin_12_with_3_leading_zero(value: str) -> None:
    assert Gtin.parse(value) == Gtin(
        value=value,
        format=GtinFormat.GTIN_12,
        prefix=GS1Prefix(value="00009", usage="GS1 US"),
        payload="00090291451",
        check_digit=1,
    )
Exemple #5
0
def test_parse_gtin_14() -> None:
    assert Gtin.parse("98765432109213") == Gtin(
        value="98765432109213",
        format=GtinFormat.GTIN_14,
        prefix=GS1Prefix(value="876", usage="GS1 Netherlands"),
        payload="9876543210921",
        check_digit=3,
        packaging_level=9,
    )
Exemple #6
0
def test_parse() -> None:
    sscc = Sscc.parse("376130321109103420")

    assert sscc == Sscc(
        value="376130321109103420",
        prefix=GS1Prefix(value="761", usage="GS1 Schweiz, Suisse, Svizzera"),
        extension_digit=3,
        payload="37613032110910342",
        check_digit=0,
    )
Exemple #7
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,
        )
Exemple #8
0
from biip.gtin import Gtin, GtinFormat
from biip.sscc import Sscc


@pytest.mark.parametrize(
    "value, expected",
    [
        (
            "00373400306809981733",
            GS1ElementString(
                ai=GS1ApplicationIdentifier.extract("00"),
                value="373400306809981733",
                pattern_groups=["373400306809981733"],
                sscc=Sscc(
                    value="373400306809981733",
                    prefix=GS1Prefix(value="734", usage="GS1 Sweden"),
                    extension_digit=3,
                    payload="37340030680998173",
                    check_digit=3,
                ),
            ),
        ),
        (
            "0107032069804988",
            GS1ElementString(
                ai=GS1ApplicationIdentifier.extract("01"),
                value="07032069804988",
                pattern_groups=["07032069804988"],
                gtin=Gtin(
                    value="07032069804988",
                    format=GtinFormat.GTIN_13,
Exemple #9
0
 element_strings=[
     GS1ElementString(
         ai=GS1ApplicationIdentifier(
             ai="01",
             description="Global Trade Item Number (GTIN)",
             data_title="GTIN",
             fnc1_required=False,
             format="N2+N14",
             pattern="^01(\\d{14})$",
         ),
         value="07032069804988",
         pattern_groups=["07032069804988"],
         gtin=Gtin(
             value="07032069804988",
             format=GtinFormat.GTIN_13,
             prefix=GS1Prefix(value="703", usage="GS1 Norway"),
             payload="703206980498",
             check_digit=8,
         ),
     ),
     GS1ElementString(
         ai=GS1ApplicationIdentifier(
             ai="15",
             description="Best before date (YYMMDD)",
             data_title="BEST BEFORE or BEST BY",
             fnc1_required=False,
             format="N2+N6",
             pattern="^15(\\d{6})$",
         ),
         value="210526",
         pattern_groups=["210526"],
Exemple #10
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
Exemple #11
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}."
Exemple #12
0
def test_is_hashable() -> None:
    prefix = GS1Prefix.extract("978")

    assert hash(prefix) is not None
Exemple #13
0
def test_gs1_prefix(value: str, expected: GS1Prefix) -> None:
    assert GS1Prefix.extract(value) == expected
Exemple #14
0

@pytest.mark.parametrize("bad_value", ["abcdef", "1a2b3c"])
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}."


@pytest.mark.parametrize(
    "value, expected",
    [
        (
            "0000001999",
            GS1Prefix(value="0000001", usage="Unused to avoid collision with GTIN-8"),
        ),
        ("060999", GS1Prefix(value="060", usage="GS1 US")),
        ("139999", GS1Prefix(value="139", usage="GS1 US")),
        ("6712670000276", None),  # Unassigned prefix
        ("701999", GS1Prefix(value="701", usage="GS1 Norway")),
        ("978-1-492-05374-3", GS1Prefix(value="978", usage="Bookland (ISBN)")),
    ],
)
def test_gs1_prefix(value: str, expected: GS1Prefix) -> None:
    assert GS1Prefix.extract(value) == expected


def test_is_hashable() -> None:
    prefix = GS1Prefix.extract("978")
Exemple #15
0
from biip.sscc import Sscc
from biip.symbology import Symbology, SymbologyIdentifier


@pytest.mark.parametrize(
    "value, expected",
    [
        (
            # GTIN-8
            "96385074",
            ParseResult(
                value="96385074",
                gtin=Gtin(
                    value="96385074",
                    format=GtinFormat.GTIN_8,
                    prefix=GS1Prefix(value="00009", usage="GS1 US"),
                    payload="9638507",
                    check_digit=4,
                ),
                gs1_message=GS1Message(
                    value="96385074",
                    element_strings=[
                        GS1ElementString(
                            ai=GS1ApplicationIdentifier.extract("96"),
                            value="385074",
                            pattern_groups=["385074"],
                        )
                    ],
                ),
                sscc_error=
                ("Failed to parse '96385074' as SSCC: Expected 18 digits, got 8."