From d804837838f1e1819e17f384c45643d91de4030b Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Wed, 20 Sep 2023 16:13:23 +0200 Subject: [PATCH] Fix inconsistent EAN checksums generation Fixes: https://github.com/WhyNotHugo/python-barcode/issues/196 --- barcode/ean.py | 32 ++++++++++++++++++++------------ tests/test_ean.py | 11 +++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 tests/test_ean.py diff --git a/barcode/ean.py b/barcode/ean.py index c532684..7ec961f 100755 --- a/barcode/ean.py +++ b/barcode/ean.py @@ -43,6 +43,20 @@ class EuropeanArticleNumber13(Barcode): digits = 12 + @property + def ean(self) -> str: + """The raw value, with the checksum appended, if applicable. + + This helper exists mainly for backwards compatibility. + """ + ean = self._raw_value + # If no checksum + if self.no_checksum: + # Add a thirteen char if given in parameter, + # otherwise pad with zero + return f"{ean}{ean[self.digits] if len(ean) > self.digits else 0}" + return f"{ean}{self.calculate_checksum()}" + def __init__(self, ean, writer=None, no_checksum=False, guardbar=False) -> None: ean = ean[: self.digits] if not ean.isdigit(): @@ -51,14 +65,8 @@ def __init__(self, ean, writer=None, no_checksum=False, guardbar=False) -> None: raise NumberOfDigitsError( f"EAN must have {self.digits} digits, not {len(ean)}." ) - self.ean = ean - # If no checksum - if no_checksum: - # Add a thirteen char if given in parameter, - # otherwise pad with zero - self.ean = f"{ean}{ean[self.digits] if len(ean) > self.digits else 0}" - else: - self.ean = f"{ean}{self.calculate_checksum()}" + self._raw_value = ean + self.no_checksum = no_checksum self.guardbar = guardbar if guardbar: @@ -86,8 +94,8 @@ def calculate_checksum(self) -> int: def sum_(x, y): return int(x) + int(y) - evensum = reduce(sum_, self.ean[-2::-2]) - oddsum = reduce(sum_, self.ean[-1::-2]) + evensum = reduce(sum_, self._raw_value[-2::-2]) + oddsum = reduce(sum_, self._raw_value[-1::-2]) return (10 - ((evensum + oddsum * 3) % 10)) % 10 def build(self): @@ -220,8 +228,8 @@ def calculate_checksum(self): def sum_(x, y): return int(x) + int(y) - evensum = reduce(sum_, self.ean[::2]) - oddsum = reduce(sum_, self.ean[1::2]) + evensum = reduce(sum_, self._raw_value[::2]) + oddsum = reduce(sum_, self._raw_value[1::2]) return (10 - (((evensum * 3) + oddsum) % 10)) % 10 diff --git a/tests/test_ean.py b/tests/test_ean.py new file mode 100644 index 0000000..817b5bd --- /dev/null +++ b/tests/test_ean.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +from barcode.ean import EAN13 + + +def test_ean_checksum() -> None: + ean = EAN13("842169142322") # input has 12 digits + assert ean.calculate_checksum() == 0 + + ean = EAN13("8421691423220") # input has 13 digits + assert ean.calculate_checksum() == 0