mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-04-29 09:52:36 +02:00
Add currency to import and export formats
This commit is contained in:
parent
6448d0d7df
commit
4bf9308908
5 changed files with 307 additions and 22 deletions
|
@ -321,7 +321,7 @@ class BillForm(FlaskForm):
|
||||||
bill.external_link = ""
|
bill.external_link = ""
|
||||||
bill.date = self.date
|
bill.date = self.date
|
||||||
bill.owers = [Person.query.get(ower, project) for ower in self.payed_for]
|
bill.owers = [Person.query.get(ower, project) for ower in self.payed_for]
|
||||||
bill.original_currency = CurrencyConverter.no_currency
|
bill.original_currency = self.original_currency
|
||||||
bill.converted_amount = self.currency_helper.exchange_currency(
|
bill.converted_amount = self.currency_helper.exchange_currency(
|
||||||
bill.amount, bill.original_currency, project.default_currency
|
bill.amount, bill.original_currency, project.default_currency
|
||||||
)
|
)
|
||||||
|
|
|
@ -179,6 +179,7 @@ class Project(db.Model):
|
||||||
"ower": transaction["ower"].name,
|
"ower": transaction["ower"].name,
|
||||||
"receiver": transaction["receiver"].name,
|
"receiver": transaction["receiver"].name,
|
||||||
"amount": round(transaction["amount"], 2),
|
"amount": round(transaction["amount"], 2),
|
||||||
|
"currency": transaction["currency"],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return pretty_transactions
|
return pretty_transactions
|
||||||
|
@ -192,6 +193,7 @@ class Project(db.Model):
|
||||||
"ower": members[ower_id],
|
"ower": members[ower_id],
|
||||||
"receiver": members[receiver_id],
|
"receiver": members[receiver_id],
|
||||||
"amount": amount,
|
"amount": amount,
|
||||||
|
"currency": self.default_currency,
|
||||||
}
|
}
|
||||||
for ower_id, amount, receiver_id in settle_plan
|
for ower_id, amount, receiver_id in settle_plan
|
||||||
]
|
]
|
||||||
|
@ -269,6 +271,7 @@ class Project(db.Model):
|
||||||
{
|
{
|
||||||
"what": bill.what,
|
"what": bill.what,
|
||||||
"amount": round(bill.amount, 2),
|
"amount": round(bill.amount, 2),
|
||||||
|
"currency": bill.original_currency,
|
||||||
"date": str(bill.date),
|
"date": str(bill.date),
|
||||||
"payer_name": Person.query.get(bill.payer_id).name,
|
"payer_name": Person.query.get(bill.payer_id).name,
|
||||||
"payer_weight": Person.query.get(bill.payer_id).weight,
|
"payer_weight": Person.query.get(bill.payer_id).weight,
|
||||||
|
|
|
@ -1008,6 +1008,8 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_export(self):
|
def test_export(self):
|
||||||
|
# Export a simple project without currencies
|
||||||
|
|
||||||
self.post_project("raclette")
|
self.post_project("raclette")
|
||||||
|
|
||||||
# add members
|
# add members
|
||||||
|
@ -1025,7 +1027,6 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"payer": 1,
|
"payer": 1,
|
||||||
"payed_for": [1, 2, 3, 4],
|
"payed_for": [1, 2, 3, 4],
|
||||||
"amount": "10.0",
|
"amount": "10.0",
|
||||||
"original_currency": "USD",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1037,7 +1038,6 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"payer": 2,
|
"payer": 2,
|
||||||
"payed_for": [1, 3],
|
"payed_for": [1, 3],
|
||||||
"amount": "200",
|
"amount": "200",
|
||||||
"original_currency": "USD",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1049,7 +1049,6 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"payer": 3,
|
"payer": 3,
|
||||||
"payed_for": [2],
|
"payed_for": [2],
|
||||||
"amount": "13.33",
|
"amount": "13.33",
|
||||||
"original_currency": "USD",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1060,6 +1059,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"date": "2017-01-01",
|
"date": "2017-01-01",
|
||||||
"what": "refund",
|
"what": "refund",
|
||||||
"amount": 13.33,
|
"amount": 13.33,
|
||||||
|
"currency": "XXX",
|
||||||
"payer_name": "tata",
|
"payer_name": "tata",
|
||||||
"payer_weight": 1.0,
|
"payer_weight": 1.0,
|
||||||
"owers": ["fred"],
|
"owers": ["fred"],
|
||||||
|
@ -1068,6 +1068,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"date": "2016-12-31",
|
"date": "2016-12-31",
|
||||||
"what": "red wine",
|
"what": "red wine",
|
||||||
"amount": 200.0,
|
"amount": 200.0,
|
||||||
|
"currency": "XXX",
|
||||||
"payer_name": "fred",
|
"payer_name": "fred",
|
||||||
"payer_weight": 1.0,
|
"payer_weight": 1.0,
|
||||||
"owers": ["zorglub", "tata"],
|
"owers": ["zorglub", "tata"],
|
||||||
|
@ -1076,6 +1077,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"date": "2016-12-31",
|
"date": "2016-12-31",
|
||||||
"what": "fromage \xe0 raclette",
|
"what": "fromage \xe0 raclette",
|
||||||
"amount": 10.0,
|
"amount": 10.0,
|
||||||
|
"currency": "XXX",
|
||||||
"payer_name": "zorglub",
|
"payer_name": "zorglub",
|
||||||
"payer_weight": 2.0,
|
"payer_weight": 2.0,
|
||||||
"owers": ["zorglub", "fred", "tata", "p\xe9p\xe9"],
|
"owers": ["zorglub", "fred", "tata", "p\xe9p\xe9"],
|
||||||
|
@ -1086,10 +1088,10 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
# generate csv export of bills
|
# generate csv export of bills
|
||||||
resp = self.client.get("/raclette/export/bills.csv")
|
resp = self.client.get("/raclette/export/bills.csv")
|
||||||
expected = [
|
expected = [
|
||||||
"date,what,amount,payer_name,payer_weight,owers",
|
"date,what,amount,currency,payer_name,payer_weight,owers",
|
||||||
"2017-01-01,refund,13.33,tata,1.0,fred",
|
"2017-01-01,refund,XXX,13.33,tata,1.0,fred",
|
||||||
'2016-12-31,red wine,200.0,fred,1.0,"zorglub, tata"',
|
'2016-12-31,red wine,XXX,200.0,fred,1.0,"zorglub, tata"',
|
||||||
'2016-12-31,fromage à raclette,10.0,zorglub,2.0,"zorglub, fred, tata, pépé"',
|
'2016-12-31,fromage à raclette,10.0,XXX,zorglub,2.0,"zorglub, fred, tata, pépé"',
|
||||||
]
|
]
|
||||||
received_lines = resp.data.decode("utf-8").split("\n")
|
received_lines = resp.data.decode("utf-8").split("\n")
|
||||||
|
|
||||||
|
@ -1101,9 +1103,19 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
# generate json export of transactions
|
# generate json export of transactions
|
||||||
resp = self.client.get("/raclette/export/transactions.json")
|
resp = self.client.get("/raclette/export/transactions.json")
|
||||||
expected = [
|
expected = [
|
||||||
{"amount": 2.00, "receiver": "fred", "ower": "p\xe9p\xe9"},
|
{
|
||||||
{"amount": 55.34, "receiver": "fred", "ower": "tata"},
|
"amount": 2.00,
|
||||||
{"amount": 127.33, "receiver": "fred", "ower": "zorglub"},
|
"currency": "XXX",
|
||||||
|
"receiver": "fred",
|
||||||
|
"ower": "p\xe9p\xe9",
|
||||||
|
},
|
||||||
|
{"amount": 55.34, "currency": "XXX", "receiver": "fred", "ower": "tata"},
|
||||||
|
{
|
||||||
|
"amount": 127.33,
|
||||||
|
"currency": "XXX",
|
||||||
|
"receiver": "fred",
|
||||||
|
"ower": "zorglub",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertEqual(json.loads(resp.data.decode("utf-8")), expected)
|
self.assertEqual(json.loads(resp.data.decode("utf-8")), expected)
|
||||||
|
@ -1112,10 +1124,10 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
resp = self.client.get("/raclette/export/transactions.csv")
|
resp = self.client.get("/raclette/export/transactions.csv")
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
"amount,receiver,ower",
|
"amount,currency,receiver,ower",
|
||||||
"2.0,fred,pépé",
|
"2.0,XXX,fred,pépé",
|
||||||
"55.34,fred,tata",
|
"55.34,XXX,fred,tata",
|
||||||
"127.33,fred,zorglub",
|
"127.33,XXX,fred,zorglub",
|
||||||
]
|
]
|
||||||
received_lines = resp.data.decode("utf-8").split("\n")
|
received_lines = resp.data.decode("utf-8").split("\n")
|
||||||
|
|
||||||
|
@ -1128,9 +1140,244 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
resp = self.client.get("/raclette/export/transactions.wrong")
|
resp = self.client.get("/raclette/export/transactions.wrong")
|
||||||
self.assertEqual(resp.status_code, 404)
|
self.assertEqual(resp.status_code, 404)
|
||||||
|
|
||||||
|
def test_export_with_currencies(self):
|
||||||
|
self.post_project("raclette", default_currency="EUR")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "zorglub", "weight": 2})
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "fred"})
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "tata"})
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "pépé"})
|
||||||
|
|
||||||
|
# create bills
|
||||||
|
self.client.post(
|
||||||
|
"/raclette/add",
|
||||||
|
data={
|
||||||
|
"date": "2016-12-31",
|
||||||
|
"what": "fromage à raclette",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2, 3, 4],
|
||||||
|
"amount": "10.0",
|
||||||
|
"original_currency": "EUR",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.post(
|
||||||
|
"/raclette/add",
|
||||||
|
data={
|
||||||
|
"date": "2016-12-31",
|
||||||
|
"what": "poutine from Québec",
|
||||||
|
"payer": 2,
|
||||||
|
"payed_for": [1, 3],
|
||||||
|
"amount": "100",
|
||||||
|
"original_currency": "CAD",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.post(
|
||||||
|
"/raclette/add",
|
||||||
|
data={
|
||||||
|
"date": "2017-01-01",
|
||||||
|
"what": "refund",
|
||||||
|
"payer": 3,
|
||||||
|
"payed_for": [2],
|
||||||
|
"amount": "13.33",
|
||||||
|
"original_currency": "EUR",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# generate json export of bills
|
||||||
|
resp = self.client.get("/raclette/export/bills.json")
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"date": "2017-01-01",
|
||||||
|
"what": "refund",
|
||||||
|
"amount": 13.33,
|
||||||
|
"currency": "EUR",
|
||||||
|
"payer_name": "tata",
|
||||||
|
"payer_weight": 1.0,
|
||||||
|
"owers": ["fred"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2016-12-31",
|
||||||
|
"what": "poutine from Qu\xe9bec",
|
||||||
|
"amount": 100.0,
|
||||||
|
"currency": "CAD",
|
||||||
|
"payer_name": "fred",
|
||||||
|
"payer_weight": 1.0,
|
||||||
|
"owers": ["zorglub", "tata"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2016-12-31",
|
||||||
|
"what": "fromage \xe0 raclette",
|
||||||
|
"amount": 10.0,
|
||||||
|
"currency": "EUR",
|
||||||
|
"payer_name": "zorglub",
|
||||||
|
"payer_weight": 2.0,
|
||||||
|
"owers": ["zorglub", "fred", "tata", "p\xe9p\xe9"],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
self.assertEqual(json.loads(resp.data.decode("utf-8")), expected)
|
||||||
|
|
||||||
|
# generate csv export of bills
|
||||||
|
resp = self.client.get("/raclette/export/bills.csv")
|
||||||
|
expected = [
|
||||||
|
"date,what,amount,currency,payer_name,payer_weight,owers",
|
||||||
|
"2017-01-01,refund,13.33,EUR,tata,1.0,fred",
|
||||||
|
'2016-12-31,poutine from Québec,100.0,CAD,fred,1.0,"zorglub, tata"',
|
||||||
|
'2016-12-31,fromage à raclette,10.0,EUR,zorglub,2.0,"zorglub, fred, tata, pépé"',
|
||||||
|
]
|
||||||
|
received_lines = resp.data.decode("utf-8").split("\n")
|
||||||
|
|
||||||
|
for i, line in enumerate(expected):
|
||||||
|
self.assertEqual(
|
||||||
|
set(line.split(",")), set(received_lines[i].strip("\r").split(","))
|
||||||
|
)
|
||||||
|
|
||||||
|
# generate json export of transactions (in EUR!)
|
||||||
|
resp = self.client.get("/raclette/export/transactions.json")
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"amount": 2.00,
|
||||||
|
"currency": "EUR",
|
||||||
|
"receiver": "fred",
|
||||||
|
"ower": "p\xe9p\xe9",
|
||||||
|
},
|
||||||
|
{"amount": 10.89, "currency": "EUR", "receiver": "fred", "ower": "tata"},
|
||||||
|
{"amount": 38.45, "currency": "EUR", "receiver": "fred", "ower": "zorglub"},
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(json.loads(resp.data.decode("utf-8")), expected)
|
||||||
|
|
||||||
|
# generate csv export of transactions
|
||||||
|
resp = self.client.get("/raclette/export/transactions.csv")
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
"amount,currency,receiver,ower",
|
||||||
|
"2.0,EUR,fred,pépé",
|
||||||
|
"10.89,EUR,fred,tata",
|
||||||
|
"38.45,EUR,fred,zorglub",
|
||||||
|
]
|
||||||
|
received_lines = resp.data.decode("utf-8").split("\n")
|
||||||
|
|
||||||
|
for i, line in enumerate(expected):
|
||||||
|
self.assertEqual(
|
||||||
|
set(line.split(",")), set(received_lines[i].strip("\r").split(","))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Change project currency to CAD
|
||||||
|
project = models.Project.query.get("raclette")
|
||||||
|
project.switch_currency("CAD")
|
||||||
|
|
||||||
|
# generate json export of transactions (now in CAD!)
|
||||||
|
resp = self.client.get("/raclette/export/transactions.json")
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"amount": 3.00,
|
||||||
|
"currency": "CAD",
|
||||||
|
"receiver": "fred",
|
||||||
|
"ower": "p\xe9p\xe9",
|
||||||
|
},
|
||||||
|
{"amount": 16.34, "currency": "CAD", "receiver": "fred", "ower": "tata"},
|
||||||
|
{"amount": 57.67, "currency": "CAD", "receiver": "fred", "ower": "zorglub"},
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(json.loads(resp.data.decode("utf-8")), expected)
|
||||||
|
|
||||||
|
# generate csv export of transactions
|
||||||
|
resp = self.client.get("/raclette/export/transactions.csv")
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
"amount,currency,receiver,ower",
|
||||||
|
"3.0,CAD,fred,pépé",
|
||||||
|
"16.34,CAD,fred,tata",
|
||||||
|
"57.67,CAD,fred,zorglub",
|
||||||
|
]
|
||||||
|
received_lines = resp.data.decode("utf-8").split("\n")
|
||||||
|
|
||||||
|
for i, line in enumerate(expected):
|
||||||
|
self.assertEqual(
|
||||||
|
set(line.split(",")), set(received_lines[i].strip("\r").split(","))
|
||||||
|
)
|
||||||
|
|
||||||
def test_import_new_project(self):
|
def test_import_new_project(self):
|
||||||
# Import JSON in an empty project
|
# Import JSON in an empty project
|
||||||
|
|
||||||
|
self.post_project("raclette", default_currency="EUR")
|
||||||
|
self.login("raclette")
|
||||||
|
|
||||||
|
project = models.Project.query.get("raclette")
|
||||||
|
|
||||||
|
json_to_import = [
|
||||||
|
{
|
||||||
|
"date": "2017-01-01",
|
||||||
|
"what": "refund",
|
||||||
|
"amount": 13.33,
|
||||||
|
"currency": "EUR",
|
||||||
|
"payer_name": "tata",
|
||||||
|
"payer_weight": 1.0,
|
||||||
|
"owers": ["fred"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2016-12-31",
|
||||||
|
"what": "poutine from québec",
|
||||||
|
"amount": 50.0,
|
||||||
|
"currency": "CAD",
|
||||||
|
"payer_name": "fred",
|
||||||
|
"payer_weight": 1.0,
|
||||||
|
"owers": ["zorglub", "tata"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2016-12-31",
|
||||||
|
"what": "fromage a raclette",
|
||||||
|
"amount": 10.0,
|
||||||
|
"currency": "EUR",
|
||||||
|
"payer_name": "zorglub",
|
||||||
|
"payer_weight": 2.0,
|
||||||
|
"owers": ["zorglub", "fred", "tata", "pepe"],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
from ihatemoney.web import import_project
|
||||||
|
|
||||||
|
file = io.StringIO()
|
||||||
|
json.dump(json_to_import, file)
|
||||||
|
file.seek(0)
|
||||||
|
import_project(file, project)
|
||||||
|
|
||||||
|
bills = project.get_pretty_bills()
|
||||||
|
|
||||||
|
# Check if all bills has been add
|
||||||
|
self.assertEqual(len(bills), len(json_to_import))
|
||||||
|
|
||||||
|
# Check if name of bills are ok
|
||||||
|
b = [e["what"] for e in bills]
|
||||||
|
b.sort()
|
||||||
|
ref = [e["what"] for e in json_to_import]
|
||||||
|
ref.sort()
|
||||||
|
|
||||||
|
self.assertEqual(b, ref)
|
||||||
|
|
||||||
|
# Check if other informations in bill are ok
|
||||||
|
for i in json_to_import:
|
||||||
|
for j in bills:
|
||||||
|
if j["what"] == i["what"]:
|
||||||
|
self.assertEqual(j["payer_name"], i["payer_name"])
|
||||||
|
self.assertEqual(j["amount"], i["amount"])
|
||||||
|
self.assertEqual(j["currency"], i["currency"])
|
||||||
|
self.assertEqual(j["payer_weight"], i["payer_weight"])
|
||||||
|
self.assertEqual(j["date"], i["date"])
|
||||||
|
|
||||||
|
list_project = [ower for ower in j["owers"]]
|
||||||
|
list_project.sort()
|
||||||
|
list_json = [ower for ower in i["owers"]]
|
||||||
|
list_json.sort()
|
||||||
|
|
||||||
|
self.assertEqual(list_project, list_json)
|
||||||
|
|
||||||
|
def test_import_without_currencies(self):
|
||||||
|
# Import JSON without currencies (from ihatemoney < 5) in an empty project
|
||||||
|
|
||||||
self.post_project("raclette")
|
self.post_project("raclette")
|
||||||
self.login("raclette")
|
self.login("raclette")
|
||||||
|
|
||||||
|
@ -1189,6 +1436,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
if j["what"] == i["what"]:
|
if j["what"] == i["what"]:
|
||||||
self.assertEqual(j["payer_name"], i["payer_name"])
|
self.assertEqual(j["payer_name"], i["payer_name"])
|
||||||
self.assertEqual(j["amount"], i["amount"])
|
self.assertEqual(j["amount"], i["amount"])
|
||||||
|
self.assertEqual(j["currency"], "XXX")
|
||||||
self.assertEqual(j["payer_weight"], i["payer_weight"])
|
self.assertEqual(j["payer_weight"], i["payer_weight"])
|
||||||
self.assertEqual(j["date"], i["date"])
|
self.assertEqual(j["date"], i["date"])
|
||||||
|
|
||||||
|
@ -1226,6 +1474,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"date": "2017-01-01",
|
"date": "2017-01-01",
|
||||||
"what": "refund",
|
"what": "refund",
|
||||||
"amount": 13.33,
|
"amount": 13.33,
|
||||||
|
"currency": "XXX",
|
||||||
"payer_name": "tata",
|
"payer_name": "tata",
|
||||||
"payer_weight": 1.0,
|
"payer_weight": 1.0,
|
||||||
"owers": ["fred"],
|
"owers": ["fred"],
|
||||||
|
@ -1234,6 +1483,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"date": "2016-12-31",
|
"date": "2016-12-31",
|
||||||
"what": "red wine",
|
"what": "red wine",
|
||||||
"amount": 200.0,
|
"amount": 200.0,
|
||||||
|
"currency": "XXX",
|
||||||
"payer_name": "fred",
|
"payer_name": "fred",
|
||||||
"payer_weight": 1.0,
|
"payer_weight": 1.0,
|
||||||
"owers": ["zorglub", "tata"],
|
"owers": ["zorglub", "tata"],
|
||||||
|
@ -1242,6 +1492,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
"date": "2016-12-31",
|
"date": "2016-12-31",
|
||||||
"what": "fromage a raclette",
|
"what": "fromage a raclette",
|
||||||
"amount": 10.0,
|
"amount": 10.0,
|
||||||
|
"currency": "XXX",
|
||||||
"payer_name": "zorglub",
|
"payer_name": "zorglub",
|
||||||
"payer_weight": 2.0,
|
"payer_weight": 2.0,
|
||||||
"owers": ["zorglub", "fred", "tata", "pepe"],
|
"owers": ["zorglub", "fred", "tata", "pepe"],
|
||||||
|
@ -1274,6 +1525,7 @@ class BudgetTestCase(IhatemoneyTestCase):
|
||||||
if j["what"] == i["what"]:
|
if j["what"] == i["what"]:
|
||||||
self.assertEqual(j["payer_name"], i["payer_name"])
|
self.assertEqual(j["payer_name"], i["payer_name"])
|
||||||
self.assertEqual(j["amount"], i["amount"])
|
self.assertEqual(j["amount"], i["amount"])
|
||||||
|
self.assertEqual(j["currency"], i["currency"])
|
||||||
self.assertEqual(j["payer_weight"], i["payer_weight"])
|
self.assertEqual(j["payer_weight"], i["payer_weight"])
|
||||||
self.assertEqual(j["date"], i["date"])
|
self.assertEqual(j["date"], i["date"])
|
||||||
|
|
||||||
|
|
|
@ -271,7 +271,7 @@ def get_members(file):
|
||||||
|
|
||||||
|
|
||||||
def same_bill(bill1, bill2):
|
def same_bill(bill1, bill2):
|
||||||
attr = ["what", "payer_name", "payer_weight", "amount", "date", "owers"]
|
attr = ["what", "payer_name", "payer_weight", "amount", "currency", "date", "owers"]
|
||||||
for a in attr:
|
for a in attr:
|
||||||
if bill1[a] != bill2[a]:
|
if bill1[a] != bill2[a]:
|
||||||
return False
|
return False
|
||||||
|
@ -370,6 +370,7 @@ def localize_list(items, surround_with_em=True):
|
||||||
|
|
||||||
|
|
||||||
def render_localized_currency(code, detailed=True):
|
def render_localized_currency(code, detailed=True):
|
||||||
|
# We cannot use CurrencyConvertor.no_currency here because of circular dependencies
|
||||||
if code == "XXX":
|
if code == "XXX":
|
||||||
return _("No Currency")
|
return _("No Currency")
|
||||||
locale = get_locale() or "en_US"
|
locale = get_locale() or "en_US"
|
||||||
|
|
|
@ -36,6 +36,7 @@ from sqlalchemy_continuum import Operation
|
||||||
from werkzeug.exceptions import NotFound
|
from werkzeug.exceptions import NotFound
|
||||||
from werkzeug.security import check_password_hash, generate_password_hash
|
from werkzeug.security import check_password_hash, generate_password_hash
|
||||||
|
|
||||||
|
from ihatemoney.currency_convertor import CurrencyConverter
|
||||||
from ihatemoney.forms import (
|
from ihatemoney.forms import (
|
||||||
AdminAuthenticationForm,
|
AdminAuthenticationForm,
|
||||||
AuthenticationForm,
|
AuthenticationForm,
|
||||||
|
@ -412,8 +413,8 @@ def edit_project():
|
||||||
flash(_("Project successfully uploaded"))
|
flash(_("Project successfully uploaded"))
|
||||||
|
|
||||||
return redirect(url_for("main.list_bills"))
|
return redirect(url_for("main.list_bills"))
|
||||||
except ValueError:
|
except ValueError as e:
|
||||||
flash(_("Invalid JSON"), category="danger")
|
flash(e.args[0], category="danger")
|
||||||
|
|
||||||
# Edit form
|
# Edit form
|
||||||
if edit_form.validate_on_submit():
|
if edit_form.validate_on_submit():
|
||||||
|
@ -447,17 +448,45 @@ def import_project(file, project):
|
||||||
json_file = json.load(file)
|
json_file = json.load(file)
|
||||||
|
|
||||||
# Check if JSON is correct
|
# Check if JSON is correct
|
||||||
attr = ["what", "payer_name", "payer_weight", "amount", "date", "owers"]
|
attr = ["what", "payer_name", "payer_weight", "amount", "currency", "date", "owers"]
|
||||||
attr.sort()
|
attr.sort()
|
||||||
|
currencies = set()
|
||||||
for e in json_file:
|
for e in json_file:
|
||||||
|
# Add compatibility with versions < 5 that did not have currencies
|
||||||
|
if "currency" not in e:
|
||||||
|
e["currency"] = CurrencyConverter.no_currency
|
||||||
|
# Empty currency should be converted to "XXX"
|
||||||
|
if e["currency"] == "":
|
||||||
|
e["currency"] = CurrencyConverter.no_currency
|
||||||
if len(e) != len(attr):
|
if len(e) != len(attr):
|
||||||
raise ValueError
|
raise ValueError(_("Invalid JSON"))
|
||||||
list_attr = []
|
list_attr = []
|
||||||
for i in e:
|
for i in e:
|
||||||
list_attr.append(i)
|
list_attr.append(i)
|
||||||
list_attr.sort()
|
list_attr.sort()
|
||||||
if list_attr != attr:
|
if list_attr != attr:
|
||||||
raise ValueError
|
raise ValueError(_("Invalid JSON"))
|
||||||
|
# If the project has a default currency, convert bills that have no currency
|
||||||
|
if (
|
||||||
|
project.default_currency != CurrencyConverter.no_currency
|
||||||
|
and e["currency"] == CurrencyConverter.no_currency
|
||||||
|
):
|
||||||
|
e["currency"] = project.default_currency
|
||||||
|
# Keep track of currencies
|
||||||
|
currencies.add(e["currency"])
|
||||||
|
|
||||||
|
# Additional checks if project has no default currency
|
||||||
|
if project.default_currency == CurrencyConverter.no_currency:
|
||||||
|
# If bills have currencies, they must be consistent
|
||||||
|
if len(currencies - {CurrencyConverter.no_currency}) >= 2:
|
||||||
|
raise ValueError(
|
||||||
|
_(
|
||||||
|
"Cannot add bills in multiple currencies to a project without default currency"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Strip currency from bills (since it's the same for every bill)
|
||||||
|
for e in json_file:
|
||||||
|
e["currency"] = CurrencyConverter.no_currency
|
||||||
|
|
||||||
# From json : export list of members
|
# From json : export list of members
|
||||||
members_json = get_members(json_file)
|
members_json = get_members(json_file)
|
||||||
|
@ -505,10 +534,10 @@ def import_project(file, project):
|
||||||
form = get_billform_for(project)
|
form = get_billform_for(project)
|
||||||
form.what = b["what"]
|
form.what = b["what"]
|
||||||
form.amount = b["amount"]
|
form.amount = b["amount"]
|
||||||
|
form.original_currency = b["currency"]
|
||||||
form.date = parse(b["date"])
|
form.date = parse(b["date"])
|
||||||
form.payer = id_dict[b["payer_name"]]
|
form.payer = id_dict[b["payer_name"]]
|
||||||
form.payed_for = owers_id
|
form.payed_for = owers_id
|
||||||
form.original_currency = b.get("original_currency")
|
|
||||||
|
|
||||||
db.session.add(form.fake_form(bill, project))
|
db.session.add(form.fake_form(bill, project))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue