feat(127): polkurier integration foundation
Single-instance globalna konfiguracja polkurier.pl jako alternatywa dla Apaczki: szyfrowany login + Token API, karta w hubie integracji i realny test polaczenia przez apimetod=test_auth_api zweryfikowany na zywym koncie operatora (Autoryzacja: 1). ShipmentProviderRegistry netkniety - PolkurierShipmentService/ TrackingService w kolejnych fazach. Kluczowe ustalenia kontraktu API (z SDK polkurier-sdk): - POST https://api.polkurier.pl/ (jeden endpoint) - JSON body: {authorization:{login,token}, apimetod, data} - Sukces: top-level status === 'success' (nie 'ok') - Blad: tresc w polu 'response' envelope'a - Content-Type: application/json (strict, bez charset suffix) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,8 @@ final class IntegrationsHubController
|
||||
private readonly ShopproIntegrationsRepository $shoppro,
|
||||
private readonly FakturowniaIntegrationRepository $fakturownia,
|
||||
private readonly HostedSmsIntegrationRepository $hostedSms,
|
||||
private readonly SmsplanetIntegrationRepository $smsplanet
|
||||
private readonly SmsplanetIntegrationRepository $smsplanet,
|
||||
private readonly PolkurierIntegrationRepository $polkurier
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -34,6 +35,7 @@ final class IntegrationsHubController
|
||||
$this->buildAllegroRow('sandbox'),
|
||||
$this->buildAllegroRow('production'),
|
||||
$this->buildApaczkaRow(),
|
||||
$this->buildPolkurierRow(),
|
||||
$this->buildInpostRow(),
|
||||
$this->buildShopproRow(),
|
||||
$this->buildFakturowniaRow(),
|
||||
@@ -224,6 +226,30 @@ final class IntegrationsHubController
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildPolkurierRow(): array
|
||||
{
|
||||
$settings = $this->polkurier->getSettings();
|
||||
$isConfigured = !empty($settings['login']) && !empty($settings['has_api_token']);
|
||||
|
||||
return [
|
||||
'provider' => $this->translator->get('settings.integrations_hub.providers.polkurier'),
|
||||
'instance' => 'polkurier.pl',
|
||||
'authorization_status' => $isConfigured
|
||||
? $this->translator->get('settings.integrations_hub.status.configured')
|
||||
: $this->translator->get('settings.integrations_hub.status.not_configured'),
|
||||
'secret_status' => !empty($settings['has_api_token'])
|
||||
? $this->translator->get('settings.integrations_hub.status.saved')
|
||||
: $this->translator->get('settings.integrations_hub.status.missing'),
|
||||
'is_active' => !empty($settings['is_active']),
|
||||
'last_test_at' => trim((string) ($settings['last_test_at'] ?? '')),
|
||||
'configure_url' => '/settings/integrations/polkurier',
|
||||
'configure_label' => $this->translator->get('settings.integrations_hub.actions.configure'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
|
||||
197
src/Modules/Settings/PolkurierApiClient.php
Normal file
197
src/Modules/Settings/PolkurierApiClient.php
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\Settings;
|
||||
|
||||
use App\Core\Http\SslCertificateResolver;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* polkurier.pl Web Service API client (Phase 127).
|
||||
*
|
||||
* Kontrakt API zweryfikowany na podstawie oficjalnego SDK (https://github.com/Polkurier/polkurier-sdk):
|
||||
* - Base URL: https://api.polkurier.pl/ (single endpoint, brak path per metoda)
|
||||
* - HTTP POST, Content-Type: application/json
|
||||
* - Body: {"authorization": {"login": "...", "token": "..."}, "apimetod": "<method_name>", "data": {...}}
|
||||
* - Test polaczenia: apimetod = "test_auth_api"
|
||||
* - Sukces: top-level "status" === "success" (ResponseStatus::SUCCESS w SDK), authorization w polu "response"
|
||||
* - Blad: top-level "status" !== "success"; tresc bledu w polu "response" (string lub tablica)
|
||||
*
|
||||
* Stuby createShipment/getLabel/getStatus/cancelOrder dolozone w kolejnych fazach.
|
||||
*/
|
||||
final class PolkurierApiClient
|
||||
{
|
||||
private const API_URL = 'https://api.polkurier.pl/';
|
||||
private const PLATFORM = 'orderPRO';
|
||||
private const PLATFORM_VERSION = '1.0';
|
||||
|
||||
public function __construct(private readonly int $timeoutSeconds = 15)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{ok: bool, http_code: int, message: string}
|
||||
*/
|
||||
public function testConnection(string $login, string $apiToken): array
|
||||
{
|
||||
$payload = [
|
||||
'authorization' => [
|
||||
'login' => trim($login),
|
||||
'token' => trim($apiToken),
|
||||
],
|
||||
'apimetod' => 'test_auth_api',
|
||||
'data' => [
|
||||
'platform' => self::PLATFORM,
|
||||
'platform_version' => self::PLATFORM_VERSION,
|
||||
],
|
||||
];
|
||||
|
||||
[$body, $httpCode, $curlError] = $this->postJson($payload);
|
||||
if ($curlError !== null) {
|
||||
return [
|
||||
'ok' => false,
|
||||
'http_code' => $httpCode,
|
||||
'message' => 'Blad polaczenia: ' . $curlError,
|
||||
];
|
||||
}
|
||||
|
||||
$decoded = json_decode(ltrim($body, "\xEF\xBB\xBF \t\n\r\0\x0B"), true);
|
||||
if (!is_array($decoded)) {
|
||||
return [
|
||||
'ok' => false,
|
||||
'http_code' => $httpCode,
|
||||
'message' => 'Niepoprawna odpowiedz JSON polkurier: ' . substr(trim(strip_tags($body)), 0, 180),
|
||||
];
|
||||
}
|
||||
|
||||
$status = strtolower(trim((string) ($decoded['status'] ?? '')));
|
||||
$responseField = $decoded['response'] ?? null;
|
||||
|
||||
if ($httpCode >= 200 && $httpCode < 300 && $status === 'success') {
|
||||
$authorization = '';
|
||||
if (is_array($responseField)) {
|
||||
$authorization = trim((string) ($responseField['authorization'] ?? ''));
|
||||
}
|
||||
$message = $authorization !== ''
|
||||
? 'Autoryzacja: ' . $authorization
|
||||
: 'Polaczenie OK (HTTP ' . $httpCode . ').';
|
||||
|
||||
return [
|
||||
'ok' => true,
|
||||
'http_code' => $httpCode,
|
||||
'message' => $message,
|
||||
];
|
||||
}
|
||||
|
||||
// Error path: w SDK polkuriera (PolkurierWebService.php) gdy status != 'success',
|
||||
// tresc bledu jest rzucana z $response->get('response') — czyli pole 'response' z envelope JSON.
|
||||
// Pole 'response' moze byc stringiem (tekst bledu), tablica (struktura) lub null.
|
||||
$errorMessage = '';
|
||||
if (is_string($responseField)) {
|
||||
$errorMessage = trim($responseField);
|
||||
} elseif (is_array($responseField)) {
|
||||
$errorMessage = trim((string) (
|
||||
$responseField['error_message']
|
||||
?? $responseField['errorMessage']
|
||||
?? $responseField['message']
|
||||
?? $responseField['error']
|
||||
?? ''
|
||||
));
|
||||
if ($errorMessage === '') {
|
||||
$jsonDump = json_encode($responseField, JSON_UNESCAPED_UNICODE);
|
||||
if (is_string($jsonDump)) {
|
||||
$errorMessage = substr($jsonDump, 0, 240);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($errorMessage === '') {
|
||||
$errorMessage = trim((string) (
|
||||
$decoded['error_message']
|
||||
?? $decoded['errorMessage']
|
||||
?? $decoded['message']
|
||||
?? $decoded['error']
|
||||
?? ''
|
||||
));
|
||||
}
|
||||
|
||||
if ($errorMessage === '') {
|
||||
$errorMessage = $status !== '' ? 'Status: ' . $status . ' (HTTP ' . $httpCode . ')' : 'HTTP ' . $httpCode;
|
||||
}
|
||||
|
||||
return [
|
||||
'ok' => false,
|
||||
'http_code' => $httpCode,
|
||||
'message' => $errorMessage,
|
||||
];
|
||||
}
|
||||
|
||||
public function createShipment(): never
|
||||
{
|
||||
throw new RuntimeException('PolkurierApiClient::createShipment not implemented in Phase 127.');
|
||||
}
|
||||
|
||||
public function getLabel(): never
|
||||
{
|
||||
throw new RuntimeException('PolkurierApiClient::getLabel not implemented in Phase 127.');
|
||||
}
|
||||
|
||||
public function getStatus(): never
|
||||
{
|
||||
throw new RuntimeException('PolkurierApiClient::getStatus not implemented in Phase 127.');
|
||||
}
|
||||
|
||||
public function cancelOrder(): never
|
||||
{
|
||||
throw new RuntimeException('PolkurierApiClient::cancelOrder not implemented in Phase 127.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array{0: string, 1: int, 2: ?string}
|
||||
*/
|
||||
private function postJson(array $payload): array
|
||||
{
|
||||
$ch = curl_init(self::API_URL);
|
||||
if ($ch === false) {
|
||||
return ['', 0, 'Nie udalo sie zainicjowac cURL.'];
|
||||
}
|
||||
|
||||
$encoded = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if ($encoded === false) {
|
||||
return ['', 0, 'Nie udalo sie zakodowac payloadu JSON.'];
|
||||
}
|
||||
|
||||
$options = [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $encoded,
|
||||
CURLOPT_TIMEOUT => $this->timeoutSeconds,
|
||||
CURLOPT_CONNECTTIMEOUT => 10,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_SSL_VERIFYHOST => 2,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Accept: application/json',
|
||||
'Content-Type: application/json',
|
||||
'User-Agent: orderPRO/1.0',
|
||||
],
|
||||
];
|
||||
|
||||
$caPath = SslCertificateResolver::resolve();
|
||||
if ($caPath !== null) {
|
||||
$options[CURLOPT_CAINFO] = $caPath;
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, $options);
|
||||
$rawBody = curl_exec($ch);
|
||||
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlError = curl_error($ch);
|
||||
unset($ch);
|
||||
|
||||
if ($rawBody === false) {
|
||||
return ['', $httpCode, $curlError !== '' ? $curlError : 'Brak odpowiedzi z API.'];
|
||||
}
|
||||
|
||||
return [(string) $rawBody, $httpCode, null];
|
||||
}
|
||||
}
|
||||
123
src/Modules/Settings/PolkurierIntegrationController.php
Normal file
123
src/Modules/Settings/PolkurierIntegrationController.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\Settings;
|
||||
|
||||
use App\Core\Exceptions\IntegrationConfigException;
|
||||
use App\Core\Http\RedirectPathResolver;
|
||||
use App\Core\Http\Request;
|
||||
use App\Core\Http\Response;
|
||||
use App\Core\I18n\Translator;
|
||||
use App\Core\Security\Csrf;
|
||||
use App\Core\Support\Flash;
|
||||
use App\Core\View\Template;
|
||||
use App\Modules\Auth\AuthService;
|
||||
use Throwable;
|
||||
|
||||
final class PolkurierIntegrationController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Template $template,
|
||||
private readonly Translator $translator,
|
||||
private readonly AuthService $auth,
|
||||
private readonly PolkurierIntegrationRepository $repository,
|
||||
private readonly PolkurierApiClient $apiClient,
|
||||
private readonly IntegrationsRepository $integrations
|
||||
) {
|
||||
}
|
||||
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$html = $this->template->render('settings/polkurier', [
|
||||
'title' => $this->translator->get('settings.polkurier.title'),
|
||||
'activeMenu' => 'settings',
|
||||
'activeSettings' => 'integrations',
|
||||
'user' => $this->auth->user(),
|
||||
'csrfToken' => Csrf::token(),
|
||||
'settings' => $this->repository->getSettings(),
|
||||
'errorMessage' => (string) Flash::get('settings_error', ''),
|
||||
'successMessage' => (string) Flash::get('settings_success', ''),
|
||||
'testMessage' => (string) Flash::get('polkurier_test', ''),
|
||||
], 'layouts/app');
|
||||
|
||||
return Response::html($html);
|
||||
}
|
||||
|
||||
public function save(Request $request): Response
|
||||
{
|
||||
$redirectTo = $this->resolveRedirect($request);
|
||||
|
||||
if (!Csrf::validate((string) $request->input('_token', ''))) {
|
||||
Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired'));
|
||||
return Response::redirect($redirectTo);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->repository->saveSettings([
|
||||
'login' => (string) $request->input('login', ''),
|
||||
'api_token' => (string) $request->input('api_token', ''),
|
||||
'default_label_format' => (string) $request->input('default_label_format', 'PDF'),
|
||||
'is_active' => $request->input('is_active', ''),
|
||||
]);
|
||||
Flash::set('settings_success', $this->translator->get('settings.polkurier.flash.saved'));
|
||||
} catch (Throwable $exception) {
|
||||
Flash::set(
|
||||
'settings_error',
|
||||
$this->translator->get('settings.polkurier.flash.save_failed') . ' ' . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return Response::redirect($redirectTo);
|
||||
}
|
||||
|
||||
public function test(Request $request): Response
|
||||
{
|
||||
$redirectTo = $this->resolveRedirect($request);
|
||||
|
||||
if (!Csrf::validate((string) $request->input('_token', ''))) {
|
||||
Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired'));
|
||||
return Response::redirect($redirectTo);
|
||||
}
|
||||
|
||||
try {
|
||||
$credentials = $this->repository->getCredentials();
|
||||
if ($credentials === null) {
|
||||
throw new IntegrationConfigException('Najpierw zapisz kompletna konfiguracje polkurier (login + Token API + aktywacja).');
|
||||
}
|
||||
|
||||
$result = $this->apiClient->testConnection(
|
||||
$credentials['login'],
|
||||
$credentials['api_token']
|
||||
);
|
||||
|
||||
$status = $result['ok'] ? 'ok' : 'fail';
|
||||
$this->integrations->updateTestResult(
|
||||
$credentials['integration_id'],
|
||||
$status,
|
||||
(int) $result['http_code'],
|
||||
(string) $result['message']
|
||||
);
|
||||
|
||||
if ($result['ok']) {
|
||||
Flash::set('polkurier_test', $this->translator->get('settings.polkurier.flash.test_success', [
|
||||
'message' => (string) $result['message'],
|
||||
]));
|
||||
} else {
|
||||
Flash::set('settings_error', $this->translator->get('settings.polkurier.flash.test_failed') . ' ' . $result['message']);
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
Flash::set('settings_error', $this->translator->get('settings.polkurier.flash.test_failed') . ' ' . $exception->getMessage());
|
||||
}
|
||||
|
||||
return Response::redirect($redirectTo);
|
||||
}
|
||||
|
||||
private function resolveRedirect(Request $request): string
|
||||
{
|
||||
return RedirectPathResolver::resolve(
|
||||
(string) $request->input('return_to', '/settings/integrations/polkurier'),
|
||||
['/settings/integrations'],
|
||||
'/settings/integrations/polkurier'
|
||||
);
|
||||
}
|
||||
}
|
||||
218
src/Modules/Settings/PolkurierIntegrationRepository.php
Normal file
218
src/Modules/Settings/PolkurierIntegrationRepository.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\Settings;
|
||||
|
||||
use App\Core\Exceptions\IntegrationConfigException;
|
||||
use App\Core\Support\StringHelper;
|
||||
use PDO;
|
||||
use Throwable;
|
||||
|
||||
final class PolkurierIntegrationRepository
|
||||
{
|
||||
private const INTEGRATION_TYPE = 'polkurier';
|
||||
private const INTEGRATION_NAME = 'polkurier';
|
||||
private const INTEGRATION_BASE_URL = 'https://api.polkurier.pl/';
|
||||
|
||||
private readonly IntegrationsRepository $integrations;
|
||||
private readonly IntegrationSecretCipher $cipher;
|
||||
|
||||
public function __construct(
|
||||
private readonly PDO $pdo,
|
||||
private readonly string $secret
|
||||
) {
|
||||
$this->integrations = new IntegrationsRepository($this->pdo);
|
||||
$this->cipher = new IntegrationSecretCipher($this->secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getSettings(): array
|
||||
{
|
||||
$this->ensureRow();
|
||||
$integrationId = $this->ensureBaseIntegration();
|
||||
$row = $this->fetchRow();
|
||||
$integration = $this->integrations->findById($integrationId);
|
||||
$tokenEncrypted = $this->resolveTokenEncrypted($row, $integration);
|
||||
|
||||
return [
|
||||
'integration_id' => $integrationId,
|
||||
'login' => trim((string) ($row['login'] ?? '')),
|
||||
'default_label_format' => trim((string) ($row['default_label_format'] ?? 'PDF')) ?: 'PDF',
|
||||
'has_api_token' => $tokenEncrypted !== null && $tokenEncrypted !== '',
|
||||
'is_active' => (int) ($integration['is_active'] ?? 1) === 1,
|
||||
'last_test_status' => trim((string) ($integration['last_test_status'] ?? '')),
|
||||
'last_test_http_code' => isset($integration['last_test_http_code']) ? (int) $integration['last_test_http_code'] : null,
|
||||
'last_test_message' => trim((string) ($integration['last_test_message'] ?? '')),
|
||||
'last_test_at' => trim((string) ($integration['last_test_at'] ?? '')),
|
||||
'updated_at' => trim((string) ($row['updated_at'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
*/
|
||||
public function saveSettings(array $payload): void
|
||||
{
|
||||
$this->ensureRow();
|
||||
$integrationId = $this->ensureBaseIntegration();
|
||||
$row = $this->fetchRow();
|
||||
if ($row === null) {
|
||||
throw new IntegrationConfigException('Brak rekordu konfiguracji polkurier.');
|
||||
}
|
||||
|
||||
$login = trim((string) ($payload['login'] ?? ''));
|
||||
if ($login === '' || strlen($login) > 190) {
|
||||
throw new IntegrationConfigException('Podaj login polkurier (e-mail lub identyfikator z panelu klienta, maks. 190 znakow).');
|
||||
}
|
||||
|
||||
$labelFormatRaw = strtoupper(trim((string) ($payload['default_label_format'] ?? 'PDF')));
|
||||
$allowedFormats = ['PDF', 'ZPL', 'EPL'];
|
||||
$labelFormat = in_array($labelFormatRaw, $allowedFormats, true) ? $labelFormatRaw : 'PDF';
|
||||
|
||||
$currentEncrypted = $this->resolveTokenEncrypted($row, $this->integrations->findById($integrationId));
|
||||
$token = trim((string) ($payload['api_token'] ?? ''));
|
||||
$nextEncrypted = $currentEncrypted;
|
||||
if ($token !== '') {
|
||||
$nextEncrypted = $this->cipher->encrypt($token);
|
||||
}
|
||||
|
||||
if ($nextEncrypted === null || $nextEncrypted === '') {
|
||||
throw new IntegrationConfigException('Podaj Token API polkurier (z Panel Klienta -> Ustawienia -> Token API).');
|
||||
}
|
||||
|
||||
$statement = $this->pdo->prepare(
|
||||
'UPDATE polkurier_integration_settings
|
||||
SET login = :login,
|
||||
api_token_encrypted = :api_token_encrypted,
|
||||
default_label_format = :default_label_format,
|
||||
updated_at = NOW()
|
||||
WHERE id = 1'
|
||||
);
|
||||
$statement->execute([
|
||||
'login' => $login,
|
||||
'api_token_encrypted' => $nextEncrypted,
|
||||
'default_label_format' => $labelFormat,
|
||||
]);
|
||||
|
||||
$this->updateIntegrationActive($integrationId, !empty($payload['is_active']));
|
||||
$this->integrations->updateApiKeyEncrypted($integrationId, $nextEncrypted);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{integration_id: int, login: string, api_token: string, default_label_format: string}|null
|
||||
*/
|
||||
public function getCredentials(): ?array
|
||||
{
|
||||
$this->ensureRow();
|
||||
$integrationId = $this->ensureBaseIntegration();
|
||||
$row = $this->fetchRow();
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$integration = $this->integrations->findById($integrationId);
|
||||
if (empty($integration) || (int) ($integration['is_active'] ?? 0) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$login = trim((string) ($row['login'] ?? ''));
|
||||
$encrypted = $this->resolveTokenEncrypted($row, $integration);
|
||||
|
||||
if ($login === '' || $encrypted === null || $encrypted === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$token = trim((string) $this->cipher->decrypt($encrypted));
|
||||
if ($token === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'integration_id' => $integrationId,
|
||||
'login' => $login,
|
||||
'api_token' => $token,
|
||||
'default_label_format' => trim((string) ($row['default_label_format'] ?? 'PDF')) ?: 'PDF',
|
||||
];
|
||||
}
|
||||
|
||||
public function getIntegrationId(): ?int
|
||||
{
|
||||
$integration = $this->integrations->findByTypeAndName(self::INTEGRATION_TYPE, self::INTEGRATION_NAME);
|
||||
if ($integration === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$id = (int) ($integration['id'] ?? 0);
|
||||
return $id > 0 ? $id : null;
|
||||
}
|
||||
|
||||
private function ensureBaseIntegration(): int
|
||||
{
|
||||
return $this->integrations->ensureIntegration(
|
||||
self::INTEGRATION_TYPE,
|
||||
self::INTEGRATION_NAME,
|
||||
self::INTEGRATION_BASE_URL,
|
||||
15,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
private function ensureRow(): void
|
||||
{
|
||||
$integrationId = $this->ensureBaseIntegration();
|
||||
$statement = $this->pdo->prepare(
|
||||
'INSERT INTO polkurier_integration_settings (id, integration_id, created_at, updated_at)
|
||||
VALUES (1, :integration_id, NOW(), NOW())
|
||||
ON DUPLICATE KEY UPDATE integration_id = VALUES(integration_id), updated_at = VALUES(updated_at)'
|
||||
);
|
||||
$statement->execute(['integration_id' => $integrationId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
private function fetchRow(): ?array
|
||||
{
|
||||
try {
|
||||
$statement = $this->pdo->prepare('SELECT * FROM polkurier_integration_settings WHERE id = 1 LIMIT 1');
|
||||
$statement->execute();
|
||||
$row = $statement->fetch(PDO::FETCH_ASSOC);
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return is_array($row) ? $row : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|null $row
|
||||
* @param array<string, mixed>|null $integration
|
||||
*/
|
||||
private function resolveTokenEncrypted(?array $row, ?array $integration): ?string
|
||||
{
|
||||
$settingsValue = trim((string) ($row['api_token_encrypted'] ?? ''));
|
||||
if ($settingsValue !== '') {
|
||||
return $settingsValue;
|
||||
}
|
||||
|
||||
$baseValue = trim((string) ($integration['api_key_encrypted'] ?? ''));
|
||||
return StringHelper::nullableString($baseValue);
|
||||
}
|
||||
|
||||
private function updateIntegrationActive(int $integrationId, bool $isActive): void
|
||||
{
|
||||
$statement = $this->pdo->prepare(
|
||||
'UPDATE integrations
|
||||
SET is_active = :is_active,
|
||||
updated_at = NOW()
|
||||
WHERE id = :id AND type = :type'
|
||||
);
|
||||
$statement->execute([
|
||||
'id' => $integrationId,
|
||||
'type' => self::INTEGRATION_TYPE,
|
||||
'is_active' => $isActive ? 1 : 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user