Skip to content

Commit

Permalink
Merge pull request #58 from AndrewSergienko/2.x/monobank_integration
Browse files Browse the repository at this point in the history
bankapi migrations | fix bugs
  • Loading branch information
andiserg authored Mar 15, 2024
2 parents f212ed8 + e9eeb3c commit 5bad4e7
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
pip install -e .[ci-tests]
- name: Test with pytest
run: |
pytest tests --cov
pytest tests --cov="../src"
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4.0.1
with:
Expand Down
4 changes: 3 additions & 1 deletion src/costy/adapters/bankapi/bankapi.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from datetime import datetime

from adaptix import Retort, name_mapping
from httpx import AsyncClient
Expand Down Expand Up @@ -86,4 +87,5 @@ async def update_bankapis(self, bankapis: list[BankAPI]) -> None:

async def read_bank_operations(self, bankapi: BankAPI) -> list[BankOperationDTO]:
bank_gateway = self._bank_gateways[bankapi.name]
return await bank_gateway.fetch_operations(bankapi.access_data, bankapi.user_id)
from_time = datetime.fromtimestamp(bankapi.updated_at) if bankapi.updated_at else None
return await bank_gateway.fetch_operations(bankapi.access_data, bankapi.user_id, from_time)
3 changes: 2 additions & 1 deletion src/costy/adapters/bankapi/monobank.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(
retort: Retort
):
self._web_session = web_session
self._bank_conf = bank_conf
self._bank_conf = bank_conf["monobank"]
self._retort = retort.extend(recipe=[loader(P[Operation].id, lambda _: None)])

async def fetch_operations(
Expand Down Expand Up @@ -47,6 +47,7 @@ async def fetch_operations(

for operation in total_operations:
operation["user_id"] = user_id
operation["bank_name"] = "monobank"

loaded_operations = self._retort.load(total_operations, list[Operation])
return [
Expand Down
6 changes: 3 additions & 3 deletions src/costy/application/common/operation/dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ class ListOperationDTO:

@dataclass(kw_only=True)
class UpdateOperationData:
amount: int | type[Sentinel] = Sentinel
amount: int | None = None
description: str | None | type[Sentinel] = Sentinel
time: int | type[Sentinel] = Sentinel
category_id: CategoryId | type[Sentinel] = Sentinel
time: int | None = None
category_id: CategoryId | None | type[Sentinel] = Sentinel


@dataclass
Expand Down
18 changes: 12 additions & 6 deletions src/costy/domain/services/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,21 @@ def create(
def update(
self,
operation: Operation,
amount: int | type[Sentinel] = Sentinel,
amount: int | None = None,
description: str | None | type[Sentinel] = Sentinel,
time: int | type[Sentinel] = Sentinel,
category_id: CategoryId | type[Sentinel] = Sentinel,
time: int | None = None,
category_id: CategoryId | None | type[Sentinel] = Sentinel,
):
exclude_params = ['self', 'operation', 'exclude_params']
exclude_params = ('self', 'operation', 'exclude_params', 'sentinel_params')
sentinel_params = ('description', 'category_id')
params = {
name: value for name, value in locals().items()
if value is not Sentinel and name not in exclude_params
name: value for name, value in locals().items() if
(name not in exclude_params) and
(
(name in sentinel_params and value is not Sentinel) or
(name not in sentinel_params and value is not None)
)

}
for name, value in params.items():
setattr(operation, name, value)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""bankapi
Revision ID: 8f0d001e35c6
Revises: 14d9cdbdf029
Create Date: 2024-03-14 19:20:38.568784
"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision: str = '8f0d001e35c6'
down_revision: Union[str, None] = '14d9cdbdf029'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('bankapis',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=True),
sa.Column('access_data', sa.JSON(), nullable=True),
sa.Column('updated_at', sa.Integer(), nullable=True),
sa.Column('user_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.add_column('categories', sa.Column('mcc', sa.Integer(), nullable=True))
op.add_column('operations', sa.Column('bank_name', sa.String(), nullable=True))
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('operations', 'bank_name')
op.drop_column('categories', 'mcc')
op.drop_table('bankapis')
# ### end Alembic commands ###
3 changes: 2 additions & 1 deletion src/costy/main/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,6 @@ async def finalization():
on_shutdown=[finalization],
exception_handlers={
BaseError: base_error_handler
}
},
debug=True
)
1 change: 1 addition & 0 deletions src/costy/presentation/api/routers/authenticate.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

class AuthenticationController(Controller):
path = "/auth"
tags = ("Authentication",)

@post(status_code=200)
async def login(self, ioc: InteractorFactory, data: LoginInputDTO) -> Response[dict[str, str]]:
Expand Down
1 change: 1 addition & 0 deletions src/costy/presentation/api/routers/bankapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

class BankAPIController(Controller):
path = "bankapi"
tags = ("Banks integration",)

@get()
async def get_bankapi_list(
Expand Down
1 change: 1 addition & 0 deletions src/costy/presentation/api/routers/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

class CategoryController(Controller):
path = '/categories'
tags = ("Categories",)

@get()
async def get_list_categories(
Expand Down
22 changes: 21 additions & 1 deletion src/costy/presentation/api/routers/operation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from dataclasses import dataclass

from litestar import Controller, delete, get, post, put

from costy.application.common.id_provider import IdProvider
Expand All @@ -7,12 +9,24 @@
UpdateOperationData,
UpdateOperationDTO,
)
from costy.domain.models.category import CategoryId
from costy.domain.models.operation import Operation, OperationId
from costy.domain.sentinel import Sentinel
from costy.presentation.interactor_factory import InteractorFactory


@dataclass(kw_only=True)
class UpdateOperationPureData:
"""Dataclass without user defined types for OpenAPI"""
amount: int | None = None
description: str | None = "" # Sentinel value
time: int | None = None
category_id: CategoryId | None = None


class OperationController(Controller):
path = '/operations'
tags = ("Operations",)

@get()
async def get_list_operations(
Expand Down Expand Up @@ -52,8 +66,14 @@ async def update_operation(
operation_id: int,
ioc: InteractorFactory,
id_provider: IdProvider,
data: UpdateOperationData,
pure_data: UpdateOperationPureData,
) -> None:
async with ioc.update_operation(id_provider) as update_operation:
data = UpdateOperationData(
amount=pure_data.amount,
description=pure_data.description if pure_data.description != "" else Sentinel,
time=pure_data.time,
category_id=pure_data.category_id if pure_data.category_id is not None else Sentinel
)
request_data = UpdateOperationDTO(OperationId(operation_id), data)
await update_operation(request_data)
1 change: 1 addition & 0 deletions src/costy/presentation/api/routers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

class UserController(Controller):
path = "/users"
tags = ("Users",)

@post()
async def register(self, ioc: InteractorFactory, data: NewUserDTO) -> dict[str, UserId]:
Expand Down
2 changes: 1 addition & 1 deletion tests/common/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async def monobank_adapter(web_session, retort) -> MonobankGateway:
with open(str(resources.files("costy.adapters.bankapi") / "_banks.json"), "r") as f:
banks = json.load(f)

return MonobankGateway(web_session, banks["monobank"], retort)
return MonobankGateway(web_session, banks, retort)


@fixture
Expand Down

0 comments on commit 5bad4e7

Please sign in to comment.