Adding auto creation of opening transaction on create
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from account.resource import AccountResource
|
from account.resource import AccountResource
|
||||||
from account.schemas import AccountCreate, CategoryCreate
|
from account.schemas import AccountCreate, CategoryCreate
|
||||||
@@ -29,36 +30,42 @@ fixtures_account = [
|
|||||||
"parent_path": None,
|
"parent_path": None,
|
||||||
"type": "Asset",
|
"type": "Asset",
|
||||||
"opening_date": date(1970, 1, 1),
|
"opening_date": date(1970, 1, 1),
|
||||||
|
"opening_balance": Decimal("0.00"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Cash in Wallet",
|
"name": "Cash in Wallet",
|
||||||
"parent_path": "/Accounts/Asset/Current Assets/",
|
"parent_path": "/Accounts/Asset/Current Assets/",
|
||||||
"type": "Asset",
|
"type": "Asset",
|
||||||
"opening_date": date(1970, 1, 1),
|
"opening_date": date(1970, 1, 1),
|
||||||
|
"opening_balance": Decimal("0.00"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Checking Account",
|
"name": "Checking Account",
|
||||||
"parent_path": "/Accounts/Asset/Current Assets/",
|
"parent_path": "/Accounts/Asset/Current Assets/",
|
||||||
"type": "Asset",
|
"type": "Asset",
|
||||||
"opening_date": date(1970, 1, 1),
|
"opening_date": date(1970, 1, 1),
|
||||||
|
"opening_balance": Decimal("0.00"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Savings Account",
|
"name": "Savings Account",
|
||||||
"parent_path": "/Accounts/Asset/Current Assets/",
|
"parent_path": "/Accounts/Asset/Current Assets/",
|
||||||
"type": "Asset",
|
"type": "Asset",
|
||||||
"opening_date": date(1970, 1, 1),
|
"opening_date": date(1970, 1, 1),
|
||||||
|
"opening_balance": Decimal("0.00"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Debt Accounts",
|
"name": "Debt Accounts",
|
||||||
"parent_path": None,
|
"parent_path": None,
|
||||||
"type": "Liability",
|
"type": "Liability",
|
||||||
"opening_date": date(1970, 1, 1),
|
"opening_date": date(1970, 1, 1),
|
||||||
|
"opening_balance": Decimal("0.00"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Credit Card",
|
"name": "Credit Card",
|
||||||
"parent_path": "/Accounts/Liability/Debt Accounts/",
|
"parent_path": "/Accounts/Liability/Debt Accounts/",
|
||||||
"type": "Liability",
|
"type": "Liability",
|
||||||
"opening_date": date(1970, 1, 1),
|
"opening_date": date(1970, 1, 1),
|
||||||
|
"opening_balance": Decimal("0.00"),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from sqlmodel import select
|
from sqlmodel import select
|
||||||
|
|
||||||
from account.models import Account
|
from account.models import Account
|
||||||
|
from transaction.models import Split, Transaction
|
||||||
|
|
||||||
|
|
||||||
class AccountResource:
|
class AccountResource:
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -18,6 +20,25 @@ class AccountResource:
|
|||||||
model.parent_account = cls.get(session, model.parent_account_id)
|
model.parent_account = cls.get(session, model.parent_account_id)
|
||||||
return model.parent_account
|
return model.parent_account
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_opening_transaction(cls, session, account, schema):
|
||||||
|
|
||||||
|
equity_account = cls.get_by_path(session, "/Equity/")
|
||||||
|
t = Transaction()
|
||||||
|
split_opening = Split()
|
||||||
|
split_opening.id = 0
|
||||||
|
split_opening.transaction = t
|
||||||
|
split_opening.account = account
|
||||||
|
split_opening.amount = schema.opening_balance
|
||||||
|
|
||||||
|
split_equity = Split()
|
||||||
|
split_equity.id = 1
|
||||||
|
split_equity.transaction = t
|
||||||
|
split_equity.account = equity_account
|
||||||
|
split_equity.amount = - schema.opening_balance
|
||||||
|
|
||||||
|
account.transaction_splits.append(split_opening)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def schema_to_model(cls, session, schema, model=None):
|
def schema_to_model(cls, session, schema, model=None):
|
||||||
try:
|
try:
|
||||||
@@ -27,6 +48,7 @@ class AccountResource:
|
|||||||
schema.path = ""
|
schema.path = ""
|
||||||
schema.family = ""
|
schema.family = ""
|
||||||
model = Account.model_validate(schema)
|
model = Account.model_validate(schema)
|
||||||
|
cls.create_opening_transaction(session, model, schema)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
raise
|
raise
|
||||||
@@ -34,6 +56,7 @@ class AccountResource:
|
|||||||
model.compute_family()
|
model.compute_family()
|
||||||
cls.validate_parent(session, model)
|
cls.validate_parent(session, model)
|
||||||
model.compute_path()
|
model.compute_path()
|
||||||
|
|
||||||
return model
|
return model
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -68,12 +91,10 @@ class AccountResource:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_equity_account(cls, session):
|
def create_equity_account(cls, session):
|
||||||
|
if cls.get_by_path(session, "/Equity/") is None:
|
||||||
account_db = Account(name="Equity", family="Equity", type="Equity", path="/Equity/")
|
account_db = Account(name="Equity", family="Equity", type="Equity", path="/Equity/")
|
||||||
session.add(account_db)
|
session.add(account_db)
|
||||||
session.commit()
|
session.commit()
|
||||||
session.refresh(account_db)
|
|
||||||
|
|
||||||
return account_db
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def select(cls):
|
def select(cls):
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ class CategoryWrite(BaseAccountWrite):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
opening_date: SkipJsonSchema[date] = Field(default=date(1970, 1, 1))
|
||||||
|
opening_balance: SkipJsonSchema[Decimal] = Field(default=0)
|
||||||
|
|
||||||
class CategoryCreate(CategoryWrite):
|
class CategoryCreate(CategoryWrite):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ from pydantic_core import core_schema
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MonetaryAmount:
|
class MonetaryAmount:
|
||||||
amount: Decimal# = Field(decimal_places=2, default=0)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __get_pydantic_core_schema__(
|
def __get_pydantic_core_schema__(
|
||||||
cls, source: type[Any], handler: GetCoreSchemaHandler
|
cls, source: type[Any], handler: GetCoreSchemaHandler
|
||||||
@@ -16,26 +14,24 @@ class MonetaryAmount:
|
|||||||
assert source is MonetaryAmount
|
assert source is MonetaryAmount
|
||||||
return core_schema.no_info_after_validator_function(
|
return core_schema.no_info_after_validator_function(
|
||||||
cls._validate,
|
cls._validate,
|
||||||
core_schema.float_schema(multiple_of=0.01),
|
core_schema.decimal_schema(multiple_of=0.01),
|
||||||
serialization=core_schema.plain_serializer_function_ser_schema(
|
serialization=core_schema.plain_serializer_function_ser_schema(
|
||||||
cls._serialize,
|
cls._serialize,
|
||||||
info_arg=False,
|
info_arg=False,
|
||||||
return_schema=core_schema.float_schema(multiple_of=0.01),
|
return_schema=core_schema.decimal_schema(multiple_of=0.01),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
def __init__(self, *args, **kwargs):
|
||||||
def _validate(value: str) -> 'CompressedString':
|
super().__init__(*args, **kwargs)
|
||||||
inverse_dictionary: dict[str, int] = {}
|
|
||||||
text: list[int] = []
|
|
||||||
for word in value.split(' '):
|
|
||||||
if word not in inverse_dictionary:
|
|
||||||
inverse_dictionary[word] = len(inverse_dictionary)
|
|
||||||
text.append(inverse_dictionary[word])
|
|
||||||
return MonetaryAmount(
|
|
||||||
{v: k for k, v in inverse_dictionary.items()}, text
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _serialize(value: 'CompressedString') -> str:
|
def _validate(value: Decimal) -> 'MonetaryAmount':
|
||||||
|
if value.as_tuple()[2] < -2:
|
||||||
|
raise ValueError(f'{value} has more than two decimal places.')
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _serialize(value: 'MonetaryAmount') -> str:
|
||||||
return value.amount
|
return value.amount
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import main
|
import main
|
||||||
|
|
||||||
|
from account.resource import AccountResource
|
||||||
from account.fixtures import inject_fixtures as account_inject_fixtures
|
from account.fixtures import inject_fixtures as account_inject_fixtures
|
||||||
from db import create_db_and_tables, get_session, drop_tables
|
from db import create_db_and_tables, get_session, drop_tables
|
||||||
from user import create_admin_account
|
from user import create_admin_user
|
||||||
|
|
||||||
drop_tables()
|
drop_tables()
|
||||||
create_db_and_tables()
|
create_db_and_tables()
|
||||||
|
|
||||||
session = get_session().__next__()
|
session = get_session().__next__()
|
||||||
create_admin_account(session)
|
create_admin_user(session)
|
||||||
|
AccountResource.create_equity_account(session)
|
||||||
account_inject_fixtures(session)
|
account_inject_fixtures(session)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import Optional
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
from sqlmodel import Field, SQLModel, select, Relationship
|
from sqlmodel import Field, SQLModel, select, Relationship
|
||||||
@@ -50,7 +51,7 @@ class Transaction(TransactionBaseId, table=True):
|
|||||||
|
|
||||||
class SplitBase(SQLModel):
|
class SplitBase(SQLModel):
|
||||||
account_id: UUID = Field(foreign_key="account.id")
|
account_id: UUID = Field(foreign_key="account.id")
|
||||||
payee_id: UUID = Field(foreign_key="payee.id")
|
payee_id: Optional[UUID] = Field(foreign_key="payee.id")
|
||||||
amount: Decimal = Field(decimal_places=2)
|
amount: Decimal = Field(decimal_places=2)
|
||||||
|
|
||||||
class SplitBaseId(SplitBase):
|
class SplitBaseId(SplitBase):
|
||||||
@@ -74,7 +75,7 @@ class SplitWrite(SplitBase):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
payee_id: UUID = PydField(json_schema_extra={
|
payee_id: UUID | None = PydField(json_schema_extra={
|
||||||
"foreign_key": {
|
"foreign_key": {
|
||||||
"reference": {
|
"reference": {
|
||||||
"resource": "payees",
|
"resource": "payees",
|
||||||
|
|||||||
Reference in New Issue
Block a user