repository->listIntegrations(); $forceNewMode = trim((string) $request->input('new', '')) === '1'; $selectedId = max(0, (int) $request->input('id', 0)); $selectedIntegration = $selectedId > 0 ? $this->repository->findIntegration($selectedId) : null; if (!$forceNewMode && $selectedIntegration === null && $integrations !== []) { $firstId = (int) ($integrations[0]['id'] ?? 0); if ($firstId > 0) { $selectedIntegration = $this->repository->findIntegration($firstId); } } $this->ensureImportScheduleExists(); $this->ensureStatusSyncScheduleExists(); $this->ensurePaymentSyncScheduleExists(); $activeTab = $this->resolveTab((string) $request->input('tab', 'integration')); $discoveredStatuses = $this->readDiscoveredStatuses(); $statusRows = $selectedIntegration !== null ? $this->buildStatusRows((int) ($selectedIntegration['id'] ?? 0), $discoveredStatuses) : []; $deliveryServicesData = $activeTab === 'delivery' ? $this->loadDeliveryServices() : [[], [], '']; $deliveryMappings = $selectedIntegration !== null ? $this->deliveryMappings->listMappings('shoppro', (int) ($selectedIntegration['id'] ?? 0)) : []; $orderDeliveryMethods = $selectedIntegration !== null ? $this->deliveryMappings->getDistinctOrderDeliveryMethods('shoppro', (int) ($selectedIntegration['id'] ?? 0)) : []; $html = $this->template->render('settings/shoppro', [ 'title' => $this->translator->get('settings.integrations.title'), 'activeMenu' => 'settings', 'activeSettings' => 'shoppro', 'user' => $this->auth->user(), 'csrfToken' => Csrf::token(), 'activeTab' => $activeTab, 'rows' => $integrations, 'selectedIntegration' => $selectedIntegration, 'form' => $this->buildFormValues($selectedIntegration), 'ordersImportIntervalMinutes' => $this->currentImportIntervalMinutes(), 'statusSyncIntervalMinutes' => $this->currentStatusSyncIntervalMinutes(), 'paymentSyncIntervalMinutes' => $this->currentPaymentSyncIntervalMinutes(), 'statusRows' => $statusRows, 'orderproStatuses' => $this->orderStatuses->listStatuses(), 'deliveryMappings' => $deliveryMappings, 'orderDeliveryMethods' => $orderDeliveryMethods, 'allegroDeliveryServices' => $deliveryServicesData[0], 'apaczkaDeliveryServices' => $deliveryServicesData[1], 'allegroDeliveryServicesError' => $deliveryServicesData[2], 'inpostDeliveryServices' => array_values(array_filter( $deliveryServicesData[0], static fn (array $svc): bool => stripos((string) ($svc['carrierId'] ?? ''), 'inpost') !== false )), 'errorMessage' => (string) Flash::get('settings_error', ''), 'successMessage' => (string) Flash::get('settings_success', ''), ], 'layouts/app'); return Response::html($html); } public function save(Request $request): Response { $integrationId = max(0, (int) $request->input('integration_id', 0)); $tab = $this->resolveTab((string) $request->input('tab', 'integration')); $redirectBase = '/settings/integrations/shoppro'; $redirectTo = $this->buildRedirectUrl($integrationId, $tab); if (!Csrf::validate((string) $request->input('_token', ''))) { Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired')); return Response::redirect($redirectTo); } $existing = $integrationId > 0 ? $this->repository->findIntegration($integrationId) : null; if ($integrationId > 0 && $existing === null) { Flash::set('settings_error', $this->translator->get('settings.integrations.flash.not_found')); return Response::redirect($this->buildRedirectUrl(0, $tab)); } $name = trim((string) $request->input('name', '')); if (mb_strlen($name) < 2) { Flash::set('settings_error', $this->translator->get('settings.integrations.validation.name_min')); return Response::redirect($redirectTo); } $baseUrl = rtrim(trim((string) $request->input('base_url', '')), '/'); if (!$this->isValidHttpUrl($baseUrl)) { Flash::set('settings_error', $this->translator->get('settings.integrations.validation.base_url_invalid')); return Response::redirect($redirectTo); } $apiKey = trim((string) $request->input('api_key', '')); $hasExistingApiKey = (bool) ($existing['has_api_key'] ?? false); if ($tab === 'integration' && $apiKey === '' && !$hasExistingApiKey) { Flash::set('settings_error', $this->translator->get('settings.integrations.validation.api_key_required')); return Response::redirect($redirectTo); } $ordersFetchStartDate = trim((string) $request->input('orders_fetch_start_date', '')); if ($ordersFetchStartDate !== '' && !$this->isValidYmdDate($ordersFetchStartDate)) { Flash::set('settings_error', $this->translator->get('settings.integrations.validation.orders_fetch_start_date_invalid')); return Response::redirect($redirectTo); } if ($this->isDuplicateName($integrationId, $name)) { Flash::set('settings_error', $this->translator->get('settings.integrations.validation.name_taken')); return Response::redirect($redirectTo); } try { $statusSyncDirectionInput = $request->input('order_status_sync_direction', null); $statusSyncDirection = $statusSyncDirectionInput !== null ? trim((string) $statusSyncDirectionInput) : (string) ($existing['order_status_sync_direction'] ?? 'shoppro_to_orderpro'); $paymentSyncStatusCodesInput = $request->input('payment_sync_status_codes', null); if (is_array($paymentSyncStatusCodesInput)) { $paymentSyncStatusCodes = $paymentSyncStatusCodesInput; } elseif ($tab === 'settings') { $paymentSyncStatusCodes = []; } else { $paymentSyncStatusCodes = $existing['payment_sync_status_codes'] ?? []; } $savedId = $this->repository->saveIntegration([ 'integration_id' => $integrationId, 'name' => $name, 'base_url' => $baseUrl, 'api_key' => $apiKey, 'timeout_seconds' => max(1, min(120, (int) $request->input('timeout_seconds', 10))), 'is_active' => $request->input('is_active', ''), 'orders_fetch_enabled' => $request->input('orders_fetch_enabled', ''), 'orders_fetch_start_date' => $ordersFetchStartDate, 'order_status_sync_direction' => $statusSyncDirection, 'payment_sync_status_codes' => $paymentSyncStatusCodes, ]); $this->saveImportIntervalIfRequested($request); $this->saveStatusSyncIntervalIfRequested($request); $this->savePaymentSyncIntervalIfRequested($request); $flashKey = $integrationId > 0 ? 'settings.integrations.flash.updated' : 'settings.integrations.flash.created'; Flash::set('settings_success', $this->translator->get($flashKey)); return Response::redirect($this->buildRedirectUrl($savedId, $tab)); } catch (Throwable) { Flash::set('settings_error', $this->translator->get('settings.integrations.flash.failed')); return Response::redirect($redirectTo); } } public function test(Request $request): Response { $integrationId = max(0, (int) $request->input('integration_id', 0)); $tab = $this->resolveTab((string) $request->input('tab', 'integration')); $redirectBase = '/settings/integrations/shoppro'; $redirectTo = $this->buildRedirectUrl($integrationId, $tab); if (!Csrf::validate((string) $request->input('_token', ''))) { Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired')); return Response::redirect($redirectTo); } if ($integrationId <= 0) { Flash::set('settings_error', $this->translator->get('settings.integrations.flash.not_found')); return Response::redirect($this->buildRedirectUrl(0, $tab)); } $result = $this->repository->testConnection($integrationId); $isOk = (string) ($result['status'] ?? 'error') === 'ok'; $message = trim((string) ($result['message'] ?? '')); $httpCode = $result['http_code'] ?? null; if ($isOk) { Flash::set('settings_success', $this->translator->get('settings.integrations.flash.test_ok')); } else { $suffix = $message !== '' ? ' ' . $message : ''; $httpPart = $httpCode !== null ? ' (HTTP ' . (string) $httpCode . ')' : ''; Flash::set( 'settings_error', $this->translator->get('settings.integrations.flash.test_failed') . $httpPart . $suffix ); } return Response::redirect($redirectTo); } public function saveStatusMappings(Request $request): Response { $integrationId = max(0, (int) $request->input('integration_id', 0)); $redirectTo = $this->buildRedirectUrl($integrationId, 'statuses'); if (!Csrf::validate((string) $request->input('_token', ''))) { Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired')); return Response::redirect($redirectTo); } if ($integrationId <= 0 || $this->repository->findIntegration($integrationId) === null) { Flash::set('settings_error', $this->translator->get('settings.integrations.flash.not_found')); return Response::redirect($this->buildRedirectUrl(0, 'statuses')); } $shopCodes = $request->input('shoppro_status_code', []); $shopNames = $request->input('shoppro_status_name', []); $orderCodes = $request->input('orderpro_status_code', []); if (!is_array($shopCodes) || !is_array($shopNames) || !is_array($orderCodes)) { Flash::set('settings_error', $this->translator->get('settings.integrations.statuses.flash.invalid_payload')); return Response::redirect($redirectTo); } $allowedOrderpro = $this->resolveAllowedOrderproStatusCodes(); $rowsCount = min(count($shopCodes), count($shopNames), count($orderCodes)); $mappings = []; for ($index = 0; $index < $rowsCount; $index++) { $shopCode = trim((string) ($shopCodes[$index] ?? '')); $shopName = trim((string) ($shopNames[$index] ?? '')); $orderCode = strtolower(trim((string) ($orderCodes[$index] ?? ''))); if ($shopCode === '') { continue; } if ($orderCode === '') { continue; } if (!isset($allowedOrderpro[$orderCode])) { continue; } $mappings[] = [ 'shoppro_status_code' => $shopCode, 'shoppro_status_name' => $shopName, 'orderpro_status_code' => $orderCode, ]; } try { $this->statusMappings->replaceForIntegration($integrationId, $mappings); Flash::set('settings_success', $this->translator->get('settings.integrations.statuses.flash.saved')); } catch (Throwable $exception) { Flash::set( 'settings_error', $this->translator->get('settings.integrations.statuses.flash.save_failed') . ' ' . $exception->getMessage() ); } return Response::redirect($redirectTo); } public function syncStatuses(Request $request): Response { $integrationId = max(0, (int) $request->input('integration_id', 0)); $redirectTo = $this->buildRedirectUrl($integrationId, 'statuses'); if (!Csrf::validate((string) $request->input('_token', ''))) { Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired')); return Response::redirect($redirectTo); } if ($integrationId <= 0 || $this->repository->findIntegration($integrationId) === null) { Flash::set('settings_error', $this->translator->get('settings.integrations.flash.not_found')); return Response::redirect($this->buildRedirectUrl(0, 'statuses')); } $result = $this->repository->fetchOrderStatuses($integrationId); if (($result['ok'] ?? false) !== true) { $message = trim((string) ($result['message'] ?? '')); Flash::set( 'settings_error', $this->translator->get('settings.integrations.statuses.flash.sync_failed') . ($message !== '' ? ' ' . $message : '') ); return Response::redirect($redirectTo); } $statuses = $result['statuses'] ?? []; Flash::set('shoppro_discovered_statuses', is_array($statuses) ? $statuses : []); Flash::set( 'settings_success', $this->translator->get('settings.integrations.statuses.flash.sync_ok', [ 'count' => (string) (is_array($statuses) ? count($statuses) : 0), ]) ); return Response::redirect($redirectTo); } public function saveDeliveryMappings(Request $request): Response { $integrationId = max(0, (int) $request->input('integration_id', 0)); $redirectTo = $this->buildRedirectUrl($integrationId, 'delivery'); if (!Csrf::validate((string) $request->input('_token', ''))) { Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired')); return Response::redirect($redirectTo); } if ($integrationId <= 0 || $this->repository->findIntegration($integrationId) === null) { Flash::set('settings_error', $this->translator->get('settings.integrations.flash.not_found')); return Response::redirect($this->buildRedirectUrl(0, 'delivery')); } $orderMethods = (array) $request->input('order_delivery_method', []); $carriers = (array) $request->input('carrier', []); $allegroMethodIds = (array) $request->input('allegro_delivery_method_id', []); $apaczkaMethodIds = (array) $request->input('apaczka_delivery_method_id', []); $credentialsIds = (array) $request->input('allegro_credentials_id', []); $carrierIds = (array) $request->input('allegro_carrier_id', []); $serviceNames = (array) $request->input('allegro_service_name', []); $mappings = []; foreach ($orderMethods as $index => $orderMethod) { $orderMethodValue = trim((string) $orderMethod); $carrier = trim((string) ($carriers[$index] ?? 'allegro')); $provider = $carrier === 'apaczka' ? 'apaczka' : 'allegro_wza'; $providerServiceId = $provider === 'apaczka' ? trim((string) ($apaczkaMethodIds[$index] ?? '')) : trim((string) ($allegroMethodIds[$index] ?? '')); if ($orderMethodValue === '' || $providerServiceId === '') { continue; } $mappings[] = [ 'order_delivery_method' => $orderMethodValue, 'provider' => $provider, 'provider_service_id' => $providerServiceId, 'provider_account_id' => $provider === 'allegro_wza' ? trim((string) ($credentialsIds[$index] ?? '')) : '', 'provider_carrier_id' => $provider === 'allegro_wza' ? trim((string) ($carrierIds[$index] ?? '')) : '', 'provider_service_name' => trim((string) ($serviceNames[$index] ?? '')), ]; } try { $this->deliveryMappings->saveMappings('shoppro', $integrationId, $mappings); Flash::set('settings_success', $this->translator->get('settings.integrations.delivery.flash.saved')); } catch (Throwable $exception) { Flash::set( 'settings_error', $this->translator->get('settings.integrations.delivery.flash.save_failed') . ' ' . $exception->getMessage() ); } return Response::redirect($redirectTo); } /** * @param array|null $integration * @return array */ private function buildFormValues(?array $integration): array { if ($integration === null) { return [ 'integration_id' => 0, 'name' => '', 'base_url' => '', 'timeout_seconds' => 10, 'is_active' => 1, 'orders_fetch_enabled' => 0, 'orders_fetch_start_date' => '', 'order_status_sync_direction' => 'shoppro_to_orderpro', 'payment_sync_status_codes' => [], ]; } return [ 'integration_id' => (int) ($integration['id'] ?? 0), 'name' => (string) ($integration['name'] ?? ''), 'base_url' => (string) ($integration['base_url'] ?? ''), 'timeout_seconds' => (int) ($integration['timeout_seconds'] ?? 10), 'is_active' => !empty($integration['is_active']) ? 1 : 0, 'orders_fetch_enabled' => !empty($integration['orders_fetch_enabled']) ? 1 : 0, 'orders_fetch_start_date' => (string) ($integration['orders_fetch_start_date'] ?? ''), 'order_status_sync_direction' => (string) ($integration['order_status_sync_direction'] ?? 'shoppro_to_orderpro'), 'payment_sync_status_codes' => is_array($integration['payment_sync_status_codes'] ?? null) ? $integration['payment_sync_status_codes'] : [], ]; } private function isDuplicateName(int $currentId, string $name): bool { $needle = mb_strtolower(trim($name)); if ($needle === '') { return false; } $rows = $this->repository->listIntegrations(); foreach ($rows as $row) { $rowId = (int) ($row['id'] ?? 0); if ($rowId === $currentId) { continue; } $rowName = mb_strtolower(trim((string) ($row['name'] ?? ''))); if ($rowName === $needle) { return true; } } return false; } private function isValidHttpUrl(string $value): bool { if (filter_var($value, FILTER_VALIDATE_URL) === false) { return false; } $scheme = strtolower((string) parse_url($value, PHP_URL_SCHEME)); return in_array($scheme, ['http', 'https'], true); } private function isValidYmdDate(string $value): bool { $date = DateTimeImmutable::createFromFormat('Y-m-d', $value); return $date !== false && $date->format('Y-m-d') === $value; } /** * @return array */ private function buildStatusRows(int $integrationId, array $discoveredStatuses): array { $mappedRows = $this->statusMappings->listByIntegration($integrationId); $result = []; foreach ($mappedRows as $row) { $code = trim((string) ($row['shoppro_status_code'] ?? '')); if ($code === '') { continue; } $key = mb_strtolower($code); $result[$key] = [ 'shoppro_status_code' => $code, 'shoppro_status_name' => trim((string) ($row['shoppro_status_name'] ?? '')), 'orderpro_status_code' => strtolower(trim((string) ($row['orderpro_status_code'] ?? ''))), ]; } foreach ($discoveredStatuses as $status) { if (!is_array($status)) { continue; } $code = trim((string) ($status['code'] ?? '')); if ($code === '') { continue; } $key = mb_strtolower($code); if (!isset($result[$key])) { $result[$key] = [ 'shoppro_status_code' => $code, 'shoppro_status_name' => trim((string) ($status['name'] ?? '')), 'orderpro_status_code' => '', ]; } } uasort($result, static function (array $left, array $right): int { return strcmp( strtolower((string) ($left['shoppro_status_code'] ?? '')), strtolower((string) ($right['shoppro_status_code'] ?? '')) ); }); return array_values($result); } /** * @return array */ private function resolveAllowedOrderproStatusCodes(): array { $allowed = []; foreach ($this->orderStatuses->listStatuses() as $status) { if (!is_array($status)) { continue; } $code = strtolower(trim((string) ($status['code'] ?? ''))); if ($code === '') { continue; } $allowed[$code] = true; } return $allowed; } /** * @return array */ private function readDiscoveredStatuses(): array { $raw = Flash::get('shoppro_discovered_statuses', []); if (!is_array($raw)) { return []; } $result = []; foreach ($raw as $item) { if (!is_array($item)) { continue; } $code = trim((string) ($item['code'] ?? '')); if ($code === '') { continue; } $result[] = [ 'code' => $code, 'name' => trim((string) ($item['name'] ?? $code)), ]; } return $result; } private function resolveTab(string $candidate): string { $value = trim($candidate); $allowed = ['integration', 'statuses', 'settings', 'delivery']; if (!in_array($value, $allowed, true)) { return 'integration'; } return $value; } private function buildRedirectUrl(int $integrationId, string $tab): string { $url = '/settings/integrations/shoppro'; $query = []; if ($integrationId > 0) { $query['id'] = (string) $integrationId; } if ($tab !== 'integration') { $query['tab'] = $tab; } if ($query === []) { return $url; } return $url . '?' . http_build_query($query); } private function currentImportIntervalMinutes(): int { $schedule = $this->findImportSchedule(); $seconds = (int) ($schedule['interval_seconds'] ?? self::ORDERS_IMPORT_DEFAULT_INTERVAL_SECONDS); return max(1, min(1440, (int) floor(max(60, $seconds) / 60))); } /** * @return array */ private function findImportSchedule(): array { foreach ($this->cronRepository->listSchedules() as $schedule) { if ((string) ($schedule['job_type'] ?? '') !== self::ORDERS_IMPORT_JOB_TYPE) { continue; } return $schedule; } return []; } /** * @return array */ private function findStatusSyncSchedule(): array { foreach ($this->cronRepository->listSchedules() as $schedule) { if ((string) ($schedule['job_type'] ?? '') !== self::ORDER_STATUS_SYNC_JOB_TYPE) { continue; } return $schedule; } return []; } /** * @return array */ private function findPaymentSyncSchedule(): array { foreach ($this->cronRepository->listSchedules() as $schedule) { if ((string) ($schedule['job_type'] ?? '') !== self::PAYMENT_SYNC_JOB_TYPE) { continue; } return $schedule; } return []; } private function ensureImportScheduleExists(): void { try { if ($this->findImportSchedule() !== []) { return; } $this->cronRepository->upsertSchedule( self::ORDERS_IMPORT_JOB_TYPE, self::ORDERS_IMPORT_DEFAULT_INTERVAL_SECONDS, self::ORDERS_IMPORT_DEFAULT_PRIORITY, self::ORDERS_IMPORT_DEFAULT_MAX_ATTEMPTS, null, true ); } catch (Throwable) { return; } } private function ensureStatusSyncScheduleExists(): void { try { if ($this->findStatusSyncSchedule() !== []) { return; } $this->cronRepository->upsertSchedule( self::ORDER_STATUS_SYNC_JOB_TYPE, self::ORDER_STATUS_SYNC_DEFAULT_INTERVAL_SECONDS, self::ORDER_STATUS_SYNC_DEFAULT_PRIORITY, self::ORDER_STATUS_SYNC_DEFAULT_MAX_ATTEMPTS, null, true ); } catch (Throwable) { return; } } private function ensurePaymentSyncScheduleExists(): void { try { if ($this->findPaymentSyncSchedule() !== []) { return; } $this->cronRepository->upsertSchedule( self::PAYMENT_SYNC_JOB_TYPE, self::PAYMENT_SYNC_DEFAULT_INTERVAL_SECONDS, self::PAYMENT_SYNC_DEFAULT_PRIORITY, self::PAYMENT_SYNC_DEFAULT_MAX_ATTEMPTS, null, true ); } catch (Throwable) { return; } } private function saveImportIntervalIfRequested(Request $request): void { if ($request->input('orders_import_interval_minutes', null) === null) { return; } $this->ensureImportScheduleExists(); $minutes = max(1, min(1440, (int) $request->input('orders_import_interval_minutes', 5))); $schedule = $this->findImportSchedule(); $priority = max(1, min(255, (int) ($schedule['priority'] ?? self::ORDERS_IMPORT_DEFAULT_PRIORITY))); $maxAttempts = max(1, min(20, (int) ($schedule['max_attempts'] ?? self::ORDERS_IMPORT_DEFAULT_MAX_ATTEMPTS))); $payload = is_array($schedule['payload'] ?? null) ? $schedule['payload'] : null; $enabled = array_key_exists('enabled', $schedule) ? !empty($schedule['enabled']) : true; $this->cronRepository->upsertSchedule( self::ORDERS_IMPORT_JOB_TYPE, $minutes * 60, $priority, $maxAttempts, $payload, $enabled ); } private function currentStatusSyncIntervalMinutes(): int { $schedule = $this->findStatusSyncSchedule(); $seconds = (int) ($schedule['interval_seconds'] ?? self::ORDER_STATUS_SYNC_DEFAULT_INTERVAL_SECONDS); return max(1, min(1440, (int) floor(max(60, $seconds) / 60))); } private function saveStatusSyncIntervalIfRequested(Request $request): void { if ($request->input('status_sync_interval_minutes', null) === null) { return; } $this->ensureStatusSyncScheduleExists(); $minutes = max(1, min(1440, (int) $request->input('status_sync_interval_minutes', 15))); $schedule = $this->findStatusSyncSchedule(); $priority = max(1, min(255, (int) ($schedule['priority'] ?? self::ORDER_STATUS_SYNC_DEFAULT_PRIORITY))); $maxAttempts = max(1, min(20, (int) ($schedule['max_attempts'] ?? self::ORDER_STATUS_SYNC_DEFAULT_MAX_ATTEMPTS))); $payload = is_array($schedule['payload'] ?? null) ? $schedule['payload'] : null; $enabled = array_key_exists('enabled', $schedule) ? !empty($schedule['enabled']) : true; $this->cronRepository->upsertSchedule( self::ORDER_STATUS_SYNC_JOB_TYPE, $minutes * 60, $priority, $maxAttempts, $payload, $enabled ); } private function currentPaymentSyncIntervalMinutes(): int { $schedule = $this->findPaymentSyncSchedule(); $seconds = (int) ($schedule['interval_seconds'] ?? self::PAYMENT_SYNC_DEFAULT_INTERVAL_SECONDS); return max(1, min(1440, (int) floor(max(60, $seconds) / 60))); } private function savePaymentSyncIntervalIfRequested(Request $request): void { if ($request->input('payment_sync_interval_minutes', null) === null) { return; } $this->ensurePaymentSyncScheduleExists(); $minutes = max(1, min(1440, (int) $request->input('payment_sync_interval_minutes', 10))); $schedule = $this->findPaymentSyncSchedule(); $priority = max(1, min(255, (int) ($schedule['priority'] ?? self::PAYMENT_SYNC_DEFAULT_PRIORITY))); $maxAttempts = max(1, min(20, (int) ($schedule['max_attempts'] ?? self::PAYMENT_SYNC_DEFAULT_MAX_ATTEMPTS))); $payload = is_array($schedule['payload'] ?? null) ? $schedule['payload'] : null; $enabled = array_key_exists('enabled', $schedule) ? !empty($schedule['enabled']) : true; $this->cronRepository->upsertSchedule( self::PAYMENT_SYNC_JOB_TYPE, $minutes * 60, $priority, $maxAttempts, $payload, $enabled ); } /** * @return array{0: array>, 1: array>, 2: string} */ private function loadDeliveryServices(): array { $allegroServices = []; $apaczkaServices = []; $errorMessage = ''; try { $oauth = $this->allegroIntegrationRepository->getTokenCredentials(); if (!is_array($oauth)) { $errorMessage = $this->translator->get('settings.integrations.delivery.not_connected'); } else { $env = (string) ($oauth['environment'] ?? 'sandbox'); $accessToken = trim((string) ($oauth['access_token'] ?? '')); if ($accessToken === '') { $errorMessage = $this->translator->get('settings.integrations.delivery.not_connected'); } else { try { $response = $this->allegroApiClient->getDeliveryServices($env, $accessToken); } catch (RuntimeException $exception) { if (trim($exception->getMessage()) !== 'ALLEGRO_HTTP_401') { throw $exception; } $refreshedToken = $this->refreshAllegroAccessToken($oauth); if ($refreshedToken === null) { $errorMessage = $this->translator->get('settings.integrations.delivery.not_connected'); $response = []; } else { $response = $this->allegroApiClient->getDeliveryServices($env, $refreshedToken); } } if (is_array($response ?? null)) { $allegroServices = is_array($response['services'] ?? null) ? $response['services'] : []; } } } } catch (Throwable $exception) { $errorMessage = $exception->getMessage(); } if ($this->apaczkaRepository !== null && $this->apaczkaApiClient !== null) { try { $credentials = $this->apaczkaRepository->getApiCredentials(); if (is_array($credentials)) { $apaczkaServices = $this->apaczkaApiClient->getServiceStructure( (string) ($credentials['app_id'] ?? ''), (string) ($credentials['app_secret'] ?? '') ); } } catch (Throwable $exception) { if ($errorMessage === '') { $errorMessage = $exception->getMessage(); } } } return [$allegroServices, $apaczkaServices, $errorMessage]; } /** * @param array $oauth */ private function refreshAllegroAccessToken(array $oauth): ?string { try { $token = $this->allegroOAuthClient->refreshAccessToken( (string) ($oauth['environment'] ?? 'sandbox'), (string) ($oauth['client_id'] ?? ''), (string) ($oauth['client_secret'] ?? ''), (string) ($oauth['refresh_token'] ?? '') ); $expiresIn = max(0, (int) ($token['expires_in'] ?? 0)); $expiresAt = $expiresIn > 0 ? (new DateTimeImmutable('now'))->add(new DateInterval('PT' . $expiresIn . 'S'))->format('Y-m-d H:i:s') : null; $refreshToken = trim((string) ($token['refresh_token'] ?? '')); if ($refreshToken === '') { $refreshToken = (string) ($oauth['refresh_token'] ?? ''); } $this->allegroIntegrationRepository->saveTokens( (string) ($token['access_token'] ?? ''), $refreshToken, (string) ($token['token_type'] ?? ''), (string) ($token['scope'] ?? ''), $expiresAt ); $accessToken = trim((string) ($token['access_token'] ?? '')); return $accessToken !== '' ? $accessToken : null; } catch (Throwable) { return null; } } }