From aac7d92f7b80a18550781bf612cbec6042939281 Mon Sep 17 00:00:00 2001 From: RepoReader5 Date: Mon, 6 May 2024 15:30:04 -0400 Subject: [PATCH 1/5] Wrote comments briefly explaining about "project_history" and "ip_recording". --- ihatemoney/forms.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index e1ddabe87..fb2aff4f7 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -136,8 +136,15 @@ class EditProjectForm(FlaskForm): description=_("Enter a new code if you want to change it"), ) contact_email = StringField(_("Email"), validators=[DataRequired(), Email()]) + + # Create a checkbox in project settings to enable project history (keeps track of project transactions, + # like adding/settling bills). "Y/N" determines if transaction history is being recorded for the project. project_history = BooleanField(_("Enable project history")) + + # Create a checkbox in project settings to allow for recording source IP address from a given transaction listed + # in project history. "Y/N" determines if an IP address will be attached to a created entry in project history. ip_recording = BooleanField(_("Use IP tracking for project history")) + currency_helper = CurrencyConverter() default_currency = SelectField( _("Default Currency"), From 5e710fb7f93abd6c23f44b47cacdd03a3be953a3 Mon Sep 17 00:00:00 2001 From: Sylvieox Date: Tue, 7 May 2024 04:22:52 -0400 Subject: [PATCH 2/5] Adding filter option for the bills --- docker-compose.yml | 2 +- hatch_build.py | 1 - ihatemoney.db | Bin 0 -> 139264 bytes ihatemoney/conf-templates/ihatemoney.cfg.j2 | 2 +- ihatemoney/default_settings.py | 2 +- ihatemoney/models.py | 89 +++++++++++++++++--- ihatemoney/templates/list_bills.html | 37 ++++++++ ihatemoney/web.py | 60 ++++++++++--- 8 files changed, 165 insertions(+), 28 deletions(-) create mode 100644 ihatemoney.db diff --git a/docker-compose.yml b/docker-compose.yml index df893beb0..cea473503 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,7 +33,7 @@ services: - SECRET_KEY=tralala - SESSION_COOKIE_SECURE=True - SHOW_ADMIN_EMAIL=True - - SQLALCHEMY_DATABASE_URI=sqlite:////database/ihatemoney.db + - SQLALCHEMY_DATABASE_URI=sqlite:///database/ihatemoney.db - SQLALCHEMY_TRACK_MODIFICATIONS=False - APPLICATION_ROOT=/ - ENABLE_CAPTCHA=False diff --git a/hatch_build.py b/hatch_build.py index d536daed0..bedd89b31 100644 --- a/hatch_build.py +++ b/hatch_build.py @@ -1,5 +1,4 @@ import sys - from hatchling.builders.hooks.plugin.interface import BuildHookInterface diff --git a/ihatemoney.db b/ihatemoney.db new file mode 100644 index 0000000000000000000000000000000000000000..b82834f27440f7340613d89af34235315fc82c91 GIT binary patch literal 139264 zcmeI5Uu+x6eaH6?$t9^j<2zg4(2chEUV2WpzP$WK>N~{y!0XHlaULOhafNc(|ZXDG(dp{?V;%5&_1M>rn!TGHrHH$ zc4q&OoLy2pyG~BleOKagcjh;{&F~6yfIg(>Dp?!vXQN6QQ?pvio(m9CI~`= zzDDRPKwlz#oue-gec1vlwha|>^Jsgy`QX0o3nANRl8_m$w`-i6>V{on2F_YW)I zPzJmo_Pp)A=J~egsPs+w9VsY&S@@Ok7X5P`7YBXnjnkq~DCPBg)i;V%_e^%HRyOW4 zo0amH^js}-SFcnHaCouaqbllrNUWbV0u=6LHmN9;v_sS?*-|x|tFh39Jn#9! zOgfoZN@}yI%gJS}TUc!&rSajlF+TQCz31rO+LUPoSwolF&Zf@CrgqVW58F-~ULsUi z2Nd-tWpl9u8@-gz@G0OmI@(1ecldT%xurt8k;94_3W*Pn*Rm@`2M1nBl?u-@;*mgp_UrnTEzL-dl#V10{reZU433r7tf3JY1sW5ED(q_w4O!%Omb1PoLLh|o5cD>zoH&L zF7D1Y4995FnAI2;0WNtB=Qed5%X(MU#vEIfGOUq4xm6?PW~k#7Zp6lk+lUSQdwqhc z4h)F*?-=^~Uho;+;{@@kH_vx!=^LrAtv?fXIUVY~D)?DklR=;Q%IIEE@v+!(-Z zg55KU!c=_lQUfu2n%@O>FROXnGRT!SSGj6eLfaR~ZboKB&1I1NIA&q4EVUBC1>kbD z9``Eh(2%%0W8ktPv)+6hw8n!v*Il2iv~^46Co4)PWm9phOKv{e3hLn$ZmgB5PoEZd17>y<^^KK6&NlKae=BjRba*oJw#SsEt&N7N(MX6(_RK8c19L7i3Ngfc{#vC&H{GV?6hXVva00ck)1V8`;KmY_l z00ck)1VG>b6EN5R-xkQ_lbvxB9ZaP#M$xK+40H5eByfZF0#D5oLs)1Of4p(QZN1az2QMKgnXnabV=7M z+Hmv!NHfqEL>fpMK1BmbhleELCrzm<<#JxDu9r7A3#GNDv+$EaBiNs?tD zfbo9=3@$(b1V8`;KmY_l00ck)1V8`;K;Qro@W_5P{`a%-zuy}Fe_-wZe}IySq<{bj zfB*=900@8p2!H?xfB*=9z-O0$`C9&s+009sH0T2KI5C8!X009sH0TB4K2?YE;`XzqB&px_Wd~~ltb{X)QjxxRUT9?${ zWBSu8*%x4e=#^w%NwOmP0xY!g{eM6Co*9sm2; z_}|aQ|9&?9_p|Z8bN@d-`Fm^sKk`2P^#5PTKT-!AAOHd&00JNY0w4eaAOHd&00JNY z0{fSMvA3V!I4j24XPmvp*<+k#Jp-rex57gK!GD-- zyT@LoYORv370RW}l{@*>$c5^9HWG_ph>x@5({RBOkdKkZ=VcLuTI2s zlhN2jG%_(h6^+FwqtV<%T#rV_bJ3~%WH?VRR;O2{CZq9KB({81^WEo6%KhG3Z##Gzwaylw|o2j!^$_5f#CbWzwZ5~{;Ka!y;p(- z&qL3*Jx8T)%I`=)@yo)mgtzFQ^SC(ZQ*WFWg+eK>->be+EY$Q&cB@u4?lYT}@|W~n zEpu0|RO!q|ChTx{vEHL9>U>D7pEUv$?zLNy(DTr@`c$8>N!6j+*jmwfnNl^IV{+0=PY zwTm`<*mm0R5}~>}pr|(~|BE(%{(%|2ly{_&7dYBQBX{_ATDhe{Jr6x^sG*Sf;CL;& zQgm?ObvR<_u*BxKT>OK9LY`*dQu1mtt)&*0wA9VHxieZYVA~?~el?Mv`C=kH7M}<) zpHg;1*OrpYOYCM_FRZQCv@3H93FDp_%H3>D&uf=%%iASb>E;riIqk=av0uWVG53 z)#W}#ogEeHqpjw@hvnN|{q2n2_UvHqwl`<$rWU<>X~9<$tmN1+_3fzzAI>gyc35qU z_Yc)ckD}h7EMje0xT~^OO?vm##2wbHjaw$vdsR53j*f~C-ZYwnmHQ_G3cLS$z`SoE z(W*<((#32VT79&!&J9C$N3YP#Xsw^K8|AH1ODmA4Er52J_6%6%ovY|(i_N)iuV-tG zRz$y7(<`NHF;gs*?lfGpmE3yauHO0}zD~D&xKifEV~c&VmLyj$(XJ0|!7_ZR%9X+z z{duTjCbw0o=%w6Fqg{;BX3>Dhx+D$lf5+`ng80;%=Q}lKOdY;$3cH*R?T+*->iP5H z{c6KXxG=5|#APp>JTn@DL(@38oUvNe4!*yKtPKXZOtEx5V|R+$b{ZywKJ}H+y*S(T zM8-gD-}UrQ3V*@I1G{GwMI9IrAH39{%pUA_v3#0kjw@YOIjWyHq^P%P4`#Nt+TwDs zO^4QH1kbgrz`Dg^*J7NUHs&s?p?ch_s6#{I?u>!U(%pLVanS7gVUN1X8ew(m#Bx?a z8#`7}Tv@ucsRuy z0gXzQcCYK|b6wkgz7cX|%k$l{g^!^_mheKMdPr2%)2GEEr-goTSqPpC{AJH+9?&gg0 zm9Z(*Ha0U&qiXBQS6S^twrK-cX<}9X{m~JlBK-PUt|C-8qZwg3jC809xy(=8Tw0h- z(ZKV`lri+&eB6#nyGpXPuh72Z(yp)aBz*?$a`H;z=G>BYimo|1)!Kuw$J^m(s40|O zzMf1iCaIvKZn9F%*G$G()~J}A@>ZqEi8m@zqawRL>|-VVmXS-=q*YaaV~h5AbjPii z%R7hX7@H_KLqmo5_FcdF)M1%hK|&SKCh@JPKb4LaMRLHY`N5U zdM!RC!D@Aj_2_HHsAOq&-WZv5=!sV7Bruz(&F3o(5V3Isq&vBF@;OCaI4#!0cCX6H zIlGN?jBy>l$1S~^GpLq<+D%(aO4y)_O`-AY@?f#yjFW)=eWmbX$#hkx+f; zMMZs$GD>t}%A36%8 zi?_eZ=3BmY+u*^*6YPayhK-Etwm$XIL;Vj=DC+U!;_iF{zcK047+dnANMpQb2pIh| zCgqr0wyODNU(Gq9vBGd88s^q^_|u4u6E|J0i5zqN|8ME<|2>-{d}s{)A*wejz^2j+0aQ`PVAzv#(#fwljT6zrKAkJiR&* z&rL>S6Vb@T_*66&pNvLx6LCEn9nVFl@{{2_y;z-InVO8oW0BZOKD?4!%|;`U_(XU$ z8fTAuxm2!g>=g2P_FTELmNa*_rkf<1-~azepg-t<0|Y<-1V8`;KmY_l00ck)1V8`; PK;VE8P~?FCn-};$cuB#` literal 0 HcmV?d00001 diff --git a/ihatemoney/conf-templates/ihatemoney.cfg.j2 b/ihatemoney/conf-templates/ihatemoney.cfg.j2 index ba4793dad..72e91973b 100644 --- a/ihatemoney/conf-templates/ihatemoney.cfg.j2 +++ b/ihatemoney/conf-templates/ihatemoney.cfg.j2 @@ -8,7 +8,7 @@ DEBUG = False # The database URI, reprensenting the type of database and how to connect to it. # Enter an absolute path here. -SQLALCHEMY_DATABASE_URI = 'sqlite:////var/lib/ihatemoney/ihatemoney.sqlite' +SQLALCHEMY_DATABASE_URI = 'sqlite:///var/lib/ihatemoney/ihatemoney.sqlite' SQLACHEMY_ECHO = DEBUG # Will likely become the default value in flask-sqlalchemy >=3 ; could be removed diff --git a/ihatemoney/default_settings.py b/ihatemoney/default_settings.py index 48112afb2..b477462e5 100644 --- a/ihatemoney/default_settings.py +++ b/ihatemoney/default_settings.py @@ -1,6 +1,6 @@ # Verbose and documented settings are in conf-templates/ihatemoney.cfg.j2 DEBUG = SQLACHEMY_ECHO = False -SQLALCHEMY_DATABASE_URI = "sqlite:////tmp/ihatemoney.db" +SQLALCHEMY_DATABASE_URI = "sqlite:///C:/Users/sylvie c/Documents/GitHub/ihatemoney/ihatemoney.db" SQLALCHEMY_TRACK_MODIFICATIONS = False SECRET_KEY = "tralala" MAIL_DEFAULT_SENDER = "Budget manager " diff --git a/ihatemoney/models.py b/ihatemoney/models.py index c591b85b6..4228edea6 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -133,7 +133,7 @@ def full_balance(self): should_receive[bill.payer.id] += bill.converted_amount for ower in bill.owers: should_pay[ower.id] += ( - ower.weight * bill.converted_amount / total_weight + ower.weight * bill.converted_amount / total_weight ) if bill.bill_type == BillType.REIMBURSEMENT: @@ -264,6 +264,51 @@ def order_bills(query): .order_by(Bill.id.desc()) ) + @staticmethod + def filter_by_date(query, start_date=None, end_date=None): + if start_date and end_date: + return query.filter(Bill.date.between(start_date, end_date)) + else: + return query + + @staticmethod + def filter_by_paid_by(query, paid_by=None): + if paid_by: + return query.filter(Bill.payer.has(paid_by)) + else: + return query + + @staticmethod + def filter_by_for_what(query, for_what=None): + if for_what: + return query.filter(Bill.what.has(for_what)) + else: + return query + + @staticmethod + def filter_by_for_whom(query, for_whom=None): + if for_whom: + return query.filter(Bill.payed_for.has(for_whom)) + else: + return query + + @staticmethod + def filter_by_how_much(query, how_much=None): + if how_much is not None: + return query.filter(Bill.amount.has(how_much)) + else: + return query + + @staticmethod + def apply_filters(self, query, **kwargs): + filtered_query = query + filtered_query = self.filter_by_date(filtered_query, kwargs.get('start_date'), kwargs.get('end_date')) + filtered_query = self.filter_by_paid_by(filtered_query, kwargs.get('paid_by')) + filtered_query = self.filter_by_for_what(filtered_query, kwargs.get('for_what')) + filtered_query = self.filter_by_for_whom(filtered_query, kwargs.get('for_whom')) + filtered_query = self.filter_by_how_much(filtered_query, kwargs.get('how_much')) + return filtered_query + def get_bill_weights(self): """ Return all bills for this project, along with the sum of weight for each bill. @@ -285,6 +330,28 @@ def get_bill_weights_ordered(self): """Ordered version of get_bill_weights""" return self.order_bills(self.get_bill_weights()) + def get_filtered_bill_weights_ordered(self, start_date=None, end_date=None, paid_by=None, for_what=None, + for_whom=None, + how_much=None): + query = self.get_bill_weights_ordered() + + if start_date and end_date: + query = self.filter_by_date(query, start_date, end_date) + + if paid_by: + query = self.filter_by_paid_by(query, paid_by) + + if for_what: + query = self.filter_by_for_what(query, for_what) + + if for_whom: + query = self.filter_by_for_whom(query, for_whom) + + if how_much is not None: + query = self.filter_by_how_much(query, how_much) + + return query + def get_member_bills(self, member_id): """Return the list of bills related to a specific member""" return ( @@ -697,16 +764,16 @@ def delete(self, project, id): currency_helper = CurrencyConverter() def __init__( - self, - amount: float, - date: datetime.datetime = None, - external_link: str = "", - original_currency: str = "", - owers: list = [], - payer_id: int = None, - project_default_currency: str = "", - what: str = "", - bill_type: str = "Expense", + self, + amount: float, + date: datetime.datetime = None, + external_link: str = "", + original_currency: str = "", + owers: list = [], + payer_id: int = None, + project_default_currency: str = "", + what: str = "", + bill_type: str = "Expense", ): super().__init__() self.amount = amount diff --git a/ihatemoney/templates/list_bills.html b/ihatemoney/templates/list_bills.html index 79e252625..f151bc86a 100644 --- a/ihatemoney/templates/list_bills.html +++ b/ihatemoney/templates/list_bills.html @@ -105,6 +105,43 @@
  • {{ _("Older bills") }} »
  • {% endif %} +
    + {{ csrf_form.csrf_token }} + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + + +
    + + {{ static_include("images/plus.svg") | safe }} diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 0d0bdd201..5005e43c0 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -642,7 +642,7 @@ def invite(): return render_template("send_invites.html", form=form, qrcode=qrcode_svg) -@main.route("//") +@main.route("//", methods=["GET", "POST"]) def list_bills(): bill_form = get_billform_for(g.project) # Used for CSRF validation @@ -666,19 +666,53 @@ def list_bills(): # 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 - ) + if request.method == "GET": + weighted_bills = g.project.get_bill_weights_ordered().paginate( + per_page=100, error_out=True + ) + return render_template( + "list_bills.html", + bills=weighted_bills, + member_form=MemberForm(g.project), + bill_form=bill_form, + csrf_form=csrf_form, + add_bill=request.values.get("add_bill", False), + current_view="list_bills", + ) + + if request.method == "POST": + start_date = request.form.get('start_date', None) + end_date = request.form.get('end_date', None) + paid_by = request.form.get('paid_by', None) + for_what = request.form.get('for_what', None) + for_whom = request.form.get('for_whom', None) + how_much = request.form.get('how_much', None) + + weighted_bills = g.project.get_filtered_bill_weights_ordered( + start_date=start_date, + end_date=end_date, + paid_by=paid_by, + for_what=for_what, + for_whom=for_whom, + how_much=how_much + ).paginate(per_page=100, error_out=True) + + return render_template( + "list_bills.html", + bills=weighted_bills, + member_form=MemberForm(g.project), + bill_form=bill_form, + csrf_form=csrf_form, + add_bill=request.values.get("add_bill", False), + current_view="list_bills", + start_date=start_date, + end_date=end_date, + paid_by=paid_by, + for_what=for_what, + for_whom=for_whom, + how_much=how_much + ) - return render_template( - "list_bills.html", - bills=weighted_bills, - member_form=MemberForm(g.project), - bill_form=bill_form, - csrf_form=csrf_form, - add_bill=request.values.get("add_bill", False), - current_view="list_bills", - ) @main.route("//members/add", methods=["GET", "POST"]) From 5578e9ddad958b689fccee96f2b64f84d09bf203 Mon Sep 17 00:00:00 2001 From: Sylvieox Date: Tue, 7 May 2024 04:31:04 -0400 Subject: [PATCH 3/5] in models.py I used the has method and added id= so it can function properly --- ihatemoney/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ihatemoney/models.py b/ihatemoney/models.py index 4228edea6..f0ea956cb 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -274,28 +274,28 @@ def filter_by_date(query, start_date=None, end_date=None): @staticmethod def filter_by_paid_by(query, paid_by=None): if paid_by: - return query.filter(Bill.payer.has(paid_by)) + return query.filter(Bill.payer.has(id=paid_by)) else: return query @staticmethod def filter_by_for_what(query, for_what=None): if for_what: - return query.filter(Bill.what.has(for_what)) + return query.filter(Bill.what.has(id=for_what)) else: return query @staticmethod def filter_by_for_whom(query, for_whom=None): if for_whom: - return query.filter(Bill.payed_for.has(for_whom)) + return query.filter(Bill.payed_for.has(id=for_whom)) else: return query @staticmethod def filter_by_how_much(query, how_much=None): if how_much is not None: - return query.filter(Bill.amount.has(how_much)) + return query.filter(Bill.amount.has(id=how_much)) else: return query From 417e14445531520e439ebbf2715b86b01dc97fc3 Mon Sep 17 00:00:00 2001 From: Sylvieox Date: Tue, 7 May 2024 05:59:54 -0400 Subject: [PATCH 4/5] Have filter by date running properly --- ihatemoney/models.py | 89 ++++++---------------------- ihatemoney/templates/list_bills.html | 34 ++--------- ihatemoney/web.py | 57 ++++++------------ 3 files changed, 38 insertions(+), 142 deletions(-) diff --git a/ihatemoney/models.py b/ihatemoney/models.py index f0ea956cb..fb0db6737 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -133,7 +133,7 @@ def full_balance(self): should_receive[bill.payer.id] += bill.converted_amount for ower in bill.owers: should_pay[ower.id] += ( - ower.weight * bill.converted_amount / total_weight + ower.weight * bill.converted_amount / total_weight ) if bill.bill_type == BillType.REIMBURSEMENT: @@ -265,50 +265,12 @@ def order_bills(query): ) @staticmethod - def filter_by_date(query, start_date=None, end_date=None): + def filter_by_date(query, start_date, end_date): if start_date and end_date: - return query.filter(Bill.date.between(start_date, end_date)) + return query.filter(Bill.date >= start_date, Bill.date <= end_date) else: return query - @staticmethod - def filter_by_paid_by(query, paid_by=None): - if paid_by: - return query.filter(Bill.payer.has(id=paid_by)) - else: - return query - - @staticmethod - def filter_by_for_what(query, for_what=None): - if for_what: - return query.filter(Bill.what.has(id=for_what)) - else: - return query - - @staticmethod - def filter_by_for_whom(query, for_whom=None): - if for_whom: - return query.filter(Bill.payed_for.has(id=for_whom)) - else: - return query - - @staticmethod - def filter_by_how_much(query, how_much=None): - if how_much is not None: - return query.filter(Bill.amount.has(id=how_much)) - else: - return query - - @staticmethod - def apply_filters(self, query, **kwargs): - filtered_query = query - filtered_query = self.filter_by_date(filtered_query, kwargs.get('start_date'), kwargs.get('end_date')) - filtered_query = self.filter_by_paid_by(filtered_query, kwargs.get('paid_by')) - filtered_query = self.filter_by_for_what(filtered_query, kwargs.get('for_what')) - filtered_query = self.filter_by_for_whom(filtered_query, kwargs.get('for_whom')) - filtered_query = self.filter_by_how_much(filtered_query, kwargs.get('how_much')) - return filtered_query - def get_bill_weights(self): """ Return all bills for this project, along with the sum of weight for each bill. @@ -330,27 +292,10 @@ def get_bill_weights_ordered(self): """Ordered version of get_bill_weights""" return self.order_bills(self.get_bill_weights()) - def get_filtered_bill_weights_ordered(self, start_date=None, end_date=None, paid_by=None, for_what=None, - for_whom=None, - how_much=None): - query = self.get_bill_weights_ordered() - - if start_date and end_date: - query = self.filter_by_date(query, start_date, end_date) - - if paid_by: - query = self.filter_by_paid_by(query, paid_by) - - if for_what: - query = self.filter_by_for_what(query, for_what) - - if for_whom: - query = self.filter_by_for_whom(query, for_whom) - - if how_much is not None: - query = self.filter_by_how_much(query, how_much) - - return query + def get_filtered_date_bill_weights_ordered(self, start_date, end_date): + bill_weights_ordered = self.get_bill_weights_ordered() + filtered_bill_weights = self.filter_by_date(bill_weights_ordered, start_date, end_date) + return filtered_bill_weights def get_member_bills(self, member_id): """Return the list of bills related to a specific member""" @@ -764,16 +709,16 @@ def delete(self, project, id): currency_helper = CurrencyConverter() def __init__( - self, - amount: float, - date: datetime.datetime = None, - external_link: str = "", - original_currency: str = "", - owers: list = [], - payer_id: int = None, - project_default_currency: str = "", - what: str = "", - bill_type: str = "Expense", + self, + amount: float, + date: datetime.datetime = None, + external_link: str = "", + original_currency: str = "", + owers: list = [], + payer_id: int = None, + project_default_currency: str = "", + what: str = "", + bill_type: str = "Expense", ): super().__init__() self.amount = amount diff --git a/ihatemoney/templates/list_bills.html b/ihatemoney/templates/list_bills.html index f151bc86a..0ae8b8afe 100644 --- a/ihatemoney/templates/list_bills.html +++ b/ihatemoney/templates/list_bills.html @@ -107,41 +107,15 @@ {% endif %}
    {{ csrf_form.csrf_token }} + + -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    + +
    -
    {{ static_include("images/plus.svg") | safe }} diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 5005e43c0..7263793b6 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -670,50 +670,27 @@ def list_bills(): weighted_bills = g.project.get_bill_weights_ordered().paginate( per_page=100, error_out=True ) - return render_template( - "list_bills.html", - bills=weighted_bills, - member_form=MemberForm(g.project), - bill_form=bill_form, - csrf_form=csrf_form, - add_bill=request.values.get("add_bill", False), - current_view="list_bills", - ) + elif request.method == "POST": + # Retrieve start_date and end_date from form data + start_date = request.form.get('start_date') + end_date = request.form.get('end_date') - if request.method == "POST": - start_date = request.form.get('start_date', None) - end_date = request.form.get('end_date', None) - paid_by = request.form.get('paid_by', None) - for_what = request.form.get('for_what', None) - for_whom = request.form.get('for_whom', None) - how_much = request.form.get('how_much', None) - - weighted_bills = g.project.get_filtered_bill_weights_ordered( - start_date=start_date, - end_date=end_date, - paid_by=paid_by, - for_what=for_what, - for_whom=for_whom, - how_much=how_much - ).paginate(per_page=100, error_out=True) - return render_template( - "list_bills.html", - bills=weighted_bills, - member_form=MemberForm(g.project), - bill_form=bill_form, - csrf_form=csrf_form, - add_bill=request.values.get("add_bill", False), - current_view="list_bills", - start_date=start_date, - end_date=end_date, - paid_by=paid_by, - for_what=for_what, - for_whom=for_whom, - how_much=how_much + weighted_bills = g.project.get_filtered_date_bill_weights_ordered(start_date, end_date).paginate( + per_page=100, error_out=True ) - + return render_template( + "list_bills.html", + bills=weighted_bills, + member_form=MemberForm(g.project), + bill_form=bill_form, + csrf_form=csrf_form, + add_bill=request.values.get("add_bill", False), + current_view="list_bills", + start_date=start_date if request.method == "POST" else None, + end_date=end_date if request.method == "POST" else None, + ) @main.route("//members/add", methods=["GET", "POST"]) def add_member(): From dce7bd78159fa159b9a7ce115ed100ea06abff2b Mon Sep 17 00:00:00 2001 From: Sylvieox Date: Tue, 7 May 2024 10:34:58 -0400 Subject: [PATCH 5/5] Have filter by date running properly --- ihatemoney.db | Bin 139264 -> 139264 bytes ihatemoney/models.py | 11 +++---- ihatemoney/templates/list_bills.html | 10 +++---- ihatemoney/tests/filterbydate_test.py | 41 ++++++++++++++++++++++++++ ihatemoney/web.py | 29 ++++++++++-------- 5 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 ihatemoney/tests/filterbydate_test.py diff --git a/ihatemoney.db b/ihatemoney.db index b82834f27440f7340613d89af34235315fc82c91..00c32ee670299b49317532077ed7f2895bb06d51 100644 GIT binary patch delta 583 zcmaiwy-Pw-7{<@RqumqAW0Xc2rK3c3yEhBnA{;Ft2%*IxTJ1l`p(zLogT@+KT5eRs zrG~Itq97=Ykmv&&`hbfOMDzjnDxnQQ<9Xj7zvq2UI;*6!%Dj*33vEMO-$*WxaIqN| zZl^$yVIOlCM{ujb-2zP&P9}N4!vZee=xfqct*=WBb*b89Dm77k4KyVZiD)7o9UhHl z##3uvi9?1@yrPIl6mW@ioZyg@1{^}#xD;C_)BWW@FT*Zo5QCSt4h)0@I0XhgF2nZr#g&1V4_SybkHKO)LG`(9>!~Nlqxl-au|2JS5 Bra1rr delta 292 zcmaLSF-yZx6o%n@X@=nPw$M#McZWg?t_scojc5 diff --git a/ihatemoney/models.py b/ihatemoney/models.py index fb0db6737..4513b3e79 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -265,12 +265,13 @@ def order_bills(query): ) @staticmethod - def filter_by_date(query, start_date, end_date): - if start_date and end_date: - return query.filter(Bill.date >= start_date, Bill.date <= end_date) + def filter_by_date(query, start, end): + if start and end: + return query.filter(Bill.date.between(start, end)) else: return query + def get_bill_weights(self): """ Return all bills for this project, along with the sum of weight for each bill. @@ -292,9 +293,9 @@ def get_bill_weights_ordered(self): """Ordered version of get_bill_weights""" return self.order_bills(self.get_bill_weights()) - def get_filtered_date_bill_weights_ordered(self, start_date, end_date): + def get_filtered_date_bill_weights_ordered(self, start, end): bill_weights_ordered = self.get_bill_weights_ordered() - filtered_bill_weights = self.filter_by_date(bill_weights_ordered, start_date, end_date) + filtered_bill_weights = self.filter_by_date(bill_weights_ordered, start,end ) return filtered_bill_weights def get_member_bills(self, member_id): diff --git a/ihatemoney/templates/list_bills.html b/ihatemoney/templates/list_bills.html index 0ae8b8afe..545e11487 100644 --- a/ihatemoney/templates/list_bills.html +++ b/ihatemoney/templates/list_bills.html @@ -107,12 +107,10 @@ {% endif %}
    {{ csrf_form.csrf_token }} - - - - - - + + + +
    diff --git a/ihatemoney/tests/filterbydate_test.py b/ihatemoney/tests/filterbydate_test.py new file mode 100644 index 000000000..917326574 --- /dev/null +++ b/ihatemoney/tests/filterbydate_test.py @@ -0,0 +1,41 @@ +import pytest +from unittest.mock import Mock +from ihatemoney.models import Project, Bill + + +@pytest.fixture +def test_filter_by_date(Project): + # Prepare mock data + mock_query = Mock() + start_date = '2024-01-01' + end_date = '2024-12-31' + + # Mock the methods being called inside filter_by_date + Project.query.filter.return_value = Mock() # Assuming you're using SQLAlchemy's Query object + + # Call the method to test + result = Project.filter_by_date(mock_query, start_date, end_date) + + # Assertions + assert result == Project.query.filter.return_value # Check if the method returns the expected result + Project.query.filter.assert_called_once_with(Bill.date >= start_date, + Bill.date <= end_date) # Check if filter was called with the correct arguments + + +def test_get_filtered_date_bill_weights_ordered(Project): + # Prepare mock data + start_date = '2024-01-01' + end_date = '2024-12-31' + + + Project.get_bill_weights_ordered.return_value = Mock() + Project.filter_by_date.return_value = Mock() + + # Call the method to test + result = Project.get_filtered_date_bill_weights_ordered(start_date, end_date) + + # Assertions + assert result == Project.filter_by_date.return_value # Check if the method returns the expected result + Project.filter_by_date.assert_called_once_with( + Project.get_bill_weights_ordered.return_value, start_date, + end_date) # Check if filter_by_date was called with the correct arguments diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 7263793b6..4ee713854 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -130,8 +130,8 @@ def set_show_admin_dashboard_link(endpoint, values): """ g.show_admin_dashboard_link = ( - current_app.config["ACTIVATE_ADMIN_DASHBOARD"] - and current_app.config["ADMIN_PASSWORD"] + current_app.config["ACTIVATE_ADMIN_DASHBOARD"] + and current_app.config["ADMIN_PASSWORD"] ) g.logout_form = LogoutForm() @@ -199,7 +199,7 @@ def admin(): if request.method == "POST" and form.validate(): # Valid password if check_password_hash( - current_app.config["ADMIN_PASSWORD"], form.admin_password.data + current_app.config["ADMIN_PASSWORD"], form.admin_password.data ): session["is_admin"] = True session.update() @@ -658,28 +658,31 @@ def list_bills(): if "last_selected_payer" in session: bill_form.payer.data = session["last_selected_payer"] if ( - "last_selected_payed_for" in session - and g.project.id in session["last_selected_payed_for"] + "last_selected_payed_for" in session + and g.project.id in session["last_selected_payed_for"] ): 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. + if request.method == "GET": + # Retrieve ordered bill weights for the project weighted_bills = g.project.get_bill_weights_ordered().paginate( per_page=100, error_out=True ) elif request.method == "POST": # Retrieve start_date and end_date from form data - start_date = request.form.get('start_date') - end_date = request.form.get('end_date') - + start = request.form.get('start') + end = request.form.get('end') - weighted_bills = g.project.get_filtered_date_bill_weights_ordered(start_date, end_date).paginate( + # Retrieve filtered bill weights by date + weighted_bills = g.project.get_filtered_date_bill_weights_ordered(start, end).paginate( per_page=100, error_out=True ) + # Render the template with the appropriate data return render_template( "list_bills.html", bills=weighted_bills, @@ -688,8 +691,8 @@ def list_bills(): csrf_form=csrf_form, add_bill=request.values.get("add_bill", False), current_view="list_bills", - start_date=start_date if request.method == "POST" else None, - end_date=end_date if request.method == "POST" else None, + start=start if request.method == "POST" else None, + end=end if request.method == "POST" else None, ) @main.route("//members/add", methods=["GET", "POST"]) @@ -985,8 +988,8 @@ def feed(token): return "", 304 if ( - request.if_modified_since - and request.if_modified_since.replace(tzinfo=None) >= last_modified + request.if_modified_since + and request.if_modified_since.replace(tzinfo=None) >= last_modified ): return "", 304