Zodiac Tech CRM Docs

Invoices & payments

How invoices are generated and renewed, where to find invoice and payment records, and what the client sees.

super-admin support Medium ⏱ 10 min Updated 2026-10-05

Invoices & payments

Agreements define the deal; invoices and payments are the paper trail. This page explains how invoices are created, how renewals work, and where to look when a client says "I paid".

  • Invoices: /super-admin/billing/commercial-invoices
  • Payments: /super-admin/billing/commercial-payments
  • Client side: /admin/billing/invoices and /admin/billing/payments

Who this is for

Super Admins and support staff answering billing questions.

  • Difficulty: Medium
  • Time: 10 min
  • Prerequisites: At least one active agreement.

How invoices appear

Renewal invoices — automatic, daily at 06:30

For every Active agreement whose next billing date has arrived, the renewal job:

  1. Creates the renewal invoice for the agreement's recurring gross amount (one-time line items are never re-billed).
  2. Issues it and advances the next billing date in the same database transaction — this is the idempotency anchor, so a job re-run cannot double-bill.
  3. Generates the invoice PDF and notifies the client.

The amount invariant The provider debit, the renewal invoice and the agreement's recurring gross amount are always the same number. If you ever see them disagree, stop and investigate — that is a reconciliation bug, not a rounding quirk.

Manual invoices and manual payments

Offline arrangements are recorded, not emailed: use Record Manual Payment on the agreement (amount, method, reference/UTR, date, apply-to-invoice, notes). This is the correct way to log a bank transfer.

Overdue marking — hourly

The payment-failure job scans issued and partially-paid invoices whose due date has passed with an amount still due, notifies the client once (no duplicate spam), and marks the invoice Overdue.

Step 1 — Read the invoice list

/super-admin/billing/commercial-invoices is an append-only list. Columns: invoice number, business, status, total, paid, due, issue date, due date, overdue flag, currency.

Internal invoice statuses: DRAFT, ISSUED, PAID, PARTIALLY_PAID, OVERDUE, VOID, CANCELLED. Draft and void invoices never reach the client.

Step 2 — Read the payments list

/super-admin/billing/commercial-payments shows every transaction: ID, business, provider, amount, status, method, provider reference, paid time.

Payment statuses: PENDING, AUTHORIZED, SUCCESS, FAILED, REFUNDED, PARTIALLY_REFUNDED.

Most payment rows are written by provider webhooks — each event is stored idempotently (unique provider + event ID) before processing, so webhook retries cannot double-count.

Step 3 — Investigate "I paid but it shows unpaid"

  1. Find the payment in the payments list (search by reference, provider or amount).
  2. If a successful payment exists but the invoice is open, the webhook may have arrived before the invoice or failed to match — check the agreement's Events and Timeline tabs.
  3. If no payment exists, the payment likely failed at the provider. The platform's reconciliation job (ReconcileProviderStatus, every 30 minutes) pulls provider status and raises reconciliation alerts when records disagree — check the Payments area for alerts.
  4. If the client paid outside the provider (bank transfer), record it manually as above.

Step 4 — Know what the client sees

In the client portal:

  • /admin/billing/invoices — their invoices with plain statuses: Paid / Due / Partially paid / Overdue. Draft and void invoices are invisible.
  • Downloads use signed URLs — safe to share from within the portal.
  • /admin/billing/payments — their payment history.

Expected result

Renewals appear as invoices on schedule, payments match invoices, and any mismatch surfaces through reconciliation alerts rather than a client complaint.

Common mistakes

  • Re-running the renewal job expecting a second invoice. The transaction anchor prevents duplicates by design.
  • Billing setup fees again at renewal. One-time line items are excluded from renewals.
  • Recording a manual payment against the wrong invoice. Use "Apply to Invoice"; leave it open only when intentional.
  • Deleting an invoice. Not possible — invoices are append-only; void or cancel instead.
  • Treating FAILED webhook events as payments. Only captured/successful events move money.

Troubleshooting

Symptom What to check
Client got a renewal for the wrong amount Agreement line items and recurring interval — the invoice mirrors the agreement
Invoice stuck in DRAFT Draft invoices are not sent; issue it (or regenerate) through the agreement flow
Duplicate overdue reminders Dedup is per invoice; check if multiple invoices are actually overdue
Payment succeeded at the provider but not here Webhook delivery + reconciliation alerts; verify the provider secret
PDF download fails for the client Signed URL expired — open the invoice from the portal again

Technical details

  • Pages: App\Filament\SuperAdmin\Pages\Commercial\CommercialInvoices and CommercialPayments (slugs billing/commercial-invoices, billing/commercial-payments).
  • Models: App\Models\BillingInvoice (table billing_invoices), App\Models\PaymentTransaction, App\Models\BillingReconciliationAlert.
  • Renewal job: App\Jobs\Billing\CreateRenewalInvoice — daily 06:30, no-overlap 30 min; creates + issues + advances next_billing_date (via BillingCalculator::addInterval) inside one transaction, then dispatches GenerateInvoicePDF and BillingNotifier::invoiceCreated.
  • Overdue job: App\Jobs\Billing\CheckPaymentFailures — hourly, no-overlap 20 min.
  • Reconciliation: ReconcileProviderStatus every 30 minutes; SyncAppliedChangeRequests every 30 minutes.
  • Webhooks: /api/webhooks/razorpay, /api/webhooks/cashfree — signature-verified, idempotent events.

Was this page helpful?