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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user