Phase 1 complete (2/2 plans): - Plan 01-01: Extract AllegroTokenManager — OAuth token logic centralized from 4 classes into dedicated manager class - Plan 01-02: Extract StringHelper — nullableString/normalizeDateTime/ normalizeColorHex extracted from 15+ classes into App\Core\Support\StringHelper; removed 19 duplicate private methods Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
220 lines
8.3 KiB
PHP
220 lines
8.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Settings;
|
|
|
|
use App\Core\Support\StringHelper;
|
|
use PDO;
|
|
use RuntimeException;
|
|
use Throwable;
|
|
|
|
final class InpostIntegrationRepository
|
|
{
|
|
private const INTEGRATION_TYPE = 'inpost';
|
|
private const INTEGRATION_NAME = 'InPost ShipX';
|
|
private const INTEGRATION_BASE_URL = 'https://api-shipx-pl.easypack24.net';
|
|
|
|
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
|
|
{
|
|
$row = $this->fetchRow();
|
|
if ($row === null) {
|
|
$row = $this->defaultSettings();
|
|
}
|
|
|
|
$encryptedToken = $this->resolveEncryptedToken($row);
|
|
|
|
return [
|
|
'has_api_token' => $encryptedToken !== null && $encryptedToken !== '',
|
|
'organization_id' => (string) ($row['organization_id'] ?? ''),
|
|
'environment' => (string) ($row['environment'] ?? 'sandbox'),
|
|
'default_dispatch_method' => (string) ($row['default_dispatch_method'] ?? 'pop'),
|
|
'default_dispatch_point' => (string) ($row['default_dispatch_point'] ?? ''),
|
|
'default_insurance' => isset($row['default_insurance']) && $row['default_insurance'] !== null
|
|
? (float) $row['default_insurance']
|
|
: null,
|
|
'default_locker_size' => (string) ($row['default_locker_size'] ?? 'small'),
|
|
'default_courier_length' => (int) ($row['default_courier_length'] ?? 20),
|
|
'default_courier_width' => (int) ($row['default_courier_width'] ?? 15),
|
|
'default_courier_height' => (int) ($row['default_courier_height'] ?? 8),
|
|
'label_format' => (string) ($row['label_format'] ?? 'Pdf'),
|
|
'weekend_delivery' => (bool) ($row['weekend_delivery'] ?? false),
|
|
'auto_insurance_value' => (bool) ($row['auto_insurance_value'] ?? false),
|
|
'multi_parcel' => (bool) ($row['multi_parcel'] ?? false),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $payload
|
|
*/
|
|
public function saveSettings(array $payload): void
|
|
{
|
|
$this->ensureRow();
|
|
$current = $this->fetchRow();
|
|
if ($current === null) {
|
|
throw new RuntimeException('Brak rekordu konfiguracji InPost.');
|
|
}
|
|
|
|
$integrationId = $this->ensureBaseIntegration();
|
|
$currentEncrypted = $this->resolveEncryptedToken($current);
|
|
|
|
$apiToken = trim((string) ($payload['api_token'] ?? ''));
|
|
$nextEncrypted = $currentEncrypted;
|
|
if ($apiToken !== '') {
|
|
$nextEncrypted = $this->cipher->encrypt($apiToken);
|
|
}
|
|
|
|
$this->integrations->updateApiKeyEncrypted($integrationId, $nextEncrypted);
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'UPDATE inpost_integration_settings
|
|
SET api_token_encrypted = :api_token_encrypted,
|
|
organization_id = :organization_id,
|
|
environment = :environment,
|
|
default_dispatch_method = :default_dispatch_method,
|
|
default_dispatch_point = :default_dispatch_point,
|
|
default_insurance = :default_insurance,
|
|
default_locker_size = :default_locker_size,
|
|
default_courier_length = :default_courier_length,
|
|
default_courier_width = :default_courier_width,
|
|
default_courier_height = :default_courier_height,
|
|
label_format = :label_format,
|
|
weekend_delivery = :weekend_delivery,
|
|
auto_insurance_value = :auto_insurance_value,
|
|
multi_parcel = :multi_parcel,
|
|
updated_at = NOW()
|
|
WHERE id = 1'
|
|
);
|
|
$statement->execute([
|
|
'api_token_encrypted' => StringHelper::nullableString((string) $nextEncrypted),
|
|
'organization_id' => StringHelper::nullableString(trim((string) ($payload['organization_id'] ?? ''))),
|
|
'environment' => in_array($payload['environment'] ?? '', ['sandbox', 'production'], true)
|
|
? $payload['environment']
|
|
: 'sandbox',
|
|
'default_dispatch_method' => in_array($payload['default_dispatch_method'] ?? '', ['pop', 'parcel_locker', 'courier'], true)
|
|
? $payload['default_dispatch_method']
|
|
: 'pop',
|
|
'default_dispatch_point' => StringHelper::nullableString(trim((string) ($payload['default_dispatch_point'] ?? ''))),
|
|
'default_insurance' => ($payload['default_insurance'] ?? '') !== ''
|
|
? (float) $payload['default_insurance']
|
|
: null,
|
|
'default_locker_size' => in_array($payload['default_locker_size'] ?? '', ['small', 'medium', 'large'], true)
|
|
? $payload['default_locker_size']
|
|
: 'small',
|
|
'default_courier_length' => max(1, (int) ($payload['default_courier_length'] ?? 20)),
|
|
'default_courier_width' => max(1, (int) ($payload['default_courier_width'] ?? 15)),
|
|
'default_courier_height' => max(1, (int) ($payload['default_courier_height'] ?? 8)),
|
|
'label_format' => in_array($payload['label_format'] ?? '', ['Pdf', 'Zpl', 'Epl'], true)
|
|
? $payload['label_format']
|
|
: 'Pdf',
|
|
'weekend_delivery' => !empty($payload['weekend_delivery']) ? 1 : 0,
|
|
'auto_insurance_value' => !empty($payload['auto_insurance_value']) ? 1 : 0,
|
|
'multi_parcel' => !empty($payload['multi_parcel']) ? 1 : 0,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return string|null Decrypted API token or null
|
|
*/
|
|
public function getDecryptedToken(): ?string
|
|
{
|
|
$row = $this->fetchRow();
|
|
if ($row === null) {
|
|
return null;
|
|
}
|
|
|
|
$encrypted = $this->resolveEncryptedToken($row);
|
|
if ($encrypted === null || $encrypted === '') {
|
|
return null;
|
|
}
|
|
|
|
return $this->cipher->decrypt($encrypted);
|
|
}
|
|
|
|
private function ensureRow(): void
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO inpost_integration_settings (id, created_at, updated_at)
|
|
VALUES (1, NOW(), NOW())
|
|
ON DUPLICATE KEY UPDATE updated_at = VALUES(updated_at)'
|
|
);
|
|
$statement->execute();
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
private function fetchRow(): ?array
|
|
{
|
|
try {
|
|
$statement = $this->pdo->prepare('SELECT * FROM inpost_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;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function defaultSettings(): array
|
|
{
|
|
return [
|
|
'has_api_token' => false,
|
|
'organization_id' => '',
|
|
'environment' => 'sandbox',
|
|
'default_dispatch_method' => 'pop',
|
|
'default_dispatch_point' => '',
|
|
'default_insurance' => null,
|
|
'default_locker_size' => 'small',
|
|
'default_courier_length' => 20,
|
|
'default_courier_width' => 15,
|
|
'default_courier_height' => 8,
|
|
'label_format' => 'Pdf',
|
|
'weekend_delivery' => false,
|
|
'auto_insurance_value' => false,
|
|
'multi_parcel' => false,
|
|
];
|
|
}
|
|
|
|
private function resolveEncryptedToken(array $row): ?string
|
|
{
|
|
$integrationId = $this->ensureBaseIntegration();
|
|
$fromBase = $this->integrations->getApiKeyEncrypted($integrationId);
|
|
if ($fromBase !== null && $fromBase !== '') {
|
|
return $fromBase;
|
|
}
|
|
|
|
$legacy = trim((string) ($row['api_token_encrypted'] ?? ''));
|
|
return $legacy === '' ? null : $legacy;
|
|
}
|
|
|
|
private function ensureBaseIntegration(): int
|
|
{
|
|
return $this->integrations->ensureIntegration(
|
|
self::INTEGRATION_TYPE,
|
|
self::INTEGRATION_NAME,
|
|
self::INTEGRATION_BASE_URL,
|
|
20,
|
|
true
|
|
);
|
|
}
|
|
|
|
}
|