Payments & Revenue
The deal payments system lets you track payment schedules and record received payments against deals. It supports both pre-planned schedules (milestones defined at deal creation) and ad-hoc recording (logging payments as they arrive).
Scope: This is payment tracking only. There is no invoicing, no email-to-client, and no Stripe/PayPal collection integration. The system records what has been agreed to and what has been received.
Payment Fields
| Field | Type | Description |
|---|---|---|
label | text | Name of the payment milestone (e.g. "Deposit", "Phase 1 Milestone", "Final Payment"). |
expected_amount | numeric(12,2) | The amount expected for this payment milestone. |
paid_amount | numeric(12,2) | The amount actually received. |
due_date | date | When the payment is expected. |
paid_date | date | When the payment was received. |
status | text | 'scheduled', 'paid', or 'waived' (CHECK constraint). Defaults to 'scheduled'. |
payment_method | text | Free text describing how payment was made (e.g. "PayPal", "Check", "Wire", "ACH"). |
payment_reference | text | Reference number, invoice ID, or transaction identifier. |
processing_fee | numeric(12,2) | Optional processor fee amount (e.g. PayPal, Stripe fees). Informational only - does not affect revenue calculations. |
notes | text | Optional freeform notes about this payment. |
created_by | uuid | FK to user_profiles.id. The user who created the record. |
Payment Statuses
| Status | Description | Counted in Totals |
|---|---|---|
scheduled | Payment is expected but not yet received. | Expected: ✅ Paid: ❌ |
paid | Payment has been received and recorded. | Expected: ✅ Paid: ✅ |
waived | Payment has been forgiven or waived. | Expected: ❌ Paid: ❌ |
No partial payments. If a client sends $3,000 of a $5,000 milestone, the intended workflow is to edit the original milestone to $3,000, record it as paid, and create a new milestone for the remaining $2,000. Every payment record represents one atomic event.
Creating Payments
The Payments section header includes two action buttons:
- "+ Schedule" — Opens a dialog to plan a future payment milestone (status = scheduled).
- "+ Record" — Opens a dialog to log a payment that has already been received (status = paid, date = today).
| Mode | Purpose | Pre-filled Fields |
|---|---|---|
| Schedule Payment | Plan a future payment milestone | Status = scheduled |
| Record Payment | Log a payment that has already been received | Status = paid, date = today |
Schedule Payment
Use this to define payment milestones up front. Fill in the label, expected amount, and due date.
The payment starts in scheduled status and can be recorded later when payment is received.
Record Payment
Use this to immediately log a received payment. All fields are available, and the status is
pre-set to paid with the date defaulting to today.
Recording a Scheduled Payment
For payments already in scheduled status, the Record button opens a dialog with:
- Amount pre-filled from the expected amount
- Date pre-filled with today's date
- Status pre-set to
paid
The user fills in the payment method and reference before confirming. This is never a one-click action; the dialog always requires confirmation.
Editing & Deleting
- Edit (pencil icon) — Opens the same dialog with all fields editable. Available on both scheduled and paid records.
- Delete (trash icon) — Confirmation dialog, then permanent removal. The progress bar recalculates after deletion.
The Payments section header displays a summary and progress bar:
Payments 1 of 2 paid + Schedule + Record
$1,600 collected $3,900 expected (41%)
[==================== ]The calculation:
- Total Collected = SUM of
paid_amountwhere status =paid - Total Expected = SUM of
expected_amountwhere status is NOTwaived - Progress % = Total Collected / Total Expected
Waived payments are excluded from both the expected and paid totals.
Overdue Detection
Scheduled payments with a due_date in the past display a red "Overdue (N days)" badge.
UI-only detection. There is no cron job or notification system for overdue payments. The badge is calculated at render time by comparing
due_dateto the current date.
Waived Payments
When a payment's status is set to waived:
- The label displays with strikethrough text
- A gray "Waived" badge is shown
- The payment is excluded from both expected and paid totals
- The progress bar recalculates accordingly
RBAC
Deal payments follow the same RBAC model as deals:
| Operation | Required Role |
|---|---|
| View (SELECT) | All members |
| Create (INSERT) | All members |
| Edit (UPDATE) | All members |
| Delete (DELETE) | Admin or Owner only |
Processing Fees
Payments track gross revenue (what the client paid), not net revenue (what hit your bank
after fees). The processing_fee field is optional and informational only.
| Field | Purpose | Affects Revenue? |
|---|---|---|
paid_amount | What the client paid (e.g. $500) | Yes - this is revenue |
processing_fee | What the processor took (e.g. $17.94) | No - informational only |
| Net received | Derived: paid_amount - processing_fee | No - display only, never stored |
The fee field is available in the Record and Edit dialogs when a payment is in paid status.
Helper text below the input reads: "Processor fees only. Does not affect revenue."
When a processing fee is recorded, the payment card displays an additional detail line:
Fee: $17.94 · Net: $482.06The fee does not affect the progress bar, the Revenue (30d) dashboard metric, or any other
revenue calculation. All revenue metrics use paid_amount (gross).
Deal Payments on the Deal Detail Page
The Payments section is displayed on the deal detail page after the Tasks section. Each payment card shows:
- Label (e.g. "Deposit", "Phase 1 Milestone")
- Expected amount and due date
- Paid details (amount, date, method, and fee/net if a processing fee is recorded) for paid records
- Reference and notes if present
- Status badge (Paid / Waived / Overdue)
- Action buttons (Record, Edit, Delete)
Payments are sorted by due date ascending (nulls last), then paid date, then creation date.
Contract URL
Deals include an optional contract_url field for linking to external contract documents
(e.g. PandaDoc, DocuSign, Google Docs). When set:
- The URL appears as a clickable "View Contract" link in the Connected Entities card on the deal detail page, with an external link icon.
- The field is editable from the Edit Deal dialog.
Dashboard Integration
The dashboard Revenue (30d) metric includes deal payment revenue alongside product purchases and event registrations:
Revenue (30d) = Product Revenue + Event Revenue + Deal Payment RevenueOnly paid_amount from payments with status = 'paid' and paid_date within the last 30 days
is counted. Expected amounts and waived payments are never included.
The revenue card subtitle reads "all sources".
Contact Integration
Paid deal payments appear in a contact's Transactions section on the Contact Detail page. The Transactions section supports four filter options:
| Filter | Shows |
|---|---|
| All | Purchases + Event Registrations + Deal Payments |
| Purchases | Stripe product purchases only |
| Events | Event registration payments only |
| Deal Payments | Paid deal payments only |
Each deal payment row displays the deal title and payment label (e.g. "Acme License - Deposit"), and links to the deal detail page.