fix: resolve open risks — invoice race condition, SMTP config, workflow seeds
- billing/service.py: pg_advisory_xact_lock on invoice_number_seq per year → prevents duplicate INV-YYYY-NNNN under concurrent requests - admin.py: SMTP settings in system_settings (smtp_host/port/user/password/ from_address/enabled) with GET+PUT support; seed-workflows endpoint creates 4 standard workflow definitions (still-cycles, still-eevee, turntable, multi-angle) idempotently - notifications/service.py: send_email_notification_stub now sends real SMTP email via smtplib when smtp_enabled=true in system_settings - Admin.tsx: SMTP settings panel (host/port/user/password/from + enable toggle, save button); Seed Standard Workflows maintenance button - Upload.tsx: fix TS error — title→aria-label on Lucide icons - Admin.tsx Settings type: add render_backend/flamenco_* fields (TS fix) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -200,8 +200,16 @@ VALID_STATUSES = {"draft", "sent", "paid", "cancelled"}
|
||||
|
||||
|
||||
async def generate_invoice_number(db: AsyncSession, tenant_id: uuid.UUID | None) -> str:
|
||||
"""Generate sequential invoice number: INV-YYYY-NNNN."""
|
||||
"""Generate sequential invoice number: INV-YYYY-NNNN.
|
||||
|
||||
Uses a PostgreSQL advisory lock to prevent race conditions when multiple
|
||||
requests create invoices concurrently. The lock is automatically released
|
||||
when the surrounding transaction commits or rolls back.
|
||||
"""
|
||||
from sqlalchemy import text
|
||||
year = datetime.utcnow().year
|
||||
# Advisory lock keyed on year — serialises concurrent invoice creation
|
||||
await db.execute(text("SELECT pg_advisory_xact_lock(hashtext(:key))"), {"key": f"invoice_number_seq_{year}"})
|
||||
count_result = await db.execute(
|
||||
select(func.count()).select_from(Invoice).where(
|
||||
func.extract("year", Invoice.created_at) == year
|
||||
|
||||
Reference in New Issue
Block a user