Skip to main content
File: app/worker/invoice_finalizer.py
Schedule: Every 5 minutes

What It Does

  1. Finds scheduled invoices — Queries DRAFT invoices where scheduled_finalize_at <= now()
  2. Finalizes — Transitions DRAFTOPEN
  3. Generates payment link — Creates a checkout URL if a payment gateway is configured
  4. Sends email — Emails the customer with the invoice and payment link

Grace Period Logic

Invoice created at:         13:07:00
scheduled_finalize_at:      14:07:00  (1 hour later)

Finalizer checks at:        14:05:00  → not yet due
Finalizer checks at:        14:10:00  → FINALIZED ✅

Email Behavior

  • Email failures do not prevent finalization — the invoice is marked OPEN regardless
  • Email failures are logged separately
  • If SMTP is not configured, finalization still succeeds (no email sent)

Log Output

[INFO] worker.invoice_finalizer | run_id=def67890 | 🚀 Invoice finalization started
[INFO] worker.invoice_finalizer | run_id=def67890 | Found 3 invoices scheduled for finalization
[INFO] worker.invoice_finalizer | run_id=def67890 | ✅ Finalized INV-2025-0055 | customer=Acme Corp | total=$145.20
[INFO] worker.invoice_finalizer | run_id=def67890 | 📧 Email sent to billing@acme.com
[INFO] worker.invoice_finalizer | run_id=def67890 | 🏁 Completed | finalized=3 | emails_sent=2

Troubleshooting

Invoices stuck in DRAFT?
  1. Check the finalizer is running:
    curl http://localhost:8000/api/v1/workers/stats?worker=invoice_finalizer
    
  2. Find overdue DRAFT invoices:
    SELECT invoice_number, scheduled_finalize_at
    FROM invoices
    WHERE status = 'DRAFT' AND scheduled_finalize_at < NOW()
    ORDER BY scheduled_finalize_at;
    
  3. Check scheduled_finalize_at is set (NULL means it won’t auto-finalize):
    SELECT invoice_number, scheduled_finalize_at
    FROM invoices
    WHERE status = 'DRAFT' AND scheduled_finalize_at IS NULL;
    
Email not being sent?
python scripts/view_worker_logs.py --worker invoice_finalizer --search "email" --level ERROR
Note: Email failures log as errors but don’t fail finalization.

Manual Finalization

Finalize an invoice immediately:
POST /api/v1/invoices/<invoice_id>/finalize
Send email manually:
POST /api/v1/invoices/<invoice_id>/send-email

Log Files

logs/workers/invoice_finalizer.log