diff --git a/src/Form/LabelSystem/ScanDialogType.php b/src/Form/LabelSystem/ScanDialogType.php index d9c1de0e..cd1440c6 100644 --- a/src/Form/LabelSystem/ScanDialogType.php +++ b/src/Form/LabelSystem/ScanDialogType.php @@ -72,12 +72,7 @@ class ScanDialogType extends AbstractType 'placeholder' => 'scan_dialog.mode.auto', 'choice_label' => fn (?BarcodeSourceType $enum) => match($enum) { null => 'scan_dialog.mode.auto', - BarcodeSourceType::INTERNAL => 'scan_dialog.mode.internal', - BarcodeSourceType::IPN => 'scan_dialog.mode.ipn', - BarcodeSourceType::USER_DEFINED => 'scan_dialog.mode.user', - BarcodeSourceType::EIGP114 => 'scan_dialog.mode.eigp', - BarcodeSourceType::GTIN => 'scan_dialog.mode.gtin', - BarcodeSourceType::LCSC => 'scan_dialog.mode.lcsc', + default => 'scan_dialog.mode.' . $enum->value, }, ]); diff --git a/src/Repository/PartRepository.php b/src/Repository/PartRepository.php index 49342301..d5ccd3a6 100644 --- a/src/Repository/PartRepository.php +++ b/src/Repository/PartRepository.php @@ -454,4 +454,28 @@ class PartRepository extends NamedDBElementRepository return $qb->getQuery()->getOneOrNullResult(); } + /** + * Finds a part based on the provided SPN (Supplier Part Number), with an option for case sensitivity. + * If no part is found with the given SPN, null is returned. + * @param string $spn + * @param bool $caseInsensitive + * @return Part|null + */ + public function getPartBySPN(string $spn, bool $caseInsensitive = true): ?Part + { + $qb = $this->createQueryBuilder('part'); + $qb->select('part'); + + $qb->leftJoin('part.orderdetails', 'o'); + + if ($caseInsensitive) { + $qb->where("LOWER(o.supplierpartnr) = LOWER(:spn)"); + } else { + $qb->where("o.supplierpartnr = :spn"); + } + + $qb->setParameter('spn', $spn); + + return $qb->getQuery()->getOneOrNullResult(); + } } diff --git a/src/Services/LabelSystem/BarcodeScanner/AmazonBarcodeScanResult.php b/src/Services/LabelSystem/BarcodeScanner/AmazonBarcodeScanResult.php new file mode 100644 index 00000000..fb756043 --- /dev/null +++ b/src/Services/LabelSystem/BarcodeScanner/AmazonBarcodeScanResult.php @@ -0,0 +1,46 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\LabelSystem\BarcodeScanner; + +final readonly class AmazonBarcodeScanResult implements BarcodeScanResultInterface +{ + public function __construct(public string $asin) { + if (!self::isAmazonBarcode($asin)) { + throw new \InvalidArgumentException("The provided input '$asin' is not a valid Amazon barcode (ASIN)"); + } + } + + public static function isAmazonBarcode(string $input): bool + { + //Amazon barcodes are 10 alphanumeric characters + return preg_match('/^[A-Z0-9]{10}$/i', $input) === 1; + } + + public function getDecodedForInfoMode(): array + { + return [ + 'ASIN' => $this->asin, + ]; + } +} diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php index b2363ec8..0bee33a1 100644 --- a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php @@ -101,6 +101,10 @@ final class BarcodeScanHelper return $this->parseLCSCBarcode($input); } + if ($type === BarcodeSourceType::AMAZON) { + return new AmazonBarcodeScanResult($input); + } + //Null means auto and we try the different formats $result = $this->parseInternalBarcode($input); @@ -135,6 +139,11 @@ final class BarcodeScanHelper return $this->parseLCSCBarcode($input); } + //Try amazon barcode + if (AmazonBarcodeScanResult::isAmazonBarcode($input)) { + return new AmazonBarcodeScanResult($input); + } + throw new InvalidArgumentException('Unknown barcode'); } diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php index 372e976e..e24c7077 100644 --- a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php @@ -144,7 +144,12 @@ final readonly class BarcodeScanResultHandler return $this->resolvePartFromLCSC($barcodeScan); } - throw new \InvalidArgumentException("Barcode does not support resolving to a local entity: ".get_class($barcodeScan)); + if ($barcodeScan instanceof AmazonBarcodeScanResult) { + return $this->em->getRepository(Part::class)->getPartByProviderInfo($barcodeScan->asin) + ?? $this->em->getRepository(Part::class)->getPartBySPN($barcodeScan->asin); + } + + return null; } /** @@ -258,6 +263,13 @@ final readonly class BarcodeScanResultHandler return $this->getCreationInfoForEIGP114($scanResult); } + if ($scanResult instanceof AmazonBarcodeScanResult) { + return [ + 'providerKey' => 'canopy', + 'providerId' => $scanResult->asin, + ]; + } + return null; } diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php index 13ab4bf3..fb6eaa77 100644 --- a/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php @@ -36,12 +36,12 @@ enum BarcodeSourceType: string /** * This barcode is a user defined barcode defined on a part lot */ - case USER_DEFINED = 'user_defined'; + case USER_DEFINED = 'user'; /** * EIGP114 formatted barcodes like used by digikey, mouser, etc. */ - case EIGP114 = 'eigp114'; + case EIGP114 = 'eigp'; /** * GTIN /EAN barcodes, which are used on most products in the world. These are checked with the GTIN field of a part. @@ -50,4 +50,6 @@ enum BarcodeSourceType: string /** For LCSC.com formatted QR codes */ case LCSC = 'lcsc'; + + case AMAZON = 'amazon'; } diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 31bc3884..c8c41b92 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -12563,5 +12563,11 @@ Buerklin-API Authentication server: Create [part] from barcode + + + scan_dialog.mode.amazon + Amazon barcode + +