feat: Implement pagination and filtering for linked offers by integration
- Refactored `listLinkedOffersByIntegration` to `paginateLinkedOffersByIntegration` in `MarketplaceRepository`. - Added pagination support with `page` and `per_page` filters. - Introduced sorting options for offers. - Created `listOfferChannelsByIntegration` method to retrieve distinct sales channels. - Enhanced SQL queries to support dynamic filtering based on provided parameters. feat: Add new fields for products and SKU generation - Introduced new fields: `new_to_date`, `additional_message`, `additional_message_required`, and `additional_message_text` in the `products` table. - Added `findAllSkus` method in `ProductRepository` to retrieve all SKUs. - Created `ProductSkuGenerator` class to handle SKU generation based on a configurable format. - Implemented `nextSku` method to generate the next available SKU. feat: Enhance product settings management in the UI - Added new settings page for product SKU format in `SettingsController`. - Implemented form handling for saving SKU format settings. - Updated the view to include SKU format configuration options. feat: Implement cron job for refreshing ShopPro offer titles - Created `ShopProOfferTitlesRefreshHandler` to handle the cron job for refreshing offer titles. - Integrated with the `OfferImportService` to import offers from ShopPro. docs: Update database schema documentation - Added documentation for new fields in the `products` table and new cron job for offer title refresh. - Documented the purpose and structure of the `app_settings` table. migrations: Add necessary migrations for new features - Created migration to add `products_sku_format` setting in `app_settings`. - Added migration to introduce new fields in the `products` table. - Created migration for the new cron job schedule for refreshing ShopPro offer titles.
This commit is contained in:
@@ -6,6 +6,7 @@ namespace App\Modules\Cron;
|
||||
final class CronJobType
|
||||
{
|
||||
public const PRODUCT_LINKS_HEALTH_CHECK = 'product_links_health_check';
|
||||
public const SHOPPRO_OFFER_TITLES_REFRESH = 'shoppro_offer_titles_refresh';
|
||||
|
||||
public const PRIORITY_HIGH = 50;
|
||||
public const PRIORITY_NORMAL = 100;
|
||||
@@ -15,6 +16,7 @@ final class CronJobType
|
||||
{
|
||||
return match (trim($jobType)) {
|
||||
self::PRODUCT_LINKS_HEALTH_CHECK => 110,
|
||||
self::SHOPPRO_OFFER_TITLES_REFRESH => 170,
|
||||
default => self::PRIORITY_NORMAL,
|
||||
};
|
||||
}
|
||||
@@ -23,6 +25,7 @@ final class CronJobType
|
||||
{
|
||||
return match (trim($jobType)) {
|
||||
self::PRODUCT_LINKS_HEALTH_CHECK => 3,
|
||||
self::SHOPPRO_OFFER_TITLES_REFRESH => 3,
|
||||
default => 3,
|
||||
};
|
||||
}
|
||||
|
||||
106
src/Modules/Cron/ShopProOfferTitlesRefreshHandler.php
Normal file
106
src/Modules/Cron/ShopProOfferTitlesRefreshHandler.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\Cron;
|
||||
|
||||
use App\Modules\ProductLinks\OfferImportService;
|
||||
use App\Modules\Settings\IntegrationRepository;
|
||||
use Throwable;
|
||||
|
||||
final class ShopProOfferTitlesRefreshHandler
|
||||
{
|
||||
public function __construct(
|
||||
private readonly IntegrationRepository $integrations,
|
||||
private readonly OfferImportService $offerImportService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
* @param array<string, mixed> $job
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function __invoke(array $payload = [], array $job = []): array
|
||||
{
|
||||
$forcedIntegrationId = max(0, (int) ($payload['integration_id'] ?? 0));
|
||||
$activeIntegrations = array_values(array_filter(
|
||||
$this->integrations->listByType('shoppro'),
|
||||
static function (array $integration) use ($forcedIntegrationId): bool {
|
||||
$id = (int) ($integration['id'] ?? 0);
|
||||
if ($forcedIntegrationId > 0 && $id !== $forcedIntegrationId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $id > 0
|
||||
&& ($integration['is_active'] ?? false) === true
|
||||
&& ($integration['has_api_key'] ?? false) === true;
|
||||
}
|
||||
));
|
||||
|
||||
if ($activeIntegrations === []) {
|
||||
return [
|
||||
'ok' => true,
|
||||
'message' => 'Brak aktywnych integracji z kluczem API do odswiezenia tytulow ofert.',
|
||||
'integrations' => 0,
|
||||
'updated_offers' => 0,
|
||||
'failed_offers' => 0,
|
||||
'integration_failures' => 0,
|
||||
'errors' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$updatedOffers = 0;
|
||||
$failedOffers = 0;
|
||||
$integrationFailures = 0;
|
||||
$errors = [];
|
||||
|
||||
foreach ($activeIntegrations as $integration) {
|
||||
$integrationId = (int) ($integration['id'] ?? 0);
|
||||
if ($integrationId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$credentials = $this->integrations->findApiCredentials($integrationId);
|
||||
} catch (Throwable $exception) {
|
||||
$integrationFailures++;
|
||||
if (count($errors) < 5) {
|
||||
$errors[] = 'Integracja #' . $integrationId . ': ' . $exception->getMessage();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($credentials === null || trim((string) ($credentials['api_key'] ?? '')) === '') {
|
||||
$integrationFailures++;
|
||||
if (count($errors) < 5) {
|
||||
$errors[] = 'Integracja #' . $integrationId . ': brak poprawnych danych API.';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$import = $this->offerImportService->importShopProOffers($credentials);
|
||||
if (($import['ok'] ?? false) !== true) {
|
||||
$integrationFailures++;
|
||||
if (count($errors) < 5) {
|
||||
$errors[] = 'Integracja #' . $integrationId . ': ' . trim((string) ($import['message'] ?? 'Blad importu ofert.'));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$updatedOffers += (int) ($import['imported'] ?? 0);
|
||||
$failedOffers += (int) ($import['failed'] ?? 0);
|
||||
}
|
||||
|
||||
return [
|
||||
'ok' => $integrationFailures === 0,
|
||||
'message' => $integrationFailures === 0
|
||||
? 'Odswiezenie tytulow ofert zakonczone.'
|
||||
: 'Odswiezenie tytulow zakonczone z bledami integracji.',
|
||||
'integrations' => count($activeIntegrations),
|
||||
'updated_offers' => $updatedOffers,
|
||||
'failed_offers' => $failedOffers,
|
||||
'integration_failures' => $integrationFailures,
|
||||
'errors' => $errors,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user