feat: per-line render overrides — override any output type setting at order time
Instead of duplicating output types for every variation (WebP vs PNG,
different resolution), keep one canonical output type and override
specific fields per order line via render_overrides JSONB.
Backend:
- render_overrides JSONB column on OrderLine (DB migration)
- Render task merges overrides with output type settings (format, width,
height, samples, engine, denoiser, transparent_bg, cycles_device)
- POST /orders/{id}/batch-render-overrides endpoint for bulk override
- PatchLineBody accepts render_overrides for per-line patching
Frontend:
- Batch render overrides section on OrderDetail: output format dropdown
(PNG/JPG/WebP) + resolution dropdown (512-4096)
- Clear button to remove overrides
MCP:
- create_order tool: accepts product_ids, output_type, render_overrides,
material_override — enables "render all products as WebP" via Claude
- set_render_overrides tool: batch override on existing orders
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,7 @@ def _build_line_out(line: OrderLine) -> OrderLineOut:
|
||||
render_started_at=line.render_started_at if hasattr(line, 'render_started_at') else None,
|
||||
render_completed_at=line.render_completed_at if hasattr(line, 'render_completed_at') else None,
|
||||
material_override=getattr(line, 'material_override', None),
|
||||
render_overrides=getattr(line, 'render_overrides', None),
|
||||
notes=line.notes,
|
||||
created_at=line.created_at,
|
||||
updated_at=line.updated_at,
|
||||
@@ -391,6 +392,7 @@ async def create_order(
|
||||
global_render_position_id=line_data.global_render_position_id,
|
||||
gewuenschte_bildnummer=line_data.gewuenschte_bildnummer,
|
||||
material_override=line_data.material_override,
|
||||
render_overrides=line_data.render_overrides,
|
||||
notes=line_data.notes,
|
||||
tenant_id=getattr(user, 'tenant_id', None),
|
||||
)
|
||||
@@ -836,6 +838,7 @@ async def add_order_line(
|
||||
global_render_position_id=body.global_render_position_id,
|
||||
gewuenschte_bildnummer=body.gewuenschte_bildnummer,
|
||||
material_override=body.material_override,
|
||||
render_overrides=body.render_overrides,
|
||||
notes=body.notes,
|
||||
tenant_id=getattr(user, 'tenant_id', None),
|
||||
)
|
||||
@@ -1125,8 +1128,35 @@ async def batch_material_override(
|
||||
return {"updated": res.rowcount, "material_override": body.material_override}
|
||||
|
||||
|
||||
class BatchRenderOverridesBody(BaseModel):
|
||||
render_overrides: dict | None = None
|
||||
|
||||
|
||||
@router.post("/{order_id}/batch-render-overrides")
|
||||
async def batch_render_overrides(
|
||||
order_id: uuid.UUID,
|
||||
body: BatchRenderOverridesBody,
|
||||
user: User = Depends(require_admin_or_pm),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Set render_overrides on ALL lines of an order at once."""
|
||||
result = await db.execute(select(Order).where(Order.id == order_id))
|
||||
if not result.scalar_one_or_none():
|
||||
raise HTTPException(404, detail="Order not found")
|
||||
|
||||
from sqlalchemy import update as sql_update
|
||||
res = await db.execute(
|
||||
sql_update(OrderLine)
|
||||
.where(OrderLine.order_id == order_id)
|
||||
.values(render_overrides=body.render_overrides)
|
||||
)
|
||||
await db.commit()
|
||||
return {"updated": res.rowcount, "render_overrides": body.render_overrides}
|
||||
|
||||
|
||||
class PatchLineBody(BaseModel):
|
||||
material_override: str | None = None
|
||||
render_overrides: dict | None = None
|
||||
|
||||
|
||||
@router.patch("/{order_id}/lines/{line_id}")
|
||||
|
||||
Reference in New Issue
Block a user