Skip to content

Commit 8738623

Browse files
committed
feat: improve currency matching
1 parent 5c63759 commit 8738623

5 files changed

Lines changed: 1053 additions & 48 deletions

File tree

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ permissions:
1414
pull-requests: write
1515

1616
concurrency:
17-
group: lint-php-cs-${{ github.head_ref || github.run_id }}
17+
group: release-${{ github.head_ref || github.run_id }}
1818
cancel-in-progress: true
1919

2020
jobs:

README.md

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,18 @@ rate.
1313

1414
Interval for fetch may be adjusted in the admin settings "Auto Currency" section.
1515

16-
## Preparing currency data
17-
18-
To make this work, a 3-letter currency code must be in the name of the currency.
16+
**Note**: This is a companion app to Cospend. Without Cospend, this app will not work.
1917

20-
Currencies of different code lengths are not currently supported (but are planned).
21-
22-
The currency code will be fetched using the first 3-uppercase-letter occurrence in the name defined
23-
on Cospend.
18+
## Preparing currency data
2419

25-
For example, to properly set USD as currency, set the name to one of (but not limited to):
20+
For both main and additional currencies, you must include in the currency name, one of the following:
2621

27-
- USD
28-
- $ USD
29-
- USD $
30-
- United States Dollars (USD)
22+
- Currency symbol (`$`, ``, `£`, etc.)
23+
- Currency code (USD, EUR, GBP, etc.) - case insensitive
3124

32-
Will all be considered "USD" for conversion purposes.
25+
Using one of these will be enough to fetch the correct rate.
3326

34-
This rule applies to **main** and **additional currencies**.
27+
For a list of available currencies, see [currencies.json](lib/Service/symbols.json).
3528

3629
To see the full list of available currencies, visit
3730
[this page](https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies.json) and

appinfo/info.xml

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,12 @@
1010
<description><![CDATA[This NextCloud app automatically fetches currency information for your Cospend projects, and fills
1111
them up using the main currency as base. No more manually updating exchange rates!
1212
13-
It will automatically run once a day and use your currency names to fetch the correct rate.
13+
It will automatically run once a day by default and use your currency names to fetch the correct
14+
rate.
1415
15-
The name will be fetched using the first 3-uppercase-letter appearance in the name.
16+
Interval for fetch may be adjusted in the admin settings "Auto Currency" section.
1617
17-
For example:
18-
19-
- USD
20-
- $ USD
21-
- USD $
22-
- United States Dollars (USD)
23-
24-
Will all be considered "USD" for conversion purposes.
25-
26-
This rule applies to main and additional currencies.
27-
28-
## Contributing
29-
30-
I am developing this package on my free time, so any support, whether code, issues, or just stars is
31-
very helpful to sustaining its life. If you are feeling incredibly generous and would like to donate
32-
just a small amount to help sustain this project, I would be very very thankful!
33-
34-
<a href='https://ko-fi.com/casraf' target='_blank'>
35-
<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' />
36-
</a>
37-
38-
I welcome any issues or pull requests on GitHub. If you find a bug, or would like a new feature,
39-
don't hesitate to open an appropriate issue and I will do my best to reply promptly.]]></description>
18+
**Note**: This is a companion app to Cospend. Without Cospend, this app will not work.]]></description>
4019
<version>0.2.1</version>
4120
<licence>agpl</licence>
4221
<author mail="contact@casraf.dev" homepage="https://casraf.dev">Chen Asraf</author>

lib/Service/FetchCurrenciesService.php

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@
1919

2020
class FetchCurrenciesService {
2121
private static $EXCHANGE_URL = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/{base}.json';
22+
private static $SYMBOLS_FILE = __DIR__ . '/symbols.json';
23+
2224
private IAppConfig $config;
25+
2326
private CurrencyMapper $currencyMapper;
27+
2428
private CospendProjectMapper $projectMapper;
29+
2530
private LoggerInterface $logger;
2631

32+
/* @var array<string, array<symbol: string, name: string, symbol_native: string, decimal_digits: int, rounding: int, code: string, name_plural: string>> */
33+
private array $symbols;
34+
2735
public function __construct(
2836
IAppConfig $config,
2937
CurrencyMapper $currencyMapper,
@@ -34,6 +42,7 @@ public function __construct(
3442
$this->currencyMapper = $currencyMapper;
3543
$this->projectMapper = $projectMapper;
3644
$this->logger = $logger;
45+
$this->loadSymbols();
3746
}
3847

3948
public function fetchCurrencyRates(): void {
@@ -68,8 +77,13 @@ public function fetchCurrencyRates(): void {
6877

6978
foreach ($currencies as $currency) {
7079
$cur = $this->getCurrencyName($currency->getName());
80+
if ($cur === null) {
81+
$this->logger->error('Currency not found: ' . $currency->getName());
82+
continue;
83+
}
7184
$lcur = strtolower($cur);
72-
$newRate = floatval(number_format(1 / $json[$lbase][$lcur], 2));
85+
$baseRate = $json[$lbase][$lcur];
86+
$newRate = floatval(number_format(1 / $baseRate, 2));
7387
$currency->setExchangeRate($newRate);
7488
$this->logger->info('Setting exchange rate for currency ' . $cur . ' to ' . $newRate);
7589
$this->currencyMapper->update($currency);
@@ -80,17 +94,35 @@ public function fetchCurrencyRates(): void {
8094
$this->config->setValueString('autocurrency', 'last_update', $lastUpdate);
8195
}
8296

83-
private function getCurrencyName(string $name): string {
84-
// find 3-letter currency code for the base currency
85-
preg_match('/([A-Z]{3})/', $name, $matches);
97+
/** Match the currency name from the known currencies. **/
98+
private function getCurrencyName(string $name): ?string {
99+
foreach ($this->symbols as $cur => $currency) {
100+
// e.g. usd
101+
$id = strtolower($cur);
102+
if (strtolower($name) === $id) {
103+
return $id;
104+
}
86105

87-
$this->logger->info('Matches: ' . json_encode($matches));
106+
// e.g. $
107+
$symbol = $currency['symbol'];
108+
if (str_contains($name, $symbol)) {
109+
return $id;
110+
}
88111

89-
if (count($matches) === 2) {
90-
$name = $matches[1];
112+
// e.g. $ USD
113+
preg_match('/\b' . $id . '\b/', strtolower($name), $matches);
114+
if (count($matches) > 0) {
115+
return $id;
116+
}
91117
}
92118

93-
return $name;
119+
return null;
120+
}
121+
122+
/** Load symbols from the symbols.json file */
123+
private function loadSymbols(): void {
124+
$this->symbols = json_decode(file_get_contents(FetchCurrenciesService::$SYMBOLS_FILE), true);
125+
$this->logger->info('Loaded symbols: ' . json_encode($this->symbols));
94126
}
95127

96128
/**

0 commit comments

Comments
 (0)