Spaces:
Running
Running
File size: 6,108 Bytes
c91455c 46b0269 4361d77 77b8d27 4361d77 77b8d27 4361d77 46b0269 8de4860 4361d77 46b0269 c91455c 46b0269 4361d77 dd482d8 4361d77 4dbb8ce 4361d77 cef37ce 4361d77 c91455c 4361d77 2ededba 4361d77 3780bca 4361d77 3988090 4361d77 cc92d5a c91455c 46b0269 4361d77 77b8d27 cb86629 4361d77 3988090 cef37ce c592c1e 4361d77 29a8d28 77b8d27 29a8d28 77b8d27 29a8d28 77b8d27 c592c1e 46b0269 77b8d27 c91455c 46b0269 77b8d27 3780bca c592c1e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | from datetime import datetime, timezone, time, date as dt_date
from sqlmodel import SQLModel, Field, Relationship
from sqlalchemy import Column, DateTime, text, Numeric, func
from enum import Enum
from sqlalchemy.dialects.postgresql import JSONB
from typing import Optional
from decimal import Decimal
class ActivityCategory(str, Enum):
prayer = "prayer"
meal = "meal"
habit = "habit"
exercise = "exercise"
productivity = "productivity"
class TransactionCategory(str, Enum):
INCOME = "income"
EXPENSE = "expense"
class User(SQLModel, table=True):
__tablename__ = "users"
id: int = Field(default=None, primary_key=True)
phone_number: str = Field(index=True, unique=True)
email: str = Field(index=True, unique=True)
hashed_password: str
name: Optional[str] = None
timezone: str = "Asia/Karachi"
created_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
sa_column=Column(DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False)
)
updated_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
sa_column=Column(
DateTime(timezone=True),
server_default=func.now(),
onupdate=func.now(), # SQLAlchemy will now handle this dynamically
nullable=False
))
activity_entries: list["ActivityEntry"] = Relationship(back_populates="user")
goals: list["Goal"] = Relationship(back_populates="user")
day_logs: list["DayLog"] = Relationship(back_populates="user")
wallet: "Wallet" = Relationship(back_populates="user")
transactions: list["Transaction"] = Relationship(back_populates="user")
class Goal(SQLModel, table=True):
__tablename__ = "goals"
id: int = Field(default=None, primary_key=True)
user_id: int = Field(
foreign_key="users.id",
index=True
)
date: dt_date = Field(default_factory=dt_date.today, index=True)
title: str = Field(index=True)
description: Optional[str] = None
total_productivity_hours: Optional[float] = Field(default=0.0)
active_status: Optional[bool] = Field(default=None)
activity_entries: list["ActivityEntry"] = Relationship(back_populates="goal")
user: "User" = Relationship(back_populates="goals")
class DayLog(SQLModel, table=True):
__tablename__ = "day_logs"
id: int = Field(default=None, primary_key=True)
user_id: int = Field(
foreign_key="users.id",
index=True
)
date: dt_date = Field(default_factory=dt_date.today, index=True)
bed_time: Optional[time] = None
sleep_time: Optional[time] = None
wake_time: Optional[time] = None
sleep_duration_hours: Optional[float] = None
total_productivity_min: Optional[float] = Field(default=0.0)
total_calories: Optional[int] = None
notes: Optional[str] = None
user: "User" = Relationship(back_populates="day_logs")
activity_entries: list["ActivityEntry"] = Relationship(
back_populates="day_log"
)
transactions: list["Transaction"] = Relationship(back_populates="day_log")
class ActivityEntry(SQLModel, table=True):
__tablename__ = "activity_entries"
id: int = Field(default=None, primary_key=True)
user_id: int = Field(
foreign_key="users.id",
index=True
)
day_log_id: int = Field(
foreign_key="day_logs.id",
index=True
)
goal_id: Optional[int] = Field(
default=None,
foreign_key="goals.id",
index=True
)
goal_name: Optional[str] = None
date: dt_date = Field(default_factory=dt_date.today, index=True)
category: ActivityCategory = Field(index=True)
activity_type_name: str = Field(index=True)
note: Optional[str] = None
#for dynamic fields like location, quantity_text, what_i_did, result_text, jamaat,
#sets, reps, on_time, duration_min, occurred_at, active_status etc.
details: dict = Field(
default_factory=dict,
sa_column=Column(JSONB, server_default='{}')
)
user: "User" = Relationship(back_populates="activity_entries")
goal: Optional["Goal"] = Relationship(back_populates="activity_entries")
day_log: "DayLog" = Relationship(
back_populates="activity_entries"
)
class Wallet(SQLModel, table=True):
"""Stores the running total/balance for the user."""
__tablename__ = "wallets"
id: int = Field(default=None, primary_key=True)
user_id: int = Field(foreign_key="users.id", index=True, unique=True)
# Using Numeric/Decimal for precise money math
balance: Decimal = Field(default=Decimal("0.00"), sa_column=Column(Numeric(10, 2)))
updated_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
sa_column=Column(DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), onupdate=text("CURRENT_TIMESTAMP"))
)
user: "User" = Relationship(back_populates="wallet")
transactions: list["Transaction"] = Relationship(back_populates="wallet")
class Transaction(SQLModel, table=True):
"""Records every addition (income) and subtraction (expense)."""
__tablename__ = "transactions"
id: int = Field(default=None, primary_key=True)
user_id: int = Field(foreign_key="users.id", index=True)
day_log_id: int = Field(foreign_key="day_logs.id", index=True)
wallet_id: int = Field(foreign_key="wallets.id", index=True)
date: dt_date = Field(default_factory=dt_date.today, index=True)
category: TransactionCategory = Field(index=True)
amount: Decimal = Field(sa_column=Column(Numeric(10, 2)))
note: Optional[str] = None
# JSONB for the dynamic fields (source, type, litre, dayMode, what_eat)
details: dict = Field(
default_factory=dict,
sa_column=Column(JSONB, server_default='{}')
)
# ADDED: Relationships to map back to your other tables
user: "User" = Relationship(back_populates="transactions")
day_log: "DayLog" = Relationship(back_populates="transactions")
wallet: "Wallet" = Relationship(back_populates="transactions") |