Skip to content

Commit f725c03

Browse files
feat(ynab): start adding ynab models
1 parent 288af63 commit f725c03

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

src/ynamazon/wrappers/__init__.py

Whitespace-only changes.

src/ynamazon/wrappers/ynab.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import abc
2+
from decimal import Decimal
3+
import enum
4+
from typing import Annotated, Any, Generic, TypeVar
5+
from pydantic import (
6+
BaseModel,
7+
ConfigDict,
8+
StrictBool,
9+
StrictInt,
10+
StrictStr,
11+
model_validator,
12+
)
13+
import datetime as dt
14+
15+
16+
class YnabBase(BaseModel, abc.ABC):
17+
"""Base class for YNAB."""
18+
19+
model_config = ConfigDict(from_attributes=True)
20+
21+
22+
_F = TypeVar("_F")
23+
24+
25+
class Field(BaseModel, Generic[_F], abc.ABC):
26+
value: _F
27+
28+
@model_validator(mode="before")
29+
@classmethod
30+
def from_value(cls, data: Any) -> Any:
31+
if not isinstance(data, dict):
32+
return {"value": data}
33+
return data
34+
35+
36+
class AccountType(enum.StrEnum):
37+
"""The type of account."""
38+
39+
CHECKING = "checking"
40+
SAVINGS = "savings"
41+
CASH = "cash"
42+
CREDIT_CARD = "creditCard"
43+
LOAN = "loan"
44+
INVESTMENT = "investment"
45+
OTHER_ASSET = "otherAsset"
46+
OTHER_LIABILITY = "otherLiability"
47+
MORTGAGE = "mortgage"
48+
AUTO_LOAN = "autoLoan"
49+
STUDENT_LOAN = "studentLoan"
50+
PERSONAL_LOAN = "personalLoan"
51+
MEDICAL_DEBT = "medicalDebt"
52+
OTHER_DEBUG = "otherDebt"
53+
54+
55+
class Account(YnabBase):
56+
id: StrictStr
57+
name: StrictStr
58+
account_type: Annotated[AccountType, Field(validation_alias="type")]
59+
on_budget: StrictBool
60+
closed: StrictBool
61+
note: StrictStr | None = None
62+
balance: StrictInt
63+
cleared_balance: StrictInt
64+
uncleared_balance: StrictInt
65+
transfer_payee: "Payee" | None = None
66+
direct_import_linked: StrictBool | None = None
67+
direct_import_in_error: StrictBool | None = None
68+
last_reconciled_at: dt.datetime | None = None
69+
debt_original_balance: StrictInt | None = None
70+
71+
def _milliunit_to_decimal(self, field_name: str) -> Decimal:
72+
"""Convert milliunit to decimal."""
73+
return getattr(self, field_name) / Decimal("1000")
74+
75+
@property
76+
def balance_decimal(self) -> Decimal:
77+
"""Returns the balance in currency."""
78+
return self._milliunit_to_decimal("balance")
79+
80+
@property
81+
def cleared_balance_decimal(self) -> Decimal:
82+
"""Returns the cleared balance in currency."""
83+
return self._milliunit_to_decimal("cleared_balance")
84+
85+
@property
86+
def uncleared_balance_decimal(self) -> Decimal:
87+
"""Returns the uncleared balance in currency."""
88+
return self._milliunit_to_decimal("uncleared_balance")
89+
90+
91+
class Payee(YnabBase):
92+
id: StrictStr
93+
name: StrictStr
94+
95+
96+
class MemoField(Field[str]):
97+
"""Memo field for YNAB."""
98+
99+
100+
class TransactionClearedStatus(enum.StrEnum):
101+
"""The cleared status of the transaction."""
102+
103+
CLEARED = "cleared"
104+
UNCLEARED = "uncleared"
105+
RECONCILED = "reconciled"
106+
107+
108+
class TransactionFlagColor(enum.StrEnum):
109+
"""The flag color of the transaction."""
110+
111+
RED = "red"
112+
ORANGE = "orange"
113+
YELLOW = "yellow"
114+
GREEN = "green"
115+
BLUE = "blue"
116+
PURPLE = "purple"
117+
118+
119+
class BaseTransaction(YnabBase):
120+
var_date: dt.date | None = None
121+
amount: StrictInt
122+
memo: MemoField | None = None
123+
cleared: TransactionClearedStatus | None = None
124+
approved: StrictBool | None = None
125+
flag_color: TransactionFlagColor | None = None
126+
account_id: StrictStr | None = None
127+
payee_id: StrictStr | None = None

0 commit comments

Comments
 (0)