"""Local development checkout. The real path is the provider webhook. This exists so the local stack can reach a paid order without a provider account, and it goes through the same service so the two cannot drift apart. """ from uuid import UUID from fastapi import APIRouter, Depends, HTTPException from .. import payments from ..core import db from ..core.auth import owner from ..core.models import Pay from ..runtime import ENVIRONMENT, payment router = APIRouter() @router.post('/api/orders/dev-paid') def dev_paid(body: Pay, session_id=Depends(owner)): if ENVIRONMENT != 'local': raise HTTPException(503, 'Checkout is not configured yet') with db.connect() as c: try: quote = payments.approved_quote(c, body.quote_id, session_id) except payments.PaymentRefused as refusal: # The quote may already be paid; that is not a refusal. existing = c.execute('SELECT * FROM dtf_local.orders WHERE quote_id=%s AND owner=%s', (body.quote_id, session_id)).fetchone() if existing: return existing raise HTTPException(404 if 'not found' in str(refusal) else 409, str(refusal)) # The charge happens inside the transaction that persists the order, so a # failure to record it cannot leave a customer charged without an order. receipt = payment.pay(str(body.quote_id), quote['approved']['total_cents']) order, _ = payments.create_order(c, quote, receipt) return order