From 7437ea8dfc99b82801648d374679e26963669e66 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sat, 9 Nov 2024 00:59:48 +0800 Subject: [PATCH 01/19] feat(InvoicesServices: implemented a get invoice and delete invoice function --- example/list_clients.py | 2 +- .../__pycache__/__init__.cpython-312.pyc | Bin 254 -> 303 bytes .../__pycache__/base_service.cpython-312.pyc | Bin 586 -> 635 bytes myfinances/__pycache__/client.cpython-312.pyc | Bin 2428 -> 2477 bytes myfinances/__pycache__/models.cpython-312.pyc | Bin 2130 -> 2179 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 371 -> 420 bytes .../__pycache__/models.cpython-312.pyc | Bin 1337 -> 1386 bytes .../__pycache__/service.cpython-312.pyc | Bin 2128 -> 2177 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 598 -> 647 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 380 -> 429 bytes .../__pycache__/models.cpython-312.pyc | Bin 1282 -> 1331 bytes .../__pycache__/service.cpython-312.pyc | Bin 1537 -> 1586 bytes myfinances/finance/invoices/service.py | 9 +++++++++ 13 files changed, 10 insertions(+), 1 deletion(-) diff --git a/example/list_clients.py b/example/list_clients.py index ddfe04f..36290d9 100644 --- a/example/list_clients.py +++ b/example/list_clients.py @@ -19,4 +19,4 @@ def main(): print(response.json()) if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/myfinances/__pycache__/__init__.cpython-312.pyc b/myfinances/__pycache__/__init__.cpython-312.pyc index aefcbdc0c1d156e0f3cd5265e15573cdc4c10079..430180ffc54d36ba724c45f5ac0914fc99364179 100644 GIT binary patch delta 82 zcmeyzxSomoG%qg~0}vcH(woTLXPxY96%$&VT2vh4m6)4atl(IjnUfzAoL^d$oEj69 gT998H;~C%|9OGY*nimfdjt?lx&q_@$nYcI_09U;oH2?qr delta 33 ncmZ3_^pBDIG%qg~0}$+5EH{z6kITr_DkeNN$tAUH;+1Fsp1KNT diff --git a/myfinances/__pycache__/base_service.cpython-312.pyc b/myfinances/__pycache__/base_service.cpython-312.pyc index f386527ee171742203d3d2cdff954b4bc3b7defb..3468d134821479aa03f3ab258120e28c702ace1a 100644 GIT binary patch delta 85 zcmX@b@|%VGG%qg~0}vcH(%Z-_&uE?QY!wq)oLW>Ii?iv=8b delta 36 qcmey(a*BofG%qg~0}wQPQ{Tuf&&XxwY84Znn&gsNwmFqij1d61_zB4X diff --git a/myfinances/__pycache__/client.cpython-312.pyc b/myfinances/__pycache__/client.cpython-312.pyc index 498d5904e1933487995f112f7a79e483237e1396..e8f839cc2418aab2b6f3b36048c47a3633b6a147 100644 GIT binary patch delta 85 zcmew(v{sn=G%qg~0}vcH(%Z=Wipe_B*(xTqIJKxa#w#&5wOGNiI5Q_dCOE&eC^22h`%4nVFY!wq)oLW>IR diff --git a/myfinances/clients/__pycache__/models.cpython-312.pyc b/myfinances/clients/__pycache__/models.cpython-312.pyc index 724a36a8f8e54b1305735e13bb6d7d762354c3c1..371d2f54657296a86df8ad2dfdae89ff9458074a 100644 GIT binary patch delta 85 zcmdnV^@@x8G%qg~0}vcH(%Z=0%w(PEY!wq)oLW>I22iZWVX(7wu%WYPAw{q@k-21Emm+W&dkY=3C=GqN=}Ul jN-fAQj`0le503FKNX?6f2*(E$#*s+w9M5#0mhY{s~tA diff --git a/myfinances/finance/__pycache__/__init__.cpython-312.pyc b/myfinances/finance/__pycache__/__init__.cpython-312.pyc index e73633661e309b98331f47bc2a2ee4c8c96f5c9a..c43931f57624e8f3854240c608d2de7063f7c079 100644 GIT binary patch delta 85 zcmcb{($30#nwOW00SJy8>22g@Wwg$Awu%WYPAw{q@k-21Emm+W&dkY=3C=GqN=}Ul jN-fAQj`0le503FKNX?6f2*(E$#*s+w9F~!w3MOZwUhc diff --git a/myfinances/finance/invoices/__pycache__/__init__.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/__init__.cpython-312.pyc index 5c0dab98044c2f2a6445f048603ddb7a3eaa5e00..67de218de201219c8bd2705f84d71c53fcce6709 100644 GIT binary patch delta 83 zcmeyvw3eCsG%qg~0}vcH(p$*QXkFrL6%$&VT2vh4m6)4atl(IjnUfzAoL^d$oEj69 hT998H;~C%|9OGY*nimfdjt?lx&q_@$nJmhf4ggl~97q5F delta 34 ocmZ3>{D+DAG%qg~0}$-`uD+0)k;~cDDkeNN$tAUHvKwPM0H22hG$!J~VY!wq)oLW>I}APLR@ diff --git a/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc index 4607e697411207c7dfd46bea332fad4e1ae0f2b9..e67235eedd3a3a4f3083a6fe2477c41f0044c7bb 100644 GIT binary patch delta 85 zcmZqV*~G(rnwOW00SJy8>22h$WwI`Iwu%WYPAw{q@k-21Emm+W&dkY=3C=GqN=}Ul jN-fAQj`0le503FKNX?6f2*(E$ MyFinancesResponse[InvoiceList]: response = self._client._get(f"/invoices/") return MyFinancesResponse(**response.dict()) + + + def get_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: + response = self._client._get(f"/invoices/{invoice_id}/") + return MyFinancesResponse(**response.dict()) + + def delete_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: + response = self._client._delete(f"/invoices/{invoice_id}/delete") + return MyFinancesResponse(**response.dict()) From 422a22a3a9cfa9cea448b7ed62fefc8e0e28ad40 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sun, 10 Nov 2024 00:12:49 +0800 Subject: [PATCH 02/19] feat(InvoicesServices: implemented a get search and update invoices --- .../__pycache__/service.cpython-312.pyc | Bin 1586 -> 2319 bytes myfinances/finance/invoices/service.py | 24 ++++++++++++++++++ tests/__pycache__/__init__.cpython-312.pyc | Bin 142 -> 191 bytes .../test_finance.cpython-312-pytest-8.3.3.pyc | Bin 7826 -> 7832 bytes tests/test_finance.py | 3 ++- 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc index e67235eedd3a3a4f3083a6fe2477c41f0044c7bb..447cbebf65e5c6bcedd16996a98dc1240190826c 100644 GIT binary patch delta 873 zcmdnQ(=Wt#nwOW00SMeY_0nZnC-NN=Dgg4PGo&&^F{Us?F>x}a@JxJWVvxd_%ACTM z%9hG036xJ`N#SZ?iQ>i(2iA{E8N!5`6so{c} z5}%op43dQbkO9m<{J987OlO$f$EdB$Si?A*A%$r!^J+$jvRbARRtSrMA%!`Up@wPl z4Myd97QZ4Xpztq7h|7wkft;1h5NF5(*$}sYOjiIo21wuH20A((>Xa&JPpHp=Q;W)g zKGZ{!1Q}dx3?v#DZU~D{x0z^jU0CI!u*!m}4O$yyb_8BfwYRz~?9jn+hhOm`zsUlR z<-QAj7yAR57dT9cKwhS{H>=q7Q&MwMOH#qnpb3oz_IRiuC?JbuL4*>JC`R!$A4Cn@ z<8tU8N0pZY836aYCB*aU7lqYVXl;nv;B$cef`-RsVNX1M*JSeZ)8w7Jg~h>K9ONVx z5CJl_NEt+^fe27y0tXa0W{NmKTo3{BNO8+#Mb-ez&kRhgrXRR~#De4xAoc}4hXc|V z^?V@`96*s3!Vn2V=L6ms4FkS_R24}~u3)Wl07U}W>|Y!7`dOPvko$$kdZ|oB}L*Of&)f? z3@#3ue1<)M{R;yVt7(zslKPz_tJY03kQb diff --git a/myfinances/finance/invoices/service.py b/myfinances/finance/invoices/service.py index ed666e9..1dc996e 100644 --- a/myfinances/finance/invoices/service.py +++ b/myfinances/finance/invoices/service.py @@ -27,6 +27,30 @@ def get_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: response = self._client._get(f"/invoices/{invoice_id}/") return MyFinancesResponse(**response.dict()) + def delete_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: response = self._client._delete(f"/invoices/{invoice_id}/delete") return MyFinancesResponse(**response.dict()) + + def search_invoices(self, customer_id: int = None, status: str = None) -> MyFinancesResponse[InvoiceList]: + params = { + "customer_id": customer_id, + "status": status + } + + params = {key: value for key, value in params.items() if value is not None} + + response = self._client._get(f"/invoices/search", params=params) + return MyFinancesResponse(**response.dict()) + + def update_invoice(self, invoice_id: int, amount: float = None, description: str = None, due_date: str = None ) -> MyFinancesResponse[CreateInvoiceResponse]: + payload = { + "amount": amount, + "description": description, + "due_date": due_date, + } + + payload = {key: value for key, value in payload.items() if value is not None } + + response = self._client._post(f"/invoices/{invoice_id}update", json=payload) + return MyFinancesResponse(**response.dict()) diff --git a/tests/__pycache__/__init__.cpython-312.pyc b/tests/__pycache__/__init__.cpython-312.pyc index e88dd316a2d531510c2fa56c8a197cf8018e445b..402ab96c8d988cc185bff2de75ebb6a7b610faa1 100644 GIT binary patch delta 82 zcmeBU+|S5;nwOW00SJy8=}qJ|wvKbQiU}=FEh>)jO3Y0yR&XrN%*l@l&Mz%WPK^ml gEyyp9@eJ?}j`1%@&5MT!#|ISUXQd{WO!ROA03Xd91ONa4 delta 33 ncmdnb*vH6ynwOW00SJyPk(uIi$Fw(fQdpNCTg0jWm%eP+ihmHBqS#G z;Kh>(bMfNAi_v&6$i)+S_d)|nlZ^*rOo%5*xOsBk7Kw3_`S#6wZ{B)Dpt5Spbus4rz9P{a4W{^Oo-n(I_#@(QQ8?kLFSNy*R^H+C}<<{9WK z6u7oJGoHRn3{29uG6jRgrb#YurdP}|){XSCQ8Gz-VQFzCy;w4eT3xLzVe^rpTl6zZ zhMHNR2DV6;p~C$TDb6vhIU#Vo?u5?*dlJ$$O`w3 z5_u$Xn7X;gx7GMam5^kK%qgE^!}|M%@NMP;w;>kcJIDS2nAPSk delta 961 zcmZ9K&rcIU6vubAOIs-2Zd-oz$Fj6oek=qiP%wZHe-wj>62(NLFvRUc7i0ue*g?oDyF~ik8Gf77cyz&F2VVa)tZmID$8B@>In}nJ5=$_PdfNCZaGWYo z^iwc7%Tdx(InBth9TI4pSekqCP+v>xo2*7=qHYLqz%=^+W$wGnQ|s)nxdzI~BY$@} z`RX={@vDm%WfDMywgWB6$Zr;mv~FsqPB+1z5^ReYg`s#)Xn+3DHTXpsq+;a*f7t2@ zfP)4RGTUoEut(7BW3%obGXB~UiUqS|iD{~*O1gIT099C0+*s_!0I!x#WwRR9i!@!x z6;o8F|J(@?YHLG=<<1q-&mhh$7V@C4mz|1Fha0;6CEYA(7oJ#vqdu6X15ymq*^Xy2 zax{DMi_lRQcs2|aR=mJ=dqMpwf`E|90;(soPry+JVIB4%dPmJY)x0(rxvQI%xR&du2fVxJ| z#%j?dVt`!^C4ABI^%7Vr*&1Vup)lJIg;{s(KTx*8>*Gw8nou-IfcMCRC?uwtLZ&3X1b990|D@HMLO zzkn5pL7ip=+6{~GG5oj_GA>2xp3$mj^w2Y2UdFsD?3%pH?#f}dD}VE0>#2Urxwc_s zOGe(LV{EHuip1Hwp414oWK$NFn&K00IEqIa-Td2mC0EF7Wc5Y*h|MX(34ur_HjbB$ id9aS#Io|nN*-?J-gbbbSgZ0baMdBxMFM$S!oBjZkmfyMn diff --git a/tests/test_finance.py b/tests/test_finance.py index f37d800..291848f 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -25,6 +25,7 @@ def test_create_invoice(invoices_service): "description": "Service Fee" } mock_response.status_code = 200 + invoices_service._client.session.post.return_value = mock_response invoice = invoices_service.create_invoice(customer_id=123, amount=250.0, description="Service Fee") @@ -49,4 +50,4 @@ def test_list_invoices(invoices_service): assert len(invoices) == 2 assert isinstance(invoices[0], Invoice) assert invoices[0].id == 1 - assert invoices[1].amount == 300.0 \ No newline at end of file + assert invoices[1].amount == 300.0 From 21a4414dbc68e446a8eafb14f6565d9da1bed753 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sun, 10 Nov 2024 12:44:33 +0800 Subject: [PATCH 03/19] feat(ClientServices): Implemented a service that could get a singular clients data by their ID --- myfinances/clients/service.py | 7 ++++++- myfinances/finance/invoices/models.py | 4 +++- myfinances/finance/invoices/service.py | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/myfinances/clients/service.py b/myfinances/clients/service.py index eca85da..4de6ebe 100644 --- a/myfinances/clients/service.py +++ b/myfinances/clients/service.py @@ -3,7 +3,7 @@ from pydantic import EmailStr from myfinances.base_service import BaseService -from myfinances.clients.models import ClientIdResponse, ClientData +from myfinances.clients.models import ClientIdResponse, ClientData, Client from myfinances.models import MyFinancesResponse @@ -51,3 +51,8 @@ def create_client( response = self._client._post("/clients/create/", params) return MyFinancesResponse(**response.dict()) + + + def get_client(self, client_id:int) -> MyFinancesResponse[Client]: + response = self._client.get(f"/clients/{client_id}") + return MyFinancesResponse(**response.dict()) diff --git a/myfinances/finance/invoices/models.py b/myfinances/finance/invoices/models.py index d54a4bb..fb1dd81 100644 --- a/myfinances/finance/invoices/models.py +++ b/myfinances/finance/invoices/models.py @@ -10,11 +10,13 @@ class Invoice(BaseModel): due_date: Optional[str] = None description: Optional[str] = None + class CreateInvoiceResponse(BaseModel): customer_id: int amount: condecimal(gt=0) description: Optional[str] = None due_date: Optional[str] = None + class InvoiceList(BaseModel): - invoices: List[Invoice] \ No newline at end of file + invoices: List[Invoice] diff --git a/myfinances/finance/invoices/service.py b/myfinances/finance/invoices/service.py index 1dc996e..a672f23 100644 --- a/myfinances/finance/invoices/service.py +++ b/myfinances/finance/invoices/service.py @@ -1,5 +1,5 @@ from myfinances.base_service import BaseService -from myfinances.finance.invoices.models import InvoiceList, CreateInvoiceResponse +from myfinances.finance.invoices.models import InvoiceList, CreateInvoiceResponse, Invoice from myfinances.models import MyFinancesResponse @@ -23,7 +23,7 @@ def list_invoices(self) -> MyFinancesResponse[InvoiceList]: return MyFinancesResponse(**response.dict()) - def get_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: + def get_invoice(self, invoice_id: int) -> MyFinancesResponse[Invoice]: response = self._client._get(f"/invoices/{invoice_id}/") return MyFinancesResponse(**response.dict()) From 92245df1b95a569d1ea059e5c108b5b074b56ea6 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Mon, 11 Nov 2024 09:05:10 +0800 Subject: [PATCH 04/19] feat(ClientServices): Implemented a service that could update and delete client --- .../__pycache__/service.cpython-312.pyc | Bin 2177 -> 2575 bytes myfinances/clients/service.py | 31 ++++++++++++++++++ .../__pycache__/models.cpython-312.pyc | Bin 1331 -> 1331 bytes .../__pycache__/service.cpython-312.pyc | Bin 2319 -> 3644 bytes myfinances/finance/invoices/service.py | 5 +-- .../test_finance.cpython-312-pytest-8.3.3.pyc | Bin 7832 -> 11453 bytes 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/myfinances/clients/__pycache__/service.cpython-312.pyc b/myfinances/clients/__pycache__/service.cpython-312.pyc index 349b24d22a42657b6376ad9194724fb7409f361e..d469d0661f7be9b0f62c70315b051a5b19dc3e96 100644 GIT binary patch delta 868 zcmY*XOK1~O6uobL$)rh}AEqA^ON!|bXNuQjV_eI;;Q>XTNg#d`)07V7v{Ws?>qN1_r3>_$MN=0p-=!& zejOW}nD;f?JIS?XD%)RE3n~E}bh#R+wH4Y32yhN`We#*7m6t^x0#FDx9}cBNCw!`E z(7JU&zeLT+M%|=N!1J6gStUpD^yZht@sAj^02B&Dhk~Gj3VPIzk}QeYqvU$G9;QKE zqB0G2A+aLqkvXZ*K1H;+{fhhv1kuSt2;25sq5pu2nj`5(+0tZ3GHJEKb{H)B=C=?O zlrVBM)t-_2a!DTDhcF$^l-+*KOqtP=MKdhMX%dU$;mF0whG{XLo$cfPAWPVH^ z1T4z$IuT4>@Zc_CUG@k0QMw1+j_Oq@8hTkk`=2PN@cC^_A}oNtD5ZPJELnu7!ZPtl zcLhuKGyq*NU{4=WvBW~Infn$?wqnWblJQ!7IkVDt{A(;X@Bh)!+v*rzI{#wq z+1T@OR9F1NjQ_YMmWG=en^x-Y*<{%+B(v3!=%J@83irb=5x0s)s zX%2iTZbG+t*2YZ^{Jol6_GiUOZzOu;k@cJ)k1QQo2Rv5NC*D)90!t;MrqJXIjQ_Z}f$EBQ zfJD{g8%!E<96;7BmXyro5>3`yEXAogX+>}qMFN}Un0c6Z`GIOQIg6w~I;AI1U{$lN z63|c1$xO{FDb`OeN=+ MyFinancesResponse[Client]: response = self._client.get(f"/clients/{client_id}") return MyFinancesResponse(**response.dict()) + + def update_client(self, + name: str, + phone_number: Optional[str] = None, + email: Optional[EmailStr] = None, + company: Optional[str] = None, + contact_method: Optional[str] = None, + is_representative: bool = False, + address: Optional[str] = None, + city: Optional[str] = None, + country: Optional[str] = None) -> MyFinancesResponse[ClientIdResponse]: + params = { + "name": name, + "phone_number": phone_number, + "email": email, + "company": company, + "contact_method": contact_method, + "is_representative": is_representative, + "address": address, + "city": city, + "country": country, + } + + params = {key: value for key, value in params.items() if value is not None} + + response = self._client._put("/clients/update/", params) + return MyFinancesResponse(**response.dict()) + + def delete_client(self, client_id: int) -> MyFinancesResponse[ClientData]: + response = self._client._delete(f"/clients/{client_id}/delete") + return MyFinancesResponse(**response.dict()) diff --git a/myfinances/finance/invoices/__pycache__/models.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/models.cpython-312.pyc index a8f1ce4550be67e9d73ac80491dccfe73ebc2b0f..efc07d6408406844ad911b1eb2b532092608969a 100644 GIT binary patch delta 63 zcmdnYwV8|eG%qg~0}yP}Fi8Ktk#{*WBj4n$%x4%yCpWQ7l@VfLRG#7ag#k!?;bUZ! PnV|WV0Z0`|0CfNWES(Sj delta 63 zcmdnYwV8|eG%qg~0}vcH(o6rik#{*WBk$y`%x4&dCpWQ7l@VZJRG#7ag#k!?;bCNy PnV|WV0Z0`|0CfNWFQE_$ diff --git a/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc index 447cbebf65e5c6bcedd16996a98dc1240190826c..72efe3cb50210de8df49fe9c23b8c4bc03ed761a 100644 GIT binary patch literal 3644 zcmd5(vXmhjw46Cf*cJ?3yN4L8JgDP#<#2ym;C69X^JN>xtOtW zT=AnP3m1z}eLX{6f9o-V(=HB7XE7}m3l#fCV1U^@r>0-Y6w(D7(`L6Vb`i28XslMD zasy$MlpK_l!^r7!WUM#}Rvi^<@Ohe}V;vj6fN@h1$GD;;L);SP7TF11QIioT40G7H zD7UIk1gsq`s~D>~QLx5>9Xf)QMW61(VC7C{3!n3#-8*4S*R&Mx_Pc_k(g2}^AGOQW zE#@(?GLEmO^Tl$(^`j1^Hp!ISOtIjHoHDi?z|GeQcFUw-H!qNZp~H_|#Ht742J$3N z_7qQbq)*g}=AkTDH8XH~si2Z-9w`NzFs_f3ru|NF zJS*s%d3?idkF4)!-%F2!xQrS)>Kj__?OWctcX@mNN?0=^vqqy6J+}SE;p>O*n1gk5 zu(tQ$?MpRtaLGJA8~Uc}iF()bb0@w$b@S9`r=eO4J--S|AzNZHC@pd@8UQ&Soet7M zuues4qk;@nkRE{wO5$E*?b1mP>^`p&6O^x7=drkCvK88Kne>7p+d)vqzW#o~e9@2P zAYwF;q%*rVLb_0HUZf{-5i*kSu*#}hW@n)SY#*LB@$c}IG-JGAIxoD zMWFH1fb*n}A&7pev;dUb08{`#`4IqA6J!_cd`}wX;E~6nF|P=yo`AZ*i}^9|T>usZ zT$^~!?A!=fTjvg#MfZca53K5NweR*DwZUI6nJ+v9wVxwWGsdWcbJ)ckF9<}OY=#vW znX7TWkpXu4b-;CsF)i%w^V;?OyElPvsBRA38m=a*uP++4r%o)HCm#ZzuTwYemZ{wy zhFhLmgXKjShY&7T6i>;vdo=X2(hR*Xp{wdu%?4W8^4k!0Q$XSh3;fz;>4UJRdfJEb z2Qd{@6mCV?c9M&wP_`B70|O{X2g z@i>fcPY4vJiTy5Qe!Y|?={yzJr}Wv86ci=DH zytnZFo$iU7JLb$eytuV~^z5}g*UHz2YuyvGdcAw%ZhIuE4gGSlw`LA3nI|@<#{X9h z)H5kjcC0@}jy|b>u7TJ*)%!38IMPh?fU>9k2ut*<#s-$?6~i+)OLWf&SfW*!^{23e z1v}+a1s)G->+ukB*Vv*#zzby`l`Td^2e#;mxU%65!K0zCmrLv&M7F^B1EP>;Se?`4 zF;;6idOX|~Ex|L|9wcNNYd*`w2opT_uutS z_Ec@}%l|me)BfaxnPdJ&Fy~K^qeJ=^8i=@@02mV>w)i2-D!?nqviyi;<%>=^$LbxH z_4{%<7xX9@_5_=PCzb0f@C*}3vd}MFyF8iiuGso@0Wgd7f6ezY&Hg z7iMjxD}cA3MW4RzhKI{MP;k0(F~m zRZF~6OXuo|{3GE41%B{W)p;+J)~CDE|3B02sPPwEzGB delta 646 zcmZ9J&1=+95WwfXyd?XP)P7*ywrji8r8Q7CU8G*Df(jK;7rh3dlznf@>h4xvR-rww z;7!9j^w_J#iy+=aynC_Ng<9|*aG~|mlQU_H*c^Vzo6K)!GWk+`J392;_j7>P%KgfE z(N2a6>`pR2Q)VDRS}nWnL=FQE_dtpsNL#TF7NrA3Zqk`xJb6=2J}->Ez{oZzh?s&12NtWPxwC*{``QrfM2R=LsHSYdCCnUTrk% zDh}&ft#wskc6f2tp@a*F!0n4zwHo@o{OKqE$g0DbvMclm-uhy7U3E2?eIc9mZou^z z9`r>-%n_xM9yecwVg*yScNQiwbj(6cHS`o>*E$hqD3DsTh*GNkwx6LEIpzjwTW%;- zOLbK$2d4wLtEa(q`pZ;h77_oea@D=Yrp;4#Iak0J0k73?HNJQKc52vUTp|dfLV-_NtGM=%CXA-9gTJ8C-oP)2(;c2P_`m6KW*IYHw$v@Xh$R?xrgaP~#@IfD2k>Mc7LS}s Nw)F1#AHZAM?=RKNf%gCa diff --git a/myfinances/finance/invoices/service.py b/myfinances/finance/invoices/service.py index a672f23..dc581b6 100644 --- a/myfinances/finance/invoices/service.py +++ b/myfinances/finance/invoices/service.py @@ -17,17 +17,14 @@ def create_invoice(self, return MyFinancesResponse(**response.dict()) - def list_invoices(self) -> MyFinancesResponse[InvoiceList]: response = self._client._get(f"/invoices/") return MyFinancesResponse(**response.dict()) - def get_invoice(self, invoice_id: int) -> MyFinancesResponse[Invoice]: response = self._client._get(f"/invoices/{invoice_id}/") return MyFinancesResponse(**response.dict()) - def delete_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: response = self._client._delete(f"/invoices/{invoice_id}/delete") return MyFinancesResponse(**response.dict()) @@ -52,5 +49,5 @@ def update_invoice(self, invoice_id: int, amount: float = None, description: str payload = {key: value for key, value in payload.items() if value is not None } - response = self._client._post(f"/invoices/{invoice_id}update", json=payload) + response = self._client._post(f"/invoices/{invoice_id}/update", json=payload) return MyFinancesResponse(**response.dict()) diff --git a/tests/__pycache__/test_finance.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_finance.cpython-312-pytest-8.3.3.pyc index a5b50407e1c16a8cef06b59cbca407fcacd20b20..0186c1c68c2feeddf4a0ac4538f679fedc340472 100644 GIT binary patch delta 1891 zcmb`H-ESL35Wu~6=d10@*|FpJ?DI#QPv`Ohwn-Bx1RPRTl*mOw6hU4rH+PMk=ELlr zfmpU2iNYgN7#{l2H(nYQP*I1sgA+69Gx!do_cb2HaR?6-aM(9J3LLI*8oGCXR1HFMbk8>WjoAhCMsuk zU{_8+MGmv*pUN4=UHK!DfYaW}pn@y?g{9)^YJnPMy0o!YE>eSb?%;t}C4KORw@T)3 zQs1}kUR>1afm0Q7k(3xmaR}BTXT>Cn{qS9+5KEvaGHAj-`=zg=b`)mRsX#x9_Iv@o zNc9onp;#1!Hr zVg~U%;swMh#NocEeImSYO`<+Dy@WXHa6md5BRR-N6XGkVnuGVEr^xx6Uq*KceBuvr z10J};^-E4&)K6R$Yh;CkbRfp*E{O1JK60I~RqU&CHEyLF?kc^0QWt7`O}I45w9cB- z{0e?o`V@D~d6DQIv|Qw_3;U~d34RD_@Nv)EM1mVVeK4tH<*uuIm0f0C)MecZH^K`N z{~@V6SyXOiz|O!Ok-_(b8HVf({1F+tpD@FSok2Jvga0@g+=sUWw-v>Y_w~5H5I9c! zj=wNwpFlh!L(g$CG!9O%>Cl4bXn;MD(k=G9mhHFFx{zy&mGyG5q*p!JbarYolbuXw zs$Fjxrj+#~p-w}LA;u9C3|Nq?tD~|3ZZ*K=qF+DmjFDBj=IP1`Npr!-}j}VKb9wZ zFc%+$Tzu$_rZBQ63^kw9IE>q{<4!b%r!)41O!I$@^y9tn3K=T1o794B*M&-H)hex< wbPB5R=g2gC9ls>aGb25ZScJZW>M@vz&D4Ao<`WCPhZA0s`fZ?>WbH720fN}mGXMYp delta 534 zcmY+AOG^S#6vw+LLpt4&k}RJYQRDTIJv1|nvLbr9uZ5V2MN~T6F>)m6Gsq!uU7w&_ zwJ4%pwQc3PZ_qmE9tEol^W&WVIrBf~-p9ShqVi6uwMQJbF?sYP)sRHcNf*NsGh_Tgo|cz_T(m@n?+iVis;gOL|r=oaA^>*UBYf>w|Bl zMpDhH?ZGnWz`_52<4#z2s*(pQW1u@XrS^7ycyZ=DUQ{IkX8v88ucA5*i>{dL$FQBR z!KEwJ&s7ux2!;s4o6CEZ#xRPAAtH!L#1vv0F@u;zbZ7GRw)l)pZeNYZvA!bEl9x3j z*Lk*?ze$`YyXC_&Kg(AVEqMT&J6V#?qsIbN-3uhsY`UL`!tAZygY)Cl%5h2O5x5S` ik|?}}PNWpJW?(7ovhIqIh)>TzA-rw<3M)kAR0uyr!FsX) From d299a0aac807e79c4d1dd455763ce32671b182a9 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Mon, 11 Nov 2024 09:58:42 +0800 Subject: [PATCH 05/19] feat(ReceiptsServices): Created base model for receipts --- myfinances/finance/receipts/__init__.py | 0 myfinances/finance/receipts/models.py | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 myfinances/finance/receipts/__init__.py create mode 100644 myfinances/finance/receipts/models.py diff --git a/myfinances/finance/receipts/__init__.py b/myfinances/finance/receipts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myfinances/finance/receipts/models.py b/myfinances/finance/receipts/models.py new file mode 100644 index 0000000..fb36587 --- /dev/null +++ b/myfinances/finance/receipts/models.py @@ -0,0 +1,22 @@ +from pydantic import BaseModel, FilePath, condecimal +from typing import Optional, List + + +class Receipt(BaseModel): + id: int + name: str + imgae: FilePath + date: Optional[str] = None + merchant_store: Optional[str] = None + purchase_category: Optional[str] = None + total_price: condecimal(gt=0) + owner: Optional[str] = None + + +class ReceiptList(BaseModel): + receipts: List[Receipt] + + +class CreateReceiptResponse(BaseModel): + receipt_id: int + message: Optional[str] == "Receipt successfully created" From a8c703d94c366228f07eea4b2e4f593663dc33a3 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Mon, 11 Nov 2024 10:41:19 +0800 Subject: [PATCH 06/19] feat(ReceiptsServices): Implemented a service that creates receipts --- myfinances/finance/receipts/models.py | 4 ++-- myfinances/finance/receipts/service.py | 33 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 myfinances/finance/receipts/service.py diff --git a/myfinances/finance/receipts/models.py b/myfinances/finance/receipts/models.py index fb36587..58beec9 100644 --- a/myfinances/finance/receipts/models.py +++ b/myfinances/finance/receipts/models.py @@ -5,7 +5,7 @@ class Receipt(BaseModel): id: int name: str - imgae: FilePath + image: FilePath date: Optional[str] = None merchant_store: Optional[str] = None purchase_category: Optional[str] = None @@ -17,6 +17,6 @@ class ReceiptList(BaseModel): receipts: List[Receipt] -class CreateReceiptResponse(BaseModel): +class ReceiptIDResponse(BaseModel): receipt_id: int message: Optional[str] == "Receipt successfully created" diff --git a/myfinances/finance/receipts/service.py b/myfinances/finance/receipts/service.py new file mode 100644 index 0000000..20376a0 --- /dev/null +++ b/myfinances/finance/receipts/service.py @@ -0,0 +1,33 @@ +from typing import Optional + +from pydantic import FilePath + +from myfinances.base_service import BaseService +from myfinances.finance.receipts.models import Receipt, ReceiptList, ReceiptIDResponse +from myfinances.models import MyFinancesResponse + + +class ReceiptService(BaseService): + def create_receipt(self, + name: str, + image: Optional[FilePath] = None, + date: Optional[str] = None, + merchant_store: Optional[str] = None, + purchase_category: Optional[str] = None, + total_amount: float = None, + owner: Optional[str] = None + ) -> MyFinancesResponse[ReceiptIDResponse]: + + params = { + "name": name, + "image": image, + "date": date, + "merchant_store": merchant_store, + "purchase_category": purchase_category, + "total_amount": total_amount, + "owner": owner + } + + response = self._client._post("/receipts/create/", json=params) + + return MyFinancesResponse(**response.dict()) From c26ef1961a8f5fedb11d47bb160f859dcbd11840 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Mon, 11 Nov 2024 11:02:41 +0800 Subject: [PATCH 07/19] feat(ReceiptsServices): Implemented a service that lists all of the receipts --- myfinances/finance/receipts/service.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/myfinances/finance/receipts/service.py b/myfinances/finance/receipts/service.py index 20376a0..ccb3e5d 100644 --- a/myfinances/finance/receipts/service.py +++ b/myfinances/finance/receipts/service.py @@ -31,3 +31,7 @@ def create_receipt(self, response = self._client._post("/receipts/create/", json=params) return MyFinancesResponse(**response.dict()) + + def list_receipts(self) -> MyFinancesResponse[ReceiptList]: + response = self._client._get(f"/receipts/list/") + return MyFinancesResponse(**response.dict()) From 580af44670f0c66b9f4a28b8a0e78e56094070c7 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Mon, 11 Nov 2024 18:04:08 +0800 Subject: [PATCH 08/19] feat(ReceiptServices): Implemented a service that can search and update the receipt --- myfinances/finance/receipts/service.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/myfinances/finance/receipts/service.py b/myfinances/finance/receipts/service.py index ccb3e5d..7a2f780 100644 --- a/myfinances/finance/receipts/service.py +++ b/myfinances/finance/receipts/service.py @@ -35,3 +35,19 @@ def create_receipt(self, def list_receipts(self) -> MyFinancesResponse[ReceiptList]: response = self._client._get(f"/receipts/list/") return MyFinancesResponse(**response.dict()) + + def delete_receipt(self, receipt_id: int) -> MyFinancesResponse[ReceiptIDResponse]: + response = self._client._delete(f"/receipts/{receipt_id}/delete") + return MyFinancesResponse(**response.dict()) + + def search_receipts(self, receipt_id: int = None, name: str = None, merchant_store: str = None) -> MyFinancesResponse[ReceiptList]: + params = { + "receipt_id": receipt_id, + "name": name, + "merchant_store": merchant_store + } + + params = {key: value for key, value in params.items() if value is not None} + + response = self._client._post("/receipts/search/", json=params) + return MyFinancesResponse(**response.dict()) From 841f1c7cf360d1123cbeb55c7cf54f2c0dde6bce Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sat, 16 Nov 2024 20:04:35 +0800 Subject: [PATCH 09/19] tests(InvoicesServices) - Implemented testing towards all of the Invoice services --- tests/test_finance.py | 249 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 223 insertions(+), 26 deletions(-) diff --git a/tests/test_finance.py b/tests/test_finance.py index 291848f..f343b16 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -1,8 +1,8 @@ - import pytest from unittest.mock import Mock from myfinances import MyFinancesClient from myfinances.finance.invoices import InvoicesService, Invoice +from myfinances.models import MyFinancesResponse @pytest.fixture def mock_client(): @@ -14,40 +14,237 @@ def mock_client(): def invoices_service(mock_client): return InvoicesService(mock_client) -def test_create_invoice(invoices_service): - mock_response = Mock() - mock_response.json.return_value = { - "id": 1, + +def test_create_invoice(invoices_service, mock_client): + new_invoice_data ={ "customer_id": 123, - "amount": 250.0, - "status": "created", - "due_date": None, - "description": "Service Fee" + "amount": 100, + "description": "Data Analytics service", + "due_date": "2020-05-21" } - mock_response.status_code = 200 - invoices_service._client.session.post.return_value = mock_response + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Successfully created" + }, + "data": { + "invoice_id": 102, + } + } + + mock_post = Mock() + mock_post.dict.return_value = mock_response_data + mock_client._post.return_value = mock_post + + response = invoices_service.create_invoice(**new_invoice_data) + + mock_client._post.assert_called_once_with("/invoices/create", json=new_invoice_data) + assert response.data["invoice_id"] == 102 + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Successfully created" + - invoice = invoices_service.create_invoice(customer_id=123, amount=250.0, description="Service Fee") +def test_list_invoices(invoices_service, mock_client): - assert isinstance(invoice, Invoice) - assert invoice.id == 1 - assert invoice.customer_id == 123 - assert invoice.amount == 250.0 - assert invoice.description == "Service Fee" + invoice_list = [ + {"id": 1, "customer_id": 123, "amount": 250.0, "description": "Service Fee", "status": "pending"}, + {"id": 2, "customer_id": 124, "amount": 300.0, "description": "Consulting Fee", "status": "pending"} + ] + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Successfully created" + }, + "data": invoice_list + } -def test_list_invoices(invoices_service): mock_response = Mock() - mock_response.json.return_value = [ + mock_response.dict.return_value = mock_response_data + mock_client._get.return_value = mock_response + + response = invoices_service.list_invoices() + + mock_client._get.assert_called_once_with("/invoices/") + + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Successfully fetched invoices" + + assert isinstance(response.data, list) + assert len(response.data) == 2 + assert response.data[0]["id"] == 1 + assert response.data[1]["amount"] == 300.0 + assert response.data[0]["status"] == "pending" + assert response.data[1]["status"] == "pending" + + +def test_delete_invoice(invoices_service, mock_client): + invoice_list = [ {"id": 1, "customer_id": 123, "amount": 250.0, "description": "Service Fee", "status": "pending"}, {"id": 2, "customer_id": 124, "amount": 300.0, "description": "Consulting Fee", "status": "pending"} ] - mock_response.status_code = 200 - invoices_service._client.session.get.return_value = mock_response - invoices = invoices_service.list_invoices() + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Successfully deleted invoice" + }, + "data": invoice_list + } + + mock_response = Mock() + mock_response.dict.return_value = mock_response_data + + mock_client._delete = Mock(return_value=mock_response) + + invoice_id = 1 + + response = invoices_service.delete_invoice(invoice_id) + + mock_client._delete.assert_called_once_with(f"/invoices/{invoice_id}/delete") + + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Successfully deleted invoice" + + remaining_invoices = [invoice for invoice in invoice_list if invoice['id'] != invoice_id] + + assert len(remaining_invoices) == 1 + assert remaining_invoices[0]['id'] == 2 + + +def test_get_invoice(invoices_service, mock_client): + invoice_data = { + "id": 2, + "customer_id": 124, + "amount": 300.0, + "description": "Consulting Fee", + "status": "pending" + } + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Successfully deleted invoice" + }, + "data": invoice_data + } + + mock_response = Mock() + mock_response.dict.return_value = mock_response_data + mock_client._get.return_value = mock_response + + invoice_id = 2 + response = invoices_service.get_invoice(invoice_id) + + mock_client._get.assert_called_once_with(f"/invoices/{invoice_id}/") + + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Successfully deleted invoice" + + assert response.data["id"] == invoice_data["id"] + assert response.data["customer_id"] == invoice_data["customer_id"] + assert response.data["amount"] == invoice_data["amount"] + assert response.data["description"] == invoice_data["description"] + assert response.data["status"] == invoice_data["status"] + + +def test_search_invoices_by_id(invoices_service, mock_client): + invoice_data = [ + {"id": 1, "customer_id": 123, "amount": 300.0, "description": "Analytics Consultant", "status": "pending"}, + {"id": 2, "customer_id": 124, "amount": 150.0, "description": "Service fee", "status": "paid"} + ] + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Invoices fetched successfully" + }, + "data": invoice_data + } + + mock_response = Mock() + mock_response.dict.return_value = mock_response_data + mock_client._get.return_value = mock_response + + customer_id = 124 + + response = invoices_service.search_invoices(customer_id) + mock_client._get.assert_called_once_with(f"/invoices/search", params={"customer_id": customer_id}) + + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Invoices fetched successfully" + + assert response.data[1]["id"] == 2 + assert response.data[1]["customer_id"] == 124 + + +def test_update_invoice(invoices_service, mock_client): + invoice_data = { + "id": 1, + "customer_id": "125", + "amount": 100, + "description": "Service fees", + "due_date": "2024-12-31", + "status": "pending" + } + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Invoices successfully updated" + }, + "data": invoice_data + } + + mock_response = Mock() + mock_response.dict.return_value = mock_response_data + mock_client._post.return_value = mock_response + + new_status = "paid" + + response = invoices_service.update_invoice(1, status=new_status) + + mock_client._post.assert_called_once_with(f"/invoices/1/update", json={"status": new_status}) + + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Invoices successfully updated" + + # updated version of the list + updated_invoice_data = { + "id": 1, + "customer_id": "125", + "amount": 100, + "description": "Service fees", + "due_date": "2024-12-31", + "status": "paid" # Updated status + } + + mock_get_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Invoice fetched successfully" + }, + "data": updated_invoice_data + } + + mock_get_response = Mock() + mock_get_response.dict.return_value = mock_get_response_data + mock_client._get.return_value = mock_get_response - assert len(invoices) == 2 - assert isinstance(invoices[0], Invoice) - assert invoices[0].id == 1 - assert invoices[1].amount == 300.0 + get_response = invoices_service.get_invoice(1) + mock_client._get.assert_called_once_with(f"/invoices/1/") + assert get_response.data["status"] == "paid" From df2ccd716a079413b54210cebca4d8d81af7df26 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sat, 16 Nov 2024 20:06:28 +0800 Subject: [PATCH 10/19] fix(InvoicesService): fix the update and search method invoice, so that they are able to choose which ones rather than using all the arguments --- myfinances/finance/invoices/service.py | 33 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/myfinances/finance/invoices/service.py b/myfinances/finance/invoices/service.py index dc581b6..87b3f70 100644 --- a/myfinances/finance/invoices/service.py +++ b/myfinances/finance/invoices/service.py @@ -30,24 +30,31 @@ def delete_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: return MyFinancesResponse(**response.dict()) def search_invoices(self, customer_id: int = None, status: str = None) -> MyFinancesResponse[InvoiceList]: - params = { - "customer_id": customer_id, - "status": status - } + params = {} + + if customer_id is not None: + params["customer_id"] = customer_id - params = {key: value for key, value in params.items() if value is not None} + if status is not None: + params["status"] = status response = self._client._get(f"/invoices/search", params=params) return MyFinancesResponse(**response.dict()) - def update_invoice(self, invoice_id: int, amount: float = None, description: str = None, due_date: str = None ) -> MyFinancesResponse[CreateInvoiceResponse]: - payload = { - "amount": amount, - "description": description, - "due_date": due_date, - } + def update_invoice(self, customer_id: int, amount: float = None, description: str = None, due_date: str = None, status: str = None ) -> MyFinancesResponse[Invoice]: + params = {} + + if amount is not None: + params["amount"] = amount + + if description is not None: + params["description"] = description + + if due_date is not None: + params["due_date"] = due_date - payload = {key: value for key, value in payload.items() if value is not None } + if status is not None: + params["status"] = status - response = self._client._post(f"/invoices/{invoice_id}/update", json=payload) + response = self._client._post(f"/invoices/{customer_id}/update", json=params) return MyFinancesResponse(**response.dict()) From 64dc816483f8ba6701fdea507c11553a1a475c6d Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sat, 16 Nov 2024 20:36:11 +0800 Subject: [PATCH 11/19] fix(ClientService): fix the update function, so that they can choose which arguments --- myfinances/__pycache__/models.cpython-312.pyc | Bin 2179 -> 2189 bytes .../__pycache__/service.cpython-312.pyc | Bin 2575 -> 3828 bytes myfinances/clients/service.py | 43 ++++++++----- .../__pycache__/service.cpython-312.pyc | Bin 3644 -> 3452 bytes myfinances/models.py | 3 +- .../new_test.cpython-312-pytest-8.3.3.pyc | Bin 0 -> 4601 bytes .../test_finance.cpython-312-pytest-8.3.3.pyc | Bin 11453 -> 24960 bytes .../test_invoice.cpython-312-pytest-8.3.3.pyc | Bin 0 -> 12177 bytes tests/test_clients.py | 58 ++++++++++++++++++ 9 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 tests/__pycache__/new_test.cpython-312-pytest-8.3.3.pyc create mode 100644 tests/__pycache__/test_invoice.cpython-312-pytest-8.3.3.pyc create mode 100644 tests/test_clients.py diff --git a/myfinances/__pycache__/models.cpython-312.pyc b/myfinances/__pycache__/models.cpython-312.pyc index 54dea4031f9774863272d6749193e85bb7bb40e7..52c504a67e7c7a11b41e5b4ab245e43ac5451fa5 100644 GIT binary patch delta 507 zcmZn`>=ooa&CAQh00a+LnWb;s$Sc9fXf=5vljLN3MlP9Dwp5lBW*eYv3QH7wDhH6q z3gT6=XtGUCWR&5!#h#m5T%4FbxrWhK;1+XnNl}piQ2rK6N@jA&M}rXE5i+5 z!DinZf+Ck$L~ig3H2d5Tk!W!52)V){Q6vRaP{cEtpIvhE1SWMR)*^nOz~logs%jvU zisXTWCR33doXrWbfh{F9IX@+}NPIFkt2Lv*WOr6MM(N3Etagkdlb5pIQj`Vh<0=va z=@SAG!XSbNM2Lb2`N<2|q~$b0Oi2&{c7`;F1=0y71Sa2PGhhQt$O7FLP!D&6pC%h_ zlO?d2sS6SV5jsFz3~~i9Ot|=(y?{iE7sPUqw4WwlkqVG5Vg?eo*h(r3GV{`lSU@7I z43qD(Ym0(i2R07L*^}it%yn59B|9v?FaW79e3Fb@Gb9(duW(%G^@Rb*`C`Gu$UnjI KD+7=M+Xeu=bz}Sh delta 495 zcmeAbY!>7_&CAQh00hU4^wL*sBXMkl7$Y8;FZRt^o!Y z7hkg%kZAFOI07W?r^#2OJozHKvnbd#U~NdwoUF-V&cn>8)M5FB0Z4t}nViER%K~yK E0L6x8KmY&$ diff --git a/myfinances/clients/__pycache__/service.cpython-312.pyc b/myfinances/clients/__pycache__/service.cpython-312.pyc index d469d0661f7be9b0f62c70315b051a5b19dc3e96..1e292170561b9d527cbd1f17f8046267aa3f14f5 100644 GIT binary patch delta 1052 zcmZ`$OH31C5T1V@UD|F7?ebP0MqVZ05=n~>JfKDef+p5z1eB27Rf|B(wqU?kFyY{V z2;@Hy4kqOWAw~>|A)fT?rHwH(jYKZoSHTz)56<5L5ff*#-_Cq9J2U_H&*blxxj(vG z4nVuze)9fXdCvVi{|W(^2Lrl^4&9s`?4aklXH=%#v`c`PBg4V~M?VM( z5$R{4LUBc;{k}SOh`I*sR1zyYHI9JB$K;svG5Cb5W(`)2=c(FY$QX`<)saVff5cEt z1!6i-S7k#OXEu1cwdlg zyFPn-c4V$T;R!ysB|X6{rD(o&u60AHN-9-}>X!9FDhnlzzjh?>-XLM7ecaJjXIl{w zG*t7zZ0KdK#iX+~f4R=Re==CiMmUll*@ER zswW=$PP$rJhs9|=G#oK=&@&quum)y;7Uvw}-Vk~==ljGCaH8Lm!GAh+GLTZ6Q-L$7 zCO>l;nh?J!C89rdw8G-?yH(Y&6kP1GMD#5il-I-`B+FDwVqp$c)-CZ1G0V;(2h^%d z;l&}#$s!r*PgpMIx%aDbS(FE5=c?nug)Ym(LhpW(&BW+*CrNbnBv1A3WQYJR8V_4+ z--O!szCNjT(MJ2Lmh*Tfc2nVM1dAtxY{HRkDBA}0D|95GV-uQoZPy6#&-VNP_BD@S F8&f(PE{FL=1Bc~>FkvLFqk;dfh?A4QxbMrIuPrlCW zC!h`#yv3ZES5m|QlGdJV&!fonm0@xc&!@=(d}~e3fuf8+T&xTvJ}@&fGTvp7e##*G fltKSKgV#j{ue%HeU)T&7O(#TuWdKq|(m-_pzDqCb diff --git a/myfinances/clients/service.py b/myfinances/clients/service.py index 28d5b57..ef43428 100644 --- a/myfinances/clients/service.py +++ b/myfinances/clients/service.py @@ -58,7 +58,7 @@ def get_client(self, client_id:int) -> MyFinancesResponse[Client]: return MyFinancesResponse(**response.dict()) def update_client(self, - name: str, + name: str = None, phone_number: Optional[str] = None, email: Optional[EmailStr] = None, company: Optional[str] = None, @@ -67,21 +67,36 @@ def update_client(self, address: Optional[str] = None, city: Optional[str] = None, country: Optional[str] = None) -> MyFinancesResponse[ClientIdResponse]: - params = { - "name": name, - "phone_number": phone_number, - "email": email, - "company": company, - "contact_method": contact_method, - "is_representative": is_representative, - "address": address, - "city": city, - "country": country, - } + params = {} + + if name is not None: + params["name"] = name + + if phone_number is not None: + params["phone_number"] = phone_number + + if email is not None: + params["email"] = email + + if company is not None: + params["company"] = company + + if contact_method is not None: + params["contact_method"] = contact_method + + if is_representative is not None: + params["is_representative"] = is_representative + + if address is not None: + params["address"] = address + + if city is not None: + params["city"] = city - params = {key: value for key, value in params.items() if value is not None} + if country is not None: + params["country"] = country - response = self._client._put("/clients/update/", params) + response = self._client._post("/clients/update/", params) return MyFinancesResponse(**response.dict()) def delete_client(self, client_id: int) -> MyFinancesResponse[ClientData]: diff --git a/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc index 72efe3cb50210de8df49fe9c23b8c4bc03ed761a..2fca536abb1455cc2ac0e91f7c574b74f6ac443a 100644 GIT binary patch delta 1165 zcmZuvOH30{6rKM}JEeewfTd6h6df#7f*6!aG%9Kg4VthqBtV$q6G}9%5ED{@8W(Id zC9@!Ej2IU}bkT?l7RInNx|xX!8{>kwG$xi*H^hbazLt-lm(02M-23k9JLmPa|Ci7E zzNpB}z_M?5jP|+~yzkszq_A?Y7QUncoXH!!DHwt&8X|li_#{&@)dR3)#It&rtzy}g z)fMg=tCvCPlQ1x9P7xVWQVyVVqylr?p5Op#Yl+W#Beb$*R#s?Z{Z@ncI9vmbEjB{- z;no1a3ZEaV!vdYX#oHFSVxYSNt5+JX$Vtcx|kQ1uVXWeKqcZ4Ad!kJakU?*1)k^w zxXENnwRvenEw|OWOhaV8J9X0W1UJ-DTdmFnLclv5kKelEYUw9_7#NlSwio88IQJ5O zijxX*q=Gme#PLaqii5iY6M*qlxCl%HCKQAp1Xmt1hV%#qUdTHJ$a@S>zyKKyh`VA$ zg&!pzgd&6{gu;tWUpI!}#Y(V5UtWVuSN0h6zu{fK6xdGv%3F3?ZJWbpVisV>vOg{Q z*Fw!!1DT)>7M^fCHGf;Wp;atK7os1vkfVi`-RaJB^V$u&@%-BnTMK>A`sS6-#X+a| z=+cE}Jx_X`S}9pk@d0!$7Sn~8rFhPDR{!O;801E| tO=M%-51b@^Yo=&!|Bjq3B|3S{n2wuW7%g5PolW-&=bVH;uP(65C*hG^N|7`Lm3mHKh?P2#_q%L_tE(Hh8yD{sh{M z%ik_7w;U?P);pBH3ReQDr9~L!K!rF&oDjXN#UYhXrRN?Txgb$-U}kM4Rm4dCW_JGe z%{OoTZ~T|!o;#6UFeE#Mb{~Kv0i@G*zxY)dr#<4KlA#H4kbOP; z1Oy(@Q9FvMPXgSKTV(_22x?`p(m`>P9ieeCz;jT1hKplZ{E<3pT1(c76|^uEJ2;Da zw(ZZ_<12W; zKul$xxO^cDFHH9pBuWah$2{eIVz4}LiF>jQ@n&fMX@k|-{ED^g1hd*HjBL+os4f0l z`4~D3P?s0259{p0>{8Kcv5E!2DhjOSyHNIpLGU<>0GG(U#DTl9FnbtnylVD7 zgdO_Bk6qtg&3ZBO2*L(8B))8%GKN3!MAnPRGgNq{Om*YP@>5mO9=f@X*izDuo8x{>X`q-rC43 z?SMGe*?%U?vez>W0_wICC_jJBpIxfumz(I^ifNFbHwdVz6)6Ap>6V^b2y}yx59q5B ysMn-((iT3=N)NHXPKcj7FZOJo_)#dg{H|GCvX0w1k&mRhCTO;__!j|XW72;WtssN| diff --git a/myfinances/models.py b/myfinances/models.py index 74c8015..8a2a22a 100644 --- a/myfinances/models.py +++ b/myfinances/models.py @@ -9,7 +9,8 @@ class Meta(BaseModel): success: bool status_code: int - content: Optional[str] = None + message: str + content: dict = None class MyFinancesResponse(BaseModel, Generic[T]): diff --git a/tests/__pycache__/new_test.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/new_test.cpython-312-pytest-8.3.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc68d06fdbf17b4e4f28f04b9ae9286e5bebfc65 GIT binary patch literal 4601 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 F{xAD+AgcfX literal 0 HcmV?d00001 diff --git a/tests/test_clients.py b/tests/test_clients.py new file mode 100644 index 0000000..b84301b --- /dev/null +++ b/tests/test_clients.py @@ -0,0 +1,58 @@ +import pytest +from unittest.mock import Mock + +from myfinances import MyFinancesClient +from myfinances.clients.service import ClientsService +from myfinances.clients.models import ClientIdResponse, ClientData + + +@pytest.fixture +def mock_client(): + mock = Mock(spec=MyFinancesClient) + mock.session = Mock() + return mock + + +@pytest.fixture +def clients_service(mock_client): + return ClientsService(mock_client) + + +def test_create_client(clients_service, mock_client): + # Arrange: Prepare the client data and mock the response + clients_data = { + "name": "John Doe", + "phone_number": "1234567890", + "email": "john.doe@example.com", + "company": "Example Inc", + "contact_method": "email", + "is_representative": True, + "address": "123 Main St", + "city": "Sample City", + "country": "Sample Country" + } + + # Updated mock response structure with both `meta` and `data` fields + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Success" + }, # Include the meta field + "data": {"client_id": 123} + } + + # Mock the _post method to return a mock response object + mock_post = Mock() + mock_post.dict.return_value = mock_response_data + mock_client._post.return_value = mock_post + + # Act: Call the method you're testing + response = clients_service.create_client(**clients_data) + + # Assert: Ensure the correct API call was made + mock_client._post.assert_called_once_with("/clients/create/", clients_data) + assert response.data["client_id"] == 123 + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Success" From 9a0818d8af997d129e80d2215385b5cf200edf62 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sat, 16 Nov 2024 21:23:13 +0800 Subject: [PATCH 12/19] test(ClientService): Implemented testing for ClientsServices that includes, create, list, delete and update clients --- .../__pycache__/service.cpython-312.pyc | Bin 3828 -> 3870 bytes myfinances/clients/service.py | 41 ++-- .../test_clients.cpython-312-pytest-8.3.3.pyc | Bin 0 -> 21104 bytes tests/test_clients.py | 180 ++++++++++++++++++ tests/test_finance.py | 8 +- 5 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc diff --git a/myfinances/clients/__pycache__/service.cpython-312.pyc b/myfinances/clients/__pycache__/service.cpython-312.pyc index 1e292170561b9d527cbd1f17f8046267aa3f14f5..7cbfcb3e67deca6b34452a6e8246e9a1dc5e1f64 100644 GIT binary patch delta 1482 zcmZvbO=ufO6vt;Jt+czNFKZ=#=_5)kX)RmsI%9Jl}I9p?eZz0a-+30CAsdLKH!bYOWx)@hAD zR)myYY>QU}UJJrZR%CCB*-L4V?*`R{rNzoht*S0)mDg$&b)P$Qy;WUZ(PT*PyR--l zhy47l)oM)>L2ErY@6~$QikPEVLknT(W3%pv)DQB|ho#s&?Pr_r5O&1E_c2NjbCxm1&sr9oTJVUAT zICU1nJz~l|4+@RK&vMF;Q_Z^veFs!e7oNz^vw5kzuEk){g8fs2z{d?Q7HeA&9*{+{ zF0FCz@oU_gROSjWx8?wH06A=O0y%-4Ho1UYKrWkjARdUf$qnQNa@*tq@+1L0HVS|O zkYJMtBm#--Ylj+@)})8@e+~1ZVGdsjtx`@{b^BHstN`AAb%L9ft)uJ(-4w^$3aUx@QmH&J(Wq)#F!xI%dR;CR( zt!E}5|I;t%ByT&(I8Qg*l|IVY4e6OLSC%TZ%CnZ#RJ`P~Ub#+3xeEJ$7W!k5$T~`; ztWbid2ya$IRVuNc=rk8)UEXj#2a67!iz_uv0Huv$IENvR0sjm3DKuGKHut2Y*!o077rQ{k@)spW5&XaB@ijLea#S+wuqP_!>T!$tDEVp znHx1T!zj*VARa}cP$(3!co?Bbbf7u5Gh%s=1QL#IUxA;>5)mZ=`zYm8VjQa#*B;;vRV98!1iJ7d z_x*%1`BK~FmpMFt_4xei{Fdi5!u|JYNolO_BgMzB$AgZ~r?%d6$vOO+MCoA0^K#O zXzjv*1C>&NwTHl^GD1~ARBftAQ7)Bo>!BB~IAmqzz@dj8A0j=Z>Y+1sOsJH1nEAdp zGjHC`_x6YO=WVV(B*{r&ee(X9+mFPO>tE)wE-;3EmATR3TjnO+S&t%StqP~uS|II~ zH7hS$Cp`;H)cCAuOsM*xcdO zAUORZAGz?gC!U$kDR=T(JfkW%^GaNmAr`f&C%{#?^xUkLS9!pyANNJI8S%^dXwZl3 zBp6Ku(|K&EE&3O>1e4P5+mgYaJ$Yos@u$1XaGxz-zCXS>zI6p)#c@_`)h+fPPd6H} zx0PeGVMCu@3c{@C22uK&vvLz$}V=gLBr`|{@Wyi%9U1-r)-0|;~7 z;s>Q91hhpkON9FMpKaaB;P5Ynox<+7Pra$lKv^y;PnwL857t6!^QBnDn_96M-qe0W zg0LZnE8TBC_V3AWzkd8L4(-HumCr5w#$LhJ$AqTn{zc@dwceDR+(1v%B$C> z_T#;do&b=lggN?8e85#tPS;=a$NH9#bhkoA)G{#Fn&Z zYC|4D&gSmqRR_`mG(%{H(cllE;#n&GfGRwKy1~n9zcPd@6KW%&Ub8cNV3)YWzAvyo zR2rZhUL&W>>cv={HaHB4|Ga_MoX1id|mHfrrB8j&-dx zL+!{M#B*}pVYs^}kJL$^N2t_B1!N*==_<<`5|xm-NU)Q-5qTO}USvMvZeG*Ao1u#` z(i4p!cBOve3|4~u20w7vj67-K66GOEz*YJ#KE7r2y?2NNdL_=AXNJxAkU9L8Iha7u zKM3|fZs8JUu!FMT_rv|$sm*c90fsMW?7VQpg=FR#@vA0K%VGvedV s@$z*M1%1@@ebbSi|2UE}v)TD+<&yf2{+FxUdxc>VYuElJ=xY`K0jvOS$p8QV diff --git a/myfinances/clients/service.py b/myfinances/clients/service.py index ef43428..10927b1 100644 --- a/myfinances/clients/service.py +++ b/myfinances/clients/service.py @@ -9,9 +9,9 @@ class ClientsService(BaseService): def list_clients( - self, - order_by: Optional[str] = None, - search: Optional[str] = None + self, + order_by: Optional[str] = None, + search: Optional[str] = None ) -> MyFinancesResponse[ClientData]: """List clients under the specified team.""" params = {} @@ -24,16 +24,16 @@ def list_clients( return MyFinancesResponse(**response.dict()) def create_client( - self, - name: str, - phone_number: Optional[str] = None, - email: Optional[EmailStr] = None, - company: Optional[str] = None, - contact_method: Optional[str] = None, - is_representative: bool = False, - address: Optional[str] = None, - city: Optional[str] = None, - country: Optional[str] = None + self, + name: str, + phone_number: Optional[str] = None, + email: Optional[EmailStr] = None, + company: Optional[str] = None, + contact_method: Optional[str] = None, + is_representative: bool = False, + address: Optional[str] = None, + city: Optional[str] = None, + country: Optional[str] = None ) -> MyFinancesResponse[ClientIdResponse]: """List clients under the specified team.""" params = { @@ -48,13 +48,12 @@ def create_client( "country": country, } - response = self._client._post("/clients/create/", params) + response = self._client._post("/clients/create/", json=params) return MyFinancesResponse(**response.dict()) - - def get_client(self, client_id:int) -> MyFinancesResponse[Client]: - response = self._client.get(f"/clients/{client_id}") + def get_client(self, client_id: int) -> MyFinancesResponse[Client]: + response = self._client._get(f"/clients/{client_id}") return MyFinancesResponse(**response.dict()) def update_client(self, @@ -63,10 +62,10 @@ def update_client(self, email: Optional[EmailStr] = None, company: Optional[str] = None, contact_method: Optional[str] = None, - is_representative: bool = False, + is_representative: bool = None, address: Optional[str] = None, city: Optional[str] = None, - country: Optional[str] = None) -> MyFinancesResponse[ClientIdResponse]: + country: Optional[str] = None) -> MyFinancesResponse[Client]: params = {} if name is not None: @@ -96,9 +95,9 @@ def update_client(self, if country is not None: params["country"] = country - response = self._client._post("/clients/update/", params) + response = self._client._post("/clients/update/", json=params) return MyFinancesResponse(**response.dict()) - def delete_client(self, client_id: int) -> MyFinancesResponse[ClientData]: + def delete_client(self, client_id: int) -> MyFinancesResponse[Client]: response = self._client._delete(f"/clients/{client_id}/delete") return MyFinancesResponse(**response.dict()) diff --git a/tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61331ba5fac7ee146df1bebd0290739714defbf2 GIT binary patch literal 21104 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 Date: Sun, 17 Nov 2024 00:25:20 +0800 Subject: [PATCH 13/19] test(ReceiptsServices): Implemented testing for all of its functions such as create, list, delete and search --- .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 213 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 1307 bytes .../__pycache__/service.cpython-312.pyc | Bin 0 -> 3149 bytes myfinances/finance/receipts/models.py | 1 - myfinances/finance/receipts/service.py | 38 +++-- ...test_receipts.cpython-312-pytest-8.3.3.pyc | Bin 0 -> 16254 bytes tests/test_clients.py | 4 +- tests/test_receipts.py | 151 ++++++++++++++++++ 8 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 myfinances/finance/receipts/__pycache__/__init__.cpython-312.pyc create mode 100644 myfinances/finance/receipts/__pycache__/models.cpython-312.pyc create mode 100644 myfinances/finance/receipts/__pycache__/service.cpython-312.pyc create mode 100644 tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc create mode 100644 tests/test_receipts.py diff --git a/myfinances/finance/receipts/__pycache__/__init__.cpython-312.pyc b/myfinances/finance/receipts/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f32eaae93b32c5e744f703b6d1d2360c293f4f48 GIT binary patch literal 213 zcmX@j%ge<81a6Ur=^*+sh(HIQS%4zb87dhx8U0o=6fpsLpFwJVl{j0)gche36~}lb z=B5@aI2LE- literal 0 HcmV?d00001 diff --git a/myfinances/finance/receipts/__pycache__/models.cpython-312.pyc b/myfinances/finance/receipts/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c516ad93c95f40a95aa13fee219758543804cc93 GIT binary patch literal 1307 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 literal 0 HcmV?d00001 diff --git a/myfinances/finance/receipts/models.py b/myfinances/finance/receipts/models.py index 58beec9..c5e989c 100644 --- a/myfinances/finance/receipts/models.py +++ b/myfinances/finance/receipts/models.py @@ -19,4 +19,3 @@ class ReceiptList(BaseModel): class ReceiptIDResponse(BaseModel): receipt_id: int - message: Optional[str] == "Receipt successfully created" diff --git a/myfinances/finance/receipts/service.py b/myfinances/finance/receipts/service.py index 7a2f780..3c7c461 100644 --- a/myfinances/finance/receipts/service.py +++ b/myfinances/finance/receipts/service.py @@ -33,21 +33,41 @@ def create_receipt(self, return MyFinancesResponse(**response.dict()) def list_receipts(self) -> MyFinancesResponse[ReceiptList]: - response = self._client._get(f"/receipts/list/") + response = self._client._get("/receipts/") return MyFinancesResponse(**response.dict()) def delete_receipt(self, receipt_id: int) -> MyFinancesResponse[ReceiptIDResponse]: response = self._client._delete(f"/receipts/{receipt_id}/delete") return MyFinancesResponse(**response.dict()) - def search_receipts(self, receipt_id: int = None, name: str = None, merchant_store: str = None) -> MyFinancesResponse[ReceiptList]: - params = { - "receipt_id": receipt_id, - "name": name, - "merchant_store": merchant_store - } + def search_receipts(self, receipt_id: int = None, name: str = None, merchant_store: str = None, + image: Optional[FilePath] = None, date: Optional[str] = None, purchase_category: Optional[str] = None, + total_amount: float = None, owner: Optional[str] = None ) -> MyFinancesResponse[ReceiptList]: + params = {} + + if receipt_id is not None: + params["id"] = receipt_id + + if name is not None: + params["name"] = name + + if merchant_store is not None: + params["merchant_store"] = merchant_store + + if image is not None: + params["image"] = image + + if date is not None: + params["date"] = date + + if purchase_category is not None: + params["purchase_category"] = purchase_category + + if total_amount is not None: + params["total_amount"] = total_amount - params = {key: value for key, value in params.items() if value is not None} + if owner is not None: + params["owner"] = owner - response = self._client._post("/receipts/search/", json=params) + response = self._client._get("/receipts/search/", params=params) return MyFinancesResponse(**response.dict()) diff --git a/tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0882008ba71264ecde025d7f76d304a732e963ef GIT binary patch literal 16254 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 literal 0 HcmV?d00001 diff --git a/tests/test_clients.py b/tests/test_clients.py index 56be1ba..d4bc678 100644 --- a/tests/test_clients.py +++ b/tests/test_clients.py @@ -3,7 +3,6 @@ from myfinances import MyFinancesClient from myfinances.clients.service import ClientsService -from myfinances.clients.models import ClientIdResponse, ClientData @pytest.fixture @@ -38,7 +37,7 @@ def test_create_client(clients_service, mock_client): "success": True, "status_code": 200, "message": "Success" - }, # Include the meta field + }, "data": {"client_id": 123} } @@ -170,7 +169,6 @@ def test_delete_clients(clients_service, mock_client): assert remaining_clients[0]["id"] == Client_Id - def test_update_clients_name(clients_service, mock_client): clients_data = { "id": 1, diff --git a/tests/test_receipts.py b/tests/test_receipts.py new file mode 100644 index 0000000..75b9a0f --- /dev/null +++ b/tests/test_receipts.py @@ -0,0 +1,151 @@ +import pytest +from unittest.mock import Mock +from myfinances import MyFinancesClient +from myfinances.finance.receipts.service import ReceiptService + +@pytest.fixture +def mock_client(): + mock = Mock(spec=MyFinancesClient) + mock.session = Mock() + return mock + + +@pytest.fixture +def receipts_service(mock_client): + return ReceiptService(mock_client) + + +def test_create_receipt(receipts_service, mock_client): + receipts_data = { + "name": "Client 1", + "image": "file_example", + "date": "2024-05-21", + "merchant_store": "Store 1", + "purchase_category": "Purchase 1", + "total_amount": 500, + "owner": "Client 2" + } + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Success" + }, + "data": receipts_data + } + + mock_post = Mock() + mock_post.dict.return_value = mock_response_data + mock_client._post.return_value = mock_post + + response = receipts_service.create_receipt(**receipts_data) + + mock_client._post.assert_called_once_with("/receipts/create/", json=receipts_data) + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Success" + + assert response.data["name"] == receipts_data["name"] + assert response.data["image"] == receipts_data["image"] + + +def test_list_receipts(receipts_service, mock_client): + list_of_receipts = [ + {"id": 1, "name": "Client 1", "image": "file_example", "date": "2024-05-21", + "merchant_store": "Store 1", "purchase_category": "Purchase 1", "total_amount": 100, "owner": "Owner 1"}, + {"id": 2, "name": "Client 2", "image": "file1_example", "date": "2024-03-21", + "merchant_store": "Store 2", "purchase_category": "Purchase 2", "total_amount": 245, "owner": "Owner 2"} + ] + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Success" + }, + "data": list_of_receipts + } + + mock_response = Mock() + mock_response.dict.return_value = mock_response_data + mock_client._get.return_value = mock_response + + + response = receipts_service.list_receipts() + mock_client._get.assert_called_once_with("/receipts/") + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Success" + + assert isinstance(response.data, list) + assert len(response.data) == 2 + + +def test_delete_receipt(receipts_service, mock_client): + list_of_receipts = [ + {"id": 1, "name": "Client 1", "image": "file_example", "date": "2024-05-21", + "merchant_store": "Store 1", "purchase_category": "Purchase 1", "total_amount": 100, "owner": "Owner 1"}, + {"id": 2, "name": "Client 2", "image": "file1_example", "date": "2024-03-21", + "merchant_store": "Store 2", "purchase_category": "Purchase 2", "total_amount": 245, "owner": "Owner 2"} + ] + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Successfully deleted invoice" + }, + "data": list_of_receipts + } + + mock_response = Mock() + mock_response.dict.return_value = mock_response_data + + mock_client._delete = Mock(return_value=mock_response) + + receipt_id = 2 + + response = receipts_service.delete_receipt(receipt_id) + + mock_client._delete.assert_called_once_with(f"/receipts/{receipt_id}/delete") + + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Successfully deleted invoice" + + remaining_receipts = [receipt for receipt in list_of_receipts if receipt["id"] != receipt_id] + assert len(remaining_receipts) == 1 + assert remaining_receipts[0]["id"] == 1 + + +def test_update_receipt(receipts_service, mock_client): + list_of_receipts = [ + {"id": 1, "name": "Client 1", "image": "file_example", "date": "2024-05-21", + "merchant_store": "Store 1", "purchase_category": "Purchase 1", "total_amount": 100, "owner": "Owner 1"}, + {"id": 2, "name": "Client 2", "image": "file1_example", "date": "2024-03-21", + "merchant_store": "Store 2", "purchase_category": "Purchase 2", "total_amount": 245, "owner": "Owner 2"} + ] + + mock_response_data = { + "meta": { + "success": True, + "status_code": 200, + "message": "Success" + }, + "data": list_of_receipts + } + + mock_response = Mock() + mock_response.dict.return_value = mock_response_data + mock_client._get.return_value = mock_response + + search_name = "Client 2" + response = receipts_service.search_receipts(name=search_name) + mock_client._get.assert_called_once_with("/receipts/search/", params={"name": search_name}) + + assert response.meta.success is True + assert response.meta.status_code == 200 + assert response.meta.message == "Success" + + assert response.data[1]["name"] == search_name From 6366d832d6a842cbaded53faa78e9bc28f0a3af4 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Tue, 19 Nov 2024 14:21:28 +0800 Subject: [PATCH 14/19] fix(Update): fixed the update function for invoice and clients, aswell adjusting the test for it --- .../__pycache__/service.cpython-312.pyc | Bin 3870 -> 3890 bytes myfinances/clients/service.py | 2 +- .../__pycache__/service.cpython-312.pyc | Bin 3452 -> 3472 bytes myfinances/finance/invoices/service.py | 2 +- .../test_clients.cpython-312-pytest-8.3.3.pyc | Bin 21104 -> 21023 bytes .../test_finance.cpython-312-pytest-8.3.3.pyc | Bin 24960 -> 24888 bytes tests/test_clients.py | 9 ++------- tests/test_finance.py | 4 ++-- 8 files changed, 6 insertions(+), 11 deletions(-) diff --git a/myfinances/clients/__pycache__/service.cpython-312.pyc b/myfinances/clients/__pycache__/service.cpython-312.pyc index 7cbfcb3e67deca6b34452a6e8246e9a1dc5e1f64..67b624357369138dc55ba20a61dc0939911181fd 100644 GIT binary patch delta 116 zcmbOyw@HroG%qg~0}#mS*`&*D+3ld9` zGm1EYoFZ`$p*6Xe^8>%yMPaoI>XrxCE(oh#7IvT9!*zpEZ*nU4a{+CTHs;K{k|GX} La{bLQJcpP7`57P* delta 96 zcmdlaH&2fDG%qg~0}#BNWsxqsk@q(%%? xMPbzoY8E@nE(oh$7IvGwfa?aM{^UyT=K?xFMYotU^Gb?1K*|j^7w{Zn0sx~I9sB?Q diff --git a/myfinances/clients/service.py b/myfinances/clients/service.py index 10927b1..de2e1de 100644 --- a/myfinances/clients/service.py +++ b/myfinances/clients/service.py @@ -95,7 +95,7 @@ def update_client(self, if country is not None: params["country"] = country - response = self._client._post("/clients/update/", json=params) + response = self._client._patch("/clients/update/", json=params) return MyFinancesResponse(**response.dict()) def delete_client(self, client_id: int) -> MyFinancesResponse[Client]: diff --git a/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc index 2fca536abb1455cc2ac0e91f7c574b74f6ac443a..d6ba7728bbc3f40bf321dad8c159db16ea5f4a0b 100644 GIT binary patch delta 479 zcmew(H9?y9G%qg~0}xzPwn-1%$UC2jQFHTJrZi({K?4boP{uAh>clUkAr)~v}=1h$_&9x4cTLXiqkaWTRa9rgmCDRbHPFltVY z;!xEF*{aD3u@&U8B25sX4I;qyvjSN_`@t?)#W4k_*Pio{4OkJ>8Kng&i9lxvfV6-- z0&@#nd_iJKat2apaDc6ue33~+4&53Km^Bcas=0c^)h-IFt&rN_y}|YX`vrB66J-~K z)h-K%O%`Ak2fD(H+uv9UWF-rTPyi8ZAVL*HXn+VE5TOquz`-jGVo7e^!Oh4B)V_0*`C*u1;hjZM~z&< delta 459 zcmbOr{YQ%TG%qg~0}xzjvPciu$UC2japmTS1@6~9c$OY7+lyN$~yVu<~l(f8x+}q$UsWjy&HwDtLNS! ztA&y{6(3BT=fxPJJ`e+8QIf`}561XrVl*RS)EiJ=NHpU@`C(Xz3VvbxQD)t5a+GjB?rA)ozDWI%&89BX5It zeQfF-VO6D6K4}zMBCJ#5f&wPOKsfK%(fZjM)VZI5u#R3 zt#T-pl+&sbS7drBIV96cK3d7XGkS?oxMlR3iK}qOvYU{mLa)tCNFy5%2Fh0RNwkhl z3lUcc-Fgnuq5D!B`%4IujjX|bfmqpB_Uh6D-0Cj;V*i~Gfptdwh2I>PY{bdl2sC$9 zahq1rJ+7!UkxC{mTQp-*qHes@3wQt*-~*}wKTrd#V1Ea?iHmIt2Ks9;5CDQe1IO)( z*5dYBMWU5u5;QTY&{mkkz($}A*aU0_)&N_8t?a{K(i1^(=Fu!XyIgfM%eDL-f)T^gDn~4$TxFkyXu>N-Ao+_<=ME>)g4b*9|-k>;Rqx zdVp=fcHkKx1mO5-z7aeDoCHQWM0ZgW4D1AYIW%E(Z0Ka1%1UM|&2`t0VK1z^fqq~B z*az$fV!(48nl+l4h$j^8rbZS%Y+_eKwf0?@w}(T4gsdy(;W029@|B+Ej~xYD{j8D4 z)jz8~vF4x0)Pukv-~)jB^ zwRDV&~sSefyy_}C#_a~ueRjjp~rxV z9`cx;0(P;Vqg(3qi=avuUXpRd^F`@3KIwcR+}&Kleu@Y_#}&c{c*~JEN}ApzC%Y4= zF;2VKd)wP9sw8)=G)bmC?8f$_&zrLh6Umn|=PHJcS4>5RY8Ddnq?&yoP6+-BrfiwP zaKq39P}w%^&t115>^uMahN*hKGV>+A0Aju>)| z6KjjxTks>fQ8dmtxzFLg){5Gki*GKJb25ALdiG`CMxp+KQQu6Jv{G8d?)L4^H^k`w zROim}rL*R3`fVL*6Nz4|vX1!+ZagC;RJm0j=9iu6gff<<`G+ZtSdo*#%y;NGG~GanmIrqpCwp*xs)ZyV`m9eevn%7>Gu)p06Q z8@5yl;6D+?rASd_DH4so1w0AhZF)VvZSEKylg3l>Q}kUvhV)ZVM`ue2A-@_7lZID> Zn}*;m!X6)c3Sbnrc~Q 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 I(&O}h0K^w-z5oCK diff --git a/tests/test_clients.py b/tests/test_clients.py index d4bc678..ee49f27 100644 --- a/tests/test_clients.py +++ b/tests/test_clients.py @@ -18,7 +18,6 @@ def clients_service(mock_client): def test_create_client(clients_service, mock_client): - # Arrange: Prepare the client data and mock the response clients_data = { "name": "John Doe", "phone_number": "1234567890", @@ -31,7 +30,6 @@ def test_create_client(clients_service, mock_client): "country": "Sample Country" } - # Updated mock response structure with both `meta` and `data` fields mock_response_data = { "meta": { "success": True, @@ -41,15 +39,12 @@ def test_create_client(clients_service, mock_client): "data": {"client_id": 123} } - # Mock the _post method to return a mock response object mock_post = Mock() mock_post.dict.return_value = mock_response_data mock_client._post.return_value = mock_post - # Act: Call the method you're testing response = clients_service.create_client(**clients_data) - # Assert: Ensure the correct API call was made mock_client._post.assert_called_once_with("/clients/create/", clients_data) assert response.data["client_id"] == 123 assert response.meta.success is True @@ -194,12 +189,12 @@ def test_update_clients_name(clients_service, mock_client): mock_response = Mock() mock_response.dict.return_value = mock_response_data - mock_client._post.return_value = mock_response + mock_client._patch = Mock(return_value=mock_response) new_name = "Client 3" response = clients_service.update_client(name=new_name) - mock_client._post.assert_called_once_with(f"/clients/update/", json={"name": new_name}) + mock_client._patch.assert_called_once_with(f"/clients/update/", json={"name": new_name}) assert response.meta.success is True assert response.meta.status_code == 200 assert response.meta.message == "Success" diff --git a/tests/test_finance.py b/tests/test_finance.py index 7793970..e43f114 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -210,13 +210,13 @@ def test_update_invoice(invoices_service, mock_client): mock_response = Mock() mock_response.dict.return_value = mock_response_data - mock_client._post.return_value = mock_response + mock_client._patch = Mock(return_value=mock_response) new_status = "paid" response = invoices_service.update_invoice(1, status=new_status) - mock_client._post.assert_called_once_with(f"/invoices/1/update", json={"status": new_status}) + mock_client._patch.assert_called_once_with(f"/invoices/1/update", json={"status": new_status}) assert response.meta.success is True assert response.meta.status_code == 200 From 1d93995bdbbc4e3d7982026c0cb81e100a121412 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Tue, 19 Nov 2024 14:32:43 +0800 Subject: [PATCH 15/19] feat(Api-Client): added patch and delete in MyfinanceClient --- example/list_invoices.py | 1 + myfinances/__pycache__/client.cpython-312.pyc | Bin 2477 -> 3357 bytes myfinances/client.py | 15 ++++++++++++++- .../test_clients.cpython-312-pytest-8.3.3.pyc | Bin 21023 -> 21007 bytes .../test_finance.cpython-312-pytest-8.3.3.pyc | Bin 24888 -> 24873 bytes tests/test_clients.py | 4 ++-- tests/test_finance.py | 6 +++--- 7 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 example/list_invoices.py diff --git a/example/list_invoices.py b/example/list_invoices.py new file mode 100644 index 0000000..b864674 --- /dev/null +++ b/example/list_invoices.py @@ -0,0 +1 @@ +from myfinances import MyFinancesClient diff --git a/myfinances/__pycache__/client.cpython-312.pyc b/myfinances/__pycache__/client.cpython-312.pyc index e8f839cc2418aab2b6f3b36048c47a3633b6a147..5ef9f8ba0f4a747ce0db949c1b2daf36164cb0ff 100644 GIT binary patch delta 594 zcmZXQ%WG3X6o>EJdEGoMy|zu1(gc&VvC<}>NHvg!P*=KfcM)RAOdn7#Wo{O2QM<{y zRL(*{gn*kC9|YaFcj>03h>(^4fKbi4;F+XF(F60%?>y$rnR(~Gx|IHsO2r+tg-UJZ zk$jdu-BIX0ceE1_Jz zim_3?vD9j=8i9kDDT`_NDK6$kV-Vk-__yEOFmVM6^43W4$S-!9UG{0^&@UeQixA4} zxQkuRjiI2p`up&M7l;d0mM0Xhi`fhAWBQi9IV*m`U_(q1274ky2)q{)N+`XqTl&vr zWp2i>m9c+jau$;oc|^n!IcsJdRZljChqp8Tk3Y;@wWl6HS>8yOj{H(5>fSx{OUHf< zpRh}+a4Ij83S_;Us9H|qKEL>yPZEtb6$TD oojADd7y5P^ggSJf`$_ojJta4x5zCMoY{q6%B{KQTK@1xI2J(uIyZ`_I delta 244 zcmbO$wN{w#G%qg~0}vcH(o0unoyhms&jZMt&XCFw#hAhn#gxL8!j#IK!ko&I$}9<# zNn=T2XC3?v@`NgTqlM}cV*ffAD zG`S|Xaoek^0hvW09V;1%BtUF25WxW>xPgpf+sR+Jt(iXaO%C9xW7MB~o=1YwWbz9h P4PHq`*-s2W0<04NS1&kt diff --git a/myfinances/client.py b/myfinances/client.py index 6389fd6..7f33b6b 100644 --- a/myfinances/client.py +++ b/myfinances/client.py @@ -32,5 +32,18 @@ def _post(self, endpoint: str, json: dict): response = self.session.post(url, json=json, headers=headers) return MyFinancesResponse.from_http_response(response) + def _patch(self, endpoint: str, json: dict): + url = f"{self.base_url}{endpoint}" + headers = {"Authorization": f"Bearer {self.api_key}"} + + response = self.session.patch(url, json=json, headers=headers) + return MyFinancesResponse.from_http_response(response) + + def _delete(self, endpoint: str): + url = f"{self.base_url}{endpoint}" + headers = {"Authorization": f"Bearer {self.api_key}"} + + response = self.session.delete(url, headers=headers) + return MyFinancesResponse.from_http_response(response) def close(self): - self.session.close() \ No newline at end of file + self.session.close() diff --git a/tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc index 61677776c6eacf5f5c58b19880af21e62c2d01cc..76878b84e01099bcc66f9c289b4b1f317c6f9852 100644 GIT binary patch delta 819 zcmb7?-%FEG7{}jdd;PJEckibAJ*V%S%`K;!&8g^I2191c!KxJq6~Q4{M3|$C;_L@R zSQlf~a}kkR7o#6+1o2+jP2pV^MIabfgxG&D><_5(4(TqihjR`b&iDDA=X{>?vQ5&N3D2KYL@pmR{|6(CO9PBpk`&fxK( zQA}DStoY{z*D8OzmE-a{(oK3W1}o${W?R}&`i;QNWo zqC^d>u0ATV+f+3k*KKJmPR^*05HB`-vzT{k&=DO3FFrH%;9R=~7o&cm|Da+c@ew~h zk7nAA+8IdVLDf{aO`;<69Kh(*7zCOwza69Y02y3WHQ#9>LnKH|S!nLe*y!?OB<6z< zmVyz)*rfa=b|0XKm!?Bdz?JE1+PlpC4x710_){th{UfF14sYG!t=oK`{NTizib3~) z0Y8m6RCOa>k4H2eq?5K}p>D!@JZm*KX<8IM$~&1A3u0x}6~T&&{#%0WZx`&u!Md=4 z<%ory{Yz08U&eAGWOX*3UH{>Hjwe72*zlNf_T*c!yT(4962MWzRUfXzP3;QJypf3l z$)LtbI~dO%YQ){Z09KO61nGceCvlTr{G80NZkB=x`Npa5psldn7i{KkVkUJ_|J55- zU|F_!%Qo+kH&Y)}tqRVi3YOC@c#O658Mg#O`!gWHBwM}U-#-m*2>(jJG(dPsVCp{< C+UCCi delta 926 zcmb7?%}*0S7{>Q4Td-~VMN7Bcey|G#T1!6=5TOgfL>r`PM5BbL5aWoc5)Xw7WS~t5 zhJ!?sH}N2-Byzye17s~ex2B=F(7Nd`OqG|3)TwS=cLAI$ad z@{h7a*^upGWvxYRF+a3|qP~~178p=_8@Ou8SKMMB7&io7|0lFt@!U;C(Z;M`0Gea zkg0wUNHsk`b%UB^erG@AUu*T^<2F0^@mbrI3Yl7%x`vvW%bprn;~|_8BwUVL@ueWM zx4op6)ZvPF0u9PxsKcx~fH#z&F;F~*l?2H_Tu{!JgZ^`Bz-O5yevMTdK9*e_ zN?p4(GMvufWap6nHv2Kn`tUvcBuyCCMc>k?HL)$5T;m0G>gWTF{|`o%-SzW~n5@u< z6^HzyCRdJMnwoVsVyD^^he$% zMXhfi+6z1Zc8WmvTd2ez-LlS}XE1JMH7Oa@d1yJKAW_CL6vD~mAwe#tZX;Ff=GaoO z!vI&^LHwSq!qI3qOsJPnZh(H4IptU%9>Gfu{l;~dcd32N)tXP(p{|^MttrhjNYCPU mj~DLaT+cbV1|nN$K!W&I0%{?+brxi3{MH4X0F7xQoBbQ%ivKYH diff --git a/tests/__pycache__/test_finance.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_finance.cpython-312-pytest-8.3.3.pyc index 0823c5ebccca3c370cde6ccf96473e8169e8a0ad..769f922dbf90bedff97fd7350745f5bba3f52d11 100644 GIT binary patch delta 2976 zcmb`JZA?>F7{_~PEq&p(^u4r{wp5@OMkyeQ6BTg7A;_zufL&pn$|_>ZZPgTSSN3U% zTjsK7*_W}`FMH81riq$tiPL>t{6J!&X=36&Ez7c)ecMcy>^!#>iV=fsB>m;wd(Lyt z;XKd(f6tBET|z5a$0bq;x9mJ|!SD90p-R+=`jaJ>6}T6fjJl=JdIyGjq26I8?n3wk=ULvi zsFcal<%Rbj4nxkMUcqIJ{{8CMjh`ju)P$EA%_4F-4H zMk5Qe)x#s#b7v#Z8!@6t$@m6Pd*bke$Ftwg))lH49&4JSXU@f|PB#aWgWQekPSmD-^E=sO=CEQJR=Z?j9G z6)zCF03RH(!gme9LagHjVvoT;ow3MdkQRPmOziWj1|I2O8a3Q>uW~`6D`bK_IvqS}(QD4J7nqYo6jZHY-NU*aOMUkgwiSi#u3~#O*;=N{Je?yp zdM$%T1RFjtAlB#YF?j(W!|)BvDI*h1*ezKU?mzES>oS6GXBl!@=2cHzYKtaSlp+tC zl83jt9o?Hv%W78gXD%h94|mrOfgv~i-EAZnvSkO(Yqe{-2*LXUj`F890XGI-Rpw6= z|t~9hN5C##L3rAP0HYg#q4{yYY{aV^Ku(q(0u zqbjOqm!aD6tL)Bmf81*;M}tipD3?}=22nM~zU677XoMA~ml>{+8Lmq-NQN7kXt7nT z-eug>BbuT_`T&_>*vZ4aiE4$H*)RMv;a6dC@k-{2jgxjV0X>s^XicnX>?D$^7L99{ zkmjbdaXQUx7q10^7qRIYgq6u)=2<>!DfUq|WlkB6PbX*I%<1xr{eRk>l?0Z;ZF?B_ zVy9hSoH@;z$oX(0Ih{P4*w}FMB?@;>jA|u2%}X0@wFF=)q}NBf9&w zt>~lH6@~S#!k4`tGMA8U_#@m(_JVinWcvskD#Q?Iz`_N@5(4KDb|E-~mf^9gV?IXD Oo{sDjK7yN5seb`b#B)*r delta 3067 zcmbW3UrbY19LG6O3T?e@Zz*kQDQ)?G!P0`F;KcD~x*>unDg(q)IYp{ix_gTXYuD+^ zUd%T4OO}|ie?Dns$xIVx*u$pV%d(hd2@hLm79aMuB}?|Qg)G_5?-oiyMC2xXIQO34 zJ?HTI{k~uBtq0`Z1HygJaq28~h24A4ynToJNKFOP3TLe-9zgrT#BdU$+#kuA<7qJu3h$u(wf(yoA#75^P{Sajx2<0d*a~lbb|MVLC!R* zkUL95&C~*|ue=363SK6MYyE{}|ADYu`!uV-hpM|EtS z71fl;s&UjE$SI)?XtQ?0FLf%IuX7Uz@V08udjzv{>Et|h(b6a%B=X;3fFm{mTJ0*h zZqo6(OC+X`siRt2CTpq~Zg_U*6)}YpS`LprKCWU(Sw>n(tKg8=S6|&D9%p$LdBh1s zKjKxy0OBNK7;y^WgGb)#?zA9o5xM=u5jHoI=b?d#KqRm!W#D4F5rc5BzUeGw!=ynB zoc9Mq!O)p>4+{!0Lmn7k%P^z$ORVW4&Wh^rbdw;7V>pwISVuQPL8e;Zk9vE2Ys$zF z2A)?a6m_`eHpE#3DnmSnup?w&SWgrUX;mcimeeXn@C{ib6FBNdgb*pQz#hF-%M2v zM^ENDo+TFGjOJj*FVc6?vclW{hni|HO18I4U_inDb3dMEs%1N{W~C0-yElSEf=7|MXPE zx8t(U_+Nn`8|5}@bsuB6oJO4#@Qb74%bAqcNhK@GvweSUF8Pe^j^b`Bd6jGY)b4&V zulXsrmlNxN_TFN0CE@G+B)fc-&vThR&o-1Vss(VoTo#}%c_t>Lf1Y8OgcP>S-G!WzMu*pxT~FANE% zS2Ql+!#KV~WJS&xRz76vJyT)oXSR(}6-yDDZdbTJ;)xGfT$v(a8yqUHz-ylHm zuugrI?e;bMkxoHy_$c?N$bPeBp{N;s*p&Eg*qBW^;8))cvJVU+V@-W{wlD(yTZ|#D dAaEJ63Be&W42$`D&ri~+iNHSbefWH2`hWE;iNXK? diff --git a/tests/test_clients.py b/tests/test_clients.py index ee49f27..6144557 100644 --- a/tests/test_clients.py +++ b/tests/test_clients.py @@ -149,7 +149,7 @@ def test_delete_clients(clients_service, mock_client): mock_response = Mock() mock_response.dict.return_value = mock_response_data - mock_client._delete = Mock(return_value=mock_response) + mock_client._delete.return_value = mock_response Client_Id = 1 response = clients_service.delete_client(Client_Id) @@ -189,7 +189,7 @@ def test_update_clients_name(clients_service, mock_client): mock_response = Mock() mock_response.dict.return_value = mock_response_data - mock_client._patch = Mock(return_value=mock_response) + mock_client._patch.return_value = mock_response new_name = "Client 3" response = clients_service.update_client(name=new_name) diff --git a/tests/test_finance.py b/tests/test_finance.py index e43f114..da93122 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -58,7 +58,7 @@ def test_list_invoices(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Successfully created" + "message": "Successfully fetched invoices" }, "data": invoice_list } @@ -101,7 +101,7 @@ def test_delete_invoice(invoices_service, mock_client): mock_response = Mock() mock_response.dict.return_value = mock_response_data - mock_client._delete = Mock(return_value=mock_response) + mock_client._delete.return_value = mock_response invoice_id = 1 @@ -210,7 +210,7 @@ def test_update_invoice(invoices_service, mock_client): mock_response = Mock() mock_response.dict.return_value = mock_response_data - mock_client._patch = Mock(return_value=mock_response) + mock_client._patch.return_value = mock_response new_status = "paid" From 249ec6dc4e0635e2063cfda5b74290243008417f Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Wed, 20 Nov 2024 23:32:37 +0800 Subject: [PATCH 16/19] Refactor(Client_Services): updated the function update_client to be less redundant with handling the parameters of the clients data --- example/list_invoices.py | 1 - myfinances/__pycache__/models.cpython-312.pyc | Bin 2189 -> 2164 bytes .../__pycache__/service.cpython-312.pyc | Bin 3890 -> 4099 bytes myfinances/clients/service.py | 53 ++++++++---------- myfinances/models.py | 1 - .../test_clients.cpython-312-pytest-8.3.3.pyc | Bin 21007 -> 18036 bytes .../test_finance.cpython-312-pytest-8.3.3.pyc | Bin 24873 -> 21167 bytes ...test_receipts.cpython-312-pytest-8.3.3.pyc | Bin 16254 -> 13831 bytes tests/test_clients.py | 13 +---- tests/test_finance.py | 13 ----- tests/test_receipts.py | 10 +--- 11 files changed, 26 insertions(+), 65 deletions(-) delete mode 100644 example/list_invoices.py diff --git a/example/list_invoices.py b/example/list_invoices.py deleted file mode 100644 index b864674..0000000 --- a/example/list_invoices.py +++ /dev/null @@ -1 +0,0 @@ -from myfinances import MyFinancesClient diff --git a/myfinances/__pycache__/models.cpython-312.pyc b/myfinances/__pycache__/models.cpython-312.pyc index 52c504a67e7c7a11b41e5b4ab245e43ac5451fa5..b3bd3cac6a6350b377628ef04e4a8c69ecf334e8 100644 GIT binary patch delta 469 zcmZ{gJxjwt7{_~gZDL~@jWt07br1<66dbDJ+af}t#lfjd3CU3qZSgK0+|(*`aXN6- z-9_;$xOLQ_9Ju)ry102yh9ZIw-0!)2UjN*kGcH;~%QADqR=#)I4=Hw*LCf{gsZ<~S$ZxWG>Hfdblo02KaXrvLx| delta 494 zcmew&&@0G$nwOW00SF$hGE3jMkynC|(Q2|ZyRu9wTPjNmvkg!tg(ZqTl>^9Q1@S6b zG}$IcGs=kGV$V%2E>28O^}EHMoS#>cnpdL9Ik}n9f&CV9aY<2;z~rNhP3kg0Ev*bU zcmHYR4!tc{=N@C|QtB zt|CE@P9YE>3?g_ygeZsrnOwvIB0&DX#hsj!SX`W&T9T2UQltqImIM)C=ShQDAoIY4 zz~s|x25evnS)jWEqTr76(`3VKp9B^&bwOevLI;S8L2d(v6&GK#7m#T2Dw3MKnms@i zY%y3Rl8Yt_aG2||FiLh$xn@W%a9`oL(CZ5Wkn_cYiIIPTY6(b#jW!`v5;PbCCYm6@O}oM(6tcTuKpHe& zB#?laizLR>8~BqLIpD>3HSq$swI@Az^RT2EVxrMEKnXI*e(!znz4_kEn|6>)Z`idaBHVFtVa(S)!W|&Rk%q_8Nn#N zHlpC3IG(soW%8=V`~=qa+bT!o;3QL8>X;(Ny))fvN=_vdy-(36CsMjH(6x8E!6=T) zhWx*HqmGk`A**Bh5oN6iW}%f(@Bpln*Nz^c4ZQovDnp(M^4AgL=^R=3awci!s%)bS zk=V+394+(9LV{IM!ZrvcH*E-|`Lr-6JYeVeIf2-g!~&ES_hM)ivd7mbM~1l4fcT1i zd5}#@h9h5<)-DaDMc%$74!$uT>u!9 zb!RMjk@6(~m`Vlm`b-=$y?(Q*)~szY>m$^us0Q3A;e)PS4=VI5D2v0pJ8?V8$Tt6t zxkWaG_x5&(YaL`(tYJ3EQ}OG($hBv>ECgmN6ni(l9qP_eV)@a@M)Pck*%~p!ZDu5D zMq|_owE*svc)517I$*J2ztn}+`k(h&9Qc+U`5Q7L+rF^np!5X7O>69G+Hz9HqsH)> z{(RgLC=*e0>zlf+b-yK1>dKcEQszd!`b__7uT?}@aXv@;0y}q^`54*m=*#W#2s!Wi Yz{JUKSAEe9hG}0J_=%|1s^PBx09H@~>;M1& delta 747 zcmZ9}L2DC16ae6v-Rva0vum2BQlv?mnxvbi+or8eY;7ruP>RwB){9D!V1un7l(c$E zNJWaRr^pkqziKye7OO`JWLRGzAMfPK(v%1e_i8e<2y$Q;HM){flNN1<{An}0V#o0kP1=*g+L)tD3AuyKw2OIA|Mhd z3<`t7fg+#?C=v^(19hMdVxwWF*Jv28=_>`UhtZ_#+P?~+C36KeD2u5X#j3C&GQ_@X z)OonNR9&wX>o#nw#~}=a>Zc)nC3jY<>vxyyx?Jd%p}?x7haDP&ttsHzM+h58bfM0! zE#lLtOM7^-Z)>()-mdtx+oc(v8wJjI=2@S1xHQ328Swe-Yd-CCX^N+9;G}0JeR{^F zIc}G>X5DzkGqXNTxHQiTQ*xr;GwuI6azV?93s0N~|ENL-Sz0IT8U2lGY}0&C#^f_f zY|iS#Z`pn8TT9VOyO#xms0Bf({@rCSSrlQ(2ukPo)t#o$r3_>j_t*9w2r6Zw!mzL|%JS6l zwy0DGO6GPKcIHJ)s`GeF-U*t#ia(XTiR(v!Z(wFc5Ah}TC7O#ZVq9w9{)J?&C*Yxf E0pSAAApigX diff --git a/myfinances/clients/service.py b/myfinances/clients/service.py index de2e1de..51b9dab 100644 --- a/myfinances/clients/service.py +++ b/myfinances/clients/service.py @@ -53,6 +53,16 @@ def create_client( return MyFinancesResponse(**response.dict()) def get_client(self, client_id: int) -> MyFinancesResponse[Client]: + """ + Retrieving a singular client via their client_id. + + Args: + client_id (int): The ID of the client to retrieve. + + Returns: + MyFinancesResponse[Client]: Data of the client's details. + + """ response = self._client._get(f"/clients/{client_id}") return MyFinancesResponse(**response.dict()) @@ -62,38 +72,23 @@ def update_client(self, email: Optional[EmailStr] = None, company: Optional[str] = None, contact_method: Optional[str] = None, - is_representative: bool = None, + is_representative: Optional[bool] = None, address: Optional[str] = None, city: Optional[str] = None, country: Optional[str] = None) -> MyFinancesResponse[Client]: - params = {} - - if name is not None: - params["name"] = name - - if phone_number is not None: - params["phone_number"] = phone_number - - if email is not None: - params["email"] = email - - if company is not None: - params["company"] = company - - if contact_method is not None: - params["contact_method"] = contact_method - - if is_representative is not None: - params["is_representative"] = is_representative - - if address is not None: - params["address"] = address - - if city is not None: - params["city"] = city - - if country is not None: - params["country"] = country + params = { + key: value for key, value in{ + "name": name, + "phone_number": phone_number, + "email": email, + "company": company, + "contact_method": contact_method, + "is_representative": is_representative, + "address": address, + "city": city, + "country": country, + }.items() if value is not None + } response = self._client._patch("/clients/update/", json=params) return MyFinancesResponse(**response.dict()) diff --git a/myfinances/models.py b/myfinances/models.py index 8a2a22a..bd7ea07 100644 --- a/myfinances/models.py +++ b/myfinances/models.py @@ -9,7 +9,6 @@ class Meta(BaseModel): success: bool status_code: int - message: str content: dict = None diff --git a/tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc index 76878b84e01099bcc66f9c289b4b1f317c6f9852..938178b2eeeb164ebe4a74cd8623bc32e7c8360f 100644 GIT binary patch delta 3318 zcmb_eTWlO>72bdL=H2z|-8<{O?|SWcvc6vm_!2uIZtK|bC6|`8Nj8rEO<2dVt(mnd zhuLl=kdRP9Qk@5?)&c|R1B$7FjQUh6^T0y|5*AcQY^AnuJb;9ol$TN}&KY}c<2s|$|v zQ+#MYi!c0mt0h=-w$^@RHhS!vRR(YLmFW$4>LZ6GWZ5tUK6b-r&fzL;!_@q)>C6W( z<%+^3R}H-A`lay?rVQM6huM8db`4mT1x?@qT+(?M^Ng6KykRwn3&~5hn(YeXA^pPzV~`2(q~ zXnV0(U8t`-Yt@B@ihWPmvWhm%c895Pp5!TL>%DDE?f%zrqrmH6B{&QpNFI1w>SlGg z02#OVx!Q5*;9xSW*FIGf$Hg;VuQ@f>?k2!`Zw78j2?*Dcw8w54>KD!2|;)hulit!-4KWZ)YVgRKNp=`=t%@xYkvw5|Uou19- z<_fAZK%-j>BWsZ0D8UfHlLSu@93%KT!Eu5(L7E^>FheklAo~>;+0_J36R=@OCW4L$ zvPTIfVQSE4IZ5U?Tu6M)GD7AUEGN3{FQD0txB5MJFLBCWVYVl_ht#jPr{SB)GW!es zI&~U0Q=7uuHdJR2KB=qTqOud5>7O$fyp^7p+?pNt(4$o$6?ZA@h0W#?^TNu|lIYu} zu7mq|4Q$Hip!DQLDWK1jzR0}zLFXIPPgcZ}4Z?C$r!}BC@&DAqTbZmF+CEDc5Az5( zGiML<5Z&<*eM}Fr9S^bp?E#szkq*Ec%^BPSVtyRuD;%(Q3oSBBU@8~}vDF5DYiV{R zcyigOv$L|Ik#TFW3e#U|OnH`0`5Of12s{MO5j>A@MmbNWkKh8qMS=)Hlz?_txrzXH zMrEDb5{PZRC1RLtRJv%Gc%wAY3$J1%dx!YS0zQ`QNd9fwe`(gs9-Zdxdw4!fAr(E) zwzjf)u5{4becX5Jgx3WyM#JNfXz#Fp3(aTnR)^tyd&hy)UwggX%8>W&P8r%dH-+<6 zI`4bB8Y(Fqd2f|8^J@lVTcrCMCU9bZXdjEiI{U*q`zwjtp(pMw_P0RhD{Yv(X>Q^R z%zYMq+T)KViEWzsS|hH7-K^HcmxY@ylcDG=iiJ9Ow`T}FyU}w>b76#CP3qYh+4qLj z?%Pq)J%-NknqzQDYKFhpB*4-41ZM4*!i_M~CyVvl>h>@|egW?tNmpgjklBqkaK|O68wjykI5JQdzD6Ee5N zOJ9{$We&7~_7aW%$51y8T_<1rB~i9!w_=vXt>6ELGD>;{2<)!_JIYXAr2oHP67=pA z!D)gs2xV)fIu+@at`wE5ae_qxl2F+(xUiJHGOt{pDs<5U+#ejUe+Nfsn%eWo60&yr zsExsIj{PzHPEeeXP46_A5T^y4Rk<8!P!f6glI8QYp%)b;E~U-8K*RYUVs! z^})*VyyVwqQ?pMt0bOzdU2@V+!3km^*e*Em-R=PUZ(luQ;?#FGo`{gxu?>aM69Xt0 zwV8-c%kYnp)Y0T)Nn{W8;lgOftWYzD3B3`1HJTLtdy_W&bu?W1 zGOY<^d}WD%niRR_k(?}7&E;Om&P`p#@CwVb31Ip1ptKWi|xApXg+RV4TeLQM0d5U!+il zP>9|N#Z!6+L;@n~Cslpd=lSAn?uhaOe5ACgUWU7qClWE%^xznav0lV9lOK$+IO}|P Lob|I#efqxvv}fld delta 4365 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 XV{?!-u)c>oScr9gws`~VP^b7Ggs1D_ literal 24873 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 diff --git a/tests/test_clients.py b/tests/test_clients.py index 6144557..d06ae5f 100644 --- a/tests/test_clients.py +++ b/tests/test_clients.py @@ -34,7 +34,6 @@ def test_create_client(clients_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": {"client_id": 123} } @@ -45,11 +44,10 @@ def test_create_client(clients_service, mock_client): response = clients_service.create_client(**clients_data) - mock_client._post.assert_called_once_with("/clients/create/", clients_data) + mock_client._post.assert_called_once_with("/clients/create/", json=clients_data) assert response.data["client_id"] == 123 assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" def test_list_clients(clients_service, mock_client): @@ -66,7 +64,6 @@ def test_list_clients(clients_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": clients_data } @@ -80,7 +77,6 @@ def test_list_clients(clients_service, mock_client): mock_client._get.assert_called_once_with("/clients/", params={}) assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" assert isinstance(response.data, list) assert len(response.data) == 2 @@ -105,7 +101,6 @@ def test_client_by_id(clients_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": clients_data } @@ -120,7 +115,6 @@ def test_client_by_id(clients_service, mock_client): mock_client._get.assert_called_once_with(f"/clients/{clients_id}") assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" assert response.data["id"] == clients_data["id"] assert response.data["name"] == clients_data["name"] @@ -142,7 +136,6 @@ def test_delete_clients(clients_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": clients_data } @@ -157,7 +150,6 @@ def test_delete_clients(clients_service, mock_client): mock_client._delete.assert_called_once_with(f"/clients/{Client_Id}/delete") assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" remaining_clients = [clients for clients in clients_data if clients["id"] == Client_Id] assert len(remaining_clients) == 1 @@ -182,7 +174,6 @@ def test_update_clients_name(clients_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": clients_data } @@ -197,7 +188,6 @@ def test_update_clients_name(clients_service, mock_client): mock_client._patch.assert_called_once_with(f"/clients/update/", json={"name": new_name}) assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" # Updated Version updated_clients_data = { @@ -217,7 +207,6 @@ def test_update_clients_name(clients_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": updated_clients_data } diff --git a/tests/test_finance.py b/tests/test_finance.py index da93122..da9137c 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -27,7 +27,6 @@ def test_create_invoice(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Successfully created" }, "data": { "invoice_id": 102, @@ -44,7 +43,6 @@ def test_create_invoice(invoices_service, mock_client): assert response.data["invoice_id"] == 102 assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Successfully created" def test_list_invoices(invoices_service, mock_client): @@ -58,7 +56,6 @@ def test_list_invoices(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Successfully fetched invoices" }, "data": invoice_list } @@ -73,7 +70,6 @@ def test_list_invoices(invoices_service, mock_client): assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Successfully fetched invoices" assert isinstance(response.data, list) assert len(response.data) == 2 @@ -93,7 +89,6 @@ def test_delete_invoice(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Successfully deleted invoice" }, "data": invoice_list } @@ -111,7 +106,6 @@ def test_delete_invoice(invoices_service, mock_client): assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Successfully deleted invoice" remaining_invoices = [invoice for invoice in invoice_list if invoice['id'] != invoice_id] @@ -132,7 +126,6 @@ def test_get_invoice(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Successfully deleted invoice" }, "data": invoice_data } @@ -148,7 +141,6 @@ def test_get_invoice(invoices_service, mock_client): assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Successfully deleted invoice" assert response.data["id"] == invoice_data["id"] assert response.data["customer_id"] == invoice_data["customer_id"] @@ -167,7 +159,6 @@ def test_search_invoices_by_id(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Invoices fetched successfully" }, "data": invoice_data } @@ -183,7 +174,6 @@ def test_search_invoices_by_id(invoices_service, mock_client): assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Invoices fetched successfully" assert response.data[1]["id"] == 2 assert response.data[1]["customer_id"] == 124 @@ -203,7 +193,6 @@ def test_update_invoice(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Invoices successfully updated" }, "data": invoice_data } @@ -220,7 +209,6 @@ def test_update_invoice(invoices_service, mock_client): assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Invoices successfully updated" # updated version updated_invoice_data = { @@ -236,7 +224,6 @@ def test_update_invoice(invoices_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Invoice fetched successfully" }, "data": updated_invoice_data } diff --git a/tests/test_receipts.py b/tests/test_receipts.py index 75b9a0f..d34af13 100644 --- a/tests/test_receipts.py +++ b/tests/test_receipts.py @@ -3,6 +3,7 @@ from myfinances import MyFinancesClient from myfinances.finance.receipts.service import ReceiptService + @pytest.fixture def mock_client(): mock = Mock(spec=MyFinancesClient) @@ -30,7 +31,6 @@ def test_create_receipt(receipts_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": receipts_data } @@ -44,7 +44,6 @@ def test_create_receipt(receipts_service, mock_client): mock_client._post.assert_called_once_with("/receipts/create/", json=receipts_data) assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" assert response.data["name"] == receipts_data["name"] assert response.data["image"] == receipts_data["image"] @@ -62,7 +61,6 @@ def test_list_receipts(receipts_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": list_of_receipts } @@ -71,12 +69,10 @@ def test_list_receipts(receipts_service, mock_client): mock_response.dict.return_value = mock_response_data mock_client._get.return_value = mock_response - response = receipts_service.list_receipts() mock_client._get.assert_called_once_with("/receipts/") assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" assert isinstance(response.data, list) assert len(response.data) == 2 @@ -94,7 +90,6 @@ def test_delete_receipt(receipts_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Successfully deleted invoice" }, "data": list_of_receipts } @@ -112,7 +107,6 @@ def test_delete_receipt(receipts_service, mock_client): assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Successfully deleted invoice" remaining_receipts = [receipt for receipt in list_of_receipts if receipt["id"] != receipt_id] assert len(remaining_receipts) == 1 @@ -131,7 +125,6 @@ def test_update_receipt(receipts_service, mock_client): "meta": { "success": True, "status_code": 200, - "message": "Success" }, "data": list_of_receipts } @@ -146,6 +139,5 @@ def test_update_receipt(receipts_service, mock_client): assert response.meta.success is True assert response.meta.status_code == 200 - assert response.meta.message == "Success" assert response.data[1]["name"] == search_name From 76931d403ce2c101346ae9b28030e644a9c86c92 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Wed, 20 Nov 2024 23:50:33 +0800 Subject: [PATCH 17/19] docs(Clients_service): Added comments to clarify the functions that i created --- .../__pycache__/service.cpython-312.pyc | Bin 4099 -> 5171 bytes myfinances/clients/service.py | 26 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/myfinances/clients/__pycache__/service.cpython-312.pyc b/myfinances/clients/__pycache__/service.cpython-312.pyc index 781aea274837c26f724df891eae77c2071ce86cc..10ad26c25ed331f12576a2326346fdba5d9b72f0 100644 GIT binary patch delta 1139 zcmaJ=&ubJh7|l>?>uk5b!6MuCL;GVb)dgXt_8^FQ5GkTX5Q;46Otu@DO~xdxR*+Tv z2gEt`*52Bi(u+rL3SQci9z^^T22{M7%*>`!N;`+iyv)nX``(wlf!%WN*J9B{`q?>k zedYDwhu(sFAL9;$T*#h>p^p`1D}Wi0=Ts)&UO)*`(-M55Fb(7^Jfo@sszD$We2x0V zhY$2Wm z5l3aLpM(Y(Ew9vS*8@PB+Hy|gw!w?3A1joSuP0)1Bi*!hw;6U9HDoVIRna4cZPl-br79a;;T%Flf*K{ z5Li{K6wP*zM+@C^!$4(r=6qXdbk6< z^h*UB0`;>EN|$ePR;QwAu93MTeon;Tbcx*~8tDo8pXy5~tNQf{#lvWLBzo8L&H1?d zqUh&%Ond>V~SZ8r8tD{+^B-3ZFt9UCv>GX}Y6y0R^| znsLFP9yD|1{lv~#Tr{Y+&FnL%AB|3KE^aKu0|pJY{|%+++T9Dzm#h184}K>TkDNkh lbyLPj4||mxpQiRJcmAM4biQwIKsZkI?b2UlMp4qW{0I1fZVLba delta 253 zcmdn2(X7CCnwOW00SLqx?9vtaHu74r!=PofL1m@f2VM}552lhI#1mkURb3D~)AxfQ zh$jS-6Nd0Cy_FbGm|e68`V1B@V`4R3Q2c=bNL|o(JfL<_-}4It)8ruG3xW}hjHVN! MzcPU6A{n4Z0830s_W%F@ diff --git a/myfinances/clients/service.py b/myfinances/clients/service.py index 51b9dab..9d7b88c 100644 --- a/myfinances/clients/service.py +++ b/myfinances/clients/service.py @@ -76,6 +76,23 @@ def update_client(self, address: Optional[str] = None, city: Optional[str] = None, country: Optional[str] = None) -> MyFinancesResponse[Client]: + """ + Updating an existing client's details, with the provided parameters + + Args: + name (Optional[str]): name of the client to update + phone_number (Optional[str]): client's phone number to update + email (Optional[EmailStr]): client's email address to update + company (Optional[str]): client's company name to update + contact_method (Optional[str]): client's preferred contact to update + is_representative (Optional[bool]): to update the client if they are representative + address (Optional[str]): client's address to update + city (Optional[str]): client's location in the city to update + country (Optional[str]): client's country location to update + + Returns: + MyFinancesResponse[Client]: Data of the client's details is updated + """ params = { key: value for key, value in{ "name": name, @@ -94,5 +111,14 @@ def update_client(self, return MyFinancesResponse(**response.dict()) def delete_client(self, client_id: int) -> MyFinancesResponse[Client]: + """ + Deletion of a specific client + + Args: + client_id (int): client's id + + Returns: + MyFinancesResponse[Client]: Confirming the deletion of the client + """ response = self._client._delete(f"/clients/{client_id}/delete") return MyFinancesResponse(**response.dict()) From f2258594461b8c87ebfa0ca0fc62db9064184f12 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Thu, 21 Nov 2024 00:37:32 +0800 Subject: [PATCH 18/19] docs(finance_services): Added comments to clarify the functions that i made for invoices and receipts --- .../__pycache__/service.cpython-312.pyc | Bin 5171 -> 5171 bytes myfinances/clients/service.py | 2 +- .../__pycache__/service.cpython-312.pyc | Bin 3472 -> 3894 bytes myfinances/finance/invoices/service.py | 65 +++++++++--- .../__pycache__/service.cpython-312.pyc | Bin 3149 -> 3782 bytes myfinances/finance/receipts/service.py | 97 ++++++++++++------ ...test_receipts.cpython-312-pytest-8.3.3.pyc | Bin 13831 -> 13836 bytes tests/test_receipts.py | 6 +- 8 files changed, 121 insertions(+), 49 deletions(-) diff --git a/myfinances/clients/__pycache__/service.cpython-312.pyc b/myfinances/clients/__pycache__/service.cpython-312.pyc index 10ad26c25ed331f12576a2326346fdba5d9b72f0..b7f102af9c1357d8c1a4c592b0884619f12a4378 100644 GIT binary patch delta 29 jcmdn2u~~!nG%qg~0}xnq*rhjZL}?`yxhZ z@EM5F&uPv2+VYA_F(PYIIr9mC7$X7AmavhvLZwJSAktYb%iaY+_G-|AEBWJAW`mJb zG^XIQyqD$W1Edw_DGwHS=FkS6L{l5gWHdE_kEPA!oh}uPbk`$plh246`nctD8B9Fs`#(|#wYE|jLrjJV7;zcw*#kpp=R!~P80GW zTLc93D&zKR?CtKIQVppU!}imPu0|I3+cWSaes4dPm`4ED$_yE0*l1_n(WO`53X2;vn-9kk<5j>XU!;shF>D?pM? eLkKs)iEm&i4~8~D+ZKBs!tg@!2QX0f6U{I1u?l$r delta 591 zcmY+AO-LI-6vt;~cQ%{MW}~dtR%2osMZ}K~O2n2ZO6iA+L91RA{J?%av-P__RLg~fJ2KC;zy9aR&@ArQ5pIPSZ&se!d{Syv{5G*U1 zU7ZSEr~?=WEAQ|j!GA0NgfPYp{7$rRj_*oy>Qgwl^#aOQWNS_QM*0Q8n7pY*9|e`) zvW{^Z&xSq^eTQTpt)Y@+kX>pJL(1bU>=^=>07g6$!9*~@GYUq*M4k<%I;nxbp}cee zr_TbX1TMoW1-7Z*A(WTbkP+a=G)aOv&RK7>sA~{jNsAwsw^s^!07QQRrAy}5EEdtb z-3@OV89E+S28Vl~*(yPS+3K}Dsmkh2)@sK)_TH8UEG1fHjV60;x2M1dEhSN9n#tmJ zq6_?$rNsDr=o$Z^^isXW{bWtq#3{ZU?%829W4CuYg3ENj&o}RV&M){}Hynh%;Av7r zsEB9Ct$W&OCNyKl)92k*eCQT|I5L!@702z(zTwLzt8ernIMMtd{rYm;N>6%0P3DT4 z7^$O~lca+H=bt>7A7*_Piaw1UkMN8MvPb|+WYvAm1Sya^RL3{e{m@Go47 MyFinancesResponse[InvoiceList]: @@ -22,14 +21,42 @@ def list_invoices(self) -> MyFinancesResponse[InvoiceList]: return MyFinancesResponse(**response.dict()) def get_invoice(self, invoice_id: int) -> MyFinancesResponse[Invoice]: + """ + Gathering a specific Invoice by ID + + Args: + invoice_id (int): Invoice ID + + Returns: + MyFinancesResponse[Client]: Invoice details + """ response = self._client._get(f"/invoices/{invoice_id}/") return MyFinancesResponse(**response.dict()) - def delete_invoice(self, invoice_id: int) -> MyFinancesResponse[InvoiceList]: + def delete_invoice(self, invoice_id: int) -> MyFinancesResponse[Invoice]: + """ + Delete a specific Invoice by ID + + Args: + invoice_id (int): Invoice ID + + Returns: + MyFinancesResponse[Invoice]: Deleting the specified Invoice + """ response = self._client._delete(f"/invoices/{invoice_id}/delete") return MyFinancesResponse(**response.dict()) def search_invoices(self, customer_id: int = None, status: str = None) -> MyFinancesResponse[InvoiceList]: + """ + Search for a specific Invoice by use of filters + + Args: + customer_id (int): Customer ID + status (str): Invoice status + + Returns: + MyFinancesResponse[InvoiceList]: invoice list with the specified filters + """ params = {} if customer_id is not None: @@ -42,19 +69,27 @@ def search_invoices(self, customer_id: int = None, status: str = None) -> MyFina return MyFinancesResponse(**response.dict()) def update_invoice(self, customer_id: int, amount: float = None, description: str = None, due_date: str = None, status: str = None ) -> MyFinancesResponse[Invoice]: - params = {} - - if amount is not None: - params["amount"] = amount - - if description is not None: - params["description"] = description - - if due_date is not None: - params["due_date"] = due_date - - if status is not None: - params["status"] = status + """ + Updating an existing Invoice + + Args: + customer_id (int): customer's ID + amount (float): Invoice total amount to be change + description (str): Invoice description to be change + due_date (str): due date of the invoice to be changed + status (str): Invoice status to be changed + + Returns: + MyFinancesResponse[Invoice]: updating an existing invoice's details + """ + params = { + key: value for key, value in{ + "amount": amount, + "description": description, + "due_date": due_date, + "status": status, + }.items() if value is not None + } response = self._client._patch(f"/invoices/{customer_id}/update", json=params) return MyFinancesResponse(**response.dict()) diff --git a/myfinances/finance/receipts/__pycache__/service.cpython-312.pyc b/myfinances/finance/receipts/__pycache__/service.cpython-312.pyc index ca0ceae2f2da461eeee0170efc3e1f9aa3d332c3..34b9465241b46f1cc0f5e2c88ed7518a9eed48ce 100644 GIT binary patch delta 1433 zcmZuv-A^1<6u)jn3bflFFfeeCDb%N>AA~J4d6}Yobx;9{LVe+ z&iSSBhql;H(WrvpY=o~Zd>{EN_7DEki{a0!WF(`VhxjdARBs0mQb^^DTU2$ZO;lpg zRbo+%>dTJuB0Od-*qIlIa||_4leS}}GUUxgT86}&Cl1(JPN#-*EL+d33p9Ci+0jiy z%}r0}xgvc-brxrUKCkB}Sq9+q%gH{dw9)VXR?V9$hLfDnnW|HH;Bvqp?|-T0szI$&*WTn_pI4sY=&!!Z=bxg^ zie;Smvy*ERx}h2xwWp}PY#KJ5o;uox*RsB6CPT^_1HaR+?e9$GT}dkB%?O=4Ey4)K z!`@WYA2{W`EKcK#I~!sM<1TM2n8hRBesD4&!=eiC9sUa93*=%q;0kV)E4o29r%WsCGLs3 zL-V$E7TDG~F8Cl;6NpsQYUXyAcSq`O+Y{cSYkT7RYHo#EE!^Jq=-rijYyLiL0c?wK&%^4mM9|xowVF;qdxCB_ zRu5QK+Urz0ilZ2zj}Qx@;VY%|h0^8GQsx>r`Y#?-C&WvoHo^qZPushk0mZG%U{ xJD0D*L%{F|7y$71W_dpYG7Kw(q&5f-!4e&mM5zw5QW2|L zH$A01BD`rQr2@gAy46L32;STVPeZqeV8S{^eQ)+w1MmC3-+bSjzkBJ=-SJPcn1SH9 zy?1){iLn;{g98@FPj_G8YZzB|Yovy8CwrrO#oKICtzmojx2j^CV?@7*3v5!q(o|r( z4C~+vglA|DE$R*Ym^5%hpTTG0Ttfm$ASsdzl0kB$Hc%U=EfN6{5Q(IK6p#{01*sr4 zk_OU1TC|a^NlsR8=r4^I65J7vMPq@qDuia}9BLTzDyteja?z}^rZEwBd!b#V?r}(N zj(s!o2{$R~6ofj3zy|4f(-C?N;SmZIboj`!640ZZX8mMtd1CeC%H@D2I8FNLEb!Dy zHK4~h&H07O@&xa&J+m*M?VP6kj1B#fm8<`ar#S8R2S&ws-ZKjU?c&t-b3-sb=9wM6 z|L*VTVw^hcghm)Or`!AB(e~xJy9;hVRIbC8%q+IphM8=3l8T@131!GZCcp8(%alU` zfcF4Suipq&Ar1AHcjV2*P!}?gGrTjrT?(m?iSkYu6IC2pg^l|9oiHKPj*Jvfl{|g$ z;E-@xA{A~8?Kqw_c7On(Cb7|2cT+<*@ig`yF8PzyA0$I6TXu*by}b}6e!UiD-zscr zo;4K8(DTPHeY8KMTlKul>-W6*`;mg&KqxK}oH_q~_+6=0Pu=3Pt~XWxDLSqtzJmCB g)naU4Vc%oVjS&!rRkzuCJe4?yE336%2vRis7dUm+IsgCw diff --git a/myfinances/finance/receipts/service.py b/myfinances/finance/receipts/service.py index 3c7c461..df1ce84 100644 --- a/myfinances/finance/receipts/service.py +++ b/myfinances/finance/receipts/service.py @@ -17,6 +17,21 @@ def create_receipt(self, total_amount: float = None, owner: Optional[str] = None ) -> MyFinancesResponse[ReceiptIDResponse]: + """ + Creates a new receipt + + Args: + name(str): The name of the client + image(Optional[FilePath]): file path of the image of the receipt. + date(Optional[str]): date of the receipt (format: YYYY-MM-DD) + merchant_store(Optional[str]): The names store or merchant + purchase_category(Optional[str]): Category of the purchase + total_amount(float): The total of the purchase + owner(Optional[str]): Owner of the store + + Returns: + MyFinancesResponse[ReceiptIDResponse]: Creation of the receipt + """ params = { "name": name, @@ -29,45 +44,67 @@ def create_receipt(self, } response = self._client._post("/receipts/create/", json=params) - return MyFinancesResponse(**response.dict()) def list_receipts(self) -> MyFinancesResponse[ReceiptList]: + """ + Lists all the receipts + + Returns: + MyFinancesResponse[ReceiptList]: lists of all the receipts in the system + """ response = self._client._get("/receipts/") return MyFinancesResponse(**response.dict()) def delete_receipt(self, receipt_id: int) -> MyFinancesResponse[ReceiptIDResponse]: - response = self._client._delete(f"/receipts/{receipt_id}/delete") - return MyFinancesResponse(**response.dict()) - - def search_receipts(self, receipt_id: int = None, name: str = None, merchant_store: str = None, - image: Optional[FilePath] = None, date: Optional[str] = None, purchase_category: Optional[str] = None, - total_amount: float = None, owner: Optional[str] = None ) -> MyFinancesResponse[ReceiptList]: - params = {} - - if receipt_id is not None: - params["id"] = receipt_id - - if name is not None: - params["name"] = name - - if merchant_store is not None: - params["merchant_store"] = merchant_store + """ + Deletes a receipt by its ID. - if image is not None: - params["image"] = image + Args: + receipt_id(int): Receipt ID's to delete the receipt - if date is not None: - params["date"] = date - - if purchase_category is not None: - params["purchase_category"] = purchase_category - - if total_amount is not None: - params["total_amount"] = total_amount - - if owner is not None: - params["owner"] = owner + Returns: + MyFinancesResponse[ReceiptIDResponse]: Deletion of the receipt + """ + response = self._client._delete(f"/receipts/{receipt_id}/delete") + return MyFinancesResponse(**response.dict()) + def search_receipts(self, + receipt_id: int = None, + name: str = None, + merchant_store: str = None, + image: Optional[FilePath] = None, + date: Optional[str] = None, + purchase_category: Optional[str] = None, + total_amount: float = None, + owner: Optional[str] = None) -> MyFinancesResponse[ReceiptList]: + """ + Searching for the receipts for a specific receipt by using filters + + Args: + receipt_id(Optional[int]): Receipt ID's + name(str): The name of the client + image(Optional[FilePath]): file path of the image of the receipt. + date(Optional[str]): date of the receipt (format: YYYY-MM-DD) + merchant_store(Optional[str]): The names store or merchant + purchase_category(Optional[str]): Category of the purchase + total_amount(float): The total of the purchase + owner(Optional[str]): Owner of the store + + Returns: + MyFinancesResponse[ReceiptList]: List of receipts returning base the filter + """ + params = { + key: value for key, value in { + "id": receipt_id, + "name": name, + "merchant_store": merchant_store, + "image": image, + "date": date, + "purchase_category": purchase_category, + "total_amount": total_amount, + "owner": owner + }.items() if value is not None + } response = self._client._get("/receipts/search/", params=params) return MyFinancesResponse(**response.dict()) diff --git a/tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc index 35f9fc8991ac2f91441c0aa668358f38c141773f..a5dd1a3dac461b5fc744a4e991b223e8b7d1fb6e 100644 GIT binary patch delta 1173 zcma)*%TE(g6vjJ1N*|0&k%2PP>J+5y7(&bNC>SXuF4Pqdb>WKC=};P`56%=58%QLY zn5c<~cj?NwbYV;r{t4KyYwAK1SNsbs(ECxI2_#H1zxi^`nKSo(_sl!{qb=@;qR+)I z)1S`m{}ea8o~q}8owte=_Su_iKi0K9?@K}GVUPR~b%<9V+{ieNMHOu@UVb&9JB?QU zpkDUYzu@lYdAiMh`QNxT$N`q^NDFcHtz-Mn6CSw9Z|A$@cY?Guq8IqTxAu!6Q%Uq6xZiv_vv_ zuG*f+TDDcOuII+z=(Lbyk(e@fZs%A=3cbz`$)xU39vK`8jRIr91b}M2i&~+Zma+G- zuymO{DGfzAydYC2bO%rX;13l!8opzTm-5*&heE@R_TxCMqx8tI64WBF2Fw8q9FEMs zsxtd+bV^M}PL7SLH5Ru$7t9r8wiykXSJ{hMtp?6U&9O3Mt|SO?U1+$=8Oju#>sh`% zqK{zqXcokB0@DL#JI9TqQnI$?EuwjDR%}F9>zu& zCdLgpD;FlZHZDw!8&@ukCa|pI#;q~@19jv5wN#3cgeLRNx#!$D>G|%=bM>ie|6;e> zO#HX|dusXDJNvfPTCrYJvr1m~(vEf9QeTvItq%mjNi(9)bAj)#w52pnVY>HhsIW06 zYeqA_F&8}+ljZ?lXI}ayJ~8_c4$@-lv>?;#)(?YoJaL*|+8e=SDw=+Dc*>pq<&K`R zG*Ir9%Pzj`DQ(#&MCyt-1PAT8T(s}%ZD+mwp`T4?*Udqa`%0n@tA4=GQL%-Yl2)<> zT??}SvLQeQ&H-Uy7>EE-dg0DGh7gW%V1OvYXe>@nXTGt)}lUFhwh@=D9eTc1HZ>BsR^`nkOr;(sz$; zqqc}!av*yfxC6`scY$tt81UVgV@C&<1vZK5BFAP+IHRbFuAI!keqc&iqM@Mls9{?4 zilbNK5yxeXt)Nmpf>A^v}1xr;R;u4&?t(XvqcD@I%G&WEoa4{OkeClVa=IoLmb zsBwv>WCv?UxfM_Wcw{*a!*HSEeW4(|`=}NsfE0&t0 tUj^YR?Tto-1f7cIFXH264A=mQzyx3iM2?E(a&9%Vt}4^)8NG_Be*pAh{t^HH diff --git a/tests/test_receipts.py b/tests/test_receipts.py index d34af13..df3aa4c 100644 --- a/tests/test_receipts.py +++ b/tests/test_receipts.py @@ -18,13 +18,13 @@ def receipts_service(mock_client): def test_create_receipt(receipts_service, mock_client): receipts_data = { - "name": "Client 1", + "name": "Client 1", "image": "file_example", "date": "2024-05-21", "merchant_store": "Store 1", "purchase_category": "Purchase 1", "total_amount": 500, - "owner": "Client 2" + "owner": "Client 2" } mock_response_data = { @@ -113,7 +113,7 @@ def test_delete_receipt(receipts_service, mock_client): assert remaining_receipts[0]["id"] == 1 -def test_update_receipt(receipts_service, mock_client): +def test_search_receipt(receipts_service, mock_client): list_of_receipts = [ {"id": 1, "name": "Client 1", "image": "file_example", "date": "2024-05-21", "merchant_store": "Store 1", "purchase_category": "Purchase 1", "total_amount": 100, "owner": "Owner 1"}, From 4c6b80e9dfbbfd65ef3b2bdddb0b41d7c38f6e33 Mon Sep 17 00:00:00 2001 From: 20128094 <20128094@tafe.wa.edu.au> Date: Sun, 24 Nov 2024 11:19:13 +0800 Subject: [PATCH 19/19] Refactor(pyache): remove __pyache__ from the file --- example/list_clients.py | 4 +++- myfinances/__pycache__/__init__.cpython-311.pyc | Bin 185 -> 0 bytes myfinances/__pycache__/__init__.cpython-312.pyc | Bin 303 -> 0 bytes .../__pycache__/base_service.cpython-312.pyc | Bin 635 -> 0 bytes myfinances/__pycache__/client.cpython-312.pyc | Bin 3357 -> 0 bytes myfinances/__pycache__/main.cpython-311.pyc | Bin 4227 -> 0 bytes myfinances/__pycache__/models.cpython-312.pyc | Bin 2164 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 420 -> 0 bytes .../clients/__pycache__/models.cpython-312.pyc | Bin 1386 -> 0 bytes .../clients/__pycache__/service.cpython-312.pyc | Bin 5171 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 647 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 429 -> 0 bytes .../invoices/__pycache__/models.cpython-312.pyc | Bin 1331 -> 0 bytes .../__pycache__/service.cpython-312.pyc | Bin 3894 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 213 -> 0 bytes .../receipts/__pycache__/models.cpython-312.pyc | Bin 1307 -> 0 bytes .../__pycache__/service.cpython-312.pyc | Bin 3782 -> 0 bytes myfinances/models.py | 2 +- tests/__pycache__/__init__.cpython-312.pyc | Bin 191 -> 0 bytes .../new_test.cpython-312-pytest-8.3.3.pyc | Bin 4601 -> 0 bytes .../test_clients.cpython-312-pytest-8.3.3.pyc | Bin 18036 -> 0 bytes .../test_finance.cpython-312-pytest-8.3.3.pyc | Bin 21167 -> 0 bytes .../test_invoice.cpython-312-pytest-8.3.3.pyc | Bin 12177 -> 0 bytes ...finances_client.cpython-312-pytest-8.3.3.pyc | Bin 7212 -> 0 bytes .../test_receipts.cpython-312-pytest-8.3.3.pyc | Bin 13836 -> 0 bytes 25 files changed, 4 insertions(+), 2 deletions(-) delete mode 100644 myfinances/__pycache__/__init__.cpython-311.pyc delete mode 100644 myfinances/__pycache__/__init__.cpython-312.pyc delete mode 100644 myfinances/__pycache__/base_service.cpython-312.pyc delete mode 100644 myfinances/__pycache__/client.cpython-312.pyc delete mode 100644 myfinances/__pycache__/main.cpython-311.pyc delete mode 100644 myfinances/__pycache__/models.cpython-312.pyc delete mode 100644 myfinances/clients/__pycache__/__init__.cpython-312.pyc delete mode 100644 myfinances/clients/__pycache__/models.cpython-312.pyc delete mode 100644 myfinances/clients/__pycache__/service.cpython-312.pyc delete mode 100644 myfinances/finance/__pycache__/__init__.cpython-312.pyc delete mode 100644 myfinances/finance/invoices/__pycache__/__init__.cpython-312.pyc delete mode 100644 myfinances/finance/invoices/__pycache__/models.cpython-312.pyc delete mode 100644 myfinances/finance/invoices/__pycache__/service.cpython-312.pyc delete mode 100644 myfinances/finance/receipts/__pycache__/__init__.cpython-312.pyc delete mode 100644 myfinances/finance/receipts/__pycache__/models.cpython-312.pyc delete mode 100644 myfinances/finance/receipts/__pycache__/service.cpython-312.pyc delete mode 100644 tests/__pycache__/__init__.cpython-312.pyc delete mode 100644 tests/__pycache__/new_test.cpython-312-pytest-8.3.3.pyc delete mode 100644 tests/__pycache__/test_clients.cpython-312-pytest-8.3.3.pyc delete mode 100644 tests/__pycache__/test_finance.cpython-312-pytest-8.3.3.pyc delete mode 100644 tests/__pycache__/test_invoice.cpython-312-pytest-8.3.3.pyc delete mode 100644 tests/__pycache__/test_myfinances_client.cpython-312-pytest-8.3.3.pyc delete mode 100644 tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc diff --git a/example/list_clients.py b/example/list_clients.py index 36290d9..c12b04a 100644 --- a/example/list_clients.py +++ b/example/list_clients.py @@ -9,7 +9,7 @@ def main(): response = client.clients.list_clients() print(response.json()) - response = client.clients.create_client(name="nerd") + response = client.clients.create_client(name="dock") print(f"Created user with the ID of {response.data.client_id}") @@ -18,5 +18,7 @@ def main(): response = client.clients.list_clients() print(response.json()) + + if __name__ == "__main__": main() diff --git a/myfinances/__pycache__/__init__.cpython-311.pyc b/myfinances/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index c818037e4a418b34b333db841f84fba3aad602eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 185 zcmZ3^%ge<81g_ryQ^kSwV-N=h7@>^MASKfoQW&BbQW%37G?}Vc4fKrl4E!`1Z*j-R zm!%dJXXfX{$FF4g4ASw-!qqA!JT*zdCABOyC%+&!HLoNlB`Yy6JzuvpH!(L8%87?? z;^Q;(GE3s)^$IF~aoFVMr#wg}W z7ERVFRs%gCe8~t@r^$Frz_-#ZGcPeOIknh1Co?s#q=*?P;it)Ri#tBPEVZaOGe0jr z{uWy@Lh=@Se0*X~PJH}IhR+~deJP6Ca2KczG$)vgE>2q4!Nivo!c%#4hTH~2&wxSukpJm8kSz$MqnUc>>E0RR-kR!jf@ diff --git a/myfinances/__pycache__/base_service.cpython-312.pyc b/myfinances/__pycache__/base_service.cpython-312.pyc deleted file mode 100644 index 3468d134821479aa03f3ab258120e28c702ace1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 zcmYjOzl#$=6n-l`~7V&=mDOucgFKi`2HYcd%}&<-bCdL z6eyO%g2jvhhsU7!3RLigdsfWrFzWmyBVtW=T2@(Ml05aOmuzFSS5Y|w4KY&?bH!E= z2Q`m^=F-E&>6x}~vQ(#=$ZIFk1HA2U?W&mKRLeWg;FO(${Ku^!3MQ6JEaS?v`cY;Q zlWKREXWCSlqPM7zH-B~?Y0bV&w^-+}NYn@hNSH-Qeu3i;J>}n7%v15sWspWB5H(e<+ zlT}i_J@{`J7fK6rTOFH;MB@7H|ke7?LoFtaY$ za-<$|NTpUSy#xtW@-b;DHK!`a9+4_lc0-kD1rieNfm^5#l{ody{=|kPMfBFLj ztrHC??Th{}o8pGsMJ%yR(oSsQ$Qn;?^{Gj0K=qRSSY=+|Ez@%yB=!v68leyerx-jm<(7}|E z&1<04kLL2%3_X={cHl^#JE>^^<`714PDAj=0veA6O~4`+_JCzv)WjJnE`eUc!Z@$_ zVCG|3^J70)CDPz(rcEj{4@EzdB<1VSDN)xM0cGk`$|X zVx$CjXKY}Y{c68}m_sH0CP(3zO_(`P38~x$=B6YM*GG+8bUi3v;xb~1(}2Ei1d$tW zGMhaADLXB^nKLfBQ;6_R4VmqpPYHSJgI)HtrsAPz>>H~WP(&Dc>OYN>1e4HXNI?{7 zu{z#4dv18_!WH%OaO|u)HhO`u0IQjrNn+9)x;aVMPA!?>>v>E~YWZWBQph07PaQzm z5mQLC3ob_%D=M4i;F%_Qncm~dV_m;;7YRnO?AsuuUu zBb+=K^h^QR4jlvW8CvTK{n|BjuWx8p{GxR&d}K9zyc#~fyysr{%&i-DgO$spmCLca zd%+sGAKbqh9H<5dR)P^W|2^1W)>eXt9h-;04Afv@I6R!ua#=lNK9gze*z8RE5rCU% zJco2N&6m&=3w-XmgG$^T^esOvXpm9h<6iJaH)hwlX%VbmQE4zwG1i}ZNu??zAbK&$>Iz}!8R0EoE=iJU$d*Z*)PUrO&t~7rgHG_V zgb8dCmfcq8ILW3}R#H^rRv2*K1t!7@0@-J~!$l=M3_&V7Wr(t9NF{j4Ze|fxShKim zGuNQr2@dos2;g}~@SAwl;O=c2cwt4eQG=`EjG^8MtmD7`DnyR-8B_5-W!L)G@7rH@wHPgdlUq|4sO z6wPL~Ci^?E1KIx(f)~UQvKMyj(n@+6W-M&xQ-mAq5K8ug!$Kp2c38-ZB?ka)B2QA; z0>#~%*<*T^1Ku@#N!I$RN?$oPZ!UjWQTkStv)i%uf8dMs!#Qo{M#?44)TDjeY;wrJ zRt)%5+pQSff&v!LSp1h9^jDSsa%xFjo~S7OE6TZTIcO|ttbnniRGSC!!aKviuqX;I zQ55--0434g&9wM}k|;h?5*uy|x6NhoY1qIft}_ym8VX(r{;wVA+!XeqXsB|2)d?vA|$ zKnvVRgeUfgL4q!lLN96`2xV__$~$=t;1>14c0UF-%EI9<%Ym-~p9fau?yB7Vo4n61 z$%HvX0<0y-K)a!;Rc z8(Kil`s@QlSTkme763E>Vg^0oebTFCVI9FRe{)$_n65GSq{Anjx*cQq)Ov>mIJJ&o znBQ4r!+IN2QAgERSCs`D*8-f>|Sn1g8|M68`MeEHdxmAk8d)>K6Uno_o*Cpj`Adlf{sx}`#`J<9LGIC gdmo|pKhPTw(2)n|*h3{+K^=dIVXo&-1j1hBZwAcMng9R* diff --git a/myfinances/__pycache__/main.cpython-311.pyc b/myfinances/__pycache__/main.cpython-311.pyc deleted file mode 100644 index 67c0cc076eddb9325ee84bc2dd144cc992fbe1e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4227 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 diff --git a/myfinances/clients/__pycache__/models.cpython-312.pyc b/myfinances/clients/__pycache__/models.cpython-312.pyc deleted file mode 100644 index 371d2f54657296a86df8ad2dfdae89ff9458074a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1386 zcmZvc&u`R56vxN**z5h3AEZD-NFY%Z?H-^NTo6K)TA(3SvOz>h?aGy9>;YW)7c*WY zb6P1>N^Z*u{)MXlMK2sURm)*D7Y>}bRm%3lsqfiN>qfD(Uq64|^StkjpY~n5-5_wi zy>|7<*D4_&@!|N=%i!oS1h0ulJS8BZ(pN&YuPXSg23kn_G}QaLLR7LzJnbd%C{upd zig)`)PIaJ0h1POf18P>Nnbo_EPxxY2mG$o&!FFPg1=745I)1R1a=_+plKOGv1d?w1 zB6W*4g_b?Z(I4>qnlRE=JknPm5~eZgDYt+!9U?W442ZOU8O6xc`!!}VV-YK!%sk4Wg81-8pI6HukV>*|6;}_67mQE!%!JaDpKz<`fpyacE`=<3!FfObgpuf2Mt?+}`+KUI=W!3|h z#KPLTzq@DcCM>cGY~SbcFU(D?o$Px*aw3SVn$?2Ycd*?YA!rkxYH3oFAr2c6ONLs({|l6y~A`Nd;1 zr;qarq)(1>K8|`Z)S24VWTP0BJ5K7rw=DMC>l*wET>C7_ITQmW-~5*tEurM?mod6@ zEcjJK3j|K3JwMtwwBFOjq7Z9N_lYZ>^jUE@S2*1A9x#!>yf9fWeA>R(>*^<+o`=== zX(rb&fr1sH1_CB$&%Epv{xH+))}@(bo)e|M%kh69A3$lOS>i`ein;vnDDrLR%l`j7 zKAX3S@&ATzz#0nt#8)7HX^NtJAe|3nb!s$~wS%9g1a8xdigIDJI3;kKnu@Y8%KnCU HA@}tUTuw;k diff --git a/myfinances/clients/__pycache__/service.cpython-312.pyc b/myfinances/clients/__pycache__/service.cpython-312.pyc deleted file mode 100644 index b7f102af9c1357d8c1a4c592b0884619f12a4378..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5171 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 QSFn5Aq-6UBP^@bH0y+|(e*gdg diff --git a/myfinances/finance/invoices/__pycache__/__init__.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 67de218de201219c8bd2705f84d71c53fcce6709..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 429 zcmaJ;ze@u#6i)7kC&i+RyXfK#-ry*rl!8#9wzRk$fpFYC>q#y-l562c{|a|E{}KmB zw}1#bxe47mnRr*+e319P_xQe-FXW}$?I07+$I|onF%q_gw!)S&w_Yuc_?S=lAm4%Mp?Mp~181RM2Q<#7%1y`Vhb`WB{-9j}5xiFm2 zm9EiB-zLwbt8hc_7xhif6P|*KS`g*UP8Ag*1Ew0473hQi*s8hacfSrOO&Fu}2`!Bf zt*ZVBxi$<%E|UV(UQgvrkg1r<6vzZhp~zr7nvziooHk=Rmf{Z5iVW+E*5XlFSGR(b zKO3YqP1dFfr8&$t07>bOU4Nv3Adz%#B1% z^oA$+3kJ^q36F4C=igun0s;jg&Kj4Z-?y{m%LyjL;8p zI9__`9Ik=0jR+z*L=m=eq}U1;XC+i4&DJ8_)-h7h93tvFL^O(b)#6**kf;u*(T7$f zS^?DTL(Qye)qaW(EhVo$_BdTk2o3X^pTvavLF9!HFqhhCki=e?YtI9o`o%+qEnh{4 zA)L1nMK&hLR#p*JsYdVvK&7V$PeD{C>Yla>eTxM*ba}%7&k!D|*cED0<8l!-ORU<5 zRRxw+tXf`~kKZJLPje+8dEM{uG>Is41Hu%z@)_sKdYT(vlyqX)dFrJd-pWnVp)T=K zn%4>CJ_}@Xkj`}7*o&y^<~7%i64D8U-*Da69WN{+Y5=K*T-S@^1o8nZ+;y1-&*dsl z85;tR2^HBnQ35&yi;mdreP@+Z#+_&I0KfW(2Vvs8NIJ}?&I)ZO+?iiqdf_a!Y3vrT zyUdbT)K8to>`4%Nu}}HUc9w1=u@hx$CE}Eh6BI;n2g;@)ztzr|DT)wARKxFqd5^kg z{q0!R5?`z}T#?ae^?&Q?w(+?Y4{A0AQO?8_yn+scGJJX*g4zw9I zcAV>M>0d(lZ0V)o%AVRMxF#jlZG(c)rObu&x?SzVDpF?MGV=?wjDlRH*ejH`fpyBn z6iK03U3ddvT9S1sf>mR~0v-|OyfCA}To6XcRos+HT@*(t+$G`3W<_D_%CQ*)hu;PR z6#mEF303>rOdpL0+EkHCq&b_oNr;>#PEw*5lancyn%B$5#pvbcvC=KeINhKD*$UZZ zm#3PU5K&=7kT<|UGlL^rcRxl4+LfYG5pG%4+-zsWi_^eoV!Vsr+eou^5U&?M_sLU| zBboc(_m0d5#RxrQO~@ezUNZPg#Tb7_H@>50&oJ<{4?z#X)*I3A^v-+_!PXnZcznzH JjbM{?{ROI&EFS;> diff --git a/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc b/myfinances/finance/invoices/__pycache__/service.cpython-312.pyc deleted file mode 100644 index aaa64480a1524448e2a10f9c1e79ebbcded5c1c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3894 zcmd57&-6`uX4Nd4LCA4QTQI@OPH zI*_nx6Tk%&v`Ad!pcY902Q5$=&OwJBjGTN7kP8U`DZ6M;13k4T3QQ5yr@on4Qq&I& z^-^>IzBlt`=FRN;-h1=-c}GVSK_i{#7vG28-`Swiw6IgZ44rl4B3H_yoRpL#)|az# zPDv^`HL2#bq{d}RR?itpLqal|Laurnxf+%pC_+y%vaBbJf3QJ93SuwY6whOFEA8Nf z62xZmw+hg`lBQm8^diBwheOddOpAp)#eoqDVE5tK<;&^3op&&8OgrKfK|8}i{ZG(Y zM;Ij~7bWF3^wZX*baAT%nZrf|!e`L()YrUC0L!w}dShY!~PRdnJ;08Xz)*=lcY^y;pk`zuGrk?TK%-X=ZfIsCA+vJ?m$GbN0{XP{kZ7 z55M^E&9XVPX-=(0{@Qi2()GgK=|9eXJp22r&@D$^sDmoxNQ{Q9=^V@rz&Q@?4$^~A z&#Kho3NpBYbO2XS=AJ~iK_`dd^!q9?fd#6yhy}>xD2x*_IR=dM0HMtL;&H;_G3dxb z)@WFguAJCy${o{8GaUu;7OI-Zg~4mft56uyOV>v!^ zDcW3nfh^K9%@NbE{ekgQ>AaUX)7;v+?;1}mySB3J+p*Bd$**1H;d*0Rk&8V$ou$oV z$q6vp6KR~|PM(FqeMO*r68ZvamV!XNz&Zvl(SUlTZ#U8{lgD8fodg0AbEFv@0_ly> zjsAx}Di3{s(|qYEkpG{-{9)5-mv9z)_wGH`a_+9}pFq1}@Ycg}MKd(a)Jm?QT_He*h2I_w^e z*35$Mf@B?~(W>H0Z)@;WDz0=EWWEd|cs5;`j}D$C6<_&8Z9bZ6OQ35I=;{FiU7r)L zTLP}p`cP7A6K4skBE4u6J4d%;DWQp2;x8@RMxJMcCs6iiLsT{5s!M2T*q^Qp?2fHn z3npMcy$%HO=pl1We;hkjjy+c$9ACS9=Uk=z2$oC!{ zE1QFx=JZn#au^zo)7EFni(HCFXEQ9@^B(aws9aM)Ougy1R_S#3wUVI(3<3$(O{0dgK_x>dA2 zXNi|Z;>C=%;J=UFK)H#R1MQZbE#Vf|VD7?QgAGo!T_>gc|6^qp5~ z3QVr)TL@U~a5IGuSIpsiy&FH=I0r#KGX2@DvN^nI{$zhY`gi>(?4}ID-*sIW(i8F= z*mw?FqC1FKRvs!o%L<~Fl`FWVEbF&h*3U|IHk?u5Aq=zyC?CB*fs#`gm+2$DjHryn z8DS1eh8Q`;$Tu1J4kN6j;UxsOBw;SW3EM#b3FJ0Ug$Q$xVYV=p~AUKyLI zvq7yF$URd`Ok8|4RhhWLC$@S)(Y@0(1neQ@tUUL6+0Itxa&;!$>R~&-!FO(ygo10= z1z)-;xc>{z;fk}eB?Eh1USv0&m6znN*zv*)%mQ diff --git a/myfinances/finance/receipts/__pycache__/models.cpython-312.pyc b/myfinances/finance/receipts/__pycache__/models.cpython-312.pyc deleted file mode 100644 index c516ad93c95f40a95aa13fee219758543804cc93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1307 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 iF!TP*BQYkF9>Hi<{kd#Dw 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 SoAY9uIP~m{ctRXvefWPm+aWOk diff --git a/tests/__pycache__/test_finance.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_finance.cpython-312-pytest-8.3.3.pyc deleted file mode 100644 index 6021d20b3a074dc016f98eb360360507091ec283..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21167 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 F{xAD+AgcfX diff --git a/tests/__pycache__/test_myfinances_client.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_myfinances_client.cpython-312-pytest-8.3.3.pyc deleted file mode 100644 index a885ecbc3b48d60f4f23d664bf961a043a4babf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7212 zcmeHMU2GHC6`ntj$G-$S351XzL4i!VI0+$;Wfw}y!fK03E9IfZi!?I6lVIb&-WdbV z+FIJ8mP#viS6Yb|9{RGiKc)OsXT8lhPJ)UE@5j4A+~Q20brPNkpNV%}E6j7MbZ%+aCDW`J z$0jB+m0YS=TX6SHWy?h?x{$f7YtW%x)@z`Haxr7*T9p>8pxa1suRGjh+~LU^r;lCu znSSvt{mKRJ00%2I^HRBV!PE`Yu%+hhqGj#lr7AT`c8YWxtfau(=mBw^`#LiCVBg&R z6U&kG11U{o(3owX2P)uU=d53Zo<1uPKa=jFB_K6;(=Bma9<}aBrpy}hxP3<=0cN!s zt|1T^ElETYye-v*yd7_wC*-4>>sZqQtc@t$XK8pEJJq>7p1&jI6CDju&G$XsR_E`! zHfo3vx$t7z^PIVZjelP>cd|0;Z%B3NL*9sx5DA-utT&H=)R9;`U*U`abA)x~M_I|s z&3;y9T2cRuJ*?NupPo_TNti@lSfjpYYg8B8n)pX{(Zm}G8bnC+g*EV>aMU{)EBP$% zdg{40@qFdZ0F9!)b9U2SV&^2W+tLz5cq3r$YwO^7Z9i-C@_K;HW%;k*dlKS9%#V4a zSg9csxe=_(_26ab#V9iV=+kYSjq`F6uS*L&*@kl#guCu1@_+ARpVr+hDl=<5XIzkt zBR#i8+wuz8P7-w`$J@2g3;Q9&R$@8&;TqqN;Vps9#r$iYRapuA!EebQ$yfgHdA8f< z;`#naF)w&I_(Rx|KYCyJ<2(Cf((?l=fj`78`J?ZZKfaqkYTRCKiZl4DfVIzaJiI=X zJ~(?#JkMR_)&6s9?}3Z{VY}&M`Q($xyiTtG-W@%o>#Ar)vQ@(@7j>%Th$Ux=Zm<&q^;%7(dyzmRt%OUM!03q^_;i6RVHyANV%CSw>nHAnZ2RceP-BmACQ z7(H$`O{&HiwoIwUYj(pS)lkC?E1WZOCBsBqZUu7=5T^*)RLK%6wMi6HC=Q`Ge20G` z96zq|OXIj0tl{hf1#h2Jj)WVd$DMs=U>lJlf1slvaFLm%xKG!ks)3D1Va@4htm!k- z=EeD?)H9|z=IosDtc`qz-#l%ABATWMxGlMSF|TJ$OQHHNsz?H?;Jj`a=&UH!%_=Qv zS2BgFZb^9q+9F_JvubGBG65^Qbi`6za~oDXYx5wD*&m^)?F1`&vQpD7R&xatykyCR zayC;itT419_s}xb+Nl|r%GCnVs9vGkVxfF7Q_xD8qHcvWBeS4mvlXASg9G$CO=+20 zNo}D_iy2eXuT=_}QU=3}?!uF8*IA-*IS(SFRUedEF?Q6ZHXI0wMdP&c!G|_rV&jV>%Vo#Ly&bQv(3Qs_)XD~2+#N^ux*EFOC&(#+Y$*9 z1-U7f7lk_CjjMO#<63(^66romYwH2r8$UW7sVg5(b_{|lvRgdcgRX$I$a_&gbnzqV)jqrWnrg@uv8Tilw(kI*GtT4CJuZiqZ6+t@ z93~eu_cCMnR{9=m^YVI|6Ee%XOilzQ7l0@bNOAy%HT8{ z?>J|Pi@HfM+URx^cqd8mi;$w>*YL}Jtqx)l-W>M@J-HM=RW2D-gk_6}<0;-NQoLLN z96O1CbedsfD0tYIVQ_%n3?Uyu09?>Z^dQcb9ITAjSO|-!Q5@L>m}ecpJWEk4hQzz< z21tJs5{G>NiQ~fbG>S9MbQ?W?!}Lz{j7#*{2$M9b7Z`3yL;vY#Rf1i%_%x;ARcU`~tIwaM z{Tl;t)JJGf2cdm3H*|JH{Bk64Rt>62_|wLvM0NyO1DeB!QV#6^GLxeERhlz_1ht#2 zpxb80pCvm}>=?FU)l$wxr>8K&9F7*Rj8F+rHvPzTyt7 na;G7v1m(BGzZ`xf@cg^{W04bj*6rdyl>|Tecs#}*uvh;#w51C9 diff --git a/tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc b/tests/__pycache__/test_receipts.cpython-312-pytest-8.3.3.pyc deleted file mode 100644 index a5dd1a3dac461b5fc744a4e991b223e8b7d1fb6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13836 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 bR|~)Y-V1yq-*InWh~IYqCBBK@&MN;O(*=E+