141 lines
5.1 KiB
PHP
141 lines
5.1 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Cron;
|
|
|
|
use App\Modules\ProductLinks\ChannelOffersRepository;
|
|
use App\Modules\ProductLinks\OfferImportService;
|
|
use App\Modules\ProductLinks\ProductLinksRepository;
|
|
use App\Modules\Settings\IntegrationRepository;
|
|
use Throwable;
|
|
|
|
final class ProductLinksHealthCheckHandler
|
|
{
|
|
private const ALERT_TYPE = 'missing_remote_link';
|
|
private const ALERT_MESSAGE = 'Powiazanie nie istnieje juz po stronie zewnetrznej.';
|
|
|
|
public function __construct(
|
|
private readonly IntegrationRepository $integrations,
|
|
private readonly OfferImportService $offerImportService,
|
|
private readonly ProductLinksRepository $links,
|
|
private readonly ChannelOffersRepository $offers
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @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 weryfikacji powiazan.',
|
|
'checked_links' => 0,
|
|
'missing_links' => 0,
|
|
'integrations' => 0,
|
|
'integration_failures' => 0,
|
|
];
|
|
}
|
|
|
|
$checkedLinks = 0;
|
|
$missingLinks = 0;
|
|
$resolvedAlerts = 0;
|
|
$integrationFailures = 0;
|
|
$errors = [];
|
|
$checkedAt = date('Y-m-d H:i:s');
|
|
|
|
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;
|
|
}
|
|
|
|
$links = $this->links->listActiveLinksForMissingCheck($integrationId);
|
|
foreach ($links as $link) {
|
|
$mapId = (int) ($link['id'] ?? 0);
|
|
$externalProductId = trim((string) ($link['external_product_id'] ?? ''));
|
|
$externalVariantId = $this->nullableText($link['external_variant_id'] ?? null);
|
|
if ($mapId <= 0 || $externalProductId === '') {
|
|
continue;
|
|
}
|
|
|
|
$checkedLinks++;
|
|
$offer = $this->offers->findByExternalIdentity($integrationId, $externalProductId, $externalVariantId);
|
|
|
|
if ($offer === null) {
|
|
$missingLinks++;
|
|
$this->links->upsertActiveAlert($mapId, self::ALERT_TYPE, self::ALERT_MESSAGE, $checkedAt);
|
|
continue;
|
|
}
|
|
|
|
$this->links->resolveActiveAlert($mapId, self::ALERT_TYPE, $checkedAt);
|
|
$resolvedAlerts++;
|
|
}
|
|
}
|
|
|
|
return [
|
|
'ok' => $integrationFailures === 0,
|
|
'message' => $integrationFailures === 0
|
|
? 'Weryfikacja powiazan zakonczona.'
|
|
: 'Weryfikacja zakonczona z bledami integracji.',
|
|
'checked_links' => $checkedLinks,
|
|
'missing_links' => $missingLinks,
|
|
'resolved_alerts' => $resolvedAlerts,
|
|
'integrations' => count($activeIntegrations),
|
|
'integration_failures' => $integrationFailures,
|
|
'errors' => $errors,
|
|
];
|
|
}
|
|
|
|
private function nullableText(mixed $value): ?string
|
|
{
|
|
$text = trim((string) $value);
|
|
return $text === '' ? null : $text;
|
|
}
|
|
}
|