first ruggedy draft
This commit is contained in:
643
apps/api/mousehold_api/models.py
Normal file
643
apps/api/mousehold_api/models.py
Normal file
@@ -0,0 +1,643 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, date, datetime
|
||||
from decimal import Decimal
|
||||
from uuid import uuid4
|
||||
|
||||
from mousehold_domain import (
|
||||
AccountType,
|
||||
EventObservationRelation,
|
||||
FinancialEventStatus,
|
||||
FinancialEventType,
|
||||
ImportConnectionStatus,
|
||||
ImportConnectionType,
|
||||
ObservationStatus,
|
||||
PaymentLineStatus,
|
||||
PaymentStatus,
|
||||
PlanningStatus,
|
||||
ProjectStatus,
|
||||
ReconciliationStatus,
|
||||
RecurringCommitmentStatus,
|
||||
RecurringInterval,
|
||||
RelationType,
|
||||
SettlementStatus,
|
||||
SourceType,
|
||||
VisibilityMode,
|
||||
)
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
Date,
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
Index,
|
||||
Integer,
|
||||
Numeric,
|
||||
String,
|
||||
Text,
|
||||
UniqueConstraint,
|
||||
)
|
||||
from sqlalchemy import Enum as SqlEnum
|
||||
from sqlalchemy.dialects.sqlite import JSON
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from .db import Base
|
||||
|
||||
|
||||
def new_id() -> str:
|
||||
return str(uuid4())
|
||||
|
||||
|
||||
def utcnow() -> datetime:
|
||||
return datetime.now(UTC)
|
||||
|
||||
|
||||
Money = Numeric(14, 2)
|
||||
|
||||
|
||||
class Household(Base):
|
||||
__tablename__ = "households"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
default_currency: Mapped[str] = mapped_column(String(3), default="EUR", nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
users: Mapped[list[User]] = relationship(
|
||||
back_populates="household", cascade="all, delete-orphan"
|
||||
)
|
||||
accounts: Mapped[list[Account]] = relationship(
|
||||
back_populates="household", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
display_name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
email: Mapped[str | None] = mapped_column(String(320), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
household: Mapped[Household] = relationship(back_populates="users")
|
||||
login_identities: Mapped[list[LoginIdentity]] = relationship(
|
||||
back_populates="user", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class LoginIdentity(Base):
|
||||
__tablename__ = "login_identities"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("provider", "provider_subject", name="uq_login_provider_subject"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
user_id: Mapped[str] = mapped_column(ForeignKey("users.id"), nullable=False, index=True)
|
||||
provider: Mapped[str] = mapped_column(String(80), nullable=False)
|
||||
provider_subject: Mapped[str] = mapped_column(String(320), nullable=False)
|
||||
email: Mapped[str | None] = mapped_column(String(320), nullable=True)
|
||||
display_name: Mapped[str | None] = mapped_column(String(200), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
user: Mapped[User] = relationship(back_populates="login_identities")
|
||||
|
||||
|
||||
class LocalSession(Base):
|
||||
__tablename__ = "local_sessions"
|
||||
__table_args__ = (
|
||||
Index("ix_local_session_token", "token_hash"),
|
||||
Index("ix_local_session_user", "user_id", "expires_at"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
user_id: Mapped[str] = mapped_column(ForeignKey("users.id"), nullable=False, index=True)
|
||||
household_id: Mapped[str] = mapped_column(ForeignKey("households.id"), nullable=False, index=True)
|
||||
token_hash: Mapped[str] = mapped_column(String(64), nullable=False, unique=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
last_seen_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
||||
revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
|
||||
class Account(Base):
|
||||
__tablename__ = "accounts"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
owner_user_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("users.id"), nullable=True, index=True
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
account_type: Mapped[AccountType] = mapped_column(SqlEnum(AccountType), nullable=False)
|
||||
institution_name: Mapped[str | None] = mapped_column(String(200), nullable=True)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="EUR", nullable=False)
|
||||
visibility_mode: Mapped[VisibilityMode] = mapped_column(SqlEnum(VisibilityMode), nullable=False)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
household: Mapped[Household] = relationship(back_populates="accounts")
|
||||
|
||||
|
||||
class RawObservation(Base):
|
||||
__tablename__ = "raw_observations"
|
||||
__table_args__ = (
|
||||
Index("ix_observation_dedupe", "household_id", "source_type", "raw_hash"),
|
||||
Index("ix_observation_external_refs", "provider_transaction_id", "message_id"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
source_type: Mapped[SourceType] = mapped_column(SqlEnum(SourceType), nullable=False, index=True)
|
||||
source_account_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True, index=True
|
||||
)
|
||||
owner_user_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("users.id"), nullable=True, index=True
|
||||
)
|
||||
observed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
received_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
raw_hash: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||||
source_reference: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||
provider_transaction_id: Mapped[str | None] = mapped_column(
|
||||
String(200), nullable=True, index=True
|
||||
)
|
||||
message_id: Mapped[str | None] = mapped_column(String(500), nullable=True, index=True)
|
||||
raw_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
raw_file_path: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
||||
raw_payload_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
parsed_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
parser_name: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
||||
parser_version: Mapped[str | None] = mapped_column(String(40), nullable=True)
|
||||
confidence: Mapped[Decimal] = mapped_column(Money, default=Decimal("1.00"), nullable=False)
|
||||
status: Mapped[ObservationStatus] = mapped_column(
|
||||
SqlEnum(ObservationStatus), default=ObservationStatus.NEW, nullable=False
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
event_links: Mapped[list[EventObservationLink]] = relationship(
|
||||
back_populates="observation", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class FinancialEvent(Base):
|
||||
__tablename__ = "financial_events"
|
||||
__table_args__ = (
|
||||
Index("ix_events_household_status_date", "household_id", "status", "event_date"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
source_account_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True, index=True
|
||||
)
|
||||
payment_account_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True, index=True
|
||||
)
|
||||
payer_user_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("users.id"), nullable=True, index=True
|
||||
)
|
||||
event_type: Mapped[FinancialEventType] = mapped_column(
|
||||
SqlEnum(FinancialEventType), nullable=False
|
||||
)
|
||||
status: Mapped[FinancialEventStatus] = mapped_column(
|
||||
SqlEnum(FinancialEventStatus), default=FinancialEventStatus.CANDIDATE, nullable=False
|
||||
)
|
||||
event_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
booking_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
due_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
amount: Mapped[Decimal] = mapped_column(Money, nullable=False)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="EUR", nullable=False)
|
||||
merchant: Mapped[str | None] = mapped_column(String(300), nullable=True)
|
||||
counterparty: Mapped[str | None] = mapped_column(String(300), nullable=True)
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
category_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("categories.id"), nullable=True, index=True
|
||||
)
|
||||
project_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("projects.id"), nullable=True, index=True
|
||||
)
|
||||
created_by_user_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("users.id"), nullable=True, index=True
|
||||
)
|
||||
fingerprint: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
||||
)
|
||||
|
||||
observation_links: Mapped[list[EventObservationLink]] = relationship(
|
||||
back_populates="event", cascade="all, delete-orphan"
|
||||
)
|
||||
split_lines: Mapped[list[SplitLine]] = relationship(
|
||||
back_populates="event", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class EventObservationLink(Base):
|
||||
__tablename__ = "event_observation_links"
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"event_id", "observation_id", "relation", name="uq_event_observation_relation"
|
||||
),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
event_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=False, index=True
|
||||
)
|
||||
observation_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("raw_observations.id"), nullable=False, index=True
|
||||
)
|
||||
relation: Mapped[EventObservationRelation] = mapped_column(
|
||||
SqlEnum(EventObservationRelation), nullable=False
|
||||
)
|
||||
confidence: Mapped[Decimal] = mapped_column(Money, default=Decimal("1.00"), nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
event: Mapped[FinancialEvent] = relationship(back_populates="observation_links")
|
||||
observation: Mapped[RawObservation] = relationship(back_populates="event_links")
|
||||
|
||||
|
||||
class EventRelation(Base):
|
||||
__tablename__ = "event_relations"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
from_event_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=False, index=True
|
||||
)
|
||||
to_event_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=False, index=True
|
||||
)
|
||||
relation_type: Mapped[RelationType] = mapped_column(SqlEnum(RelationType), nullable=False)
|
||||
confidence: Mapped[Decimal] = mapped_column(Money, default=Decimal("1.00"), nullable=False)
|
||||
created_by: Mapped[str] = mapped_column(String(40), default="system", nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class ReconciliationDecision(Base):
|
||||
__tablename__ = "reconciliation_decisions"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("household_id", "suggestion_id", name="uq_reconciliation_decision"),
|
||||
Index("ix_reconciliation_decision_household", "household_id", "decision"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
suggestion_id: Mapped[str] = mapped_column(String(160), nullable=False)
|
||||
decision: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||
kind: Mapped[str] = mapped_column(String(80), nullable=False)
|
||||
relation_type: Mapped[RelationType] = mapped_column(SqlEnum(RelationType), nullable=False)
|
||||
primary_event_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=False, index=True
|
||||
)
|
||||
confirming_event_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=False, index=True
|
||||
)
|
||||
confidence: Mapped[Decimal] = mapped_column(Money, default=Decimal("1.00"), nullable=False)
|
||||
actor_user_id: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True)
|
||||
reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class SplitLine(Base):
|
||||
__tablename__ = "split_lines"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
event_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=False, index=True
|
||||
)
|
||||
user_id: Mapped[str] = mapped_column(ForeignKey("users.id"), nullable=False, index=True)
|
||||
share_amount: Mapped[Decimal] = mapped_column(Money, nullable=False)
|
||||
share_percent: Mapped[Decimal | None] = mapped_column(Money, nullable=True)
|
||||
reason: Mapped[str] = mapped_column(String(80), default="manual", nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
event: Mapped[FinancialEvent] = relationship(back_populates="split_lines")
|
||||
|
||||
|
||||
class Category(Base):
|
||||
__tablename__ = "categories"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
parent_id: Mapped[str | None] = mapped_column(ForeignKey("categories.id"), nullable=True)
|
||||
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
||||
path: Mapped[str] = mapped_column(String(500), nullable=False)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
|
||||
|
||||
class Tag(Base):
|
||||
__tablename__ = "tags"
|
||||
__table_args__ = (UniqueConstraint("household_id", "name", name="uq_tag_household_name"),)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
|
||||
|
||||
class EventTag(Base):
|
||||
__tablename__ = "event_tags"
|
||||
__table_args__ = (UniqueConstraint("event_id", "tag_id", name="uq_event_tag"),)
|
||||
|
||||
event_id: Mapped[str] = mapped_column(ForeignKey("financial_events.id"), primary_key=True)
|
||||
tag_id: Mapped[str] = mapped_column(ForeignKey("tags.id"), primary_key=True)
|
||||
|
||||
|
||||
class Project(Base):
|
||||
__tablename__ = "projects"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(220), nullable=False)
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
start_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
end_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
default_split_rule_id: Mapped[str | None] = mapped_column(String(36), nullable=True)
|
||||
status: Mapped[ProjectStatus] = mapped_column(
|
||||
SqlEnum(ProjectStatus), default=ProjectStatus.PLANNING, nullable=False
|
||||
)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="EUR", nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class ProjectParticipant(Base):
|
||||
__tablename__ = "project_participants"
|
||||
__table_args__ = (UniqueConstraint("project_id", "user_id", name="uq_project_participant"),)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
project_id: Mapped[str] = mapped_column(ForeignKey("projects.id"), nullable=False, index=True)
|
||||
user_id: Mapped[str] = mapped_column(ForeignKey("users.id"), nullable=False, index=True)
|
||||
role: Mapped[str] = mapped_column(String(80), default="participant", nullable=False)
|
||||
default_share_percent: Mapped[Decimal | None] = mapped_column(Money, nullable=True)
|
||||
|
||||
|
||||
class ProjectBudgetLine(Base):
|
||||
__tablename__ = "project_budget_lines"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
project_id: Mapped[str] = mapped_column(ForeignKey("projects.id"), nullable=False, index=True)
|
||||
category_id: Mapped[str | None] = mapped_column(ForeignKey("categories.id"), nullable=True)
|
||||
name: Mapped[str] = mapped_column(String(180), nullable=False)
|
||||
budgeted_amount: Mapped[Decimal] = mapped_column(Money, default=Decimal("0.00"), nullable=False)
|
||||
committed_amount_cached: Mapped[Decimal | None] = mapped_column(Money, nullable=True)
|
||||
paid_amount_cached: Mapped[Decimal | None] = mapped_column(Money, nullable=True)
|
||||
sort_order: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
|
||||
|
||||
class ProjectPlannedItem(Base):
|
||||
__tablename__ = "project_planned_items"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
project_id: Mapped[str] = mapped_column(ForeignKey("projects.id"), nullable=False, index=True)
|
||||
budget_line_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("project_budget_lines.id"), nullable=True, index=True
|
||||
)
|
||||
description: Mapped[str] = mapped_column(String(300), nullable=False)
|
||||
estimated_amount: Mapped[Decimal] = mapped_column(
|
||||
Money, default=Decimal("0.00"), nullable=False
|
||||
)
|
||||
committed_amount: Mapped[Decimal | None] = mapped_column(Money, nullable=True)
|
||||
expected_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
due_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
expected_payer_account_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True
|
||||
)
|
||||
split_rule_id: Mapped[str | None] = mapped_column(String(36), nullable=True)
|
||||
planning_status: Mapped[PlanningStatus] = mapped_column(
|
||||
SqlEnum(PlanningStatus), default=PlanningStatus.IDEA, nullable=False
|
||||
)
|
||||
payment_status: Mapped[PaymentStatus] = mapped_column(
|
||||
SqlEnum(PaymentStatus), default=PaymentStatus.UNPAID, nullable=False
|
||||
)
|
||||
reconciliation_status: Mapped[ReconciliationStatus] = mapped_column(
|
||||
SqlEnum(ReconciliationStatus), default=ReconciliationStatus.NO_EVIDENCE, nullable=False
|
||||
)
|
||||
settlement_status: Mapped[SettlementStatus] = mapped_column(
|
||||
SqlEnum(SettlementStatus), default=SettlementStatus.UNSETTLED, nullable=False
|
||||
)
|
||||
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class PaymentLine(Base):
|
||||
__tablename__ = "payment_lines"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
planned_item_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("project_planned_items.id"), nullable=True, index=True
|
||||
)
|
||||
event_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=True, index=True
|
||||
)
|
||||
amount: Mapped[Decimal] = mapped_column(Money, nullable=False)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="EUR", nullable=False)
|
||||
date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
paid_by_user_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("users.id"), nullable=True, index=True
|
||||
)
|
||||
payment_account_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True, index=True
|
||||
)
|
||||
source_observation_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("raw_observations.id"), nullable=True
|
||||
)
|
||||
status: Mapped[PaymentLineStatus] = mapped_column(
|
||||
SqlEnum(PaymentLineStatus), default=PaymentLineStatus.EXPECTED, nullable=False
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class RecurringCommitment(Base):
|
||||
__tablename__ = "recurring_commitments"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
provider: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
amount_expected: Mapped[Decimal] = mapped_column(Money, nullable=False)
|
||||
amount_min: Mapped[Decimal | None] = mapped_column(Money, nullable=True)
|
||||
amount_max: Mapped[Decimal | None] = mapped_column(Money, nullable=True)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="EUR", nullable=False)
|
||||
interval: Mapped[RecurringInterval] = mapped_column(SqlEnum(RecurringInterval), nullable=False)
|
||||
next_due_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
payer_account_id: Mapped[str | None] = mapped_column(ForeignKey("accounts.id"), nullable=True)
|
||||
split_rule_id: Mapped[str | None] = mapped_column(String(36), nullable=True)
|
||||
category_id: Mapped[str | None] = mapped_column(ForeignKey("categories.id"), nullable=True)
|
||||
project_id: Mapped[str | None] = mapped_column(ForeignKey("projects.id"), nullable=True)
|
||||
notice_period: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
||||
renewal_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
status: Mapped[RecurringCommitmentStatus] = mapped_column(
|
||||
SqlEnum(RecurringCommitmentStatus), default=RecurringCommitmentStatus.ACTIVE, nullable=False
|
||||
)
|
||||
matching_rule_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class PromisedPayment(Base):
|
||||
__tablename__ = "promised_payments"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
related_event_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("financial_events.id"), nullable=True, index=True
|
||||
)
|
||||
provider: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
amount: Mapped[Decimal] = mapped_column(Money, nullable=False)
|
||||
currency: Mapped[str] = mapped_column(String(3), default="EUR", nullable=False)
|
||||
created_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
due_date: Mapped[date] = mapped_column(Date, nullable=False, index=True)
|
||||
expected_funding_account_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("accounts.id"), nullable=True
|
||||
)
|
||||
responsible_user_id: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(40), default="expected", nullable=False)
|
||||
source_observation_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("raw_observations.id"), nullable=True
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class ImportConnection(Base):
|
||||
__tablename__ = "import_connections"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
owner_user_id: Mapped[str] = mapped_column(ForeignKey("users.id"), nullable=False, index=True)
|
||||
connection_type: Mapped[ImportConnectionType] = mapped_column(
|
||||
SqlEnum(ImportConnectionType), nullable=False
|
||||
)
|
||||
display_name: Mapped[str] = mapped_column(String(200), nullable=False)
|
||||
status: Mapped[ImportConnectionStatus] = mapped_column(
|
||||
SqlEnum(ImportConnectionStatus), default=ImportConnectionStatus.NEEDS_AUTH, nullable=False
|
||||
)
|
||||
last_sync_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
secret_storage_ref: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||
runs_locally: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
connector_config_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
||||
)
|
||||
|
||||
|
||||
class ImportRun(Base):
|
||||
__tablename__ = "import_runs"
|
||||
__table_args__ = (
|
||||
Index("ix_import_runs_household_started", "household_id", "started_at"),
|
||||
Index("ix_import_runs_connection_started", "connection_id", "started_at"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
connection_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("import_connections.id"), nullable=True, index=True
|
||||
)
|
||||
actor_user_id: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True)
|
||||
source_type: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(40), default="running", nullable=False)
|
||||
imported_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
duplicate_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
created_event_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
skipped_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
summary_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
started_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
|
||||
class AuditLog(Base):
|
||||
__tablename__ = "audit_log"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_id)
|
||||
household_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("households.id"), nullable=False, index=True
|
||||
)
|
||||
actor_user_id: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True)
|
||||
action: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
entity_type: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
entity_id: Mapped[str | None] = mapped_column(String(36), nullable=True)
|
||||
details_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=utcnow, nullable=False
|
||||
)
|
||||
Reference in New Issue
Block a user