"""Quotes: the customer's cart, and the operator-reviewed version of it.""" import hashlib import json from uuid import UUID, uuid4 from fastapi import APIRouter, Depends, HTTPException from psycopg.types.json import Jsonb from ..core import db from ..core.auth import owner from ..core.models import QuoteRequest from ..runtime import freight, quote_view, upload_row from ..scanning import require_clean router = APIRouter() @router.post('/api/quotes') def create_quote(body: QuoteRequest, session_id=Depends(owner)): draft = body.model_dump(mode='json', exclude={'request_key'}) digest = hashlib.sha256(json.dumps(draft, sort_keys=True).encode()).hexdigest() try: freight.quote(body.freight.service, body.freight.postal_code) except ValueError as exc: raise HTTPException(422, str(exc)) with db.connect() as c: for item in body.items: for uid in item.uploads: row = upload_row(c, uid, session_id) if not row['complete']: raise HTTPException(409, 'Complete every upload before requesting a quote') require_clean(row) uid = uuid4() c.execute('INSERT INTO dtf_local.quotes(id,owner,request_key,request_hash,draft) VALUES(%s,%s,%s,%s,%s) ON CONFLICT(owner,request_key) DO NOTHING', (uid, session_id, body.request_key, digest, Jsonb(draft))) row = c.execute('SELECT * FROM dtf_local.quotes WHERE owner=%s AND request_key=%s', (session_id, body.request_key)).fetchone() if row['request_hash'] != digest: raise HTTPException(409, 'Request key already used for a different cart') return {'id': row['id'], 'status': 'pending_review'} @router.get('/api/quotes/{uid}') def get_quote(uid: UUID, session_id=Depends(owner)): with db.connect() as c: row = c.execute('SELECT * FROM dtf_local.quotes WHERE id=%s AND owner=%s', (uid,session_id)).fetchone() if not row: raise HTTPException(404, 'Quote not found') return quote_view(c, row)