diff --git a/src/Types/TypeITF14.php b/src/Types/TypeITF14.php index ff395d9..d2f87bb 100644 --- a/src/Types/TypeITF14.php +++ b/src/Types/TypeITF14.php @@ -5,6 +5,7 @@ use Picqer\Barcode\Barcode; use Picqer\Barcode\BarcodeBar; use Picqer\Barcode\Exceptions\InvalidCharacterException; +use Picqer\Barcode\Exceptions\InvalidCheckDigitException; use Picqer\Barcode\Exceptions\InvalidLengthException; class TypeITF14 implements TypeInterface @@ -12,6 +13,7 @@ class TypeITF14 implements TypeInterface /** * @throws InvalidLengthException * @throws InvalidCharacterException + * @throws InvalidCheckDigitException */ public function getBarcodeData(string $code): Barcode { @@ -35,6 +37,10 @@ public function getBarcodeData(string $code): Barcode if (strlen($code) === 13) { $code .= $this->getChecksum($code); + } elseif (substr($code, -1) !== $this->getChecksum(substr($code, 0, -1))) { + // If length of given barcode is same as final length, barcode is including checksum + // Make sure that checksum is the same as we calculated + throw new InvalidCheckDigitException(); } $barcode = new Barcode($code); @@ -73,8 +79,8 @@ private function getChecksum(string $code): string $total = 0; for ($charIndex = 0; $charIndex <= (strlen($code) - 1); $charIndex++) { - $integerOfChar = intval($code . substr($charIndex, 1)); - $total += $integerOfChar * (($charIndex === 0 || $charIndex % 2 === 0) ? 3 : 1); + $integerOfChar = intval($code[$charIndex]); + $total += $integerOfChar * ($charIndex % 2 === 0 ? 3 : 1); } $checksum = 10 - ($total % 10); diff --git a/tests/ChecksumBarcodeTest.php b/tests/ChecksumBarcodeTest.php new file mode 100644 index 0000000..eff35ab --- /dev/null +++ b/tests/ChecksumBarcodeTest.php @@ -0,0 +1,61 @@ + TypeEan13::class, 'barcodes' => [ + '081231723897' => '0812317238973', + '004900000463' => '0049000004632', + ]], + ['type' => TypeITF14::class, 'barcodes' => [ + '0001234560001' => '00012345600012', + '0540014128876' => '05400141288766', + ]], + ]; + private const INVALID_BARCODES = [ + ['type' => TypeEan13::class, 'barcodes' => ['0812317238972', '0049000004633']], + ['type' => TypeITF14::class, 'barcodes' => ['00012345600016', '05400141288762']], + ]; + + public function testAllValidBarcodeTypes() + { + foreach (self::VALID_BARCODES as $barcodeTestSet) { + $barcodeType = $this->getBarcodeType($barcodeTestSet['type']); + + foreach ($barcodeTestSet['barcodes'] as $testBarcode => $validBarcode) { + $this->assertEquals($validBarcode, $barcodeType->getBarcodeData($testBarcode)->getBarcode()); + } + } + } + + public function testAllInvalidBarcodeTypes() + { + foreach (self::INVALID_BARCODES as $barcodeTestSet) { + $barcodeType = $this->getBarcodeType($barcodeTestSet['type']); + + foreach ($barcodeTestSet['barcodes'] as $invalidBarcode) { + try { + $barcodeType->getBarcodeData($invalidBarcode)->getBarcode(); + } catch (BarcodeException $exception) { + $this->assertInstanceOf(InvalidCheckDigitException::class, $exception); + continue; + } + + $this->assertTrue(false, sprintf('Exception was not thrown for barcode "%s".', $invalidBarcode)); + } + } + } + + + private function getBarcodeType(string $typeClass): TypeInterface + { + return new $typeClass; + } +}