File size: 9,234 Bytes
5aaca54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
DataFlow Server — Database Engine & Session
"""
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import Session
from models import Base, User, Project, Task, Expense, Document, AIForecast, Notification, SubTask
from datetime import datetime, timedelta
from passlib.context import CryptContext
import uuid
import os

DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:///./dataflow.db")

engine = create_async_engine(DATABASE_URL, echo=False)
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


async def get_db() -> AsyncSession:
    async with AsyncSessionLocal() as session:
        yield session


async def init_db():
    """Create tables and seed demo data if empty."""
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    async with AsyncSessionLocal() as db:
        # Check if already seeded
        from sqlalchemy import select, text
        result = await db.execute(select(User).limit(1))
        if result.scalar_one_or_none() is not None:
            return  # Already seeded

        print("Seeding database with demo data...")
        uid1 = str(uuid.uuid4())
        uid2 = str(uuid.uuid4())
        uid3 = str(uuid.uuid4())

        # Users
        users = [
            User(id=uid1, full_name="Анастасия Иванова", email="nastya@example.com",
                 hashed_password=pwd_context.hash("123456"), position="Проект-менеджер", role="manager"),
            User(id=uid2, full_name="Алексей Петров", email="alexey@example.com",
                 hashed_password=pwd_context.hash("123456"), position="Backend-разработчик", role="developer"),
            User(id=uid3, full_name="Мария Сидорова", email="maria@example.com",
                 hashed_password=pwd_context.hash("123456"), position="Frontend-разработчик", role="developer"),
        ]
        db.add_all(users)
        await db.flush()

        # Projects
        p1_id = str(uuid.uuid4())
        p2_id = str(uuid.uuid4())
        projects = [
            Project(id=p1_id, name="Мобильное приложение E-Commerce",
                    description="Разработка мобильного приложения для интернет-магазина",
                    start_date=datetime(2026, 1, 15), end_date=datetime(2026, 6, 30),
                    budget=5000000, spent=2750000, status="active", progress=0.55,
                    risk_level="yellow", owner_id=uid1),
            Project(id=p2_id, name="CRM Система",
                    description="Внедрение CRM системы для отдела продаж",
                    start_date=datetime(2026, 3, 1), end_date=datetime(2026, 8, 31),
                    budget=3200000, spent=800000, status="active", progress=0.25,
                    risk_level="green", owner_id=uid1),
        ]
        db.add_all(projects)
        await db.flush()

        # Tasks
        t1_id = str(uuid.uuid4())
        t2_id = str(uuid.uuid4())
        tasks = [
            Task(id=t1_id, title="Разработка API авторизации", project_id=p1_id,
                 status="done", priority="high", assignee_id=uid2, assignee_name="Алексей П.",
                 deadline=datetime(2026, 4, 15),
                 description="Реализовать REST API для регистрации, входа, JWT и 2FA"),
            Task(id=t2_id, title="Дизайн каталога товаров", project_id=p1_id,
                 status="inProgress", priority="high", assignee_id=uid3, assignee_name="Мария С.",
                 deadline=datetime(2026, 5, 20),
                 description="Разработать UI/UX для каталога с фильтрами"),
            Task(id=str(uuid.uuid4()), title="Интеграция платежного шлюза", project_id=p1_id,
                 status="todo", priority="critical", assignee_id=uid2, assignee_name="Алексей П.",
                 deadline=datetime(2026, 5, 30),
                 description="Подключить Kaspi Pay и Halyk Bank"),
            Task(id=str(uuid.uuid4()), title="Анализ требований CRM", project_id=p2_id,
                 status="done", priority="high", assignee_id=uid3, assignee_name="Мария С.",
                 deadline=datetime(2026, 4, 10)),
        ]
        db.add_all(tasks)
        await db.flush()

        # Subtasks
        db.add_all([
            SubTask(id=str(uuid.uuid4()), task_id=t1_id, title="JWT Token", completed=True),
            SubTask(id=str(uuid.uuid4()), task_id=t1_id, title="Refresh Token", completed=True),
            SubTask(id=str(uuid.uuid4()), task_id=t1_id, title="2FA SMS", completed=True),
            SubTask(id=str(uuid.uuid4()), task_id=t2_id, title="Wireframes", completed=True),
            SubTask(id=str(uuid.uuid4()), task_id=t2_id, title="Mockups", completed=True),
            SubTask(id=str(uuid.uuid4()), task_id=t2_id, title="Prototype", completed=False),
        ])

        # Expenses
        db.add_all([
            Expense(id=str(uuid.uuid4()), project_id=p1_id, title="Зарплата разработчиков (Март)",
                    amount=900000, category="personnel", status="approved",
                    date=datetime(2026, 3, 31)),
            Expense(id=str(uuid.uuid4()), project_id=p1_id, title="Облачный хостинг AWS",
                    amount=150000, category="infrastructure", status="approved",
                    date=datetime(2026, 4, 5)),
            Expense(id=str(uuid.uuid4()), project_id=p1_id, title="Лицензия Figma Team",
                    amount=85000, category="software", status="approved",
                    date=datetime(2026, 4, 10)),
            Expense(id=str(uuid.uuid4()), project_id=p1_id, title="Командировка в Астану",
                    amount=120000, category="travel", status="pending",
                    date=datetime(2026, 5, 5)),
            Expense(id=str(uuid.uuid4()), project_id=p2_id, title="Консультация по 1С",
                    amount=200000, category="training", status="approved",
                    date=datetime(2026, 4, 20)),
        ])

        # Documents
        db.add_all([
            Document(id=str(uuid.uuid4()), project_id=p1_id,
                     name="Техническое задание E-Commerce.pdf", type="pdf",
                     size_bytes=2450000, is_favorite=True),
            Document(id=str(uuid.uuid4()), project_id=p1_id,
                     name="Смета проекта.xlsx", type="xlsx",
                     size_bytes=340000, is_favorite=True),
            Document(id=str(uuid.uuid4()), project_id=p1_id,
                     name="Счёт AWS Март 2026.pdf", type="pdf", size_bytes=120000,
                     detected_type="invoice", recognition_confidence=0.97,
                     extracted_text="Сумма: 150 000 KZT\nДата: 31.03.2026\nПоставщик: Amazon Web Services",
                     extracted_amount=150000, extracted_supplier="Amazon Web Services"),
        ])

        # AI Forecasts
        db.add_all([
            AIForecast(id=str(uuid.uuid4()), project_id=p1_id,
                       current_spent=2750000, planned_budget=5000000,
                       risk_level="yellow", overrun_probability=35.0,
                       optimistic_forecast=4600000, realistic_forecast=5200000, pessimistic_forecast=5800000,
                       recommendations='["Оптимизировать расходы на облачную инфраструктуру","Рассмотреть аутсорсинг QA-тестирования","Пересмотреть приоритеты задач","Использовать Open Source альтернативы"]'),
            AIForecast(id=str(uuid.uuid4()), project_id=p2_id,
                       current_spent=800000, planned_budget=3200000,
                       risk_level="green", overrun_probability=12.0,
                       optimistic_forecast=2800000, realistic_forecast=3100000, pessimistic_forecast=3400000,
                       recommendations='["Проект идёт в рамках бюджета","Рекомендуется создать резерв на интеграцию с 1С"]'),
        ])

        # Notifications
        db.add_all([
            Notification(id=str(uuid.uuid4()), user_id=uid1,
                         title="AI прогноз: Внимание",
                         body="Проект 'E-Commerce' — риск перерасхода 35%",
                         type="ai"),
            Notification(id=str(uuid.uuid4()), user_id=uid1,
                         title="Новый расход на согласование",
                         body="Командировка в Астану — 120 000 ₸",
                         type="expense"),
        ])

        await db.commit()
        print("Database seeded successfully!")