- Introduced ShipmentProviderInterface to define the contract for shipment providers. - Implemented ShipmentProviderRegistry to manage and retrieve shipment providers. - Added a new tool for probing Apaczka order_send payload variants, enhancing debugging capabilities.
200 lines
6.1 KiB
PHP
200 lines
6.1 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Settings;
|
|
|
|
use PDO;
|
|
use RuntimeException;
|
|
use Throwable;
|
|
|
|
final class ApaczkaIntegrationRepository
|
|
{
|
|
private const INTEGRATION_TYPE = 'apaczka';
|
|
private const INTEGRATION_NAME = 'Apaczka';
|
|
private const INTEGRATION_BASE_URL = 'https://www.apaczka.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);
|
|
|
|
$appId = trim((string) ($row['app_id'] ?? ''));
|
|
$secretEncrypted = $this->resolveSecretEncrypted($row, $integration);
|
|
|
|
return [
|
|
'app_id' => $appId,
|
|
'has_app_id' => $appId !== '',
|
|
'has_app_secret' => $secretEncrypted !== null && $secretEncrypted !== '',
|
|
'has_api_key' => $secretEncrypted !== null && $secretEncrypted !== '',
|
|
'updated_at' => (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 RuntimeException('Brak rekordu konfiguracji Apaczka.');
|
|
}
|
|
|
|
$appId = trim((string) ($payload['app_id'] ?? ''));
|
|
if ($appId === '') {
|
|
throw new RuntimeException('Podaj App ID Apaczka.');
|
|
}
|
|
|
|
$currentEncrypted = $this->resolveSecretEncrypted($row, $this->integrations->findById($integrationId));
|
|
$appSecret = trim((string) ($payload['app_secret'] ?? ($payload['api_key'] ?? '')));
|
|
$nextEncrypted = $currentEncrypted;
|
|
if ($appSecret !== '') {
|
|
$nextEncrypted = $this->cipher->encrypt($appSecret);
|
|
}
|
|
|
|
if ($nextEncrypted === null || $nextEncrypted === '') {
|
|
throw new RuntimeException('Podaj App Secret Apaczka.');
|
|
}
|
|
|
|
$stmt = $this->pdo->prepare(
|
|
'UPDATE apaczka_integration_settings
|
|
SET app_id = :app_id,
|
|
app_secret_encrypted = :app_secret_encrypted,
|
|
api_key_encrypted = :api_key_encrypted,
|
|
updated_at = NOW()
|
|
WHERE id = 1'
|
|
);
|
|
$stmt->execute([
|
|
'app_id' => $appId,
|
|
'app_secret_encrypted' => $nextEncrypted,
|
|
'api_key_encrypted' => $nextEncrypted,
|
|
]);
|
|
|
|
$this->integrations->updateApiKeyEncrypted($integrationId, $nextEncrypted);
|
|
}
|
|
|
|
/**
|
|
* @return array{app_id:string, app_secret:string}|null
|
|
*/
|
|
public function getApiCredentials(): ?array
|
|
{
|
|
$settings = $this->getSettings();
|
|
$appId = trim((string) ($settings['app_id'] ?? ''));
|
|
if ($appId === '') {
|
|
return null;
|
|
}
|
|
|
|
$row = $this->fetchRow();
|
|
$integrationId = $this->ensureBaseIntegration();
|
|
$integration = $this->integrations->findById($integrationId);
|
|
$encrypted = $this->resolveSecretEncrypted($row, $integration);
|
|
if ($encrypted === null || $encrypted === '') {
|
|
return null;
|
|
}
|
|
|
|
$secret = trim($this->cipher->decrypt($encrypted));
|
|
if ($secret === '') {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'app_id' => $appId,
|
|
'app_secret' => $secret,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
public function testConnection(ApaczkaApiClient $apiClient): array
|
|
{
|
|
$credentials = $this->getApiCredentials();
|
|
if ($credentials === null) {
|
|
throw new RuntimeException('Brak konfiguracji App ID/App Secret Apaczka.');
|
|
}
|
|
|
|
return $apiClient->getServiceStructure(
|
|
(string) $credentials['app_id'],
|
|
(string) $credentials['app_secret']
|
|
);
|
|
}
|
|
|
|
private function ensureBaseIntegration(): int
|
|
{
|
|
return $this->integrations->ensureIntegration(
|
|
self::INTEGRATION_TYPE,
|
|
self::INTEGRATION_NAME,
|
|
self::INTEGRATION_BASE_URL,
|
|
20,
|
|
true
|
|
);
|
|
}
|
|
|
|
private function ensureRow(): void
|
|
{
|
|
$integrationId = $this->ensureBaseIntegration();
|
|
|
|
$stmt = $this->pdo->prepare(
|
|
'INSERT INTO apaczka_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)'
|
|
);
|
|
$stmt->execute(['integration_id' => $integrationId]);
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
private function fetchRow(): ?array
|
|
{
|
|
try {
|
|
$stmt = $this->pdo->prepare('SELECT * FROM apaczka_integration_settings WHERE id = 1 LIMIT 1');
|
|
$stmt->execute();
|
|
$row = $stmt->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 resolveSecretEncrypted(?array $row, ?array $integration): ?string
|
|
{
|
|
$base = trim((string) ($integration['api_key_encrypted'] ?? ''));
|
|
if ($base !== '') {
|
|
return $base;
|
|
}
|
|
|
|
$modern = trim((string) ($row['app_secret_encrypted'] ?? ''));
|
|
if ($modern !== '') {
|
|
return $modern;
|
|
}
|
|
|
|
$legacy = trim((string) ($row['api_key_encrypted'] ?? ''));
|
|
return $legacy !== '' ? $legacy : null;
|
|
}
|
|
}
|