diff --git a/src/Controller/ScanController.php b/src/Controller/ScanController.php
index 468b2de6..a841c605 100644
--- a/src/Controller/ScanController.php
+++ b/src/Controller/ScanController.php
@@ -42,10 +42,10 @@ declare(strict_types=1);
namespace App\Controller;
use App\Form\LabelSystem\ScanDialogType;
-use App\Services\LabelSystem\Barcodes\BarcodeScanHelper;
-use App\Services\LabelSystem\Barcodes\BarcodeRedirector;
-use App\Services\LabelSystem\Barcodes\LocalBarcodeScanResult;
-use App\Services\LabelSystem\Barcodes\BarcodeSourceType;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeRedirector;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeScanHelper;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType;
+use App\Services\LabelSystem\BarcodeScanner\LocalBarcodeScanResult;
use Doctrine\ORM\EntityNotFoundException;
use InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
diff --git a/src/Form/LabelSystem/ScanDialogType.php b/src/Form/LabelSystem/ScanDialogType.php
index 4723bbf9..a12517dd 100644
--- a/src/Form/LabelSystem/ScanDialogType.php
+++ b/src/Form/LabelSystem/ScanDialogType.php
@@ -41,7 +41,7 @@ declare(strict_types=1);
namespace App\Form\LabelSystem;
-use App\Services\LabelSystem\Barcodes\BarcodeSourceType;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EnumType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@@ -72,7 +72,7 @@ class ScanDialogType extends AbstractType
BarcodeSourceType::INTERNAL => 'scan_dialog.mode.internal',
BarcodeSourceType::IPN => 'scan_dialog.mode.ipn',
BarcodeSourceType::USER_DEFINED => 'scan_dialog.mode.user',
- BarcodeSourceType::VENDOR => 'scan_dialog.mode.eigp'
+ BarcodeSourceType::EIGP114 => 'scan_dialog.mode.eigp'
},
]);
diff --git a/src/Services/LabelSystem/Barcodes/BarcodeRedirector.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeRedirector.php
similarity index 93%
rename from src/Services/LabelSystem/Barcodes/BarcodeRedirector.php
rename to src/Services/LabelSystem/BarcodeScanner/BarcodeRedirector.php
index 8a573321..8aecf180 100644
--- a/src/Services/LabelSystem/Barcodes/BarcodeRedirector.php
+++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeRedirector.php
@@ -39,7 +39,7 @@ declare(strict_types=1);
* along with this program. If not, see .
*/
-namespace App\Services\LabelSystem\Barcodes;
+namespace App\Services\LabelSystem\BarcodeScanner;
use App\Entity\LabelSystem\LabelSupportedElement;
use App\Entity\Parts\Manufacturer;
@@ -62,12 +62,12 @@ final class BarcodeRedirector
/**
* Determines the URL to which the user should be redirected, when scanning a QR code.
*
- * @param LocalBarcodeScanResult | VendorBarcodeScanResult $barcodeScan The result of the barcode scan
+ * @param LocalBarcodeScanResult | EIGP114BarcodeScanResult $barcodeScan The result of the barcode scan
* @return string the URL to which should be redirected
*
* @throws EntityNotFoundException
*/
- public function getRedirectURL(LocalBarcodeScanResult | VendorBarcodeScanResult $barcodeScan): string
+ public function getRedirectURL(LocalBarcodeScanResult | EIGP114BarcodeScanResult $barcodeScan): string
{
if($barcodeScan instanceof LocalBarcodeScanResult) {
return $this->getURLLocalBarcode($barcodeScan);
@@ -102,7 +102,7 @@ final class BarcodeRedirector
/**
* Gets the URL to a part from a scan of a Vendor Barcode
*/
- private function getURLVendorBarcode(VendorBarcodeScanResult $barcodeScan): string
+ private function getURLVendorBarcode(EIGP114BarcodeScanResult $barcodeScan): string
{
$part = $this->getPartFromVendor($barcodeScan);
return $this->urlGenerator->generate('app_part_show', ['id' => $part->getID()]);
@@ -113,7 +113,7 @@ final class BarcodeRedirector
* with the same Info Provider Id or, if that fails, by looking for parts with a
* matching manufacturer product number. Only returns the first matching part.
*/
- private function getPartFromVendor(VendorBarcodeScanResult $barcodeScan) : Part
+ private function getPartFromVendor(EIGP114BarcodeScanResult $barcodeScan) : Part
{
// first check via the info provider ID (e.g. Vendor ID). This might fail if the part was not added via
// the info provider system or if the part was bought from a different vendor than the data was retrieved
diff --git a/src/Services/LabelSystem/Barcodes/BarcodeScanHelper.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php
similarity index 67%
rename from src/Services/LabelSystem/Barcodes/BarcodeScanHelper.php
rename to src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php
index 6dbd3219..322922ff 100644
--- a/src/Services/LabelSystem/Barcodes/BarcodeScanHelper.php
+++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php
@@ -39,7 +39,7 @@ declare(strict_types=1);
* along with this program. If not, see .
*/
-namespace App\Services\LabelSystem\Barcodes;
+namespace App\Services\LabelSystem\BarcodeScanner;
use App\Entity\LabelSystem\LabelSupportedElement;
use App\Entity\Parts\Part;
@@ -77,7 +77,7 @@ final class BarcodeScanHelper
* @param BarcodeSourceType|null $type
* @return LocalBarcodeScanResult
*/
- public function scanBarcodeContent(string $input, ?BarcodeSourceType $type = null): LocalBarcodeScanResult | VendorBarcodeScanResult
+ public function scanBarcodeContent(string $input, ?BarcodeSourceType $type = null): BarcodeScanResultInterface
{
//Do specific parsing
if ($type === BarcodeSourceType::INTERNAL) {
@@ -89,11 +89,17 @@ final class BarcodeScanHelper
if ($type === BarcodeSourceType::IPN) {
return $this->parseIPNBarcode($input) ?? throw new InvalidArgumentException('Could not parse barcode');
}
- if ($type === BarcodeSourceType::VENDOR) {
- return $this->parseFormat06Barcode($input) ?? throw new InvalidArgumentException('Could not parse barcode');
+ if ($type === BarcodeSourceType::EIGP114) {
+ return $this->parseEIGP114Barcode($input);
}
//Null means auto and we try the different formats
+
+ //If the barcode is formatted as EIGP114, we can parse it directly
+ if (EIGP114BarcodeScanResult::isFormat06Code($input)) {
+ return $this->parseEIGP114Barcode($input);
+ }
+
$result = $this->parseInternalBarcode($input);
if ($result !== null) {
@@ -112,108 +118,12 @@ final class BarcodeScanHelper
return $result;
}
- $result = $this->parseFormat06Barcode($input);
- if ($result !== null) {
- return $result;
- }
-
throw new InvalidArgumentException('Unknown barcode');
}
-
- /**
- * Parses Format 06 Barcodes according to ISO/IEC 15434. That standard calls on ASC MH10 to specify
- * the data identifiers, but these are way too many to incorporate here. EIGP 114.2018 is yet another standard
- * based on Format 06 which specifies identifiers for the electronics industry. I've included the identifiers
- * from that standard, plus the extra ones I found on Digikey and Mouser Bags.
- * @param string $input what was read from the barcode
- * @return ?array Array of the form ["Meaning" => "Value"]
- */
- private function decodeFormat06Barcode(string $input): ?array
+ private function parseEIGP114Barcode(string $input): EIGP114BarcodeScanResult
{
- if(!str_starts_with($input, "[)>\u{1E}06\u{1D}")){
- return null;
- }
- if(str_ends_with($input, "\u{04}")){
- $input = substr($input, 0, -1);
- }
-
- $barcodeParts = explode("\u{1D}",$input);
- //get rid of the Format 06 identifier
- array_shift($barcodeParts);
- if (count($barcodeParts) < 2){
- return null;
- }
-
- $fieldIds = [
- //IDs per EIGP 114.2018
- '6D' => 'Ship Date',
- 'P' => 'Customer Part Number',
- '1P' => 'Supplier Part Number',
- 'Q' => 'Quantity',
- 'K' => 'Purchase Order Part Number',
- '4K' => 'Purchase Order Line Number',
- '9D' => 'Date Code',
- '10D' => 'Alternative Date Code',
- '1T' => 'Lot Code',
- '4L' => 'Country of Origin',
- '3S' => 'Package ID 1',
- '4S' => 'Package ID 2',
- '5S' => 'Package ID 3',
- '11K' => 'Packing List Number',
- 'S' => 'Serial Number',
- '33P' => 'BIN Code',
- '13Q' => 'Package Count',
- '2P' => 'Revision Number',
- //IDs used by Digikey
- '30P' => 'Digikey Part Number',
- '1K' => 'Sales Order Number',
- '10K' => 'Invoice Number',
- '11Z' => 'Label Type',
- '12Z' => 'Part ID',
- '13Z' => 'NA',
- '20Z' => 'Padding',
- //IDs used by Mouser
- '14K' => 'Position in Order',
- '1V' => 'Manufacturer',
- ];
-
- $results = [];
-
- foreach($barcodeParts as $part) {
- //^ 0* ([1-9]? \d* [A-Z])
- //Start of the string Leading zeros are discarded Not a zero Any number of digits single uppercase Letter
- // 00 1 4 K
-
- if(!preg_match('/^0*([1-9]?\d*[A-Z])/', $part, $matches)) {
- return null;
- }
- $meaning = $fieldIds[$matches[0]];
- $fieldValue = substr($part, strlen($matches[0]));
- $results[$meaning] = $fieldValue;
-
- }
- return $results;
- }
-
- /**
- * Decodes a Format06 Barcode and puts it into a VendorBarcodeScanResult
- * See decodeFormat06Barcode for details
- */
- private function parseFormat06Barcode(string $input): ?VendorBarcodeScanResult{
- $results = $this->decodeFormat06Barcode($input);
-
- if($results === null){
- return null;
- }
-
- return new VendorBarcodeScanResult(
- manufacturer_part_number: $results['Supplier Part Number'] ?? null,
- vendor_part_number: $results['Digikey Part Number'] ?? null,
- date_code: $results['Date Code'] ?? null,
- quantity: $results['Quantity'] ?? null,
- manufacturer: $results['Manufacturer'] ?? null,
- );
+ return EIGP114BarcodeScanResult::parseFormat06Code($input);
}
private function parseUserDefinedBarcode(string $input): ?LocalBarcodeScanResult
diff --git a/src/Services/LabelSystem/Barcodes/VendorBarcodeScanResult.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultInterface.php
similarity index 53%
rename from src/Services/LabelSystem/Barcodes/VendorBarcodeScanResult.php
rename to src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultInterface.php
index fc8cd2a3..862c0aa8 100644
--- a/src/Services/LabelSystem/Barcodes/VendorBarcodeScanResult.php
+++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultInterface.php
@@ -2,7 +2,7 @@
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
- * Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
+ * Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
@@ -21,23 +21,9 @@
declare(strict_types=1);
-namespace App\Services\LabelSystem\Barcodes;
+namespace App\Services\LabelSystem\BarcodeScanner;
-/**
- * This class represents the result of a scan of a barcode that was printed by a third party
- * and contains useful information about an item, like a vendor id or the order quantity
- */
-
-class VendorBarcodeScanResult
+interface BarcodeScanResultInterface
{
- public function __construct(
- public readonly ?string $vendor = null,
- public readonly ?string $manufacturer_part_number = null,
- public readonly ?string $vendor_part_number = null,
- public readonly ?string $date_code = null,
- public readonly ?string $quantity = null,
- public readonly ?string $manufacturer = null
- )
- {
- }
+
}
\ No newline at end of file
diff --git a/src/Services/LabelSystem/Barcodes/BarcodeSourceType.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php
similarity index 89%
rename from src/Services/LabelSystem/Barcodes/BarcodeSourceType.php
rename to src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php
index 06ff0bea..40f707de 100644
--- a/src/Services/LabelSystem/Barcodes/BarcodeSourceType.php
+++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php
@@ -21,7 +21,7 @@
declare(strict_types=1);
-namespace App\Services\LabelSystem\Barcodes;
+namespace App\Services\LabelSystem\BarcodeScanner;
/**
* This enum represents the different types, where a barcode/QR-code can be generated from
@@ -38,5 +38,8 @@ enum BarcodeSourceType
*/
case USER_DEFINED;
- case VENDOR;
+ /**
+ * EIGP114 formatted barcodes like used by digikey, mouser, etc.
+ */
+ case EIGP114;
}
\ No newline at end of file
diff --git a/src/Services/LabelSystem/Barcodes/EIGP114Barcode.php b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php
similarity index 98%
rename from src/Services/LabelSystem/Barcodes/EIGP114Barcode.php
rename to src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php
index b4dced70..b9d5f30e 100644
--- a/src/Services/LabelSystem/Barcodes/EIGP114Barcode.php
+++ b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php
@@ -21,14 +21,14 @@
declare(strict_types=1);
-namespace App\Services\LabelSystem\Barcodes;
+namespace App\Services\LabelSystem\BarcodeScanner;
/**
* This class represents the content of a EIGP114 barcode.
* Based on PR 811, EIGP 114.2018 (https://www.ecianow.org/assets/docs/GIPC/EIGP-114.2018%20ECIA%20Labeling%20Specification%20for%20Product%20and%20Shipment%20Identification%20in%20the%20Electronics%20Industry%20-%202D%20Barcode.pdf),
* , https://forum.digikey.com/t/digikey-product-labels-decoding-digikey-barcodes/41097
*/
-class EIGP114Barcode
+class EIGP114BarcodeScanResult implements BarcodeScanResultInterface
{
/**
diff --git a/src/Services/LabelSystem/Barcodes/LocalBarcodeScanResult.php b/src/Services/LabelSystem/BarcodeScanner/LocalBarcodeScanResult.php
similarity index 91%
rename from src/Services/LabelSystem/Barcodes/LocalBarcodeScanResult.php
rename to src/Services/LabelSystem/BarcodeScanner/LocalBarcodeScanResult.php
index 3f92fe14..5a24ddb4 100644
--- a/src/Services/LabelSystem/Barcodes/LocalBarcodeScanResult.php
+++ b/src/Services/LabelSystem/BarcodeScanner/LocalBarcodeScanResult.php
@@ -21,7 +21,7 @@
declare(strict_types=1);
-namespace App\Services\LabelSystem\Barcodes;
+namespace App\Services\LabelSystem\BarcodeScanner;
use App\Entity\LabelSystem\LabelSupportedElement;
@@ -29,7 +29,7 @@ use App\Entity\LabelSystem\LabelSupportedElement;
* This class represents the result of a barcode scan of a barcode that uniquely identifies a local entity,
* like an internally generated barcode or a barcode that was added manually to the system by a user
*/
-class LocalBarcodeScanResult
+class LocalBarcodeScanResult implements BarcodeScanResultInterface
{
public function __construct(
public readonly LabelSupportedElement $target_type,
diff --git a/tests/Services/LabelSystem/Barcodes/BarcodeRedirectorTest.php b/tests/Services/LabelSystem/Barcodes/BarcodeRedirectorTest.php
index 4f85af1c..cf2a87be 100644
--- a/tests/Services/LabelSystem/Barcodes/BarcodeRedirectorTest.php
+++ b/tests/Services/LabelSystem/Barcodes/BarcodeRedirectorTest.php
@@ -42,9 +42,9 @@ declare(strict_types=1);
namespace App\Tests\Services\LabelSystem\Barcodes;
use App\Entity\LabelSystem\LabelSupportedElement;
-use App\Services\LabelSystem\Barcodes\BarcodeRedirector;
-use App\Services\LabelSystem\Barcodes\LocalBarcodeScanResult;
-use App\Services\LabelSystem\Barcodes\BarcodeSourceType;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeRedirector;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType;
+use App\Services\LabelSystem\BarcodeScanner\LocalBarcodeScanResult;
use Doctrine\ORM\EntityNotFoundException;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
diff --git a/tests/Services/LabelSystem/Barcodes/BarcodeScanHelperTest.php b/tests/Services/LabelSystem/Barcodes/BarcodeScanHelperTest.php
index ba41a6d4..e24c960b 100644
--- a/tests/Services/LabelSystem/Barcodes/BarcodeScanHelperTest.php
+++ b/tests/Services/LabelSystem/Barcodes/BarcodeScanHelperTest.php
@@ -42,10 +42,9 @@ declare(strict_types=1);
namespace App\Tests\Services\LabelSystem\Barcodes;
use App\Entity\LabelSystem\LabelSupportedElement;
-use App\Services\LabelSystem\Barcodes\BarcodeScanHelper;
-use App\Services\LabelSystem\Barcodes\LocalBarcodeScanResult;
-use App\Services\LabelSystem\Barcodes\BarcodeSourceType;
-use Com\Tecnick\Barcode\Barcode;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeScanHelper;
+use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType;
+use App\Services\LabelSystem\BarcodeScanner\LocalBarcodeScanResult;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class BarcodeScanHelperTest extends WebTestCase
diff --git a/tests/Services/LabelSystem/Barcodes/EIGP114BarcodeTest.php b/tests/Services/LabelSystem/Barcodes/EIGP114BarcodeTest.php
index c23ea06d..9eca7104 100644
--- a/tests/Services/LabelSystem/Barcodes/EIGP114BarcodeTest.php
+++ b/tests/Services/LabelSystem/Barcodes/EIGP114BarcodeTest.php
@@ -20,7 +20,7 @@
namespace App\Tests\Services\LabelSystem\Barcodes;
-use App\Services\LabelSystem\Barcodes\EIGP114Barcode;
+use App\Services\LabelSystem\BarcodeScanner\EIGP114BarcodeScanResult;
use PHPUnit\Framework\TestCase;
class EIGP114BarcodeTest extends TestCase
@@ -30,7 +30,7 @@ class EIGP114BarcodeTest extends TestCase
{
//Generic barcode:
- $barcode = new EIGP114Barcode([
+ $barcode = new EIGP114BarcodeScanResult([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
'Q' => '3',
@@ -42,7 +42,7 @@ class EIGP114BarcodeTest extends TestCase
$this->assertNull($barcode->guessBarcodeVendor());
//Digikey barcode:
- $barcode = new EIGP114Barcode([
+ $barcode = new EIGP114BarcodeScanResult([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
'Q' => '3',
@@ -54,7 +54,7 @@ class EIGP114BarcodeTest extends TestCase
$this->assertEquals('digikey', $barcode->guessBarcodeVendor());
//Mouser barcode:
- $barcode = new EIGP114Barcode([
+ $barcode = new EIGP114BarcodeScanResult([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
'Q' => '3',
@@ -67,7 +67,7 @@ class EIGP114BarcodeTest extends TestCase
$this->assertEquals('mouser', $barcode->guessBarcodeVendor());
//Farnell barcode:
- $barcode = new EIGP114Barcode([
+ $barcode = new EIGP114BarcodeScanResult([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
'Q' => '3',
@@ -82,25 +82,25 @@ class EIGP114BarcodeTest extends TestCase
public function testIsFormat06Code(): void
{
- $this->assertFalse(EIGP114Barcode::isFormat06Code(''));
- $this->assertFalse(EIGP114Barcode::isFormat06Code('test'));
- $this->assertFalse(EIGP114Barcode::isFormat06Code('12232435ew4rf'));
+ $this->assertFalse(EIGP114BarcodeScanResult::isFormat06Code(''));
+ $this->assertFalse(EIGP114BarcodeScanResult::isFormat06Code('test'));
+ $this->assertFalse(EIGP114BarcodeScanResult::isFormat06Code('12232435ew4rf'));
//Missing trailer
- $this->assertFalse(EIGP114Barcode::isFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS"));
+ $this->assertFalse(EIGP114BarcodeScanResult::isFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS"));
//Valid code
- $this->assertTrue(EIGP114Barcode::isFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04"));
+ $this->assertTrue(EIGP114BarcodeScanResult::isFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04"));
}
public function testParseFormat06CodeInvalid(): void
{
$this->expectException(\InvalidArgumentException::class);
- EIGP114Barcode::parseFormat06Code('');
+ EIGP114BarcodeScanResult::parseFormat06Code('');
}
public function testParseFormat06Code(): void
{
- $barcode = EIGP114Barcode::parseFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04");
+ $barcode = EIGP114BarcodeScanResult::parseFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04");
$this->assertEquals([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
@@ -113,7 +113,7 @@ class EIGP114BarcodeTest extends TestCase
public function testDataParsing(): void
{
- $barcode = new EIGP114Barcode([
+ $barcode = new EIGP114BarcodeScanResult([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
'Q' => '3',
diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf
index c7dfa641..5adce468 100644
--- a/translations/messages.en.xlf
+++ b/translations/messages.en.xlf
@@ -12275,5 +12275,11 @@ Please note, that you can not impersonate a disabled user. If you try you will g
User defined barcode (configured at part lot)
+
+
+ scan_dialog.mode.eigp
+ EIGP 114 barcode (e.g. the datamatrix codes on digikey and mouser orders)
+
+