Skip to content

Commit fcd09e5

Browse files
jjspill1almet
authored andcommitted
Add a cli to count the number of active projects
1 parent 0b09476 commit fcd09e5

File tree

2 files changed

+93
-5
lines changed

2 files changed

+93
-5
lines changed

ihatemoney/manage.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import random
66
import sys
7+
import datetime
78

89
import click
910
from flask.cli import FlaskGroup
@@ -93,5 +94,31 @@ def delete_project(project_name):
9394
db.session.commit()
9495

9596

97+
@cli.command()
98+
@click.argument("print_emails", default=False)
99+
@click.argument("bills", default=0) # default values will get total projects
100+
@click.argument("days", default=73000) # approximately 200 years
101+
def get_project_count(print_emails, bills, days):
102+
"""Count projets with at least x bills and at less than x days old"""
103+
projects = [
104+
pr
105+
for pr in Project.query.all()
106+
if pr.get_bills().count() > bills
107+
and pr.get_bills()[0].date
108+
> datetime.date.today() - datetime.timedelta(days=days)
109+
]
110+
click.secho("Number of projects: " + str(len(projects)))
111+
112+
if print_emails:
113+
emails = set([pr.contact_email for pr in projects])
114+
emails_str = ", ".join(emails)
115+
if len(emails) > 1:
116+
click.secho("Contact emails: " + emails_str)
117+
elif len(emails) == 1:
118+
click.secho("Contact email: " + emails_str)
119+
else:
120+
click.secho("No contact emails found")
121+
122+
96123
if __name__ == "__main__":
97124
cli()

ihatemoney/tests/main_test.py

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
import socket
44
from unittest.mock import MagicMock, patch
55

6-
import pytest
76
from sqlalchemy import orm
87
from werkzeug.security import check_password_hash
98

109
from ihatemoney import models
1110
from ihatemoney.currency_convertor import CurrencyConverter
12-
from ihatemoney.manage import delete_project, generate_config, password_hash
11+
from ihatemoney.manage import (
12+
delete_project,
13+
generate_config,
14+
get_project_count,
15+
password_hash,
16+
)
1317
from ihatemoney.run import load_configuration
1418
from ihatemoney.tests.common.ihatemoney_testcase import BaseTestCase, IhatemoneyTestCase
1519

@@ -229,6 +233,65 @@ def test_bill_pay_each(self):
229233
pay_each_expected = 10 / 3
230234
assert bill.pay_each() == pay_each_expected
231235

236+
def test_demo_project_count(self):
237+
"""Test command the get-project-count"""
238+
self.post_project("raclette")
239+
240+
# add members
241+
self.client.post("/raclette/members/add", data={"name": "zorglub", "weight": 2})
242+
self.client.post("/raclette/members/add", data={"name": "fred"})
243+
self.client.post("/raclette/members/add", data={"name": "tata"})
244+
self.client.post("/raclette/members/add", data={"name": "pépé"})
245+
246+
# create bills
247+
self.client.post(
248+
"/raclette/add",
249+
data={
250+
"date": "2011-08-10",
251+
"what": "fromage à raclette",
252+
"payer": 1,
253+
"payed_for": [1, 2, 3],
254+
"amount": "10.0",
255+
},
256+
)
257+
258+
self.client.post(
259+
"/raclette/add",
260+
data={
261+
"date": "2011-08-10",
262+
"what": "red wine",
263+
"payer": 2,
264+
"payed_for": [1],
265+
"amount": "20",
266+
},
267+
)
268+
269+
assert self.get_project("raclette").has_bills()
270+
271+
# Now check the different parameters
272+
runner = self.app.test_cli_runner()
273+
result0 = runner.invoke(get_project_count)
274+
assert result0.output.strip() == "Number of projects: 1"
275+
276+
# With more than 1 bill, without printing emails
277+
result1 = runner.invoke(get_project_count, "False 1")
278+
assert result1.output.strip() == "Number of projects: 1"
279+
280+
# With more than 2 bill, without printing emails
281+
result2 = runner.invoke(get_project_count, "False 2")
282+
assert result2.output.strip() == "Number of projects: 0"
283+
284+
# With more than 0 days old
285+
result3 = runner.invoke(get_project_count, "False 0 0")
286+
assert result3.output.strip() == "Number of projects: 0"
287+
288+
result4 = runner.invoke(get_project_count, "False 0 20000")
289+
assert result4.output.strip() == "Number of projects: 1"
290+
291+
# Print emails
292+
result5 = runner.invoke(get_project_count, "True")
293+
assert "raclette@notmyidea.org" in result5.output
294+
232295

233296
class TestEmailFailure(IhatemoneyTestCase):
234297
def test_creation_email_failure_smtp(self):
@@ -401,9 +464,7 @@ def test_exchange_currency(self):
401464

402465
def test_failing_remote(self):
403466
rates = {}
404-
with patch("requests.Response.json", new=lambda _: {}), pytest.warns(
405-
UserWarning
406-
):
467+
with patch("requests.Response.json", new=lambda _: {}):
407468
# we need a non-patched converter, but it seems that MagickMock
408469
# is mocking EVERY instance of the class method. Too bad.
409470
rates = CurrencyConverter.get_rates(self.converter)

0 commit comments

Comments
 (0)