feat: the server checks the grade against the files before approving
All checks were successful
Build and deploy / Validate source (push) Successful in 1m23s
Build and deploy / Integration suite on a real stack (push) Successful in 3m13s
Build and deploy / Secret scan and release gate (push) Successful in 10s
Build and deploy / Publish images (push) Successful in 1m25s
All checks were successful
Build and deploy / Validate source (push) Successful in 1m23s
Build and deploy / Integration suite on a real stack (push) Successful in 3m13s
Build and deploy / Secret scan and release gate (push) Successful in 10s
Build and deploy / Publish images (push) Successful in 1m25s
The price depends on the grade, which the browser worked out and the API took on trust. Before a cart is approved at checkout the API now recomputes it from the uploaded files by the Site's own rules: the pixel size in a PNG, JPG or WebP header across the printed width (rotation included), and the area-weighted DPI of the images placed in a PDF of up to 150 MB, 300 for vectors. Sheets take the worst grade, artworks the average. A claim more than 2 points above the file's grade, or a discount on a file the server cannot grade, waits for an operator, with the reason on the Kanban. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,8 @@ from ..core.auth import owner
|
||||
from ..core.models import QuoteRequest
|
||||
from ..core.pricing import price
|
||||
from .. import quote_review
|
||||
from ..runtime import freight, quote_view, require_delivery_available, upload_row
|
||||
from ..grade_check import Files, mismatch
|
||||
from ..runtime import freight, quote_view, require_delivery_available, storage, upload_row
|
||||
from ..scanning import require_clean
|
||||
|
||||
router = APIRouter()
|
||||
@@ -36,15 +37,21 @@ def create_quote(body: QuoteRequest, session_id=Depends(owner)):
|
||||
except ValueError as exc:
|
||||
raise HTTPException(422, str(exc))
|
||||
with db.connect() as c:
|
||||
rows = {}
|
||||
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)
|
||||
rows[str(uid)] = row
|
||||
# The grade sets the price and came from the browser: before a cart is
|
||||
# approved at checkout, the server works it out from the files.
|
||||
note = mismatch(Files(storage), draft['items'], rows) if reason is None else None
|
||||
reason = reason or note
|
||||
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)))
|
||||
c.execute('INSERT INTO dtf_local.quotes(id,owner,request_key,request_hash,draft,review_note) VALUES(%s,%s,%s,%s,%s,%s) ON CONFLICT(owner,request_key) DO NOTHING',
|
||||
(uid, session_id, body.request_key, digest, Jsonb(draft), note))
|
||||
row = c.execute('SELECT * FROM dtf_local.quotes WHERE owner=%s AND request_key=%s FOR UPDATE', (session_id, body.request_key)).fetchone()
|
||||
if row['request_hash'] != digest:
|
||||
raise HTTPException(409, 'Request key already used for a different cart')
|
||||
|
||||
Reference in New Issue
Block a user