mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-04-28 09:22:38 +02:00
Currency hotfixes (#1240)
* hotfix: hardcode list of currencies to workaround failing API calls See https://github.com/spiral-project/ihatemoney/issues/1232 for a discussion on currencies * Temporarily disable some currency operations to prevent crashes Here is what is disabled: - setting or changing the default currency on an existing project - adding or editing a bill with a currency that differs from the default currency of the project --------- Co-authored-by: Baptiste Jonglez <git@bitsofnetworks.org>
This commit is contained in:
parent
c5c8dba631
commit
1a2fa0476b
6 changed files with 216 additions and 19 deletions
|
@ -36,13 +36,181 @@ class CurrencyConverter(object, metaclass=Singleton):
|
|||
return rates
|
||||
|
||||
def get_currencies(self, with_no_currency=True):
|
||||
rates = [
|
||||
rate
|
||||
for rate in self.get_rates()
|
||||
if with_no_currency or rate != self.no_currency
|
||||
currencies = [
|
||||
"AED",
|
||||
"AFN",
|
||||
"ALL",
|
||||
"AMD",
|
||||
"ANG",
|
||||
"AOA",
|
||||
"ARS",
|
||||
"AUD",
|
||||
"AWG",
|
||||
"AZN",
|
||||
"BAM",
|
||||
"BBD",
|
||||
"BDT",
|
||||
"BGN",
|
||||
"BHD",
|
||||
"BIF",
|
||||
"BMD",
|
||||
"BND",
|
||||
"BOB",
|
||||
"BRL",
|
||||
"BSD",
|
||||
"BTC",
|
||||
"BTN",
|
||||
"BWP",
|
||||
"BYN",
|
||||
"BZD",
|
||||
"CAD",
|
||||
"CDF",
|
||||
"CHF",
|
||||
"CLF",
|
||||
"CLP",
|
||||
"CNH",
|
||||
"CNY",
|
||||
"COP",
|
||||
"CRC",
|
||||
"CUC",
|
||||
"CUP",
|
||||
"CVE",
|
||||
"CZK",
|
||||
"DJF",
|
||||
"DKK",
|
||||
"DOP",
|
||||
"DZD",
|
||||
"EGP",
|
||||
"ERN",
|
||||
"ETB",
|
||||
"EUR",
|
||||
"FJD",
|
||||
"FKP",
|
||||
"GBP",
|
||||
"GEL",
|
||||
"GGP",
|
||||
"GHS",
|
||||
"GIP",
|
||||
"GMD",
|
||||
"GNF",
|
||||
"GTQ",
|
||||
"GYD",
|
||||
"HKD",
|
||||
"HNL",
|
||||
"HRK",
|
||||
"HTG",
|
||||
"HUF",
|
||||
"IDR",
|
||||
"ILS",
|
||||
"IMP",
|
||||
"INR",
|
||||
"IQD",
|
||||
"IRR",
|
||||
"ISK",
|
||||
"JEP",
|
||||
"JMD",
|
||||
"JOD",
|
||||
"JPY",
|
||||
"KES",
|
||||
"KGS",
|
||||
"KHR",
|
||||
"KMF",
|
||||
"KPW",
|
||||
"KRW",
|
||||
"KWD",
|
||||
"KYD",
|
||||
"KZT",
|
||||
"LAK",
|
||||
"LBP",
|
||||
"LKR",
|
||||
"LRD",
|
||||
"LSL",
|
||||
"LYD",
|
||||
"MAD",
|
||||
"MDL",
|
||||
"MGA",
|
||||
"MKD",
|
||||
"MMK",
|
||||
"MNT",
|
||||
"MOP",
|
||||
"MRU",
|
||||
"MUR",
|
||||
"MVR",
|
||||
"MWK",
|
||||
"MXN",
|
||||
"MYR",
|
||||
"MZN",
|
||||
"NAD",
|
||||
"NGN",
|
||||
"NIO",
|
||||
"NOK",
|
||||
"NPR",
|
||||
"NZD",
|
||||
"OMR",
|
||||
"PAB",
|
||||
"PEN",
|
||||
"PGK",
|
||||
"PHP",
|
||||
"PKR",
|
||||
"PLN",
|
||||
"PYG",
|
||||
"QAR",
|
||||
"RON",
|
||||
"RSD",
|
||||
"RUB",
|
||||
"RWF",
|
||||
"SAR",
|
||||
"SBD",
|
||||
"SCR",
|
||||
"SDG",
|
||||
"SEK",
|
||||
"SGD",
|
||||
"SHP",
|
||||
"SLL",
|
||||
"SOS",
|
||||
"SRD",
|
||||
"SSP",
|
||||
"STD",
|
||||
"STN",
|
||||
"SVC",
|
||||
"SYP",
|
||||
"SZL",
|
||||
"THB",
|
||||
"TJS",
|
||||
"TMT",
|
||||
"TND",
|
||||
"TOP",
|
||||
"TRY",
|
||||
"TTD",
|
||||
"TWD",
|
||||
"TZS",
|
||||
"UAH",
|
||||
"UGX",
|
||||
"USD",
|
||||
"UYU",
|
||||
"UZS",
|
||||
"VEF",
|
||||
"VES",
|
||||
"VND",
|
||||
"VUV",
|
||||
"WST",
|
||||
"XAF",
|
||||
"XAG",
|
||||
"XAU",
|
||||
"XCD",
|
||||
"XDR",
|
||||
"XOF",
|
||||
"XPD",
|
||||
"XPF",
|
||||
"XPT",
|
||||
"YER",
|
||||
"ZAR",
|
||||
"ZMW",
|
||||
"ZWL",
|
||||
]
|
||||
rates.sort(key=lambda rate: "" if rate == self.no_currency else rate)
|
||||
return rates
|
||||
if with_no_currency:
|
||||
currencies.append(self.no_currency)
|
||||
return currencies
|
||||
|
||||
def exchange_currency(self, amount, source_currency, dest_currency):
|
||||
if (
|
||||
|
|
|
@ -67,6 +67,9 @@ def get_billform_for(project, set_default=True, **kwargs):
|
|||
if form.original_currency.data is None:
|
||||
form.original_currency.data = project.default_currency
|
||||
|
||||
# Used in validate_original_currency
|
||||
form.project_currency = project.default_currency
|
||||
|
||||
show_no_currency = form.original_currency.data == CurrencyConverter.no_currency
|
||||
|
||||
form.original_currency.choices = [
|
||||
|
@ -185,12 +188,20 @@ class EditProjectForm(FlaskForm):
|
|||
and field.data == CurrencyConverter.no_currency
|
||||
and project.has_multiple_currencies()
|
||||
):
|
||||
raise ValidationError(
|
||||
_(
|
||||
msg = _(
|
||||
"This project cannot be set to 'no currency'"
|
||||
" because it contains bills in multiple currencies."
|
||||
)
|
||||
raise ValidationError(msg)
|
||||
if (
|
||||
project is not None
|
||||
and field.data != CurrencyConverter.no_currency
|
||||
and project.has_bills()
|
||||
):
|
||||
msg = _(
|
||||
"Cannot change project currency because currency conversion is broken"
|
||||
)
|
||||
raise ValidationError(msg)
|
||||
|
||||
def update(self, project):
|
||||
"""Update the project with the information from the form"""
|
||||
|
@ -406,6 +417,17 @@ class BillForm(FlaskForm):
|
|||
# See https://github.com/python-babel/babel/issues/821
|
||||
raise ValidationError(f"Result is too high: {field.data}")
|
||||
|
||||
def validate_original_currency(self, field):
|
||||
# Workaround for currency API breakage
|
||||
# See #1232
|
||||
if field.data not in [CurrencyConverter.no_currency, self.project_currency]:
|
||||
msg = _(
|
||||
"Failed to convert from %(bill_currency)s currency to %(project_currency)s",
|
||||
bill_currency=field.data,
|
||||
project_currency=self.project_currency,
|
||||
)
|
||||
raise ValidationError(msg)
|
||||
|
||||
|
||||
class MemberForm(FlaskForm):
|
||||
name = StringField(_("Name"), validators=[DataRequired()], filters=[strip_filter])
|
||||
|
|
|
@ -2,6 +2,8 @@ import base64
|
|||
import datetime
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from ihatemoney.tests.common.help_functions import em_surround
|
||||
from ihatemoney.tests.common.ihatemoney_testcase import IhatemoneyTestCase
|
||||
|
||||
|
@ -615,6 +617,7 @@ class TestAPI(IhatemoneyTestCase):
|
|||
)
|
||||
self.assertStatus(400, req)
|
||||
|
||||
@pytest.mark.skip(reason="Currency conversion is broken")
|
||||
def test_currencies(self):
|
||||
# check /currencies for list of supported currencies
|
||||
resp = self.client.get("/api/currencies")
|
||||
|
|
|
@ -1403,6 +1403,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
member = models.Person.query.filter(models.Person.id == 1).one_or_none()
|
||||
assert member is None
|
||||
|
||||
@pytest.mark.skip(reason="Currency conversion is broken")
|
||||
def test_currency_switch(self):
|
||||
# A project should be editable
|
||||
self.post_project("raclette")
|
||||
|
@ -1529,6 +1530,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
assert '<p class="alert alert-danger">' in resp.data.decode("utf-8")
|
||||
assert self.get_project("raclette").default_currency == "USD"
|
||||
|
||||
@pytest.mark.skip(reason="Currency conversion is broken")
|
||||
def test_currency_switch_to_bill_currency(self):
|
||||
# Default currency is 'XXX', but we should start from a project with a currency
|
||||
self.post_project("raclette", default_currency="USD")
|
||||
|
@ -1563,6 +1565,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
bill = project.get_bills().first()
|
||||
assert bill.converted_amount == bill.amount
|
||||
|
||||
@pytest.mark.skip(reason="Currency conversion is broken")
|
||||
def test_currency_switch_to_no_currency(self):
|
||||
# Default currency is 'XXX', but we should start from a project with a currency
|
||||
self.post_project("raclette", default_currency="USD")
|
||||
|
@ -1626,7 +1629,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
"payer": 1,
|
||||
"payed_for": [1],
|
||||
"amount": "0",
|
||||
"original_currency": "EUR",
|
||||
"original_currency": "XXX",
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -1703,7 +1706,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
Tests that the RSS feed output content is expected.
|
||||
"""
|
||||
with fake_time("2023-07-25 12:00:00"):
|
||||
self.post_project("raclette")
|
||||
self.post_project("raclette", default_currency="EUR")
|
||||
self.client.post("/raclette/members/add", data={"name": "george"})
|
||||
self.client.post("/raclette/members/add", data={"name": "peter"})
|
||||
self.client.post("/raclette/members/add", data={"name": "steven"})
|
||||
|
@ -1787,7 +1790,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
history is disabled.
|
||||
"""
|
||||
with fake_time("2023-07-25 12:00:00"):
|
||||
self.post_project("raclette", project_history=False)
|
||||
self.post_project("raclette", default_currency="EUR", project_history=False)
|
||||
self.client.post("/raclette/members/add", data={"name": "george"})
|
||||
self.client.post("/raclette/members/add", data={"name": "peter"})
|
||||
self.client.post("/raclette/members/add", data={"name": "steven"})
|
||||
|
@ -1900,7 +1903,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
"payer": 1,
|
||||
"payed_for": [1],
|
||||
"amount": "12",
|
||||
"original_currency": "EUR",
|
||||
"original_currency": "XXX",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
@ -1961,7 +1964,7 @@ class TestBudget(IhatemoneyTestCase):
|
|||
"payer": 1,
|
||||
"payed_for": [1],
|
||||
"amount": "12",
|
||||
"original_currency": "EUR",
|
||||
"original_currency": "XXX",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
|
|
@ -466,6 +466,7 @@ class TestExport(IhatemoneyTestCase):
|
|||
resp = self.client.get("/raclette/export/transactions.wrong")
|
||||
assert resp.status_code == 404
|
||||
|
||||
@pytest.mark.skip(reason="Currency conversion is broken")
|
||||
def test_export_with_currencies(self):
|
||||
self.post_project("raclette", default_currency="EUR")
|
||||
|
||||
|
|
|
@ -385,9 +385,9 @@ class TestCurrencyConverter:
|
|||
assert one == two
|
||||
|
||||
def test_get_currencies(self):
|
||||
assert set(self.converter.get_currencies()) == set(
|
||||
["USD", "EUR", "CAD", "PLN", CurrencyConverter.no_currency]
|
||||
)
|
||||
currencies = self.converter.get_currencies()
|
||||
for currency in ["USD", "EUR", "CAD", "PLN", CurrencyConverter.no_currency]:
|
||||
assert currency in currencies
|
||||
|
||||
def test_exchange_currency(self):
|
||||
result = self.converter.exchange_currency(100, "USD", "EUR")
|
||||
|
|
Loading…
Reference in a new issue