Files
filam3d/backend/app/routers/orders.py
2026-03-22 14:26:45 +03:00

118 lines
4.6 KiB
Python

import logging
import uuid
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.models.calculation import Calculation
from app.models.client import Client
from app.models.material import Material
from app.models.order import Order
from app.schemas.order import OrderCreate, OrderResponse
from app.services.auth import decode_access_token
from app.services.telegram_notify import notify_new_order
logger = logging.getLogger("app.routers.orders")
router = APIRouter()
async def generate_order_id(db: AsyncSession) -> str:
year = datetime.now().year
result = await db.execute(
select(func.count(Order.id)).where(Order.order_id.like(f"ORD-{year}-%"))
)
count = result.scalar() or 0
order_id = f"ORD-{year}-{count + 1:04d}"
logger.debug("Generated order_id: %s (existing count: %d)", order_id, count)
return order_id
@router.post("/orders", response_model=OrderResponse)
async def create_order(order_data: OrderCreate, db: AsyncSession = Depends(get_db)):
logger.info("===== POST /api/orders =====")
logger.info("Client: name=%s, phone=%s, email=%s, company=%s",
order_data.client_name, order_data.client_phone,
order_data.client_email, order_data.client_company)
logger.info("Calculation ID: %s", order_data.calculation_id)
logger.info("Delivery: %s, comment: %s", order_data.delivery_method, order_data.comment)
# Get calculation
try:
calc_uuid = uuid.UUID(order_data.calculation_id)
except ValueError:
logger.warning("Invalid calculation_id format: %s", order_data.calculation_id)
raise HTTPException(400, "Некорректный calculation_id")
logger.info("Looking up calculation: %s", calc_uuid)
result = await db.execute(select(Calculation).where(Calculation.id == calc_uuid))
calc = result.scalar_one_or_none()
if not calc:
logger.warning("Calculation not found: %s", calc_uuid)
raise HTTPException(404, "Расчёт не найден")
logger.info("Calculation found: total=%.2f RUB, material_id=%d, estimated_days=%s",
calc.total_rub, calc.material_id, calc.estimated_days)
# Get material name for notification
logger.debug("Looking up material id=%d for notification...", calc.material_id)
mat_result = await db.execute(select(Material).where(Material.id == calc.material_id))
material = mat_result.scalar_one_or_none()
material_name = material.name if material else "Неизвестный"
logger.info("Material for notification: %s", material_name)
# Resolve client_id from token if provided
client_id = None
if order_data.client_token:
payload = decode_access_token(order_data.client_token)
if payload and payload.get("type") == "client":
client_id = int(payload["sub"])
logger.info("Order linked to client_id=%d", client_id)
order_id = await generate_order_id(db)
estimated_ready = datetime.now() + timedelta(days=calc.estimated_days or 3)
logger.info("Order ID: %s, estimated ready: %s", order_id, estimated_ready.strftime("%Y-%m-%d"))
order = Order(
order_id=order_id,
calculation_id=calc.id,
client_id=client_id,
client_name=order_data.client_name,
client_phone=order_data.client_phone,
client_email=order_data.client_email,
client_company=order_data.client_company,
delivery_method=order_data.delivery_method,
comment=order_data.comment,
total_rub=calc.total_rub,
)
db.add(order)
await db.commit()
await db.refresh(order)
logger.info("Order saved to database: id=%d, order_id=%s", order.id, order_id)
# Send Telegram notification
logger.info("Sending Telegram notification...")
try:
await notify_new_order(
order_id=order_id,
client_name=order_data.client_name,
client_phone=order_data.client_phone,
material_name=material_name,
total_rub=calc.total_rub,
comment=order_data.comment,
)
logger.info("Telegram notification sent successfully")
except Exception:
logger.exception("Telegram notification failed (order still created)")
logger.info("===== Order created: %s -> %.2f RUB =====", order_id, calc.total_rub)
return OrderResponse(
order_id=order_id,
status="pending",
total_rub=calc.total_rub,
estimated_ready_date=estimated_ready.strftime("%Y-%m-%d"),
)