---
name: evolution_billing_dashboard_gotchas
description: "supportdashboard/mybilling outstanding + resolved-tickets gotchas — invoices.balance is stale, closedate is never written"
metadata: 
  node_type: memory
  type: project
  originSessionId: 7efb43f7-ef7d-4b10-9d00-f413fb733314
  modified: 2026-07-19T15:41:10.061Z
---

Two data-integrity gotchas behind the customer-facing support dashboard (`supportdashboard.inc`) and billing history (`mybilling.inc` → `library/billinghistory.php`). Both confirmed 2026-07-19 against prod billing DB for Otter Fencing.

**1. `invoices.balance` is NOT reliable — gate on `paidstatus` instead.**
The billing DB does not consistently zero `invoices.balance` when an invoice is paid. A fully-paid invoice (`paidstatus=1`, `paid=total+tax`) can still carry a stale non-zero `balance` equal to the amount paid — so code that trusts `balance` reports the *paid* amount as *outstanding*. Fix: an invoice is outstanding only if `paidstatus = 0`; amount = `max(0, total+tax-paid)`, never the stored `balance`. Canonical writer that *should* keep balance in sync: `library/invoice.php:634` (`balance = total+tax-paid-credit`), but many rows are stale. See [[evolution_invoice_total_reconciliation]], [[evolution_float_money_columns]].

**2. `closedate` is a dead column — use `lastupdated`.**
Nothing writes `supportTickets.closedate`; the close handler (`tickets.php:256`) only sets `status=0, lastupdated=now()`. All closed tickets have `closedate='0000-00-00 00:00:00'`, so any date-bounded "resolved" query keyed on closedate returns 0. Use `lastupdated` as the resolve-time proxy for `status=0` tickets.

**Scope note:** dashboard "Outstanding balance" is all-time (correct = total owed regardless of age); `mybilling` history footer only totals the trailing-12-month visible rows, so the two legitimately differ. billing DB access: prod ESS_DB is a per-env db name (dev `.env` sets `ESS_DB=85-1384947162`; prod's Evolution-billing db is `85-1684121907`, where each SaaS customer = a contact and `evolution.companies.contactID` maps the tenant to `invoices.clientid`).
