mirror of
https://github.com/chenasraf/nextcloud-autocurrency.git
synced 2026-05-17 17:28:06 +00:00
147 lines
4.2 KiB
PHP
147 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
// SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
namespace OCA\AutoCurrency\Service;
|
|
|
|
use Exception;
|
|
|
|
use OCA\AutoCurrency\Db\CospendProjectMapper;
|
|
use OCA\AutoCurrency\Db\Currency;
|
|
use OCA\AutoCurrency\Db\CurrencyMapper;
|
|
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
|
use OCP\IAppConfig;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class FetchCurrenciesService {
|
|
private static $EXCHANGE_URL = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/{base}.json';
|
|
private static $SYMBOLS_FILE = __DIR__ . '/symbols.json';
|
|
|
|
private IAppConfig $config;
|
|
|
|
private CurrencyMapper $currencyMapper;
|
|
|
|
private CospendProjectMapper $projectMapper;
|
|
|
|
private LoggerInterface $logger;
|
|
|
|
/* @var array<string, array<symbol: string, name: string, symbol_native: string, decimal_digits: int, rounding: int, code: string, name_plural: string>> */
|
|
private array $symbols;
|
|
|
|
public function __construct(
|
|
IAppConfig $config,
|
|
CurrencyMapper $currencyMapper,
|
|
CospendProjectMapper $projectMapper,
|
|
LoggerInterface $logger,
|
|
) {
|
|
$this->config = $config;
|
|
$this->currencyMapper = $currencyMapper;
|
|
$this->projectMapper = $projectMapper;
|
|
$this->logger = $logger;
|
|
$this->loadSymbols();
|
|
}
|
|
|
|
public function fetchCurrencyRates(): void {
|
|
$this->logger->info('Starting cron job to fetch currencies');
|
|
$projects = $this->projectMapper->findAll();
|
|
$currencyMap = [];
|
|
|
|
$this->logger->info('Found ' . count($projects) . ' projects');
|
|
|
|
foreach ($projects as $project) {
|
|
$base = $this->getCurrencyName($project->getCurrencyname());
|
|
$lbase = strtolower($base);
|
|
|
|
if (isset($currencyMap[$base])) {
|
|
$json = $currencyMap[$base];
|
|
} else {
|
|
// request currency exchange rates from the API
|
|
$this->logger->info('Fetching exchange rates for base currency ' . $base);
|
|
$fp = fopen(str_replace('{base}', $lbase, FetchCurrenciesService::$EXCHANGE_URL), 'r');
|
|
$data = stream_get_contents($fp);
|
|
fclose($fp);
|
|
$json = json_decode($data, true);
|
|
$this->logger->info('Fetched exchange rates for base currency: ' . json_encode($json));
|
|
if ($json[$lbase] == null) {
|
|
$this->logger->error(new \Error('Failed to fetch exchange rates for base currency ' . $base));
|
|
continue;
|
|
}
|
|
$currencyMap[$lbase] = $json;
|
|
}
|
|
|
|
$currencies = $this->findAll($project->id);
|
|
|
|
foreach ($currencies as $currency) {
|
|
$cur = $this->getCurrencyName($currency->getName());
|
|
if ($cur === null) {
|
|
$this->logger->error('Currency not found: ' . $currency->getName());
|
|
continue;
|
|
}
|
|
$lcur = strtolower($cur);
|
|
$baseRate = $json[$lbase][$lcur];
|
|
$newRate = floatval(number_format(1 / $baseRate, 2));
|
|
$currency->setExchangeRate($newRate);
|
|
$this->logger->info('Setting exchange rate for currency ' . $cur . ' to ' . $newRate);
|
|
$this->currencyMapper->update($currency);
|
|
}
|
|
}
|
|
|
|
$lastUpdate = date('c');
|
|
$this->config->setValueString('autocurrency', 'last_update', $lastUpdate);
|
|
}
|
|
|
|
/** Match the currency name from the known currencies. **/
|
|
private function getCurrencyName(string $name): ?string {
|
|
foreach ($this->symbols as $cur => $currency) {
|
|
// e.g. usd
|
|
$id = strtolower($cur);
|
|
if (strtolower($name) === $id) {
|
|
return $id;
|
|
}
|
|
|
|
// e.g. $
|
|
$symbol = $currency['symbol'];
|
|
if (str_contains($name, $symbol)) {
|
|
return $id;
|
|
}
|
|
|
|
// e.g. $ USD
|
|
preg_match('/\b' . $id . '\b/', strtolower($name), $matches);
|
|
if (count($matches) > 0) {
|
|
return $id;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/** Load symbols from the symbols.json file */
|
|
private function loadSymbols(): void {
|
|
$this->symbols = json_decode(file_get_contents(FetchCurrenciesService::$SYMBOLS_FILE), true);
|
|
$this->logger->info('Loaded symbols: ' . json_encode($this->symbols));
|
|
}
|
|
|
|
/**
|
|
* @return list<Currency>
|
|
*/
|
|
public function findAll(string $projectId): array {
|
|
return $this->currencyMapper->findAll($projectId);
|
|
}
|
|
|
|
/**
|
|
* @return never
|
|
*/
|
|
private function handleException(Exception $e): void {
|
|
if ($e instanceof DoesNotExistException ||
|
|
$e instanceof MultipleObjectsReturnedException) {
|
|
throw new CurrencyNotFound($e->getMessage());
|
|
} else {
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|