diff --git a/app_data.json b/app_data.json index c53853f..9f3fa8f 100644 --- a/app_data.json +++ b/app_data.json @@ -1,16 +1,16 @@ [ { "id": -1, - "type": "Income", - "date": "2000-11-10T00:00:00", - "amount": 100.1, - "description": "sdfsdfsgdhfgh" + "description": "shoping", + "amount": -200.75, + "date": "2021-01-01T00:00:00", + "type": "Expense" }, { "id": -1, - "type": "Income", - "date": "2000-11-10T00:00:00", - "amount": 100.1, - "description": "d" + "description": "shoping", + "amount": 200.75, + "date": "2021-01-01T00:00:00", + "type": "Income" } ] diff --git a/src/clifinance/application/dto/selector.py b/src/clifinance/application/dto/selector.py new file mode 100644 index 0000000..4e4ed1b --- /dev/null +++ b/src/clifinance/application/dto/selector.py @@ -0,0 +1,9 @@ +from dataclasses import dataclass +from datetime import datetime + + +@dataclass(frozen=True) +class SelectorDTO: + type: str + date: datetime + amount: float diff --git a/src/clifinance/application/usecases/get_expenses.py b/src/clifinance/application/usecases/get_expenses.py new file mode 100644 index 0000000..efc00f7 --- /dev/null +++ b/src/clifinance/application/usecases/get_expenses.py @@ -0,0 +1,23 @@ +from clifinance.application.dto.selector import SelectorDTO +from clifinance.domain.expense.gateway import ExpenseGateway +from clifinance.domain.expense.model import ( + Expense, + ExpenseAmount, + ExpenseDate, + ExpenseType, +) + + +class GetExpensesByFilter: + def __init__( + self, + gateway: ExpenseGateway, + ) -> None: + self.__gateway = gateway + + def __call__(self, filter: SelectorDTO) -> list[Expense]: + return self.__gateway.get_all_expenses_by_filter( + type=ExpenseType(filter.type) if filter.type else None, + date=ExpenseDate(filter.date) if filter.date else None, + amount=ExpenseAmount(filter.amount) if filter.amount else None, + ) diff --git a/src/clifinance/domain/expense/gateway.py b/src/clifinance/domain/expense/gateway.py index 8d29890..6725812 100644 --- a/src/clifinance/domain/expense/gateway.py +++ b/src/clifinance/domain/expense/gateway.py @@ -1,8 +1,12 @@ from abc import abstractmethod -from datetime import datetime from typing import Protocol -from clifinance.domain.expense.model import Expense, ExpenseType +from clifinance.domain.expense.model import ( + Expense, + ExpenseAmount, + ExpenseDate, + ExpenseType, +) class ExpenseGateway(Protocol): @@ -23,9 +27,18 @@ class ExpenseGateway(Protocol): raise NotImplementedError @abstractmethod - def get_all_expenses_by_date(self, date: datetime) -> list[Expense]: + def get_all_expenses_by_date(self, date: ExpenseDate) -> list[Expense]: raise NotImplementedError @abstractmethod - def get_all_expenses_by_price(self, price: float) -> list[Expense]: + def get_all_expenses_by_amount(self, amount: ExpenseAmount) -> list[Expense]: + raise NotImplementedError + + @abstractmethod + def get_all_expenses_by_filter( + self, + type: ExpenseType | None, + date: ExpenseDate | None, + amount: ExpenseAmount | None, + ) -> list[Expense]: raise NotImplementedError diff --git a/src/clifinance/domain/expense/model.py b/src/clifinance/domain/expense/model.py index c94ae50..6704bb5 100644 --- a/src/clifinance/domain/expense/model.py +++ b/src/clifinance/domain/expense/model.py @@ -53,3 +53,6 @@ class Expense(DomainEntity[ExpenseId]): amount=ExpenseAmount(amount), description=ExpenseDescription(description), ) + + def __str__(self): + return f"Expense(id={self.id.value}, type={self.type.value}, date={self.date.value}, amount={self.amount.value}, description={self.description.value})" diff --git a/src/clifinance/infrastructure/persistence/json_gateway.py b/src/clifinance/infrastructure/persistence/json_gateway.py index b13905e..1f05eed 100644 --- a/src/clifinance/infrastructure/persistence/json_gateway.py +++ b/src/clifinance/infrastructure/persistence/json_gateway.py @@ -1,8 +1,11 @@ -from datetime import datetime - from clifinance.application.abstractions.protocols.session import Session from clifinance.domain.expense.gateway import ExpenseGateway -from clifinance.domain.expense.model import Expense, ExpenseType +from clifinance.domain.expense.model import ( + Expense, + ExpenseAmount, + ExpenseDate, + ExpenseType, +) class JsonExpenseGateway(ExpenseGateway): @@ -22,8 +25,24 @@ class JsonExpenseGateway(ExpenseGateway): def get_all_expenses_by_type(self, type: ExpenseType) -> list[Expense]: return [x for x in self.session.get_all() if x.type == type] - def get_all_expenses_by_date(self, date: datetime) -> list[Expense]: + def get_all_expenses_by_date(self, date: ExpenseDate) -> list[Expense]: return [x for x in self.session.get_all() if x.date == date] - def get_all_expenses_by_price(self, price: float) -> list[Expense]: - return [x for x in self.session.get_all() if x.amount == price] + def get_all_expenses_by_amount(self, amount: ExpenseAmount) -> list[Expense]: + return [x for x in self.session.get_all() if x.amount == amount] + + def get_all_expenses_by_filter( + self, + type: ExpenseType | None, + date: ExpenseDate | None, + amount: ExpenseAmount | None, + ) -> list[Expense]: + + result = self.get_all_expenses() + if type is not None: + result = [x for x in result if x.type == type] + if date is not None: + result = [x for x in result if x.date == date] + if amount is not None: + result = [x for x in result if x.amount == amount] + return result diff --git a/src/clifinance/infrastructure/persistence/mappers/expense.py b/src/clifinance/infrastructure/persistence/mappers/expense.py index 5f8dcb7..9bc11ca 100644 --- a/src/clifinance/infrastructure/persistence/mappers/expense.py +++ b/src/clifinance/infrastructure/persistence/mappers/expense.py @@ -1,3 +1,5 @@ +from datetime import datetime + from clifinance.domain.expense.model import ( Expense, ExpenseAmount, @@ -13,7 +15,7 @@ def expense_to_json(expense: Expense): "id": expense.id.value, "description": expense.description.value, "amount": expense.amount.value, - "date": expense.date, + "date": expense.date.value.isoformat(), "type": expense.type.value, } @@ -23,6 +25,6 @@ def expense_from_json(data: dict): id=ExpenseId(data["id"]), description=ExpenseDescription(data["description"]), amount=ExpenseAmount(data["amount"]), - date=ExpenseDate(data["date"]), + date=ExpenseDate(datetime.fromisoformat(data["date"])), type=ExpenseType(data["type"]), ) diff --git a/src/clifinance/main/container.py b/src/clifinance/main/container.py index f37452e..28326f3 100644 --- a/src/clifinance/main/container.py +++ b/src/clifinance/main/container.py @@ -8,6 +8,7 @@ from clifinance.application.abstractions.protocols.driver import FileDriver from clifinance.application.abstractions.protocols.session import Session from clifinance.application.usecases.add_expense import AddExpense from clifinance.application.usecases.get_balance import GetBalance +from clifinance.application.usecases.get_expenses import GetExpensesByFilter from clifinance.domain.expense.gateway import ExpenseGateway from clifinance.infrastructure.persistence.json_driver import JsonFileDriver from clifinance.infrastructure.persistence.json_gateway import JsonExpenseGateway @@ -24,6 +25,10 @@ class Container: def provide_add_expense(self) -> Generator[AddExpense, None, None]: yield AddExpense(gateway=self.json_gateway()) + @contextmanager + def provade_get_filtred_expenses(self) -> Generator[GetExpensesByFilter, None, None]: + yield GetExpensesByFilter(gateway=self.json_gateway()) + def json_gateway(self) -> ExpenseGateway: return JsonExpenseGateway(session=self.get_session()) diff --git a/src/clifinance/presentation/cli/commands.py b/src/clifinance/presentation/cli/commands.py index e3dca5f..2e77ace 100644 --- a/src/clifinance/presentation/cli/commands.py +++ b/src/clifinance/presentation/cli/commands.py @@ -1,17 +1,26 @@ import argparse from clifinance.application.dto.expense import ExpenseDTO +from clifinance.application.dto.selector import SelectorDTO from clifinance.main.container import Container def get_balance(args: argparse.Namespace, ioc: Container) -> None: with ioc.provide_get_balance() as usecase: print(usecase()) - print() def select_expenses(args: argparse.Namespace, ioc: Container) -> None: - print(args) + with ioc.provade_get_filtred_expenses() as usecase: + for expense in usecase( + filter=SelectorDTO( + type=args.__dict__.get("type", None), + date=args.__dict__.get("date", None), + amount=args.__dict__.get("amount", None), + ) + ): + + print(expense) def add_expense(args: argparse.Namespace, ioc: Container) -> None: