Merge branch 'gtin'

This commit is contained in:
Jan Böhmer 2026-02-14 22:12:39 +01:00
commit 7a83581597
71 changed files with 1405 additions and 92 deletions

View file

@ -42,6 +42,7 @@ class PartDetailDTO extends SearchResultDTO
?ManufacturingStatus $manufacturing_status = null,
?string $provider_url = null,
?string $footprint = null,
?string $gtin = null,
public readonly ?string $notes = null,
/** @var FileDTO[]|null */
public readonly ?array $datasheets = null,
@ -68,6 +69,7 @@ class PartDetailDTO extends SearchResultDTO
manufacturing_status: $manufacturing_status,
provider_url: $provider_url,
footprint: $footprint,
gtin: $gtin
);
}
}

View file

@ -39,7 +39,9 @@ readonly class PriceDTO
public string $price,
/** @var string The currency of the used ISO code of this price detail */
public ?string $currency_iso_code,
/** @var bool If the price includes tax */
/** @var bool If the price includes tax
* @deprecated Use the prices_include_vat property of the PurchaseInfoDTO instead, as this property is not reliable if there are multiple prices with different values for includes_tax
*/
public ?bool $includes_tax = true,
/** @var float the price related quantity */
public ?float $price_related_quantity = 1.0,

View file

@ -29,6 +29,9 @@ namespace App\Services\InfoProviderSystem\DTOs;
*/
readonly class PurchaseInfoDTO
{
/** @var bool|null If the prices contain VAT or not. Null if state is unknown. */
public ?bool $prices_include_vat;
public function __construct(
public string $distributor_name,
public string $order_number,
@ -36,6 +39,7 @@ readonly class PurchaseInfoDTO
public array $prices,
/** @var string|null An url to the product page of the vendor */
public ?string $product_url = null,
?bool $prices_include_vat = null,
)
{
//Ensure that the prices are PriceDTO instances
@ -44,5 +48,17 @@ readonly class PurchaseInfoDTO
throw new \InvalidArgumentException('The prices array must only contain PriceDTO instances');
}
}
//If no prices_include_vat information is given, try to deduct it from the prices
if ($prices_include_vat === null) {
$vatValues = array_unique(array_map(fn(PriceDTO $price) => $price->includes_tax, $this->prices));
if (count($vatValues) === 1) {
$this->prices_include_vat = $vatValues[0]; //Use the value of the prices if they are all the same
} else {
$this->prices_include_vat = null; //If there are different values for the prices, we cannot determine if the prices include VAT or not
}
} else {
$this->prices_include_vat = $prices_include_vat;
}
}
}

View file

@ -59,6 +59,8 @@ class SearchResultDTO
public readonly ?string $provider_url = null,
/** @var string|null A footprint representation of the providers page */
public readonly ?string $footprint = null,
/** @var string|null The GTIN / EAN of the part */
public readonly ?string $gtin = null,
)
{
if ($preview_image_url !== null) {
@ -90,6 +92,7 @@ class SearchResultDTO
'manufacturing_status' => $this->manufacturing_status?->value,
'provider_url' => $this->provider_url,
'footprint' => $this->footprint,
'gtin' => $this->gtin,
];
}
@ -112,6 +115,7 @@ class SearchResultDTO
manufacturing_status: isset($data['manufacturing_status']) ? ManufacturingStatus::tryFrom($data['manufacturing_status']) : null,
provider_url: $data['provider_url'] ?? null,
footprint: $data['footprint'] ?? null,
gtin: $data['gtin'] ?? null,
);
}
}

View file

@ -94,7 +94,6 @@ final class DTOtoEntityConverter
$entity->setPrice($dto->getPriceAsBigDecimal());
$entity->setPriceRelatedQuantity($dto->price_related_quantity);
//Currency TODO
if ($dto->currency_iso_code !== null) {
$entity->setCurrency($this->getCurrency($dto->currency_iso_code));
} else {
@ -117,6 +116,8 @@ final class DTOtoEntityConverter
$entity->addPricedetail($this->convertPrice($price));
}
$entity->setPricesIncludesVAT($dto->prices_include_vat);
return $entity;
}
@ -175,6 +176,8 @@ final class DTOtoEntityConverter
$entity->setManufacturingStatus($dto->manufacturing_status ?? ManufacturingStatus::NOT_SET);
$entity->setManufacturerProductURL($dto->manufacturer_product_url ?? '');
$entity->setGtin($dto->gtin);
//Set the provider reference on the part
$entity->setProviderReference(InfoProviderReference::fromPartDTO($dto));

View file

@ -120,6 +120,7 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
preview_image_url: $result['image'] ?? null,
provider_url: $this->getProductUrl($result['productId']),
footprint: $this->getFootprintFromTechnicalDetails($result['technicalDetails'] ?? []),
gtin: $result['ean'] ?? null,
);
}
@ -302,6 +303,7 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
preview_image_url: $data['productShortInformation']['mainImage']['imageUrl'] ?? null,
provider_url: $this->getProductUrl($data['shortProductNumber']),
footprint: $this->getFootprintFromTechnicalAttributes($data['productFullInformation']['technicalAttributes'] ?? []),
gtin: $data['productFullInformation']['eanCode'] ?? null,
notes: $data['productFullInformation']['description'] ?? null,
datasheets: $this->productMediaToDatasheets($data['productMedia'] ?? []),
parameters: $this->technicalAttributesToParameters($data['productFullInformation']['technicalAttributes'] ?? []),
@ -316,6 +318,8 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
ProviderCapabilities::PICTURE,
ProviderCapabilities::DATASHEET,
ProviderCapabilities::PRICE,
ProviderCapabilities::FOOTPRINT,
ProviderCapabilities::GTIN,
];
}

View file

@ -227,10 +227,11 @@ class GenericWebProvider implements InfoProviderInterface
mpn: $product->mpn?->toString(),
preview_image_url: $image,
provider_url: $url,
gtin: $product->gtin14?->toString() ?? $product->gtin13?->toString() ?? $product->gtin12?->toString() ?? $product->gtin8?->toString(),
notes: $notes,
parameters: $parameters,
vendor_infos: $vendor_infos,
mass: $mass
mass: $mass,
);
}
@ -429,7 +430,8 @@ class GenericWebProvider implements InfoProviderInterface
return [
ProviderCapabilities::BASIC,
ProviderCapabilities::PICTURE,
ProviderCapabilities::PRICE
ProviderCapabilities::PRICE,
ProviderCapabilities::GTIN,
];
}
}

View file

@ -43,6 +43,9 @@ enum ProviderCapabilities
/** Information about the footprint of a part */
case FOOTPRINT;
/** Provider can provide GTIN for a part */
case GTIN;
/**
* Get the order index for displaying capabilities in a stable order.
* @return int
@ -55,6 +58,7 @@ enum ProviderCapabilities
self::DATASHEET => 3,
self::PRICE => 4,
self::FOOTPRINT => 5,
self::GTIN => 6,
};
}
@ -66,6 +70,7 @@ enum ProviderCapabilities
self::PICTURE => 'picture',
self::DATASHEET => 'datasheet',
self::PRICE => 'price',
self::GTIN => 'gtin',
};
}
@ -77,6 +82,7 @@ enum ProviderCapabilities
self::PICTURE => 'fa-image',
self::DATASHEET => 'fa-file-alt',
self::PRICE => 'fa-money-bill-wave',
self::GTIN => 'fa-barcode',
};
}
}

View file

@ -84,6 +84,8 @@ class ReicheltProvider implements InfoProviderInterface
$name = $element->filter('meta[itemprop="name"]')->attr('content');
$sku = $element->filter('meta[itemprop="sku"]')->attr('content');
//Try to extract a picture URL:
$pictureURL = $element->filter("div.al_artlogo img")->attr('src');
@ -95,7 +97,8 @@ class ReicheltProvider implements InfoProviderInterface
category: null,
manufacturer: $sku,
preview_image_url: $pictureURL,
provider_url: $element->filter('a.al_artinfo_link')->attr('href')
provider_url: $element->filter('a.al_artinfo_link')->attr('href'),
);
});
@ -146,6 +149,15 @@ class ReicheltProvider implements InfoProviderInterface
$priceString = $dom->filter('meta[itemprop="price"]')->attr('content');
$currency = $dom->filter('meta[itemprop="priceCurrency"]')->attr('content', 'EUR');
$gtin = null;
foreach (['gtin13', 'gtin14', 'gtin12', 'gtin8'] as $gtinType) {
if ($dom->filter("[itemprop=\"$gtinType\"]")->count() > 0) {
$gtin = $dom->filter("[itemprop=\"$gtinType\"]")->innerText();
break;
}
}
//Create purchase info
$purchaseInfo = new PurchaseInfoDTO(
distributor_name: self::DISTRIBUTOR_NAME,
@ -167,10 +179,11 @@ class ReicheltProvider implements InfoProviderInterface
mpn: $this->parseMPN($dom),
preview_image_url: $json[0]['article_picture'],
provider_url: $productPage,
gtin: $gtin,
notes: $notes,
datasheets: $datasheets,
parameters: $this->parseParameters($dom),
vendor_infos: [$purchaseInfo]
vendor_infos: [$purchaseInfo],
);
}
@ -273,6 +286,7 @@ class ReicheltProvider implements InfoProviderInterface
ProviderCapabilities::PICTURE,
ProviderCapabilities::DATASHEET,
ProviderCapabilities::PRICE,
ProviderCapabilities::GTIN,
];
}
}