feat: add Shoppro payment status synchronization service

- Implemented ShopproPaymentStatusSyncService to handle payment status synchronization between Shoppro and Orderpro.
- Added methods for resolving watched status codes, finding candidate orders, and syncing individual order payments.
- Introduced ShopproStatusMappingRepository for managing status mappings between Shoppro and Orderpro.
- Created ShopproStatusSyncService to facilitate synchronization of order statuses from Shoppro to Orderpro.
This commit is contained in:
2026-03-08 20:41:10 +01:00
parent 3ba6202770
commit af052e1ff5
50 changed files with 6110 additions and 2602 deletions

View File

@@ -4,15 +4,22 @@ 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);
}
/**
@@ -20,13 +27,11 @@ final class ApaczkaIntegrationRepository
*/
public function getSettings(): array
{
$row = $this->fetchRow();
if ($row === null) {
return $this->defaultSettings();
}
$integrationId = $this->ensureBaseIntegration();
$integration = $this->integrations->findById($integrationId);
return [
'has_api_key' => trim((string) ($row['api_key_encrypted'] ?? '')) !== '',
'has_api_key' => trim((string) ($integration['api_key_encrypted'] ?? '')) !== '',
];
}
@@ -35,90 +40,25 @@ final class ApaczkaIntegrationRepository
*/
public function saveSettings(array $payload): void
{
$this->ensureRow();
$current = $this->fetchRow();
if ($current === null) {
throw new RuntimeException('Brak rekordu konfiguracji Apaczka.');
}
$integrationId = $this->ensureBaseIntegration();
$apiKey = trim((string) ($payload['api_key'] ?? ''));
$apiKeyEncrypted = trim((string) ($current['api_key_encrypted'] ?? ''));
if ($apiKey !== '') {
$apiKeyEncrypted = (string) $this->encrypt($apiKey);
if ($apiKey === '') {
return;
}
$statement = $this->pdo->prepare(
'UPDATE apaczka_integration_settings
SET api_key_encrypted = :api_key_encrypted,
updated_at = NOW()
WHERE id = 1'
$encrypted = $this->cipher->encrypt($apiKey);
$this->integrations->updateApiKeyEncrypted($integrationId, $encrypted);
}
private function ensureBaseIntegration(): int
{
return $this->integrations->ensureIntegration(
self::INTEGRATION_TYPE,
self::INTEGRATION_NAME,
self::INTEGRATION_BASE_URL,
20,
true
);
$statement->execute([
'api_key_encrypted' => $this->nullableString($apiKeyEncrypted),
]);
}
private function ensureRow(): void
{
$statement = $this->pdo->prepare(
'INSERT INTO apaczka_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 apaczka_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_key' => false,
];
}
private function nullableString(string $value): ?string
{
$trimmed = trim($value);
return $trimmed === '' ? null : $trimmed;
}
private function encrypt(string $plainText): ?string
{
$value = trim($plainText);
if ($value === '') {
return null;
}
if ($this->secret === '') {
throw new RuntimeException('Brak INTEGRATIONS_SECRET do szyfrowania danych integracji.');
}
$encryptionKey = hash('sha256', 'enc|' . $this->secret, true);
$hmacKey = hash('sha256', 'auth|' . $this->secret, true);
$iv = random_bytes(16);
$cipherRaw = openssl_encrypt($value, 'AES-256-CBC', $encryptionKey, OPENSSL_RAW_DATA, $iv);
if ($cipherRaw === false) {
throw new RuntimeException('Nie udalo sie zaszyfrowac danych integracji.');
}
$mac = hash_hmac('sha256', $iv . $cipherRaw, $hmacKey, true);
return 'v1:' . base64_encode($iv . $mac . $cipherRaw);
}
}