Обновление приложения
This commit is contained in:
29
backend/app/schemas/__init__.py
Normal file
29
backend/app/schemas/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from app.schemas.user import RoleOut, UserCreate, UserUpdate, UserOut, UserWithRole
|
||||
from app.schemas.currency import CurrencyCreate, CurrencyUpdate, CurrencyOut, ExchangeRateCreate, ExchangeRateOut
|
||||
from app.schemas.location import LocationCreate, LocationUpdate, LocationOut
|
||||
from app.schemas.account import AccountTypeOut, AccountCreate, AccountUpdate, AccountOut
|
||||
from app.schemas.category import CategoryCreate, CategoryUpdate, CategoryOut
|
||||
from app.schemas.budget import BudgetCreate, BudgetUpdate, BudgetOut
|
||||
from app.schemas.operation import (
|
||||
OperationTypeOut,
|
||||
OperationCreate, OperationUpdate, OperationOut,
|
||||
OperationRelationCreate, OperationRelationOut,
|
||||
TransferCreate,
|
||||
)
|
||||
from app.schemas.calendar import CalendarEventCreate, CalendarEventUpdate, CalendarEventOut
|
||||
from app.schemas.auth import Token, TokenData, LoginRequest
|
||||
|
||||
__all__ = [
|
||||
"RoleOut", "UserCreate", "UserUpdate", "UserOut", "UserWithRole",
|
||||
"CurrencyCreate", "CurrencyUpdate", "CurrencyOut",
|
||||
"ExchangeRateCreate", "ExchangeRateOut",
|
||||
"LocationCreate", "LocationUpdate", "LocationOut",
|
||||
"AccountTypeOut", "AccountCreate", "AccountUpdate", "AccountOut",
|
||||
"CategoryCreate", "CategoryUpdate", "CategoryOut",
|
||||
"BudgetCreate", "BudgetUpdate", "BudgetOut",
|
||||
"OperationTypeOut",
|
||||
"OperationCreate", "OperationUpdate", "OperationOut",
|
||||
"OperationRelationCreate", "OperationRelationOut", "TransferCreate",
|
||||
"CalendarEventCreate", "CalendarEventUpdate", "CalendarEventOut",
|
||||
"Token", "TokenData", "LoginRequest",
|
||||
]
|
||||
53
backend/app/schemas/account.py
Normal file
53
backend/app/schemas/account.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from pydantic import BaseModel, Field
|
||||
from app.schemas.currency import CurrencyOut
|
||||
|
||||
|
||||
class AccountTypeOut(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
icon: str | None = None
|
||||
description: str | None = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class AccountCreate(BaseModel):
|
||||
name: str = Field(..., max_length=200)
|
||||
account_type_id: int
|
||||
currency_id: int
|
||||
initial_balance: Decimal = Decimal("0.00")
|
||||
credit_limit: Decimal | None = None
|
||||
description: str | None = None
|
||||
icon: str | None = None
|
||||
color: str | None = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$")
|
||||
|
||||
|
||||
class AccountUpdate(BaseModel):
|
||||
name: str | None = Field(None, max_length=200)
|
||||
is_active: bool | None = None
|
||||
credit_limit: Decimal | None = None
|
||||
description: str | None = None
|
||||
icon: str | None = None
|
||||
color: str | None = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$")
|
||||
|
||||
|
||||
class AccountOut(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
name: str
|
||||
account_type_id: int
|
||||
account_type: AccountTypeOut
|
||||
currency_id: int
|
||||
currency: CurrencyOut
|
||||
balance: Decimal
|
||||
initial_balance: Decimal
|
||||
is_active: bool
|
||||
credit_limit: Decimal | None = None
|
||||
description: str | None = None
|
||||
icon: str | None = None
|
||||
color: str | None = None
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
17
backend/app/schemas/auth.py
Normal file
17
backend/app/schemas/auth.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
token_type: str = "bearer"
|
||||
|
||||
|
||||
class TokenData(BaseModel):
|
||||
user_id: int | None = None
|
||||
role: str | None = None
|
||||
43
backend/app/schemas/budget.py
Normal file
43
backend/app/schemas/budget.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
from pydantic import BaseModel, Field
|
||||
from app.schemas.category import CategoryOut
|
||||
from app.schemas.currency import CurrencyOut
|
||||
|
||||
|
||||
class BudgetCreate(BaseModel):
|
||||
category_id: int
|
||||
name: str = Field(..., max_length=200)
|
||||
amount: Decimal = Field(..., gt=0)
|
||||
currency_id: int
|
||||
period_type: str = Field(..., pattern="^(monthly|weekly|yearly|custom)$")
|
||||
start_date: date
|
||||
end_date: date | None = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class BudgetUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
amount: Decimal | None = Field(None, gt=0)
|
||||
period_type: str | None = None
|
||||
end_date: date | None = None
|
||||
is_active: bool | None = None
|
||||
|
||||
|
||||
class BudgetOut(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
category_id: int
|
||||
category: CategoryOut
|
||||
name: str
|
||||
amount: Decimal
|
||||
currency_id: int
|
||||
currency: CurrencyOut
|
||||
period_type: str
|
||||
start_date: date
|
||||
end_date: date | None = None
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
spent: Decimal | None = None # computed field
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
55
backend/app/schemas/calendar.py
Normal file
55
backend/app/schemas/calendar.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from datetime import datetime, date, time
|
||||
from decimal import Decimal
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class CalendarEventCreate(BaseModel):
|
||||
title: str = Field(..., max_length=200)
|
||||
description: str | None = None
|
||||
event_date: date
|
||||
event_time: time | None = None
|
||||
is_recurring: bool = False
|
||||
recurrence_pattern: str | None = Field(None, pattern="^(daily|weekly|monthly|yearly)$")
|
||||
recurrence_end_date: date | None = None
|
||||
related_operation_id: int | None = None
|
||||
category_id: int | None = None
|
||||
amount: Decimal | None = None
|
||||
currency_id: int | None = None
|
||||
reminder_days: int | None = Field(None, ge=0)
|
||||
is_completed: bool = False
|
||||
|
||||
|
||||
class CalendarEventUpdate(BaseModel):
|
||||
title: str | None = Field(None, max_length=200)
|
||||
description: str | None = None
|
||||
event_date: date | None = None
|
||||
event_time: time | None = None
|
||||
is_recurring: bool | None = None
|
||||
recurrence_pattern: str | None = None
|
||||
recurrence_end_date: date | None = None
|
||||
related_operation_id: int | None = None
|
||||
category_id: int | None = None
|
||||
amount: Decimal | None = None
|
||||
reminder_days: int | None = None
|
||||
is_completed: bool | None = None
|
||||
|
||||
|
||||
class CalendarEventOut(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
title: str
|
||||
description: str | None = None
|
||||
event_date: date
|
||||
event_time: time | None = None
|
||||
is_recurring: bool
|
||||
recurrence_pattern: str | None = None
|
||||
recurrence_end_date: date | None = None
|
||||
related_operation_id: int | None = None
|
||||
category_id: int | None = None
|
||||
amount: Decimal | None = None
|
||||
currency_id: int | None = None
|
||||
reminder_days: int | None = None
|
||||
is_completed: bool
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
30
backend/app/schemas/category.py
Normal file
30
backend/app/schemas/category.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class CategoryCreate(BaseModel):
|
||||
name: str = Field(..., max_length=200)
|
||||
type: str = Field(..., pattern="^(income|expense|transfer)$")
|
||||
parent_id: int | None = None
|
||||
icon: str | None = None
|
||||
color: str | None = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$")
|
||||
|
||||
|
||||
class CategoryUpdate(BaseModel):
|
||||
name: str | None = Field(None, max_length=200)
|
||||
parent_id: int | None = None
|
||||
icon: str | None = None
|
||||
color: str | None = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$")
|
||||
|
||||
|
||||
class CategoryOut(BaseModel):
|
||||
id: int
|
||||
user_id: int | None = None
|
||||
name: str
|
||||
type: str
|
||||
parent_id: int | None = None
|
||||
icon: str | None = None
|
||||
color: str | None = None
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
48
backend/app/schemas/currency.py
Normal file
48
backend/app/schemas/currency.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class CurrencyCreate(BaseModel):
|
||||
code: str = Field(..., min_length=3, max_length=3)
|
||||
name: str = Field(..., max_length=100)
|
||||
symbol: str | None = Field(None, max_length=10)
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class CurrencyUpdate(BaseModel):
|
||||
name: str | None = Field(None, max_length=100)
|
||||
symbol: str | None = Field(None, max_length=10)
|
||||
is_active: bool | None = None
|
||||
|
||||
|
||||
class CurrencyOut(BaseModel):
|
||||
id: int
|
||||
code: str
|
||||
name: str
|
||||
symbol: str | None = None
|
||||
is_active: bool
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class ExchangeRateCreate(BaseModel):
|
||||
currency_from_id: int
|
||||
currency_to_id: int
|
||||
rate: Decimal = Field(..., gt=0)
|
||||
rate_date: date
|
||||
source: str | None = None
|
||||
|
||||
|
||||
class ExchangeRateOut(BaseModel):
|
||||
id: int
|
||||
currency_from_id: int
|
||||
currency_to_id: int
|
||||
rate: Decimal
|
||||
rate_date: date
|
||||
source: str | None = None
|
||||
created_at: datetime
|
||||
currency_from: CurrencyOut
|
||||
currency_to: CurrencyOut
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
41
backend/app/schemas/location.py
Normal file
41
backend/app/schemas/location.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class LocationCreate(BaseModel):
|
||||
name: str = Field(..., max_length=200)
|
||||
type: str | None = Field(None, max_length=50)
|
||||
address: str | None = None
|
||||
city: str | None = Field(None, max_length=100)
|
||||
country: str | None = Field(None, max_length=100)
|
||||
latitude: Decimal | None = None
|
||||
longitude: Decimal | None = None
|
||||
parent_id: int | None = None
|
||||
|
||||
|
||||
class LocationUpdate(BaseModel):
|
||||
name: str | None = Field(None, max_length=200)
|
||||
type: str | None = None
|
||||
address: str | None = None
|
||||
city: str | None = None
|
||||
country: str | None = None
|
||||
latitude: Decimal | None = None
|
||||
longitude: Decimal | None = None
|
||||
parent_id: int | None = None
|
||||
|
||||
|
||||
class LocationOut(BaseModel):
|
||||
id: int
|
||||
user_id: int | None = None
|
||||
name: str
|
||||
type: str | None = None
|
||||
address: str | None = None
|
||||
city: str | None = None
|
||||
country: str | None = None
|
||||
latitude: Decimal | None = None
|
||||
longitude: Decimal | None = None
|
||||
parent_id: int | None = None
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
89
backend/app/schemas/operation.py
Normal file
89
backend/app/schemas/operation.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from pydantic import BaseModel, Field
|
||||
from app.schemas.currency import CurrencyOut
|
||||
from app.schemas.category import CategoryOut
|
||||
from app.schemas.location import LocationOut
|
||||
|
||||
|
||||
class OperationTypeOut(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
description: str | None = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class OperationCreate(BaseModel):
|
||||
account_id: int
|
||||
category_id: int | None = None
|
||||
operation_type_id: int
|
||||
amount: Decimal = Field(..., gt=0)
|
||||
currency_id: int
|
||||
amount_converted: Decimal | None = None
|
||||
exchange_rate: Decimal | None = None
|
||||
date: datetime
|
||||
description: str | None = None
|
||||
location_id: int | None = None
|
||||
is_planned: bool = False
|
||||
|
||||
|
||||
class OperationUpdate(BaseModel):
|
||||
category_id: int | None = None
|
||||
amount: Decimal | None = Field(None, gt=0)
|
||||
date: datetime | None = None
|
||||
description: str | None = None
|
||||
location_id: int | None = None
|
||||
is_planned: bool | None = None
|
||||
|
||||
|
||||
class OperationOut(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
account_id: int
|
||||
category_id: int | None = None
|
||||
category: CategoryOut | None = None
|
||||
operation_type_id: int
|
||||
operation_type: OperationTypeOut
|
||||
amount: Decimal
|
||||
currency_id: int
|
||||
currency: CurrencyOut
|
||||
amount_converted: Decimal | None = None
|
||||
exchange_rate: Decimal | None = None
|
||||
date: datetime
|
||||
description: str | None = None
|
||||
location_id: int | None = None
|
||||
location: LocationOut | None = None
|
||||
is_planned: bool
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class OperationRelationCreate(BaseModel):
|
||||
operation_from_id: int
|
||||
operation_to_id: int
|
||||
relation_type: str = Field(..., pattern="^(transfer|split|correction)$")
|
||||
|
||||
|
||||
class OperationRelationOut(BaseModel):
|
||||
id: int
|
||||
operation_from_id: int
|
||||
operation_to_id: int
|
||||
relation_type: str
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class TransferCreate(BaseModel):
|
||||
"""Convenience schema: creates two linked operations in one request."""
|
||||
from_account_id: int
|
||||
to_account_id: int
|
||||
amount: Decimal = Field(..., gt=0)
|
||||
currency_id: int
|
||||
amount_converted: Decimal | None = None
|
||||
exchange_rate: Decimal | None = None
|
||||
date: datetime
|
||||
description: str | None = None
|
||||
location_id: int | None = None
|
||||
39
backend/app/schemas/user.py
Normal file
39
backend/app/schemas/user.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
|
||||
|
||||
class RoleOut(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
description: str | None = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
username: str = Field(..., min_length=3, max_length=100)
|
||||
email: EmailStr
|
||||
password: str = Field(..., min_length=8)
|
||||
role_id: int = 3 # default: user
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
username: str | None = Field(None, min_length=3, max_length=100)
|
||||
email: EmailStr | None = None
|
||||
is_active: bool | None = None
|
||||
role_id: int | None = None
|
||||
|
||||
|
||||
class UserOut(BaseModel):
|
||||
id: int
|
||||
username: str
|
||||
email: str
|
||||
role_id: int
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class UserWithRole(UserOut):
|
||||
role: RoleOut
|
||||
Reference in New Issue
Block a user