Skip to content

Commit

Permalink
Use GS1CompanyPrefix for grouping in SSCC's HRI (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
jodal committed Dec 18, 2022
1 parent bb29536 commit 2183e75
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 48 deletions.
65 changes: 35 additions & 30 deletions src/biip/sscc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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


Expand Down Expand Up @@ -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}"
27 changes: 9 additions & 18 deletions tests/test_sscc.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Tests of parsing SSCCs."""

from typing import Optional

import pytest

from biip import ParseError
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 2183e75

Please sign in to comment.