from datetime import datetime from enum import Enum from typing import Optional from pydantic import BaseModel, Field class AccountType(str, Enum): ASSET = "asset" LIABILITY = "liability" EQUITY = "equity" REVENUE = "revenue" EXPENSE = "expense" class Account(BaseModel): id: str name: str account_type: AccountType description: Optional[str] = None user_id: Optional[str] = None # For user-specific accounts created_at: datetime class CreateAccount(BaseModel): name: str account_type: AccountType description: Optional[str] = None user_id: Optional[str] = None class EntryLine(BaseModel): id: str journal_entry_id: str account_id: str debit: int = 0 # in satoshis credit: int = 0 # in satoshis description: Optional[str] = None metadata: dict = {} # Stores currency info: fiat_currency, fiat_amount, fiat_rate, etc. class CreateEntryLine(BaseModel): account_id: str debit: int = 0 credit: int = 0 description: Optional[str] = None metadata: dict = {} # Stores currency info class JournalEntry(BaseModel): id: str description: str entry_date: datetime created_by: str # wallet ID of user who created it created_at: datetime reference: Optional[str] = None # Invoice ID or reference number lines: list[EntryLine] = [] class CreateJournalEntry(BaseModel): description: str entry_date: Optional[datetime] = None reference: Optional[str] = None lines: list[CreateEntryLine] class UserBalance(BaseModel): user_id: str balance: int # positive = castle owes user, negative = user owes castle accounts: list[Account] = [] class ExpenseEntry(BaseModel): """Helper model for creating expense entries""" description: str amount: float # Amount in the specified currency (or satoshis if currency is None) expense_account: str # account name or ID is_equity: bool = False # True = equity contribution, False = liability (castle owes user) user_wallet: str reference: Optional[str] = None currency: Optional[str] = None # If None, amount is in satoshis. Otherwise, fiat currency code (EUR, USD, etc.) class ReceivableEntry(BaseModel): """Helper model for creating accounts receivable entries""" description: str amount: float # Amount in the specified currency (or satoshis if currency is None) revenue_account: str # account name or ID user_wallet: str reference: Optional[str] = None currency: Optional[str] = None # If None, amount is in satoshis. Otherwise, fiat currency code class RevenueEntry(BaseModel): """Helper model for creating revenue entries""" description: str amount: float # Amount in the specified currency (or satoshis if currency is None) revenue_account: str payment_method_account: str # e.g., "Cash", "Bank", "Lightning" reference: Optional[str] = None currency: Optional[str] = None # If None, amount is in satoshis. Otherwise, fiat currency code