Skip to content

Commit 4f1bb66

Browse files
committed
* UPC-E barcodes are now working with UPC-E codes as well (before, were only working with UPC-A codes, which were converted into UPC-E codes).
* * Parity digit and checksum digit can be omitted. A proper barcode will always be created, except the checksum digit is provided and differs from the calculated checksum digit. * * * If omitted, the parity digit defaults to 0. * * * If omitted, the checksum digit will be calculated.
1 parent bed3468 commit 4f1bb66

File tree

1 file changed

+83
-4
lines changed

1 file changed

+83
-4
lines changed

src/Types/TypeEanUpcBase.php

+83-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,74 @@ public function getBarcodeData(string $code): Barcode
3434

3535
$dataLength = $length - 1;
3636

37+
// Convert proper UPC-E codes into UPC-A codes.
38+
if ($this->upce) {
39+
$strLen = strlen($code);
40+
41+
if ($strLen === 8) {
42+
// Parity and checksum digits are provided. Store them for later usage.
43+
$checksumDigit = $code[7];
44+
$parityDigit = $code[0];
45+
$code = substr($code, 1, 6);
46+
$strLen -= 2;
47+
}
48+
if ($strLen === 7) {
49+
// Either parity or checksum digit is provided.
50+
if (($code[0] === '0') || ($code[0] === '1')) {
51+
// Assume parity digit.
52+
$parityDigit = $code[0];
53+
$code = substr($code, 1, 6);
54+
} else {
55+
// Assume checksum digit.
56+
$checksumDigit = $code[6];
57+
$code = substr($code, 0, 6);
58+
}
59+
60+
--$strLen;
61+
}
62+
if ($strLen === 6) {
63+
// Store original UPC-E code for later usage.
64+
$upce_code = $code; // Neither parity digit nor checksum digit are printed in UPC-E barcode.
65+
66+
// Convert UPC-E code into UPC-A code.
67+
$conversionData = array (
68+
'0' => array (2, '00000'),
69+
'1' => array (2, '10000'),
70+
'2' => array (2, '20000'),
71+
'3' => array (3, '00000'),
72+
'4' => array (4, '00000'),
73+
'5' => array (5, '00005'),
74+
'6' => array (5, '00006'),
75+
'7' => array (5, '00007'),
76+
'8' => array (5, '00008'),
77+
'9' => array (5, '00009')
78+
);
79+
$lastUpcEDigit = $code[5];
80+
81+
if (!isset ($conversionData[$lastUpcEDigit])) {
82+
throw new InvalidCharacterException('Char ' . $lastUpcEDigit . ' not allowed');
83+
}
84+
85+
$conversionData = $conversionData[$lastUpcEDigit];
86+
$code = substr($upce_code, 0, $conversionData[0]); // Add all Xs.
87+
$code .= $conversionData[1]; // Add constant number.
88+
$code .= substr($upce_code, $conversionData[0], 5 - $conversionData[0]); // Add all Ns.
89+
90+
// Add parity digit.
91+
if (!isset ($parityDigit)) {
92+
// Provide '0' as default parity digit.
93+
$parityDigit = '0';
94+
}
95+
96+
$code = $parityDigit . $code;
97+
98+
// Add checksum digit.
99+
if (isset ($checksumDigit)) {
100+
$code .= $checksumDigit;
101+
} // else { The checksum digit will be calculated and added, later. }
102+
}
103+
}
104+
37105
// Add zero padding in front
38106
$code = str_pad($code, $dataLength, '0', STR_PAD_LEFT);
39107

@@ -44,16 +112,27 @@ public function getBarcodeData(string $code): Barcode
44112
} elseif ($checksumDigit !== intval($code[$dataLength])) {
45113
// If length of given barcode is same as final length, barcode is including checksum
46114
// Make sure that checksum is the same as we calculated
47-
throw new InvalidCheckDigitException();
115+
if ($this->upce && isset ($upce_code)) {
116+
// It's possible that parity digit was not provided and the assumed '0' is wrong. Try again with '1'.
117+
$parityDigit = '1';
118+
$code[0] = $parityDigit;
119+
$checksumDigit = $this->calculateChecksumDigit($code);
120+
121+
if ($checksumDigit !== intval($code[$dataLength])) {
122+
throw new InvalidCheckDigitException();
123+
}
124+
} else {
125+
throw new InvalidCheckDigitException();
126+
}
48127
}
49128

50129
if ($this->upca || $this->upce) {
51130
$code = '0' . $code;
52131
++$length;
53132
}
54-
55-
if ($this->upce) {
56-
// convert UPC-A to UPC-E
133+
134+
if ($this->upce && !isset ($upce_code)) {
135+
// UPC-A code shall be printed as UPC-E code. Convert UPC-A into UPC-E:
57136
$tmp = substr($code, 4, 3);
58137
if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
59138
// manufacturer code ends in 000, 100, or 200

0 commit comments

Comments
 (0)