51 lines
2.2 KiB
Python
51 lines
2.2 KiB
Python
"""Quotes: the customer's cart, and the operator-reviewed version of it."""
|
|
import hashlib
|
|
import json
|
|
from decimal import Decimal
|
|
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)):
|
|
for item in body.items:
|
|
if abs(item.metres*100-item.production.height_cm) > Decimal('0.02'):
|
|
raise HTTPException(422, 'Quoted metres do not match the submitted layout height')
|
|
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)
|