invix_test_task/api/app/schemas.py

122 lines
2.8 KiB
Python

import re
from datetime import datetime
from decimal import Decimal
from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator
def money(value: Decimal) -> str:
return f"{value.quantize(Decimal('0.01')):.2f}"
class CategoryOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
name: str
class ProductOut(BaseModel):
id: int
category_id: int
category_name: str
title: str
description: str
price: Decimal
@field_serializer("price")
def serialize_price(self, value: Decimal) -> str:
return money(value)
class CatalogOut(BaseModel):
categories: list[CategoryOut]
products: list[ProductOut]
class CartAdd(BaseModel):
product_id: int
qty: int = Field(default=1, ge=1, le=99)
class CartItemOut(BaseModel):
product_id: int
title: str
price: str
qty: int
line_total: str
class CartOut(BaseModel):
items: list[CartItemOut]
total: str
class OrderCreate(BaseModel):
customer_name: str = Field(min_length=1, max_length=120)
customer_phone: str = Field(min_length=5, max_length=32)
@field_validator("customer_name", "customer_phone", mode="before")
@classmethod
def strip_value(cls, value: object) -> object:
if isinstance(value, str):
return value.strip()
return value
@field_validator("customer_phone")
@classmethod
def check_phone(cls, value: str) -> str:
if re.fullmatch(r"[0-9+()\-\s]{5,32}", value) is None:
raise ValueError("Телефон: цифры, пробелы и символы +()-")
return value
class OrderItemOut(BaseModel):
product_id: int
title: str
price: str
qty: int
class OrderOut(BaseModel):
id: int
status: str
customer_name: str
customer_phone: str
total: str
created_at: datetime
items: list[OrderItemOut]
@field_serializer("created_at")
def serialize_created_at(self, value: datetime) -> str:
return value.isoformat()
class DialogIn(BaseModel):
step: str = Field(pattern=r"^(name|phone)$")
name: str | None = Field(default=None, max_length=120)
@field_validator("name", mode="before")
@classmethod
def strip_name(cls, value: object) -> object:
if isinstance(value, str):
stripped = value.strip()
return stripped or None
return value
class DialogOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
telegram_user_id: int
step: str
name: str | None
class BotOrderCreate(OrderCreate):
telegram_user_id: int = Field(gt=0)
class BotCartAdd(CartAdd):
telegram_user_id: int = Field(gt=0)