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.material import Material from app.models.order import Order from app.schemas.order import OrderCreate, OrderResponse 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) 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_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"), )