118 lines
4.6 KiB
Python
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"),
|
|
)
|