Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
CurrencySyncService
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
2 / 2
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 syncRates
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Modules\Currencies\Application\Service;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Modules\Currencies\Domain\Repository\CurrencyRepositoryInterface;
12use App\Modules\Integrations\Domain\Contract\ExchangeRatesProviderInterface;
13use RuntimeException;
14
15/**
16 * Service orchestrating exchange rate synchronization from external providers (e.g. NBP).
17 */
18final readonly class CurrencySyncService implements CurrencySyncServiceInterface
19{
20    public function __construct(
21        private ExchangeRatesProviderInterface $exchangeRatesProvider,
22        private CurrencyRepositoryInterface $currencyRepository
23    ) {
24    }
25
26    /**
27     * Synchronizes current exchange rates with external provider.
28     *
29     * @return array{
30     *     table: string,
31     *     effective_date: string,
32     *     updated_count: int,
33     *     updated_codes: list<string>
34     * }
35     * @throws RuntimeException If provider fails to fetch rates.
36     */
37    public function syncRates(): array
38    {
39        $data = $this->exchangeRatesProvider->fetchExchangeRates();
40        $tableNo = $data['table'];
41        $effectiveDate = $data['effective_date'];
42        $rates = $data['rates'];
43
44        $existingCurrencies = $this->currencyRepository->findAll();
45        $updatedCodes = [];
46
47        foreach ($existingCurrencies as $currency) {
48            $code = strtoupper($currency->getCode());
49            if ($currency->isBase() || !isset($rates[$code])) {
50                continue;
51            }
52
53            $newRate = (float) $rates[$code];
54            $this->currencyRepository->updateRate($code, $newRate, $tableNo, $effectiveDate);
55            $this->currencyRepository->recordRateHistory($code, $newRate, $tableNo, $effectiveDate, 'NBP');
56            $updatedCodes[] = $code;
57        }
58
59        return [
60            'table' => $tableNo,
61            'effective_date' => $effectiveDate,
62            'updated_count' => count($updatedCodes),
63            'updated_codes' => $updatedCodes,
64        ];
65    }
66}