import and export bill feature updated with bill type, tests modified to reflect the behavior

This commit is contained in:
Ruitao Li 2022-12-11 21:12:57 -05:00
parent 48d50f7249
commit 4a84ca6d04
11 changed files with 84 additions and 64 deletions

View file

@ -1,5 +1,5 @@
# Verbose and documented settings are in conf-templates/ihatemoney.cfg.j2 # Verbose and documented settings are in conf-templates/ihatemoney.cfg.j2
DEBUG = SQLACHEMY_ECHO = True DEBUG = SQLACHEMY_ECHO = False
SQLALCHEMY_DATABASE_URI = "sqlite:////tmp/ihatemoney.db" SQLALCHEMY_DATABASE_URI = "sqlite:////tmp/ihatemoney.db"
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = "tralala" SECRET_KEY = "tralala"
@ -10,7 +10,7 @@ ADMIN_PASSWORD = ""
ALLOW_PUBLIC_PROJECT_CREATION = True ALLOW_PUBLIC_PROJECT_CREATION = True
ACTIVATE_ADMIN_DASHBOARD = False ACTIVATE_ADMIN_DASHBOARD = False
SESSION_COOKIE_SECURE = False SESSION_COOKIE_SECURE = False
TEMPLATES_AUTO_RELOAD=True TEMPLATES_AUTO_RELOAD = True
SUPPORTED_LANGUAGES = [ SUPPORTED_LANGUAGES = [
"de", "de",
"el", "el",

View file

@ -76,7 +76,7 @@ def get_billform_for(project, set_default=True, **kwargs):
] ]
active_members = [(m.id, m.name) for m in project.active_members] active_members = [(m.id, m.name) for m in project.active_members]
form.bill_type.choices = project.bill_types form.bill_type.choices = project.bill_types
form.payed_for.choices = form.payer.choices = active_members form.payed_for.choices = form.payer.choices = active_members
form.payed_for.default = [m.id for m in project.active_members] form.payed_for.default = [m.id for m in project.active_members]
@ -339,9 +339,7 @@ class BillForm(FlaskForm):
payed_for = SelectMultipleField( payed_for = SelectMultipleField(
_("For Who?"), validators=[DataRequired()], coerce=int _("For Who?"), validators=[DataRequired()], coerce=int
) )
bill_type = SelectField( bill_type = SelectField(_("Bill Type"), validators=[DataRequired()], coerce=str)
_("Bill Type"), validators=[DataRequired()], coerce=str
)
submit = SubmitField(_("Submit")) submit = SubmitField(_("Submit"))
submit2 = SubmitField(_("Submit and add a new one")) submit2 = SubmitField(_("Submit and add a new one"))
@ -355,7 +353,7 @@ class BillForm(FlaskForm):
payer_id=self.payer.data, payer_id=self.payer.data,
project_default_currency=project.default_currency, project_default_currency=project.default_currency,
what=self.what.data, what=self.what.data,
bill_type=self.bill_type.data bill_type=self.bill_type.data,
) )
def save(self, bill, project): def save(self, bill, project):
@ -403,7 +401,7 @@ class BillForm(FlaskForm):
def validate_bill_type(self, field): def validate_bill_type(self, field):
if (field.data, field.data) not in Project.bill_types: if (field.data, field.data) not in Project.bill_types:
raise ValidationError(_("Invalid Bill Type")) raise ValidationError(_("Invalid Bill Type"))
class MemberForm(FlaskForm): class MemberForm(FlaskForm):
name = StringField(_("Name"), validators=[DataRequired()], filters=[strip_filter]) name = StringField(_("Name"), validators=[DataRequired()], filters=[strip_filter])

View file

@ -1,26 +0,0 @@
"""add bill type into bill_version
Revision ID: 3263a8f198b0
Revises: 7a9b38559992
Create Date: 2022-12-10 20:00:48.611280
"""
# revision identifiers, used by Alembic.
revision = '3263a8f198b0'
down_revision = '7a9b38559992'
from alembic import op
import sqlalchemy as sa
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('bill_version', sa.Column('bill_type', sa.UnicodeText(), autoincrement=False, nullable=True))
# ### end Alembic commands ###
def downgrade():
pass
# ### end Alembic commands ###

View file

@ -7,16 +7,16 @@ Create Date: 2022-12-10 17:25:38.387643
""" """
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '7a9b38559992' revision = "7a9b38559992"
down_revision = '927ed575acbd' down_revision = "927ed575acbd"
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
def upgrade(): def upgrade():
op.add_column("bill", sa.Column("bill_type", sa.UnicodeText())) op.add_column("bill", sa.Column("bill_type", sa.UnicodeText()))
op.add_column("bill_version", sa.Column("bill_type", sa.UnicodeText())) op.add_column("bill_version", sa.Column("bill_type", sa.UnicodeText()))
def downgrade(): def downgrade():

View file

@ -74,7 +74,14 @@ class Project(db.Model):
query_class = ProjectQuery query_class = ProjectQuery
default_currency = db.Column(db.String(3)) default_currency = db.Column(db.String(3))
bill_types = [("Expense","Expense"), ("Reimbursment","Reimbursment"), ("Refund","Refund"), ("Transfer","Transfer"), ("Payment","Payment")] bill_types = [
("Expense", "Expense"),
("Reimbursment", "Reimbursment"),
("Refund", "Refund"),
("Transfer", "Transfer"),
("Payment", "Payment"),
]
@property @property
def _to_serialize(self): def _to_serialize(self):
obj = { obj = {
@ -334,6 +341,7 @@ class Project(db.Model):
pretty_bills.append( pretty_bills.append(
{ {
"what": bill.what, "what": bill.what,
"bill_type": bill.bill_type,
"amount": round(bill.amount, 2), "amount": round(bill.amount, 2),
"currency": bill.original_currency, "currency": bill.original_currency,
"date": str(bill.date), "date": str(bill.date),
@ -405,6 +413,7 @@ class Project(db.Model):
new_bill = Bill( new_bill = Bill(
amount=b["amount"], amount=b["amount"],
date=parse(b["date"]), date=parse(b["date"]),
bill_type=b["bill_type"],
external_link="", external_link="",
original_currency=b["currency"], original_currency=b["currency"],
owers=Person.query.get_by_names(b["owers"], self), owers=Person.query.get_by_names(b["owers"], self),
@ -533,14 +542,15 @@ class Project(db.Model):
db.session.commit() db.session.commit()
operations = ( operations = (
("Georg", 200, ("Amina", "Georg", "Alice"), "Food shopping"), ("Georg", 200, ("Amina", "Georg", "Alice"), "Food shopping", "Expense"),
("Alice", 20, ("Amina", "Alice"), "Beer !"), ("Alice", 20, ("Amina", "Alice"), "Beer !", "Expense"),
("Amina", 50, ("Amina", "Alice", "Georg"), "AMAP"), ("Amina", 50, ("Amina", "Alice", "Georg"), "AMAP", "Expense"),
) )
for (payer, amount, owers, what) in operations: for (payer, amount, owers, what, bill_type) in operations:
db.session.add( db.session.add(
Bill( Bill(
amount=amount, amount=amount,
bill_type=bill_type,
original_currency=project.default_currency, original_currency=project.default_currency,
owers=[members[name] for name in owers], owers=[members[name] for name in owers],
payer_id=members[payer].id, payer_id=members[payer].id,

View file

@ -105,6 +105,7 @@
<table id="bill_table" class="col table table-striped table-hover table-responsive-sm"> <table id="bill_table" class="col table table-striped table-hover table-responsive-sm">
<thead> <thead>
<tr><th>{{ _("When?") }} <tr><th>{{ _("When?") }}
</th><th>{{ _("Bill Type") }}
</th><th>{{ _("Who paid?") }} </th><th>{{ _("Who paid?") }}
</th><th>{{ _("For what?") }} </th><th>{{ _("For what?") }}
</th><th>{{ _("For whom?") }} </th><th>{{ _("For whom?") }}
@ -120,6 +121,7 @@
{{ bill.date }} {{ bill.date }}
</span> </span>
</td> </td>
<td>{{ bill.bill_type }}</td>
<td>{{ bill.payer }}</td> <td>{{ bill.payer }}</td>
<td>{{ bill.what }}</td> <td>{{ bill.what }}</td>
<td>{% if bill.owers|length == g.project.members|length -%} <td>{% if bill.owers|length == g.project.members|length -%}

View file

@ -96,7 +96,8 @@ class APITestCase(IhatemoneyTestCase):
self.assertTrue(400, resp.status_code) self.assertTrue(400, resp.status_code)
self.assertEqual( self.assertEqual(
'{"contact_email": ["Invalid email address."]}\n', resp.data.decode("utf-8") "".join('{"contact_email": ["Invalid email address."]}\n'.split()),
"".join(resp.data.decode("utf-8").split()),
) )
# create it # create it
@ -429,7 +430,8 @@ class APITestCase(IhatemoneyTestCase):
self.assertStatus(400, req) self.assertStatus(400, req)
self.assertEqual( self.assertEqual(
'{"date": ["This field is required."]}\n', req.data.decode("utf-8") "".join('{"date": ["This field is required."]}'.split()),
"".join(req.data.decode("utf-8").split()),
) )
# edit a bill # edit a bill

View file

@ -1207,8 +1207,8 @@ class BudgetTestCase(IhatemoneyTestCase):
members = defaultdict(int) members = defaultdict(int)
# We should have the same values between transactions and project balances # We should have the same values between transactions and project balances
for t in transactions: for t in transactions:
members[t["ower"]] -= t["bill_type":"Expense", "amount"] members[t["ower"]] -= t["amount"]
members[t["receiver"]] += t["bill_type":"Expense", "amount"] members[t["receiver"]] += t["amount"]
balance = self.get_project("raclette").balance balance = self.get_project("raclette").balance
for m, a in members.items(): for m, a in members.items():
assert abs(a - balance[m.id]) < 0.01 assert abs(a - balance[m.id]) < 0.01
@ -1263,7 +1263,7 @@ class BudgetTestCase(IhatemoneyTestCase):
# There should not be any zero-amount transfer after rounding # There should not be any zero-amount transfer after rounding
for t in transactions: for t in transactions:
rounded_amount = round(t["bill_type":"Expense", "amount"], 2) rounded_amount = round(t["amount"], 2)
self.assertNotEqual( self.assertNotEqual(
0.0, 0.0,
rounded_amount, rounded_amount,

View file

@ -14,6 +14,7 @@ class CommonTestCase(object):
{ {
"date": "2017-01-01", "date": "2017-01-01",
"what": "refund", "what": "refund",
"bill_type": "Expense",
"amount": 13.33, "amount": 13.33,
"payer_name": "tata", "payer_name": "tata",
"payer_weight": 1.0, "payer_weight": 1.0,
@ -22,6 +23,7 @@ class CommonTestCase(object):
{ {
"date": "2016-12-31", "date": "2016-12-31",
"what": "red wine", "what": "red wine",
"bill_type": "Expense",
"amount": 200.0, "amount": 200.0,
"payer_name": "fred", "payer_name": "fred",
"payer_weight": 1.0, "payer_weight": 1.0,
@ -29,7 +31,8 @@ class CommonTestCase(object):
}, },
{ {
"date": "2016-12-31", "date": "2016-12-31",
"what": "fromage a raclette", "what": "a raclette",
"bill_type": "Expense",
"amount": 10.0, "amount": 10.0,
"payer_name": "zorglub", "payer_name": "zorglub",
"payer_weight": 2.0, "payer_weight": 2.0,
@ -71,6 +74,7 @@ class CommonTestCase(object):
if b["what"] == d["what"]: if b["what"] == d["what"]:
self.assertEqual(b["payer_name"], d["payer_name"]) self.assertEqual(b["payer_name"], d["payer_name"])
self.assertEqual(b["amount"], d["amount"]) self.assertEqual(b["amount"], d["amount"])
self.assertEqual(b["bill_type"], d["bill_type"])
self.assertEqual(b["currency"], d["currency"]) self.assertEqual(b["currency"], d["currency"])
self.assertEqual(b["payer_weight"], d["payer_weight"]) self.assertEqual(b["payer_weight"], d["payer_weight"])
self.assertEqual(b["date"], d["date"]) self.assertEqual(b["date"], d["date"])
@ -114,6 +118,7 @@ class CommonTestCase(object):
self.assertEqual(b["amount"], d["amount"]) self.assertEqual(b["amount"], d["amount"])
# Currency should have been stripped # Currency should have been stripped
self.assertEqual(b["currency"], "XXX") self.assertEqual(b["currency"], "XXX")
self.assertEqual(b["bill_type"], d["bill_type"])
self.assertEqual(b["payer_weight"], d["payer_weight"]) self.assertEqual(b["payer_weight"], d["payer_weight"])
self.assertEqual(b["date"], d["date"]) self.assertEqual(b["date"], d["date"])
list_project = [ower for ower in b["owers"]] list_project = [ower for ower in b["owers"]]
@ -172,6 +177,7 @@ class CommonTestCase(object):
self.assertEqual(b["amount"], d["amount"]) self.assertEqual(b["amount"], d["amount"])
# All bills are converted to default project currency # All bills are converted to default project currency
self.assertEqual(b["currency"], "EUR") self.assertEqual(b["currency"], "EUR")
self.assertEqual(b["bill_type"], d["bill_type"])
self.assertEqual(b["payer_weight"], d["payer_weight"]) self.assertEqual(b["payer_weight"], d["payer_weight"])
self.assertEqual(b["date"], d["date"]) self.assertEqual(b["date"], d["date"])
list_project = [ower for ower in b["owers"]] list_project = [ower for ower in b["owers"]]
@ -210,6 +216,7 @@ class CommonTestCase(object):
if b["what"] == d["what"]: if b["what"] == d["what"]:
self.assertEqual(b["payer_name"], d["payer_name"]) self.assertEqual(b["payer_name"], d["payer_name"])
self.assertEqual(b["amount"], d["amount"]) self.assertEqual(b["amount"], d["amount"])
self.assertEqual(b["bill_type"], d["bill_type"])
self.assertEqual(b["currency"], "XXX") self.assertEqual(b["currency"], "XXX")
self.assertEqual(b["payer_weight"], d["payer_weight"]) self.assertEqual(b["payer_weight"], d["payer_weight"])
self.assertEqual(b["date"], d["date"]) self.assertEqual(b["date"], d["date"])
@ -237,6 +244,7 @@ class CommonTestCase(object):
data={ data={
"date": "2016-12-31", "date": "2016-12-31",
"what": "red wine", "what": "red wine",
"bill_type": "Expense",
"payer": 2, "payer": 2,
"payed_for": [1, 3], "payed_for": [1, 3],
"amount": "200", "amount": "200",
@ -266,6 +274,7 @@ class CommonTestCase(object):
if b["what"] == d["what"]: if b["what"] == d["what"]:
self.assertEqual(b["payer_name"], d["payer_name"]) self.assertEqual(b["payer_name"], d["payer_name"])
self.assertEqual(b["amount"], d["amount"]) self.assertEqual(b["amount"], d["amount"])
self.assertEqual(b["bill_type"], d["bill_type"])
self.assertEqual(b["currency"], d["currency"]) self.assertEqual(b["currency"], d["currency"])
self.assertEqual(b["payer_weight"], d["payer_weight"]) self.assertEqual(b["payer_weight"], d["payer_weight"])
self.assertEqual(b["date"], d["date"]) self.assertEqual(b["date"], d["date"])
@ -292,6 +301,7 @@ class CommonTestCase(object):
{ {
"date": "2017-01-01", "date": "2017-01-01",
"what": "refund", "what": "refund",
"bill_type": "Refund",
"payer_name": "tata", "payer_name": "tata",
"payer_weight": 1.0, "payer_weight": 1.0,
"owers": ["fred"], "owers": ["fred"],
@ -319,7 +329,8 @@ class ExportTestCase(IhatemoneyTestCase):
"/raclette/add", "/raclette/add",
data={ data={
"date": "2016-12-31", "date": "2016-12-31",
"what": "fromage à raclette", "bill_type": "Expense",
"what": "à raclette",
"payer": 1, "payer": 1,
"payed_for": [1, 2, 3, 4], "payed_for": [1, 2, 3, 4],
"amount": "10.0", "amount": "10.0",
@ -330,6 +341,7 @@ class ExportTestCase(IhatemoneyTestCase):
"/raclette/add", "/raclette/add",
data={ data={
"date": "2016-12-31", "date": "2016-12-31",
"bill_type": "Expense",
"what": "red wine", "what": "red wine",
"payer": 2, "payer": 2,
"payed_for": [1, 3], "payed_for": [1, 3],
@ -341,6 +353,7 @@ class ExportTestCase(IhatemoneyTestCase):
"/raclette/add", "/raclette/add",
data={ data={
"date": "2017-01-01", "date": "2017-01-01",
"bill_type": "Refund",
"what": "refund", "what": "refund",
"payer": 3, "payer": 3,
"payed_for": [2], "payed_for": [2],
@ -353,6 +366,7 @@ class ExportTestCase(IhatemoneyTestCase):
expected = [ expected = [
{ {
"date": "2017-01-01", "date": "2017-01-01",
"bill_type": "Refund",
"what": "refund", "what": "refund",
"amount": 13.33, "amount": 13.33,
"currency": "XXX", "currency": "XXX",
@ -362,6 +376,7 @@ class ExportTestCase(IhatemoneyTestCase):
}, },
{ {
"date": "2016-12-31", "date": "2016-12-31",
"bill_type": "Expense",
"what": "red wine", "what": "red wine",
"amount": 200.0, "amount": 200.0,
"currency": "XXX", "currency": "XXX",
@ -371,7 +386,8 @@ class ExportTestCase(IhatemoneyTestCase):
}, },
{ {
"date": "2016-12-31", "date": "2016-12-31",
"what": "fromage \xe0 raclette", "bill_type": "Expense",
"what": "\xe0 raclette",
"amount": 10.0, "amount": 10.0,
"currency": "XXX", "currency": "XXX",
"payer_name": "zorglub", "payer_name": "zorglub",
@ -384,10 +400,10 @@ class ExportTestCase(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,currency,payer_name,payer_weight,owers", "date,what,bill_type,amount,currency,payer_name,payer_weight,owers",
"2017-01-01,refund,XXX,13.33,tata,1.0,fred", "2017-01-01,refund,Refund,XXX,13.33,tata,1.0,fred",
'2016-12-31,red wine,XXX,200.0,fred,1.0,"zorglub, tata"', '2016-12-31,red wine,Expense,XXX,200.0,fred,1.0,"zorglub, tata"',
'2016-12-31,fromage à raclette,10.0,XXX,zorglub,2.0,"zorglub, fred, tata, pépé"', '2016-12-31,à raclette,Expense,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")
@ -450,7 +466,8 @@ class ExportTestCase(IhatemoneyTestCase):
"/raclette/add", "/raclette/add",
data={ data={
"date": "2016-12-31", "date": "2016-12-31",
"what": "fromage à raclette", "what": "à raclette",
"bill_type": "Expense",
"payer": 1, "payer": 1,
"payed_for": [1, 2, 3, 4], "payed_for": [1, 2, 3, 4],
"amount": "10.0", "amount": "10.0",
@ -463,6 +480,7 @@ class ExportTestCase(IhatemoneyTestCase):
data={ data={
"date": "2016-12-31", "date": "2016-12-31",
"what": "poutine from Québec", "what": "poutine from Québec",
"bill_type": "Expense",
"payer": 2, "payer": 2,
"payed_for": [1, 3], "payed_for": [1, 3],
"amount": "100", "amount": "100",
@ -475,6 +493,7 @@ class ExportTestCase(IhatemoneyTestCase):
data={ data={
"date": "2017-01-01", "date": "2017-01-01",
"what": "refund", "what": "refund",
"bill_type": "Refund",
"payer": 3, "payer": 3,
"payed_for": [2], "payed_for": [2],
"amount": "13.33", "amount": "13.33",
@ -488,6 +507,7 @@ class ExportTestCase(IhatemoneyTestCase):
{ {
"date": "2017-01-01", "date": "2017-01-01",
"what": "refund", "what": "refund",
"bill_type": "Refund",
"amount": 13.33, "amount": 13.33,
"currency": "EUR", "currency": "EUR",
"payer_name": "tata", "payer_name": "tata",
@ -497,6 +517,7 @@ class ExportTestCase(IhatemoneyTestCase):
{ {
"date": "2016-12-31", "date": "2016-12-31",
"what": "poutine from Qu\xe9bec", "what": "poutine from Qu\xe9bec",
"bill_type": "Expense",
"amount": 100.0, "amount": 100.0,
"currency": "CAD", "currency": "CAD",
"payer_name": "fred", "payer_name": "fred",
@ -505,7 +526,8 @@ class ExportTestCase(IhatemoneyTestCase):
}, },
{ {
"date": "2016-12-31", "date": "2016-12-31",
"what": "fromage \xe0 raclette", "what": "\xe0 raclette",
"bill_type": "Expense",
"amount": 10.0, "amount": 10.0,
"currency": "EUR", "currency": "EUR",
"payer_name": "zorglub", "payer_name": "zorglub",
@ -518,10 +540,10 @@ class ExportTestCase(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,currency,payer_name,payer_weight,owers", "date,what,bill_type,amount,currency,payer_name,payer_weight,owers",
"2017-01-01,refund,13.33,EUR,tata,1.0,fred", "2017-01-01,refund,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,poutine from Québec,Expense,100.0,CAD,fred,1.0,"zorglub, tata"',
'2016-12-31,fromage à raclette,10.0,EUR,zorglub,2.0,"zorglub, fred, tata, pépé"', '2016-12-31,à raclette,Expense,10.0,EUR,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")
@ -608,6 +630,7 @@ class ExportTestCase(IhatemoneyTestCase):
data={ data={
"date": "2016-12-31", "date": "2016-12-31",
"what": "=COS(36)", "what": "=COS(36)",
"bill_type": "Expense",
"payer": 1, "payer": 1,
"payed_for": [1], "payed_for": [1],
"amount": "10.0", "amount": "10.0",
@ -618,8 +641,8 @@ class ExportTestCase(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,currency,payer_name,payer_weight,owers", "date,what,bill_type,amount,currency,payer_name,payer_weight,owers",
"2016-12-31,'=COS(36),10.0,EUR,zorglub,1.0,zorglub", "2016-12-31,'=COS(36),Expense,10.0,EUR,zorglub,1.0,zorglub",
] ]
received_lines = resp.data.decode("utf-8").split("\n") received_lines = resp.data.decode("utf-8").split("\n")

View file

@ -216,6 +216,7 @@ def csv2list_of_dicts(csv_to_convert):
r["amount"] = float(r["amount"]) r["amount"] = float(r["amount"])
r["payer_weight"] = float(r["payer_weight"]) r["payer_weight"] = float(r["payer_weight"])
r["owers"] = [o.strip() for o in r["owers"].split(",")] r["owers"] = [o.strip() for o in r["owers"].split(",")]
r["bill_type"] = str(r["bill_type"])
result.append(r) result.append(r)
return result return result
@ -299,7 +300,16 @@ def get_members(file):
def same_bill(bill1, bill2): def same_bill(bill1, bill2):
attr = ["what", "payer_name", "payer_weight", "amount", "currency", "date", "owers"] attr = [
"what",
"bill_type",
"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

View file

@ -456,6 +456,7 @@ def import_project():
# Check data # Check data
attr = [ attr = [
"amount", "amount",
"bill_type",
"currency", "currency",
"date", "date",
"owers", "owers",