Skip to content

Invoices, Estimates & Recurring Invoices

BottleCRM ships a lightweight billing layer covering one-off invoices, customer-facing estimates (quotes), and scheduled recurring invoices. All three share the same line-item model and PDF renderer.

Documents

Type Purpose Public URL
Estimate Pre-sale quote. Customer can review and accept yes
Invoice Bill for delivered work or goods yes
Recurring invoice A schedule that generates invoices automatically no

Estimates and invoices each get a tokenised public URL so a customer can view (and accept / pay) without a login.

Line items

Each document is a list of line items:

  • Item name and description
  • Quantity, unit, unit price
  • Tax rate (per line: useful for mixed tax jurisdictions)
  • Discount (% or flat)

Totals (subtotal, tax, discount, grand total) are recomputed server-side on every save, never trust client-computed totals.

Statuses

draft → sent → (paid | overdue | void)

The transition rules:

  • draft → sent stamps sent_at and emails the customer's primary contact.
  • sent → paid records paid_at and an optional payment reference.
  • sent → overdue is automatic when the due date passes without payment.
  • void is irreversible. Voided documents stay visible for the audit trail but can't be re-sent.

Recurring invoices

A recurring invoice is a template plus a cadence:

  • Frequency: daily / weekly / monthly / yearly
  • Start date and optional end date
  • Day-of-month or day-of-week anchor
  • Auto-send toggle

A Celery beat task scans active recurring schedules every hour and materialises invoices that are due. The generated invoice inherits the template's line items, contact, and (optionally) custom field values.

Converting an estimate to an invoice

POST /api/invoices/estimates/<id>/convert/ clones the estimate's line items into a new invoice, links the two for traceability, and refuses a second attempt once an estimate has already been converted. Note the invoices/ prefix: estimates are mounted under the invoices app rather than at their own top-level path.

Public actions

Customers can:

  • View an estimate or invoice at its tokenised public URL.
  • Accept an estimate, fires the estimate.accepted event. There is no online payment step. BottleCRM has no payment-gateway integration and the public invoice page deliberately does not draw a "Pay now" button, so a customer pays you however they already do and you record the payment against the invoice yourself, in full or in parts.

See also

  • Custom fields: PO number, tax exemption ID, payment terms.
  • API reference: poll invoice and estimate state from your own systems.