diff --git a/tests/conftest.py b/tests/conftest.py index 42534c4..35e570f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,29 +9,26 @@ @pytest.fixture def mock_subtransaction(request): return SubTransaction(memo='memo', amount=500, - category=Category(name='cname', id=None), + category=Category(name='cname', id='cid'), payee=Payee(name='pname')) @pytest.fixture def mock_original_transaction(request): - subs = [] + subs = () try: if request.param: - ost = OriginalSubTransaction(memo='memo1', amount=500, - category=Category(name='cname', id=None), + st = OriginalSubTransaction(memo='memo1', amount=500, + category=Category(name='cname', id='cid'), payee=Payee(name='pname')) - ost2 = OriginalSubTransaction(memo='memo2', amount=500, - category=Category(name='cname', id=None), - payee=Payee(name='pname')) - subs = [ost, ost2] + subs = (st, st) except AttributeError as e: pass return OriginalTransaction(id='id', memo='memo', category=Category(id='cid1', name='cname'), payee=Payee(id='pid', name='pname'), - subtransactions=frozenset(subs), + subtransactions=subs, flag_color='red', amount=1000, import_payee_name='ipn', diff --git a/tests/test_modifiedtransaction.py b/tests/test_modifiedtransaction.py index 238ac6b..e041b59 100644 --- a/tests/test_modifiedtransaction.py +++ b/tests/test_modifiedtransaction.py @@ -1,10 +1,9 @@ -from datetime import date -from unittest.mock import MagicMock +from datetime import date, datetime import pytest from pydantic import ValidationError -from ynabtransactionadjuster.models import OriginalTransaction, Category, Payee, TransactionModifier, ModifiedTransaction, OriginalSubTransaction, SubTransaction +from ynabtransactionadjuster.models import Category, Payee, TransactionModifier, ModifiedTransaction @pytest.mark.parametrize('test_attribute, test_input', [ @@ -42,3 +41,42 @@ def test_invalid_subtransactions(mock_original_transaction, mock_subtransaction) mock_modifier.subtransactions = [mock_subtransaction, mock_subtransaction] with pytest.raises(ValidationError): ModifiedTransaction(original_transaction=mock_original_transaction, transaction_modifier=mock_modifier) + + +def test_as_dict(mock_original_transaction, mock_subtransaction): + # Arrange + mock_modifier = TransactionModifier.from_original_transaction(mock_original_transaction) + mock_modifier.payee = Payee(id='pid2', name='pname2') + mock_modifier.category = Category(id='cid2', name='cname2') + mock_modifier.flag_color = 'blue' + mock_modifier.subtransactions = [mock_subtransaction, mock_subtransaction] + mt = ModifiedTransaction(original_transaction=mock_original_transaction, transaction_modifier=mock_modifier) + + # Act + d = mt.as_dict() + + # Assert + assert d['id'] == mock_original_transaction.id + assert d['payee_name'] == mt.transaction_modifier.payee.name + assert d['payee_id'] == mt.transaction_modifier.payee.id + assert d['category_id'] == mt.transaction_modifier.category.id + assert d['flag_color'] == mt.transaction_modifier.flag_color + assert len(d['subtransactions']) == 2 + assert isinstance(d['subtransactions'][0], dict) + assert d['date'] == datetime.strftime(mock_modifier.transaction_date, '%Y-%m-%d') + + +def test_as_dict_none_values(mock_original_transaction): + # Arrange + mock_modifier = TransactionModifier.from_original_transaction(mock_original_transaction) + mock_modifier.category = None + mock_modifier.flag_color = None + mt = ModifiedTransaction(original_transaction=mock_original_transaction, transaction_modifier=mock_modifier) + + # Act + d = mt.as_dict() + + # Assert + assert 'category_id' not in d.keys() + assert 'flag_color' not in d.keys() + assert 'subtransactions' not in d.keys() diff --git a/tests/test_originaltransaction.py b/tests/test_originaltransaction.py new file mode 100644 index 0000000..6e5a565 --- /dev/null +++ b/tests/test_originaltransaction.py @@ -0,0 +1,57 @@ +from datetime import datetime + +import pytest + +from ynabtransactionadjuster.models import OriginalTransaction, Category, Payee + + +@pytest.fixture +def mock_transaction_dict(): + return dict(id='id', amount=1000, date='2024-01-01', category_name='category', category_id='categoryid', + payee_name='payee', payee_id='payeeid', flag_color=None, memo=None, subtransactions=[], + import_payee_name_original=None, import_payee_name=None, transfer_account_id=None) + + +def test_from_dict(mock_transaction_dict): + o = OriginalTransaction.from_dict(mock_transaction_dict) + assert o.id == mock_transaction_dict['id'] + assert o.amount == mock_transaction_dict['amount'] + assert o.transaction_date == datetime.strptime(mock_transaction_dict['date'], '%Y-%m-%d').date() + assert o.category == Category(id=mock_transaction_dict['category_id'], name=mock_transaction_dict['category_name']) + assert o.payee == Payee(id=mock_transaction_dict['payee_id'], name=mock_transaction_dict['payee_name']) + assert o.flag_color == mock_transaction_dict['flag_color'] + assert o.memo == mock_transaction_dict['memo'] + assert o.import_payee_name_original == mock_transaction_dict['import_payee_name_original'] + assert o.import_payee_name == mock_transaction_dict['import_payee_name'] + assert not o.subtransactions + + +@pytest.mark.parametrize('name, cid, expected', [ + ('Uncategorized', None, None), + ('Split', 'id', None), + ('category', 'id', Category(id='id', name='category'))]) +def test_from_dict_category(mock_transaction_dict, name, cid, expected): + # Arrange + mock_transaction_dict['category_name'] = name + mock_transaction_dict['category_id'] = cid + + o = OriginalTransaction.from_dict(mock_transaction_dict) + + assert o.category == expected + + +def test_from_dict_subtransactions(mock_transaction_dict): + # Arrange + st = dict(amount=500, memo='memo', category_name='category', category_id='categoryid', payee_name='payee', + payee_id='payeeid', transfer_account_id='transferid') + mock_transaction_dict['subtransactions'] = [st, st] + + # Act + o = OriginalTransaction.from_dict(mock_transaction_dict) + + # Assert + assert len(o.subtransactions) == 2 + assert o.subtransactions[0].amount == st['amount'] + assert o.subtransactions[0].payee == Payee(id=st['payee_id'], name=st['payee_name'], transfer_account_id=st['transfer_account_id']) + assert o.subtransactions[0].memo == st['memo'] + assert o.subtransactions[0].category == Category(id=st['category_id'], name=st['category_name']) diff --git a/tests/test_transationmodifier.py b/tests/test_transationmodifier.py index bfdc94d..7ba8e8d 100644 --- a/tests/test_transationmodifier.py +++ b/tests/test_transationmodifier.py @@ -1,5 +1,4 @@ from datetime import date, datetime -from unittest.mock import MagicMock import pytest from pydantic import ValidationError @@ -26,13 +25,8 @@ def mock_subtransaction(): ('memo', 1), ('payee', None), ('payee', 'xxx'), - ('category', None), ('category', 'xxx'), ('flag_color', 'brown'), - # ('subtransactions', [SubTransaction(memo='memo', - # payee=Payee(name='pname'), - # category=Category(name='cname', id='cid'), - # amount=500)]), ('subtransactions', ['xxx', 'xxx']), ('transaction_date', 'xxx') ]) diff --git a/ynabtransactionadjuster/models/category.py b/ynabtransactionadjuster/models/category.py index e1738cb..5bd7362 100644 --- a/ynabtransactionadjuster/models/category.py +++ b/ynabtransactionadjuster/models/category.py @@ -1,5 +1,3 @@ -from typing import Optional - from pydantic import BaseModel, ConfigDict @@ -10,6 +8,6 @@ class Category(BaseModel): :ivar name: The name of the category """ model_config = ConfigDict(frozen=True) - id: Optional[str] + id: str name: str diff --git a/ynabtransactionadjuster/models/modifiedtransaction.py b/ynabtransactionadjuster/models/modifiedtransaction.py index 0dc41f0..8a835b3 100644 --- a/ynabtransactionadjuster/models/modifiedtransaction.py +++ b/ynabtransactionadjuster/models/modifiedtransaction.py @@ -20,19 +20,24 @@ def is_changed(self) -> bool: return False def as_dict(self) -> dict: - """Returns a dictionary representation of the transaction""" + """Returns a dictionary representation of the transaction which is used for the update call to YNAB""" t_dict = dict(id=self.original_transaction.id, - memo=self.transaction_modifier.memo, payee_name=self.transaction_modifier.payee.name, payee_id=self.transaction_modifier.payee.id, - category_id=self.transaction_modifier.category.id, - flag_color=self.transaction_modifier.flag_color, date=datetime.strftime(self.transaction_modifier.transaction_date, '%Y-%m-%d')) if len(self.transaction_modifier.subtransactions) > 0: - t_dict = {**t_dict, 'subtransactions': [s.as_dict() for s in self.transaction_modifier.subtransactions]} + t_dict['subtransactions'] = [s.as_dict() for s in self.transaction_modifier.subtransactions] + if self.transaction_modifier.category: + t_dict['category_id'] = self.transaction_modifier.category.id + if self.transaction_modifier.flag_color: + t_dict['flag_color'] = self.transaction_modifier.flag_color + if self.transaction_modifier.memo: + t_dict['memo'] = self.transaction_modifier.memo + return t_dict def changed_attributes(self) -> dict: + """Returns a dictionary representation of the modified values and the original transaction""" changed_attributes = {} if self.transaction_modifier.payee != self.original_transaction.payee: changed_attributes['payee'] = dict(original=self.original_transaction.payee, diff --git a/ynabtransactionadjuster/models/originalsubtransaction.py b/ynabtransactionadjuster/models/originalsubtransaction.py index f50824b..704dbc4 100644 --- a/ynabtransactionadjuster/models/originalsubtransaction.py +++ b/ynabtransactionadjuster/models/originalsubtransaction.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from typing import Optional from ynabtransactionadjuster.models.category import Category from ynabtransactionadjuster.models.payee import Payee @@ -14,6 +15,6 @@ class OriginalSubTransaction: :ivar memo: The memo of the subtransaction """ payee: Payee - category: Category - memo: str + category: Optional[Category] + memo: Optional[str] amount: int