From 2183e7503897a30fd5117b68791772631985181a Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 18 Dec 2022 23:51:12 +0100 Subject: [PATCH] Use GS1CompanyPrefix for grouping in SSCC's HRI (#173) --- src/biip/sscc.py | 65 +++++++++++++++++++++++++--------------------- tests/test_sscc.py | 27 +++++++------------ 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/biip/sscc.py b/src/biip/sscc.py index e41abdb..cd384d5 100644 --- a/src/biip/sscc.py +++ b/src/biip/sscc.py @@ -10,18 +10,20 @@ If parsing succeeds, it returns a :class:`Sscc` object. - >>> sscc = Sscc.parse("376130321109103420") + >>> sscc = Sscc.parse("157035381410375177") >>> sscc - Sscc(value='376130321109103420', prefix=GS1Prefix(value='761', - usage='GS1 Schweiz, Suisse, Svizzera'), extension_digit=3, - payload='37613032110910342', check_digit=0) + Sscc(value='157035381410375177', prefix=GS1Prefix(value='570', usage='GS1 + Denmark'), extension_digit=1, payload='15703538141037517', check_digit=7) Biip can format the SSCC in HRI format for printing on a label. >>> sscc.as_hri() - '3 761 3032110910342 0' - >>> sscc.as_hri(company_prefix_length=8) - '3 761 30321 10910342 0' + '1 5703538 141037517 7' + +If the detected GS1 Company Prefix length is wrong, it can be overridden: + + >>> sscc.as_hri(company_prefix_length=9) + '1 570353814 1037517 7' """ from __future__ import annotations @@ -30,7 +32,7 @@ from typing import Optional from biip import ParseError -from biip.gs1 import GS1Prefix +from biip.gs1 import GS1CompanyPrefix, GS1Prefix from biip.gs1.checksums import numeric_check_digit @@ -108,37 +110,40 @@ def as_hri(self, *, company_prefix_length: Optional[int] = None) -> str: The HRI is often printed directly below barcodes. + The GS1 Company Prefix length will be detected and used to render the + Company Prefix and the Serial Reference as two separate groups. If the + GS1 Company Prefix length cannot be found, the Company Prefix and the + Serial Reference are rendered as a single group. + Args: - company_prefix_length: Length of the assigned GS1 Company prefix. - 7-10 characters. If not specified, the GS1 Company Prefix and - the Serial Reference are rendered as a single group. + company_prefix_length: Override the detected GS1 Company Prefix + length. 7-10 characters. If not specified, the GS1 Company + Prefix is automatically detected. Raises: - ValueError: If an illegal company prefix length is used. + ValueError: If an illegal company prefix length is given. Returns: A human-readable string where the logic parts are separated by whitespace. """ value = self.payload[1:] # Strip extension digit - if self.prefix is None: - return f"{self.extension_digit} {value} {self.check_digit}" - - gs1_prefix = self.prefix.value + if company_prefix_length is not None: + # Using override of GS1 Company Prefix length + if not (7 <= company_prefix_length <= 10): + raise ValueError( + "Expected company prefix length between 7 and 10, " + f"got {company_prefix_length!r}." + ) + else: + # Using auto-detection of GS1 Company Prefix length + gs1_company_prefix = GS1CompanyPrefix.extract(value) + if gs1_company_prefix is not None: + company_prefix_length = len(gs1_company_prefix.value) if company_prefix_length is None: - data = value[len(gs1_prefix) :] - return f"{self.extension_digit} {gs1_prefix} {data} {self.check_digit}" - - if not (7 <= company_prefix_length <= 10): - raise ValueError( - "Expected company prefix length between 7 and 10, " - f"got {company_prefix_length!r}." - ) + return f"{self.extension_digit} {value} {self.check_digit}" - company_prefix = value[len(gs1_prefix) : company_prefix_length] - serial_reference = value[company_prefix_length:] - return ( - f"{self.extension_digit} {gs1_prefix} {company_prefix} " - f"{serial_reference} {self.check_digit}" - ) + company_prefix = value[:company_prefix_length] + serial = value[company_prefix_length:] + return f"{self.extension_digit} {company_prefix} {serial} {self.check_digit}" diff --git a/tests/test_sscc.py b/tests/test_sscc.py index b63d12a..d4a4f5d 100644 --- a/tests/test_sscc.py +++ b/tests/test_sscc.py @@ -1,7 +1,5 @@ """Tests of parsing SSCCs.""" -from typing import Optional - import pytest from biip import ParseError @@ -59,26 +57,19 @@ def test_parse_with_invalid_check_digit() -> None: @pytest.mark.parametrize( - "prefix_length, expected", + "value, expected", [ - (None, "3 761 3032110910342 0"), - (7, "3 761 3032 110910342 0"), - (8, "3 761 30321 10910342 0"), - (9, "3 761 303211 0910342 0"), - (10, "3 761 3032110 910342 0"), + ("157035381410375177", "1 5703538 141037517 7"), + ("357081300469846950", "3 5708130 046984695 0"), + ("370595680445154697", "3 705956 8044515469 7"), + # GS1 Prefix 671 is currently unassigned: + ("376130321109103420", "3 7613032110910342 0"), ], ) -def test_as_hri(prefix_length: Optional[int], expected: str) -> None: - sscc = Sscc.parse("376130321109103420") - - assert sscc.as_hri(company_prefix_length=prefix_length) == expected - - -def test_as_hri_with_unknown_gs1_prefix() -> None: - # GS1 prefix 671 is currently unassigned. - sscc = Sscc.parse("367130321109103428") +def test_as_hri(value: str, expected: str) -> None: + sscc = Sscc.parse(value) - assert sscc.as_hri() == "3 6713032110910342 8" + assert sscc.as_hri() == expected def test_as_hri_with_too_low_company_prefix_length() -> None: