diff --git a/ihatemoney/templates/list_bills.html b/ihatemoney/templates/list_bills.html index 79e25262..61e14ea1 100644 --- a/ihatemoney/templates/list_bills.html +++ b/ihatemoney/templates/list_bills.html @@ -94,17 +94,25 @@
{% if bills.pages > 1 %} {% endif %} + +
+ +
+ {{ static_include("images/plus.svg") | safe }} @@ -113,6 +121,40 @@
+
+
+
+ +
+
+
+ {% if bills.total > 0 %} @@ -125,6 +167,7 @@ {% for (weights, bill) in bills.items %} + {% if bill %} + {% endif %} {% endfor %}
diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 37bd811f..681b4af9 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -60,7 +60,8 @@ from ihatemoney.forms import ( get_billform_for, ) from ihatemoney.history import get_history, get_history_queries, purge_history -from ihatemoney.models import Bill, BillType, LoggingMode, Person, Project, db +from ihatemoney.models import Bill, BillType, LoggingMode, Person, Project, billowers, db +from sqlalchemy import func from ihatemoney.utils import ( Redirect303, csv2list_of_dicts, @@ -670,12 +671,55 @@ def list_bills(): ): bill_form.payed_for.data = session["last_selected_payed_for"][g.project.id] - # Each item will be a (weight_sum, Bill) tuple. - # TODO: improve this awkward result using column_property: - # https://docs.sqlalchemy.org/en/14/orm/mapped_sql_expr.html. - weighted_bills = g.project.get_bill_weights_ordered().paginate( - per_page=100, error_out=True - ) + # get filter values + search_query = request.args.get('search', '') + filter_date = request.args.get('date', '') + filter_amount = request.args.get('amount', '') + filter_payer = request.args.get('payer', '') + + filters_active = any([search_query, filter_date, filter_amount, filter_payer]) + + # if no filters active, use standard query + if not filters_active: + weighted_bills = g.project.get_bill_weights_ordered().paginate( + per_page=100, error_out=True + ) + else: + # start with all bills + query = Bill.query.filter(Bill.payer_id == Person.id).filter(Person.project_id == g.project.id) + + # apply filters if there are any + if search_query: + query = query.filter(Bill.what.ilike(f'%{search_query}%')) + + if filter_date: + try: + date_obj = datetime.datetime.strptime(filter_date, '%Y-%m-%d').date() + query = query.filter(Bill.date == date_obj) + except ValueError: + logging.error(f"invalid date format provided: {filter_date}. expected format: YYYY-MM-DD") + + + if filter_amount: + try: + amount = float(filter_amount) + query = query.filter(Bill.amount == amount) + except ValueError: + logging.error(f"invalid amount format provided: {filter_amount}. amount must be a number") + + if filter_payer: + query = query.filter(Bill.payer_id == filter_payer) + + filtered_bill_ids = [bill.id for bill in query.all()] + + # Now get the weighted bills with these IDs + if filtered_bill_ids: + bills_query = g.project.get_bill_weights().filter(Bill.id.in_(filtered_bill_ids)) + bills_query = g.project.order_bills(bills_query) + weighted_bills = bills_query.paginate(per_page=100, error_out=True) + else: + # no bills match the filters + weighted_bills = db.session.query(func.sum(Person.weight), Bill).filter(Bill.id == None).paginate(per_page=100, error_out=True) return render_template( "list_bills.html", @@ -685,6 +729,11 @@ def list_bills(): csrf_form=csrf_form, add_bill=request.values.get("add_bill", False), current_view="list_bills", + search_query=search_query, + filter_date=filter_date, + filter_amount=filter_amount, + filter_payer=filter_payer, + search_active=filters_active, )