feat: improve currency matching

This commit is contained in:
2024-12-05 00:23:33 +02:00
parent 5c637598e5
commit 87386235c2
5 changed files with 1053 additions and 48 deletions

View File

@@ -14,7 +14,7 @@ permissions:
pull-requests: write
concurrency:
group: lint-php-cs-${{ github.head_ref || github.run_id }}
group: release-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:

View File

@@ -13,25 +13,18 @@ rate.
Interval for fetch may be adjusted in the admin settings "Auto Currency" section.
**Note**: This is a companion app to Cospend. Without Cospend, this app will not work.
## Preparing currency data
To make this work, a 3-letter currency code must be in the name of the currency.
For both main and additional currencies, you must include in the currency name, one of the following:
Currencies of different code lengths are not currently supported (but are planned).
- Currency symbol (`$`, `€`, `£`, etc.)
- Currency code (USD, EUR, GBP, etc.) - case insensitive
The currency code will be fetched using the first 3-uppercase-letter occurrence in the name defined
on Cospend.
Using one of these will be enough to fetch the correct rate.
For example, to properly set USD as currency, set the name to one of (but not limited to):
- USD
- $ USD
- USD $
- United States Dollars (USD)
Will all be considered "USD" for conversion purposes.
This rule applies to **main** and **additional currencies**.
For a list of available currencies, see [currencies.json](lib/Service/symbols.json).
To see the full list of available currencies, visit
[this page](https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies.json) and

View File

@@ -10,33 +10,12 @@
<description><![CDATA[This NextCloud app automatically fetches currency information for your Cospend projects, and fills
them up using the main currency as base. No more manually updating exchange rates!
It will automatically run once a day and use your currency names to fetch the correct rate.
It will automatically run once a day by default and use your currency names to fetch the correct
rate.
The name will be fetched using the first 3-uppercase-letter appearance in the name.
Interval for fetch may be adjusted in the admin settings "Auto Currency" section.
For example:
- USD
- $ USD
- USD $
- United States Dollars (USD)
Will all be considered "USD" for conversion purposes.
This rule applies to main and additional currencies.
## Contributing
I am developing this package on my free time, so any support, whether code, issues, or just stars is
very helpful to sustaining its life. If you are feeling incredibly generous and would like to donate
just a small amount to help sustain this project, I would be very very thankful!
<a href='https://ko-fi.com/casraf' target='_blank'>
<img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3' alt='Buy Me a Coffee at ko-fi.com' />
</a>
I welcome any issues or pull requests on GitHub. If you find a bug, or would like a new feature,
don't hesitate to open an appropriate issue and I will do my best to reply promptly.]]></description>
**Note**: This is a companion app to Cospend. Without Cospend, this app will not work.]]></description>
<version>0.2.1</version>
<licence>agpl</licence>
<author mail="contact@casraf.dev" homepage="https://casraf.dev">Chen Asraf</author>

View File

@@ -19,11 +19,19 @@ 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,
@@ -34,6 +42,7 @@ class FetchCurrenciesService {
$this->currencyMapper = $currencyMapper;
$this->projectMapper = $projectMapper;
$this->logger = $logger;
$this->loadSymbols();
}
public function fetchCurrencyRates(): void {
@@ -68,8 +77,13 @@ class FetchCurrenciesService {
foreach ($currencies as $currency) {
$cur = $this->getCurrencyName($currency->getName());
if ($cur === null) {
$this->logger->error('Currency not found: ' . $currency->getName());
continue;
}
$lcur = strtolower($cur);
$newRate = floatval(number_format(1 / $json[$lbase][$lcur], 2));
$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);
@@ -80,17 +94,35 @@ class FetchCurrenciesService {
$this->config->setValueString('autocurrency', 'last_update', $lastUpdate);
}
private function getCurrencyName(string $name): string {
// find 3-letter currency code for the base currency
preg_match('/([A-Z]{3})/', $name, $matches);
/** 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;
}
$this->logger->info('Matches: ' . json_encode($matches));
// e.g. $
$symbol = $currency['symbol'];
if (str_contains($name, $symbol)) {
return $id;
}
if (count($matches) === 2) {
$name = $matches[1];
// e.g. $ USD
preg_match('/\b' . $id . '\b/', strtolower($name), $matches);
if (count($matches) > 0) {
return $id;
}
}
return $name;
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));
}
/**

1001
lib/Service/symbols.json Normal file

File diff suppressed because it is too large Load Diff