Skip to content

Commit

Permalink
improved handling from optional values in transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
dnbasta committed Mar 25, 2024
1 parent 652b5a7 commit 60dec15
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 28 deletions.
15 changes: 6 additions & 9 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
44 changes: 41 additions & 3 deletions tests/test_modifiedtransaction.py
Original file line number Diff line number Diff line change
@@ -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', [
Expand Down Expand Up @@ -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()
57 changes: 57 additions & 0 deletions tests/test_originaltransaction.py
Original file line number Diff line number Diff line change
@@ -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'])
6 changes: 0 additions & 6 deletions tests/test_transationmodifier.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from datetime import date, datetime
from unittest.mock import MagicMock

import pytest
from pydantic import ValidationError
Expand All @@ -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')
])
Expand Down
4 changes: 1 addition & 3 deletions ynabtransactionadjuster/models/category.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Optional

from pydantic import BaseModel, ConfigDict


Expand All @@ -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

15 changes: 10 additions & 5 deletions ynabtransactionadjuster/models/modifiedtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions ynabtransactionadjuster/models/originalsubtransaction.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from typing import Optional

from ynabtransactionadjuster.models.category import Category
from ynabtransactionadjuster.models.payee import Payee
Expand All @@ -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

0 comments on commit 60dec15

Please sign in to comment.