diff --git a/config/services.yaml b/config/services.yaml index adb454b3..dfc9a7c7 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -216,16 +216,6 @@ services: $onlyAuthorizedSellers: '%env(bool:PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS)%' - App\Services\InfoProviderSystem\Providers\OEMSecretsProvider: - arguments: - $api_key: '%env(string:PROVIDER_OEMSECRETS_KEY)%' - $country_code: '%env(string:PROVIDER_OEMSECRETS_COUNTRY_CODE)%' - $currency: '%env(PROVIDER_OEMSECRETS_CURRENCY)%' - $zero_price: '%env(PROVIDER_OEMSECRETS_ZERO_PRICE)%' - $set_param: '%env(PROVIDER_OEMSECRETS_SET_PARAM)%' - $sort_criteria: '%env(PROVIDER_OEMSECRETS_SORT_CRITERIA)%' - - #################################################################################################################### # API system #################################################################################################################### diff --git a/src/Services/InfoProviderSystem/Providers/OEMSecretsProvider.php b/src/Services/InfoProviderSystem/Providers/OEMSecretsProvider.php index 57c5b815..07b4a56e 100644 --- a/src/Services/InfoProviderSystem/Providers/OEMSecretsProvider.php +++ b/src/Services/InfoProviderSystem/Providers/OEMSecretsProvider.php @@ -88,6 +88,8 @@ use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\InfoProviderSystem\DTOs\PriceDTO; use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; use App\Services\InfoProviderSystem\DTOs\ParameterDTO; +use App\Settings\InfoProviderSystem\OEMSecretsSettings; +use App\Settings\InfoProviderSystem\OEMSecretsSortMode; use Symfony\Contracts\HttpClient\HttpClientInterface; use Psr\Cache\CacheItemPoolInterface; @@ -99,12 +101,7 @@ class OEMSecretsProvider implements InfoProviderInterface public function __construct( private readonly HttpClientInterface $oemsecretsClient, - private readonly string $api_key, - private readonly string $country_code, - private readonly string $currency, - private readonly string $zero_price, - private readonly string $set_param, - private readonly string $sort_criteria, + private readonly OEMSecretsSettings $settings, private readonly CacheItemPoolInterface $partInfoCache ) { @@ -268,7 +265,7 @@ class OEMSecretsProvider implements InfoProviderInterface */ public function isActive(): bool { - return $this->api_key !== ''; + return $this->settings->apiKey !== ''; } @@ -324,9 +321,9 @@ class OEMSecretsProvider implements InfoProviderInterface $response = $this->oemsecretsClient->request('GET', self::ENDPOINT_URL, [ 'query' => [ 'searchTerm' => $keyword, - 'apiKey' => $this->api_key, - 'currency' => $this->currency, - 'countryCode' => $this->country_code, + 'apiKey' => $this->settings->apiKey, + 'currency' => $this->settings->currency, + 'countryCode' => $this->settings->country, ], ]); @@ -533,7 +530,7 @@ class OEMSecretsProvider implements InfoProviderInterface // Extract prices $priceDTOs = $this->getPrices($product); - if (empty($priceDTOs) && (int)$this->zero_price === 0) { + if (empty($priceDTOs) && !$this->settings->keepZeroPrices) { return null; // Skip products without valid prices } @@ -557,7 +554,7 @@ class OEMSecretsProvider implements InfoProviderInterface } $imagesResults[$provider_id] = $this->getImages($product, $imagesResults[$provider_id] ?? []); - if ($this->set_param == 1) { + if ($this->settings->parseParams) { $parametersResults[$provider_id] = $this->getParameters($product, $parametersResults[$provider_id] ?? []); } else { $parametersResults[$provider_id] = []; @@ -582,7 +579,7 @@ class OEMSecretsProvider implements InfoProviderInterface $regionB = $this->countryCodeToRegionMap[$countryCodeB] ?? ''; // If the map is empty or doesn't contain the key for $this->country_code, assign a placeholder region. - $regionForEnvCountry = $this->countryCodeToRegionMap[$this->country_code] ?? ''; + $regionForEnvCountry = $this->countryCodeToRegionMap[$this->settings->country] ?? ''; // Convert to string before comparison to avoid mixed types $countryCodeA = (string) $countryCodeA; @@ -599,9 +596,9 @@ class OEMSecretsProvider implements InfoProviderInterface } // Step 1: country_code from the environment - if ($countryCodeA === $this->country_code && $countryCodeB !== $this->country_code) { + if ($countryCodeA === $this->settings->country && $countryCodeB !== $this->settings->country) { return -1; - } elseif ($countryCodeA !== $this->country_code && $countryCodeB === $this->country_code) { + } elseif ($countryCodeA !== $this->settings->country && $countryCodeB === $this->settings->country) { return 1; } @@ -681,8 +678,8 @@ class OEMSecretsProvider implements InfoProviderInterface if (is_array($prices)) { // Step 1: Check if prices exist in the preferred currency - if (isset($prices[$this->currency]) && is_array($prices[$this->currency])) { - $priceDetails = $prices[$this->currency]; + if (isset($prices[$this->settings->currency]) && is_array($prices[$this->settings->currency])) { + $priceDetails = $prices[$this->$this->settings->currency]; foreach ($priceDetails as $priceDetail) { if ( is_array($priceDetail) && @@ -694,7 +691,7 @@ class OEMSecretsProvider implements InfoProviderInterface $priceDTOs[] = new PriceDTO( minimum_discount_amount: (float)$priceDetail['unit_break'], price: (string)$priceDetail['unit_price'], - currency_iso_code: $this->currency, + currency_iso_code: $this->settings->currency, includes_tax: false, price_related_quantity: 1.0 ); @@ -1293,7 +1290,7 @@ class OEMSecretsProvider implements InfoProviderInterface private function sortResultsData(array &$resultsData, string $searchKeyword): void { // If the SORT_CRITERIA is not 'C' or 'M', do not sort - if ($this->sort_criteria !== 'C' && $this->sort_criteria !== 'M') { + if ($this->settings->sortMode !== OEMSecretsSortMode::COMPLETENESS && $this->settings->sortMode !== OEMSecretsSortMode::MANUFACTURER) { return; } usort($resultsData, function ($a, $b) use ($searchKeyword) { @@ -1332,9 +1329,9 @@ class OEMSecretsProvider implements InfoProviderInterface } // Final sorting: by completeness or manufacturer, if necessary - if ($this->sort_criteria === 'C') { + if ($this->settings->sortMode === OEMSecretsSortMode::COMPLETENESS) { return $this->compareByCompleteness($a, $b); - } elseif ($this->sort_criteria === 'M') { + } elseif ($this->settings->sortMode === OEMSecretsSortMode::MANUFACTURER) { return strcasecmp($a->manufacturer, $b->manufacturer); } diff --git a/src/Settings/InfoProviderSystem/InfoProviderSettings.php b/src/Settings/InfoProviderSystem/InfoProviderSettings.php index fe798713..d087facc 100644 --- a/src/Settings/InfoProviderSystem/InfoProviderSettings.php +++ b/src/Settings/InfoProviderSystem/InfoProviderSettings.php @@ -43,4 +43,7 @@ class InfoProviderSettings #[EmbeddedSettings] public ?LCSCSettings $lcsc = null; + + #[EmbeddedSettings] + public ?OEMSecretsSettings $oemsecrets = null; } \ No newline at end of file diff --git a/src/Settings/InfoProviderSystem/OEMSecretsSettings.php b/src/Settings/InfoProviderSystem/OEMSecretsSettings.php new file mode 100644 index 00000000..dfb2d689 --- /dev/null +++ b/src/Settings/InfoProviderSystem/OEMSecretsSettings.php @@ -0,0 +1,82 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Settings\InfoProviderSystem; + +use App\Settings\SettingsIcon; +use Jbtronics\SettingsBundle\Settings\Settings; +use Jbtronics\SettingsBundle\Settings\SettingsParameter; +use Jbtronics\SettingsBundle\Settings\SettingsTrait; +use Symfony\Component\Form\Extension\Core\Type\CountryType; +use Symfony\Component\Form\Extension\Core\Type\CurrencyType; +use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Translation\TranslatableMessage as TM; + +#[Settings(label: new TM("settings.ips.oemsecrets"))] +#[SettingsIcon("fa-plug")] +class OEMSecretsSettings +{ + use SettingsTrait; + + public const SUPPORTED_CURRENCIES = ["AUD", "CAD", "CHF", "CNY", "DKK", "EUR", "GBP", "HKD", "ILS", "INR", "JPY", "KRW", "NOK", + "NZD", "RUB", "SEK", "SGD", "TWD", "USD"]; + + #[SettingsParameter(label: new TM("settings.ips.element14.apiKey"), envVar: "PROVIDER_OEMSECRETS_KEY")] + public ?string $apiKey = null; + + #[Assert\Country] + #[SettingsParameter(label: new TM("settings.ips.tme.country"), formType: CountryType::class, formOptions: ["preferred_choices" => ["DE", "PL", "GB", "FR", "US"]], envVar: "PROVIDER_OEMSECRETS_COUNTRY_CODE")] + public ?string $country = "DE"; + + #[SettingsParameter(label: new TM("settings.ips.tme.currency"), formType: CurrencyType::class, formOptions: ["preferred_choices" => self::SUPPORTED_CURRENCIES], envVar: "PROVIDER_OEMSECRETS_CURRENCY")] + #[Assert\Choice(choices: self::SUPPORTED_CURRENCIES)] + public string $currency = "EUR"; + + /** + * @var bool If this is enabled, distributors with zero prices + * will be discarded from the creation of a new part + */ + #[SettingsParameter(label: new TM("settings.ips.oemsecrets.keepZeroPrices"), description: new TM("settings.ips.oemsecrets.keepZeroPrices.help"), envVar: "bool:PROVIDER_OEMSECRETS_ZERO_PRICE")] + public bool $keepZeroPrices = false; + + /** + * @var bool If set to 1 the parameters for the part are generated + * # from the description transforming unstructured descriptions into structured parameters; + * # each parameter in description should have the form: "...;name1:value1;name2:value2" + */ + #[SettingsParameter(label: new TM("settings.ips.oemsecrets.parseParams"), description: new TM("settings.ips.oemsecrets.parseParams.help"), envVar: "bool:PROVIDER_OEMSECRETS_SET_PARAM")] + public bool $parseParams = true; + + #[SettingsParameter(label: new TM("settings.ips.oemsecrets.sortMode"), envVar: "PROVIDER_OEMSECRETS_SORT_CRITERIA", envVarMapper: [self::class, "mapSortModeEnvVar"])] + public OEMSecretsSortMode $sortMode = OEMSecretsSortMode::COMPLETENESS; + + + public static function mapSortModeEnvVar(?string $value): OEMSecretsSortMode + { + if (!$value) { + return OEMSecretsSortMode::NONE; + } + + return OEMSecretsSortMode::tryFrom($value) ?? OEMSecretsSortMode::NONE; + } +} \ No newline at end of file diff --git a/src/Settings/InfoProviderSystem/OEMSecretsSortMode.php b/src/Settings/InfoProviderSystem/OEMSecretsSortMode.php new file mode 100644 index 00000000..e479e07e --- /dev/null +++ b/src/Settings/InfoProviderSystem/OEMSecretsSortMode.php @@ -0,0 +1,46 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Settings\InfoProviderSystem; + +use Symfony\Contracts\Translation\TranslatableInterface; +use Symfony\Contracts\Translation\TranslatorInterface; + +/** + * This environment variable determines the sorting criteria for product results. + * The sorting process first arranges items based on the provided keyword. + * Then, if set to 'C', it further sorts by completeness (prioritizing items with the most + * detailed information). If set to 'M', it further sorts by manufacturer name. + * If unset or set to any other value, no sorting is performed. + */ +enum OEMSecretsSortMode : string implements TranslatableInterface +{ + case NONE = "N"; + case COMPLETENESS = "C"; + case MANUFACTURER = "M"; + + public function trans(TranslatorInterface $translator, ?string $locale = null): string + { + return $translator->trans('settings.ips.oemsecrets.sortMode.' . $this->value, locale: $locale); + } +} \ No newline at end of file diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 45b8d706..6fa6ffa6 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -12323,474 +12323,528 @@ Please note, that you can not impersonate a disabled user. If you try you will g Profile saved! - + settings.ips.element14 Element 14 / Farnell - + settings.ips.element14.apiKey API Key - + settings.ips.element14.apiKey.help https://partner.element14.com/.]]> - + settings.ips.element14.storeId Store Domain - + settings.ips.element14.storeId.help here for a list of valid domains.]]> - + settings.ips.tme TME - + settings.ips.tme.token API Token - + settings.ips.tme.token.help https://developers.tme.eu/en/.]]> - + settings.ips.tme.secret API Secret - + settings.ips.tme.currency Currency - + settings.ips.tme.language Language - + settings.ips.tme.country Country - + settings.ips.tme.grossPrices Get gross prices (including tax) - + settings.ips.mouser Mouser - + settings.ips.mouser.apiKey API key - + settings.ips.mouser.apiKey.help https://eu.mouser.com/api-hub/.]]> - + settings.ips.mouser.searchLimit Search limit - + settings.ips.mouser.searchLimit.help The maximum amount of results for a single search. Can not be higher than 50. - + settings.ips.mouser.searchOptions Search filters - + settings.ips.mouser.searchOptions.help This allows you to only show parts with a certain availability and/or compliance. - + settings.ips.mouser.searchOptions.none No filter - + settings.ips.mouser.searchOptions.rohs Only RoHS compliant parts - + settings.ips.mouser.searchOptions.inStock Only in stock parts - + settings.ips.mouser.searchOptions.rohsAndInStock Only in stock, RoHS compliant parts - + settings.ips.lcsc LCSC - + settings.ips.lcsc.help Warning: LCSC does not provide an official API. This provider utilizes the webshop API. LCSC did not intend the use of this API, and it could break any time, so use it on your own risk. - + settings.ips.lcsc.enabled Enable - + settings.ips.lcsc.currency Currency - + settings.system.attachments - + settings.system.attachments.maxFileSize Maximum file size - + settings.system.attachments.maxFileSize.help The maximum size of files that can be uploaded. Please note that this is also limited by PHP configuration. - + settings.system.attachments.allowDownloads Allow downloading of external files - + settings.system.attachments.allowDownloads.help Attention: This can be a security issue, as it might allow users to access intranet ressources via Part-DB!]]> - + settings.system.attachments.downloadByDefault Download new attachment URLs by default - + settings.system.customization Customization - + settings.system.customization.instanceName Instance name - + settings.system.customization.instanceName.help Name of this Part-DB installation. The value is shown in nav bar and titles. - + settings.system.customization.banner Homepage banner - + settings.system.history History log - + settings.system.history.saveChangedFields Save which fields of an element were changed in log entries - + settings.system.history.saveOldData Save the old data in log entries on element changes - + settings.system.history.saveNewData Save the new data in log entries on element change/creation - + settings.system.history.saveRemovedData Save removed data in log entries on element deletion - + settings.system.customization.theme Global theme - + settings.system.history.enforceComments Enforce comments for action types - + settings.system.history.enforceComments.description With this option, you can specify for which actions, users are enforced to give a reason, which will be logged in history. - + settings.system.history.enforceComments.type.part_edit Part edit - + settings.system.history.enforceComments.type.part_create Part creation - + settings.system.history.enforceComments.type.part_delete Part deletion - + settings.system.history.enforceComments.type.part_stock_operation Part stock operation - + settings.system.history.enforceComments.type.datastructure_edit Data structure edit - + settings.system.history.enforceComments.type.datastructure_create Data structure creation - + settings.system.history.enforceComments.type.datastructure_delete Data structure deletion - + settings.system.privacy.useGravatar Use Gravatar avatars - + settings.system.privacy.useGravatar.description If a user does not have an avatar image specified, use the avatar from Gravatar based on the user email. This causes the browser to load pictures from a third-party! - + settings.system.privacy.checkForUpdates Check for Part-DB updates - + settings.system.privacy.checkForUpdates.description Part-DB regularly checks if a new version is available on GitHub. Disable this here, if you do not want this or if your server can not connect to the internet. - + settings.system.localization.locale Default language / locale - + settings.system.localization Localization - + settings.system.localization.timezone Default timezone - + settings.system.localization.base_currency Base currency - + settings.system.localization.base_currency_description Please note that the currencies are not converted, when changing this value. So changing the default currency after you already added price information, will result in wrong prices!]]> - + settings.system.privacy Privacy - + settings.title Server settings - + settings.misc.kicad_eda KiCAD integration - + settings.misc.kicad_eda.category_depth Category depth - + settings.misc.kicad_eda.category_depth.help 0 to show more levels. Set to -1, to show all parts of Part-DB inside a sigle cnategory in KiCad.]]> - + settings.behavior.sidebar Sidebar - + settings.behavior.sidebar.items Sidebar items - + settings.behavior.sidebar.items.help - + settings.behavior.sidebar.rootNodeEnabled Use root node - + settings.behavior.sidebar.rootNodeEnabled.help If this is enabled, all top-level categories, footprints, etc. will be put under a single root node. If disabled, the top-level categories will be put directly into the menu. - + settings.behavior.sidebar.rootNodeExpanded Expand root node by default - + settings.behavior.table Tables - + settings.behavior.table.default_page_size Default page size - + settings.behavior.table.default_page_size.help The default page size on full page tables. Set to -1 to show all items by default without pagination. - + settings.behavior.table.parts_default_columns Default columns for part tables - + settings.behavior.table.parts_default_columns.help + + + settings.ips.oemsecrets + OEMSecrets + + + + + settings.ips.oemsecrets.keepZeroPrices + Keep distributors with zero prices + + + + + settings.ips.oemsecrets.keepZeroPrices.help + If this is not set, distributors where the prices are 0 will be discarded as invalid + + + + + settings.ips.oemsecrets.parseParams + Extract parameters from description + + + + + settings.ips.oemsecrets.parseParams.help + If enabled, the provider tries to convert the unstructured descriptions of OEMSecrets into structured parameters. Each parameter in the description should have the form "...;name1:value1;name2:value2" + + + + + settings.ips.oemsecrets.sortMode + Result sort mode + + + + + settings.ips.oemsecrets.sortMode.N + None + + + + + settings.ips.oemsecrets.sortMode.C + Completeness (prioritize items with detailed information) + + + + + settings.ips.oemsecrets.sortMode.M + + +