Refactored LCSCBarcocdeScanResult to be an value object like the other Barcode results

This commit is contained in:
Jan Böhmer 2026-02-21 23:26:25 +01:00
parent 76584c3d99
commit 338c5ebf0b
7 changed files with 74 additions and 47 deletions

View file

@ -170,7 +170,7 @@ class ScanController extends AbstractController
{ {
// LCSC // LCSC
if ($scanResult instanceof LCSCBarcodeScanResult) { if ($scanResult instanceof LCSCBarcodeScanResult) {
$lcscCode = $scanResult->getPC(); $lcscCode = $scanResult->lcscCode;
if ($lcscCode !== null && $lcscCode !== '') { if ($lcscCode !== null && $lcscCode !== '') {
return $this->generateUrl('info_providers_create_part', [ return $this->generateUrl('info_providers_create_part', [
'providerKey' => 'lcsc', 'providerKey' => 'lcsc',

View file

@ -130,7 +130,7 @@ final class BarcodeRedirector
private function getPartFromLCSC(LCSCBarcodeScanResult $barcodeScan): Part private function getPartFromLCSC(LCSCBarcodeScanResult $barcodeScan): Part
{ {
// Try LCSC code (pc) as provider id if available // Try LCSC code (pc) as provider id if available
$pc = $barcodeScan->getPC(); // e.g. C138033 $pc = $barcodeScan->lcscCode; // e.g. C138033
if ($pc) { if ($pc) {
$qb = $this->em->getRepository(Part::class)->createQueryBuilder('part'); $qb = $this->em->getRepository(Part::class)->createQueryBuilder('part');
$qb->where($qb->expr()->like('LOWER(part.providerReference.provider_id)', 'LOWER(:vendor_id)')); $qb->where($qb->expr()->like('LOWER(part.providerReference.provider_id)', 'LOWER(:vendor_id)'));
@ -142,7 +142,7 @@ final class BarcodeRedirector
} }
// Fallback to MPN (pm) // Fallback to MPN (pm)
$pm = $barcodeScan->getPM(); // e.g. RC0402FR-071ML $pm = $barcodeScan->mpn; // e.g. RC0402FR-071ML
if (!$pm) { if (!$pm) {
throw new EntityNotFoundException(); throw new EntityNotFoundException();
} }

View file

@ -131,7 +131,7 @@ final class BarcodeScanHelper
} }
// Try LCSC barcode // Try LCSC barcode
if (LCSCBarcodeScanResult::looksLike($input)) { if (LCSCBarcodeScanResult::isLCSCBarcode($input)) {
return $this->parseLCSCBarcode($input); return $this->parseLCSCBarcode($input);
} }

View file

@ -10,41 +10,67 @@ use InvalidArgumentException;
* This class represents the content of a lcsc.com barcode * This class represents the content of a lcsc.com barcode
* Its data structure is represented by {pbn:...,on:...,pc:...,pm:...,qty:...} * Its data structure is represented by {pbn:...,on:...,pc:...,pm:...,qty:...}
*/ */
class LCSCBarcodeScanResult implements BarcodeScanResultInterface readonly class LCSCBarcodeScanResult implements BarcodeScanResultInterface
{ {
/** @var string|null (pbn) */
public ?string $pickBatchNumber;
/** @var string|null (on) */
public ?string $orderNumber;
/** @var string|null LCSC Supplier part number (pc) */
public ?string $lcscCode;
/** @var string|null (pm) */
public ?string $mpn;
/** @var int|null (qty) */
public ?int $quantity;
/** @var string|null Country Channel as raw value (CC) */
public ?string $countryChannel;
/**
* @var string|null Warehouse code as raw value (WC)
*/
public ?string $warehouseCode;
/**
* @var string|null Unknown numeric code (pdi)
*/
public ?string $pdi;
/**
* @var string|null Unknown value (hp)
*/
public ?string $hp;
/** /**
* @param array<string, string> $fields * @param array<string, string> $fields
*/ */
public function __construct( public function __construct(
public readonly array $fields, public array $fields,
public readonly string $raw_input, public string $raw_input,
) {} ) {
$this->pickBatchNumber = $this->fields['pbn'] ?? null;
$this->orderNumber = $this->fields['on'] ?? null;
$this->lcscCode = $this->fields['pc'] ?? null;
$this->mpn = $this->fields['pm'] ?? null;
$this->quantity = isset($this->fields['qty']) ? (int)$this->fields['qty'] : null;
$this->countryChannel = $this->fields['cc'] ?? null;
$this->warehouseCode = $this->fields['wc'] ?? null;
$this->pdi = $this->fields['pdi'] ?? null;
$this->hp = $this->fields['hp'] ?? null;
}
public function getSourceType(): BarcodeSourceType public function getSourceType(): BarcodeSourceType
{ {
return BarcodeSourceType::LCSC; return BarcodeSourceType::LCSC;
} }
/**
* @return string|null The manufactures part number
*/
public function getPM(): ?string
{
$v = $this->fields['pm'] ?? null;
$v = $v !== null ? trim($v) : null;
return ($v === '') ? null : $v;
}
/**
* @return string|null The lcsc.com part number
*/
public function getPC(): ?string
{
$v = $this->fields['pc'] ?? null;
$v = $v !== null ? trim($v) : null;
return ($v === '') ? null : $v;
}
/** /**
* @return array|float[]|int[]|null[]|string[] An array of fields decoded from the barcode * @return array|float[]|int[]|null[]|string[] An array of fields decoded from the barcode
*/ */
@ -53,13 +79,15 @@ class LCSCBarcodeScanResult implements BarcodeScanResultInterface
// Keep it human-friendly // Keep it human-friendly
return [ return [
'Barcode type' => 'LCSC', 'Barcode type' => 'LCSC',
'MPN (pm)' => $this->getPM() ?? '', 'MPN (pm)' => $this->mpn ?? '',
'LCSC code (pc)' => $this->getPC() ?? '', 'LCSC code (pc)' => $this->lcscCode ?? '',
'Qty' => $this->fields['qty'] ?? '', 'Qty' => $this->quantity !== null ? (string) $this->quantity : '',
'Order No (on)' => $this->fields['on'] ?? '', 'Order No (on)' => $this->orderNumber ?? '',
'Pick Batch (pbn)' => $this->fields['pbn'] ?? '', 'Pick Batch (pbn)' => $this->pickBatchNumber ?? '',
'Warehouse (wc)' => $this->fields['wc'] ?? '', 'Warehouse (wc)' => $this->warehouseCode ?? '',
'Country/Channel (cc)' => $this->fields['cc'] ?? '', 'Country/Channel (cc)' => $this->countryChannel ?? '',
'PDI (unknown meaning)' => $this->pdi ?? '',
'HP (unknown meaning)' => $this->hp ?? '',
]; ];
} }
@ -68,7 +96,7 @@ class LCSCBarcodeScanResult implements BarcodeScanResultInterface
* @param string $input * @param string $input
* @return bool * @return bool
*/ */
public static function looksLike(string $input): bool public static function isLCSCBarcode(string $input): bool
{ {
$s = trim($input); $s = trim($input);
@ -90,18 +118,17 @@ class LCSCBarcodeScanResult implements BarcodeScanResultInterface
{ {
$raw = trim($input); $raw = trim($input);
if (!self::looksLike($raw)) { if (!self::isLCSCBarcode($raw)) {
throw new InvalidArgumentException('Not an LCSC barcode'); throw new InvalidArgumentException('Not an LCSC barcode');
} }
$inner = trim($raw); $inner = substr($raw, 1, -1); // remove { }
$inner = substr($inner, 1, -1); // remove { }
$fields = []; $fields = [];
// This format is comma-separated pairs, values do not contain commas in your sample. // This format is comma-separated pairs, values do not contain commas in your sample.
$pairs = array_filter( $pairs = array_filter(
array_map('trim', explode(',', $inner)), array_map(trim(...), explode(',', $inner)),
static fn(string $s): bool => $s !== '' static fn(string $s): bool => $s !== ''
); );

View file

@ -149,8 +149,8 @@ final class BarcodeRedirectorTest extends KernelTestCase
{ {
$scan = LCSCBarcodeScanResult::parse('{pbn:PB1,on:ON1,pc:C138033,pm:RC0402FR-071ML,qty:10}'); $scan = LCSCBarcodeScanResult::parse('{pbn:PB1,on:ON1,pc:C138033,pm:RC0402FR-071ML,qty:10}');
$this->assertSame('RC0402FR-071ML', $scan->getPM()); $this->assertSame('RC0402FR-071ML', $scan->mpn);
$this->assertSame('C138033', $scan->getPC()); $this->assertSame('C138033', $scan->lcscCode);
$decoded = $scan->getDecodedForInfoMode(); $decoded = $scan->getDecodedForInfoMode();
$this->assertSame('LCSC', $decoded['Barcode type']); $this->assertSame('LCSC', $decoded['Barcode type']);

View file

@ -170,8 +170,8 @@ final class BarcodeScanHelperTest extends WebTestCase
$result = $this->service->scanBarcodeContent($input); $result = $this->service->scanBarcodeContent($input);
$this->assertInstanceOf(LCSCBarcodeScanResult::class, $result); $this->assertInstanceOf(LCSCBarcodeScanResult::class, $result);
$this->assertSame('C138033', $result->getPC()); $this->assertSame('C138033', $result->lcscCode);
$this->assertSame('RC0402FR-071ML', $result->getPM()); $this->assertSame('RC0402FR-071ML', $result->mpn);
} }
public function testLcscExplicitTypeParses(): void public function testLcscExplicitTypeParses(): void
@ -181,8 +181,8 @@ final class BarcodeScanHelperTest extends WebTestCase
$result = $this->service->scanBarcodeContent($input, BarcodeSourceType::LCSC); $result = $this->service->scanBarcodeContent($input, BarcodeSourceType::LCSC);
$this->assertInstanceOf(LCSCBarcodeScanResult::class, $result); $this->assertInstanceOf(LCSCBarcodeScanResult::class, $result);
$this->assertSame('C138033', $result->getPC()); $this->assertSame('C138033', $result->lcscCode);
$this->assertSame('RC0402FR-071ML', $result->getPM()); $this->assertSame('RC0402FR-071ML', $result->mpn);
} }
public function testLcscExplicitTypeRejectsNonLcsc(): void public function testLcscExplicitTypeRejectsNonLcsc(): void