Обновление приложения

This commit is contained in:
2026-04-28 22:37:19 +03:00
parent 7d00cf062e
commit 52594b5dc6
99 changed files with 5736 additions and 1052 deletions

121
backend/seed.py Normal file
View File

@@ -0,0 +1,121 @@
"""Seed initial reference data. Run once after migrations: python seed.py"""
import os
from dotenv import load_dotenv
load_dotenv()
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from app.auth.security import hash_password
from app.models import Role, User, Currency, AccountType, OperationType, Category
engine = create_engine(os.environ["DATABASE_URL"])
ROLES = [
("admin", "Full access — manages users, all financial data"),
("accountant", "Manages all financial data, cannot manage users"),
("user", "Manages own financial data"),
("viewer", "Read-only access to own data"),
]
CURRENCIES = [
("RUB", "Российский рубль", "₽"),
("USD", "Доллар США", "$"),
("EUR", "Евро", "€"),
("GBP", "Фунт стерлингов", "£"),
("CNY", "Китайский юань", "¥"),
("BTC", "Биткоин", "₿"),
]
ACCOUNT_TYPES = [
("Наличные", "wallet", "Наличные деньги"),
("Банковский счёт", "bank", "Текущий/расчётный счёт"),
("Кредитная карта", "credit-card", "Кредитная карта"),
("Накопительный", "piggy-bank", "Вклад / накопительный счёт"),
("Инвестиционный", "chart-line", "Брокерский или инвест. счёт"),
("Криптовалюта", "bitcoin", "Криптовалютный кошелёк"),
("Другое", "dots", "Прочий тип счёта"),
]
OPERATION_TYPES = [
("income", "Доход — пополнение счёта"),
("expense", "Расход — списание со счёта"),
("transfer", "Перевод между счетами"),
]
CATEGORIES = [
# (name, type, icon, color)
# --- Доходы ---
("Зарплата", "income", "briefcase", "#4CAF50"),
("Фриланс", "income", "laptop", "#8BC34A"),
("Инвестиции", "income", "chart-line", "#00BCD4"),
("Подарки", "income", "gift", "#E91E63"),
("Прочие доходы", "income", "plus-circle", "#9E9E9E"),
# --- Расходы ---
("Продукты", "expense", "shopping-cart","#FF5722"),
("Транспорт", "expense", "car", "#FF9800"),
("ЖКХ", "expense", "home", "#795548"),
("Здоровье", "expense", "heart", "#F44336"),
("Рестораны и кафе", "expense", "utensils", "#E91E63"),
("Развлечения", "expense", "gamepad", "#9C27B0"),
("Одежда", "expense", "tshirt", "#3F51B5"),
("Образование", "expense", "book", "#2196F3"),
("Путешествия", "expense", "plane", "#03A9F4"),
("Связь и интернет", "expense", "wifi", "#009688"),
("Подписки", "expense", "repeat", "#607D8B"),
("Прочие расходы", "expense", "minus-circle", "#9E9E9E"),
# --- Переводы ---
("Переводы", "transfer", "arrows-h", "#607D8B"),
]
def seed():
with Session(engine) as db:
# Roles
role_map: dict[str, Role] = {}
for name, desc in ROLES:
role = db.query(Role).filter(Role.name == name).first()
if not role:
role = Role(name=name, description=desc)
db.add(role)
db.flush()
role_map[name] = role
# Admin user
if not db.query(User).filter(User.username == "admin").first():
admin_pwd = os.getenv("ADMIN_PASSWORD", "Admin1234!")
admin = User(
username="admin",
email="admin@finance.local",
password_hash=hash_password(admin_pwd),
role_id=role_map["admin"].id,
)
db.add(admin)
print(f"[seed] Admin user created. Password from ADMIN_PASSWORD env (default: Admin1234!)")
# Currencies
for code, name, symbol in CURRENCIES:
if not db.query(Currency).filter(Currency.code == code).first():
db.add(Currency(code=code, name=name, symbol=symbol))
# Account types
for name, icon, desc in ACCOUNT_TYPES:
if not db.query(AccountType).filter(AccountType.name == name).first():
db.add(AccountType(name=name, icon=icon, description=desc))
# Operation types
for name, desc in OPERATION_TYPES:
if not db.query(OperationType).filter(OperationType.name == name).first():
db.add(OperationType(name=name, description=desc))
# System categories (user_id=None)
for name, ctype, icon, color in CATEGORIES:
if not db.query(Category).filter(Category.name == name, Category.user_id == None).first():
db.add(Category(name=name, type=ctype, icon=icon, color=color, user_id=None))
db.commit()
print("[seed] Done.")
if __name__ == "__main__":
seed()