-
Notifications
You must be signed in to change notification settings - Fork 262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CSV bills import (cospend compatible) #951
Changes from 20 commits
d24efac
e7d991e
61df8aa
12f59f8
ef3b9aa
1765c1b
97729a7
8d9cb82
7a7d0a2
186d42c
9352ad6
ef92181
7d3d669
b38a1c1
030fb37
64ce4cd
99a78f8
946fa3e
edbddab
07f23ce
fbd8c69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
from collections import defaultdict | ||
from datetime import datetime | ||
|
||
from dateutil.parser import parse | ||
from debts import settle | ||
from flask import current_app, g | ||
from flask_sqlalchemy import BaseQuery, SQLAlchemy | ||
|
@@ -19,6 +20,7 @@ | |
|
||
from ihatemoney.currency_convertor import CurrencyConverter | ||
from ihatemoney.patch_sqlalchemy_continuum import PatchedBuilder | ||
from ihatemoney.utils import get_members, same_bill | ||
from ihatemoney.versioning import ( | ||
ConditionalVersioningManager, | ||
LoggingMode, | ||
|
@@ -320,6 +322,42 @@ def switch_currency(self, new_currency): | |
db.session.add(self) | ||
db.session.commit() | ||
|
||
def import_bills(self, bills: list): | ||
"""Import bills from a list of dictionaries""" | ||
# Add members not already in the project | ||
members_project = [str(m) for m in self.members] | ||
members_new = [ | ||
m for m in get_members(bills) if str(m[0]) not in members_project | ||
] | ||
for m in members_new: | ||
Person(name=m[0], project=self, weight=m[1]) | ||
db.session.commit() | ||
|
||
# Import bills not already in the project | ||
bills_project = self.get_pretty_bills() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I follow here: this is named There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I understand. It seems to be the bills of the existing project. If this is the case, we could name it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok ! |
||
id_dict = {m.name: m.id for m in self.members} | ||
for b in bills: | ||
same = False | ||
for b_p in bills_project: | ||
if same_bill(b_p, b): | ||
same = True | ||
break | ||
if not same: | ||
# Create bills | ||
db.session.add( | ||
Bill( | ||
amount=b["amount"], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably should check that the data contains this key before using it, otherwise it may fail. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or we might want to try/catch this entire block and display an error message with the format of the required data. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import_bills is already called from a try/catch block in web.import_project |
||
date=parse(b["date"]), | ||
external_link="", | ||
original_currency=b["currency"], | ||
owers=Person.query.get_by_names(b["owers"], self), | ||
payer_id=id_dict[b["payer_name"]], | ||
project_default_currency=self.default_currency, | ||
what=b["what"], | ||
) | ||
) | ||
db.session.commit() | ||
|
||
def remove_member(self, member_id): | ||
"""Remove a member from the project. | ||
|
||
|
@@ -435,16 +473,17 @@ def create_demo_project(): | |
("Alice", 20, ("Amina", "Alice"), "Beer !"), | ||
("Amina", 50, ("Amina", "Alice", "Georg"), "AMAP"), | ||
) | ||
for (payer, amount, owers, subject) in operations: | ||
bill = Bill() | ||
bill.payer_id = members[payer].id | ||
bill.what = subject | ||
bill.owers = [members[name] for name in owers] | ||
bill.amount = amount | ||
bill.original_currency = "XXX" | ||
bill.converted_amount = amount | ||
|
||
db.session.add(bill) | ||
for (payer, amount, owers, what) in operations: | ||
db.session.add( | ||
Bill( | ||
amount=amount, | ||
original_currency=project.default_currency, | ||
owers=[members[name] for name in owers], | ||
payer_id=members[payer].id, | ||
project_default_currency=project.default_currency, | ||
what=what, | ||
) | ||
) | ||
|
||
db.session.commit() | ||
return project | ||
|
@@ -459,6 +498,13 @@ def get_by_name(self, name, project): | |
.one_or_none() | ||
) | ||
|
||
def get_by_names(self, names, project): | ||
return ( | ||
Person.query.filter(Person.name.in_(names)) | ||
.filter(Person.project_id == project.id) | ||
.all() | ||
) | ||
|
||
def get(self, id, project=None): | ||
if not project: | ||
project = g.project | ||
|
@@ -468,6 +514,15 @@ def get(self, id, project=None): | |
.one_or_none() | ||
) | ||
|
||
def get_by_ids(self, ids, project=None): | ||
if not project: | ||
project = g.project | ||
return ( | ||
Person.query.filter(Person.id.in_(ids)) | ||
.filter(Person.project_id == project.id) | ||
.all() | ||
) | ||
|
||
query_class = PersonQuery | ||
|
||
# Direct SQLAlchemy-Continuum to track changes to this model | ||
|
@@ -561,6 +616,31 @@ def delete(self, project, id): | |
|
||
archive = db.Column(db.Integer, db.ForeignKey("archive.id")) | ||
|
||
currency_helper = CurrencyConverter() | ||
|
||
def __init__( | ||
self, | ||
amount: float, | ||
date: datetime = None, | ||
external_link: str = "", | ||
original_currency: str = "", | ||
owers: list = [], | ||
payer_id: int = None, | ||
project_default_currency: str = "", | ||
what: str = "", | ||
): | ||
super().__init__() | ||
self.amount = amount | ||
self.date = date | ||
self.external_link = external_link | ||
self.original_currency = original_currency | ||
self.owers = owers | ||
self.payer_id = payer_id | ||
self.what = what | ||
self.converted_amount = self.currency_helper.exchange_currency( | ||
self.amount, self.original_currency, project_default_currency | ||
) | ||
|
||
@property | ||
def _to_serialize(self): | ||
return { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be good to also use named parameters here for consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, forgot to include them here, fixed !