Allow to scan gtin barcodes and find parts via it

This commit is contained in:
Jan Böhmer 2026-02-08 16:06:01 +01:00
parent 4de6dbba27
commit 35e844dd7b
6 changed files with 105 additions and 2 deletions

View file

@ -75,7 +75,8 @@ class ScanDialogType extends AbstractType
BarcodeSourceType::INTERNAL => 'scan_dialog.mode.internal', BarcodeSourceType::INTERNAL => 'scan_dialog.mode.internal',
BarcodeSourceType::IPN => 'scan_dialog.mode.ipn', BarcodeSourceType::IPN => 'scan_dialog.mode.ipn',
BarcodeSourceType::USER_DEFINED => 'scan_dialog.mode.user', BarcodeSourceType::USER_DEFINED => 'scan_dialog.mode.user',
BarcodeSourceType::EIGP114 => 'scan_dialog.mode.eigp' BarcodeSourceType::EIGP114 => 'scan_dialog.mode.eigp',
BarcodeSourceType::GTIN => 'scan_dialog.mode.gtin',
}, },
]); ]);

View file

@ -77,6 +77,10 @@ final class BarcodeRedirector
return $this->getURLVendorBarcode($barcodeScan); return $this->getURLVendorBarcode($barcodeScan);
} }
if ($barcodeScan instanceof GTINBarcodeScanResult) {
return $this->getURLGTINBarcode($barcodeScan);
}
throw new InvalidArgumentException('Unknown $barcodeScan type: '.get_class($barcodeScan)); throw new InvalidArgumentException('Unknown $barcodeScan type: '.get_class($barcodeScan));
} }
@ -111,6 +115,16 @@ final class BarcodeRedirector
return $this->urlGenerator->generate('app_part_show', ['id' => $part->getID()]); return $this->urlGenerator->generate('app_part_show', ['id' => $part->getID()]);
} }
private function getURLGTINBarcode(GTINBarcodeScanResult $barcodeScan): string
{
$part = $this->em->getRepository(Part::class)->findOneBy(['gtin' => $barcodeScan->gtin]);
if (!$part instanceof Part) {
throw new EntityNotFoundException();
}
return $this->urlGenerator->generate('app_part_show', ['id' => $part->getID()]);
}
/** /**
* Gets a part from a scan of a Vendor Barcode by filtering for parts * Gets a part from a scan of a Vendor Barcode by filtering for parts
* with the same Info Provider Id or, if that fails, by looking for parts with a * with the same Info Provider Id or, if that fails, by looking for parts with a

View file

@ -92,6 +92,9 @@ final class BarcodeScanHelper
if ($type === BarcodeSourceType::EIGP114) { if ($type === BarcodeSourceType::EIGP114) {
return $this->parseEIGP114Barcode($input); return $this->parseEIGP114Barcode($input);
} }
if ($type === BarcodeSourceType::GTIN) {
return $this->parseGTINBarcode($input);
}
//Null means auto and we try the different formats //Null means auto and we try the different formats
$result = $this->parseInternalBarcode($input); $result = $this->parseInternalBarcode($input);
@ -117,9 +120,19 @@ final class BarcodeScanHelper
return $result; return $result;
} }
//If the result is a valid GTIN barcode, we can parse it directly
if (GTINBarcodeScanResult::isValidGTIN($input)) {
return $this->parseGTINBarcode($input);
}
throw new InvalidArgumentException('Unknown barcode'); throw new InvalidArgumentException('Unknown barcode');
} }
private function parseGTINBarcode(string $input): GTINBarcodeScanResult
{
return new GTINBarcodeScanResult($input);
}
private function parseEIGP114Barcode(string $input): EIGP114BarcodeScanResult private function parseEIGP114Barcode(string $input): EIGP114BarcodeScanResult
{ {
return EIGP114BarcodeScanResult::parseFormat06Code($input); return EIGP114BarcodeScanResult::parseFormat06Code($input);

View file

@ -42,4 +42,9 @@ enum BarcodeSourceType
* EIGP114 formatted barcodes like used by digikey, mouser, etc. * EIGP114 formatted barcodes like used by digikey, mouser, etc.
*/ */
case EIGP114; case EIGP114;
}
/**
* GTIN /EAN barcodes, which are used on most products in the world. These are checked with the GTIN field of a part.
*/
case GTIN;
}

View file

@ -0,0 +1,64 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2026 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
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\LabelSystem\BarcodeScanner;
use GtinValidation\GtinValidator;
readonly class GTINBarcodeScanResult implements BarcodeScanResultInterface
{
private GtinValidator $validator;
public function __construct(
public string $gtin,
) {
$this->validator = new GtinValidator($this->gtin);
}
public function getDecodedForInfoMode(): array
{
$obj = $this->validator->getGtinObject();
return [
'GTIN' => $this->gtin,
'GTIN type' => $obj->getType(),
'Valid' => $this->validator->isValid() ? 'Yes' : 'No',
'Reference Number' => $obj->getReferenceNumber(),
'Check Digit' => $obj->getCheckDigit(),
];
}
/**
* Checks if the given input is a valid GTIN. This is used to determine whether a scanned barcode should be interpreted as a GTIN or not.
* @param string $input
* @return bool
*/
public static function isValidGTIN(string $input): bool
{
try {
return (new GtinValidator($input))->isValid();
} catch (\Exception $e) {
return false;
}
}
}

View file

@ -12419,5 +12419,11 @@ Buerklin-API Authentication server:
<target>GTIN</target> <target>GTIN</target>
</segment> </segment>
</unit> </unit>
<unit id="0qHQof." name="scan_dialog.mode.gtin">
<segment>
<source>scan_dialog.mode.gtin</source>
<target>GTIN / EAN</target>
</segment>
</unit>
</file> </file>
</xliff> </xliff>