1,990 bytes · the Python implementation · view raw
import re
_PREFIX = re.compile(r"^[0-9]{4,12}$")
def _whole(value: object) -> bool:
return isinstance(value, int) andnot isinstance(value, bool)
def build_sscc(extension_digit: int, company_prefix: str, serial_reference: int) -> str:
"""Build an 18-digit SSCC: extension digit, GS1 company prefix, zero-padded serial reference and GS1 mod-10 check digit."""ifnot _whole(extension_digit) or extension_digit < 0or extension_digit > 9:
raise ValueError("extensionDigit must be 0 to 9, received %r" % (extension_digit,))
# fullmatch, not match: "$" in re also matches before a trailing newline.ifnot isinstance(company_prefix, str) ornot _PREFIX.fullmatch(company_prefix):
raise ValueError('companyPrefix must be 4 to 12 digits, received "%s"' % (company_prefix,))
ifnot _whole(serial_reference):
raise TypeError("serialReference must be an integer, received %r" % (serial_reference,))
if serial_reference < 0:
raise ValueError("serialReference must not be negative, received %d" % serial_reference)
# Prefix and serial share 16 digits, so a longer prefix leaves less room.# Too large is an error: truncating would reuse another unit's number.
room = 16 - len(company_prefix)
serial = str(serial_reference)
if len(serial) > room:
raise ValueError(
"serialReference must fit in %d digits after a %d-digit company prefix, received %d"
% (room, len(company_prefix), serial_reference)
)
data = str(extension_digit) + company_prefix + serial.rjust(room, "0")
# GS1 mod-10: weights 3, 1, 3, 1 ... from the rightmost data digit leftwards.# validation.gtin does the same sum but only exports validate_gtin, which# takes 8 to 14 digits, not an 18-digit SSCC.
total = 0
weight = 3for ch in reversed(data):
total += (ord(ch) - 48) * weight
weight = 1if weight == 3else3return data + str((10 - total % 10) % 10)