# RentalDriveGo Customer Billing Review and Remediation Plan

## Document Status

- **Purpose:** Review and implementation plan only
- **Code changes performed:** None
- **Primary route:** `/dashboard/billing`
- **Primary file reviewed:** `src/app/(dashboard)/billing/page.tsx`
- **Related areas reviewed:** dashboard navigation, route access, team-role descriptions, reservation payment fields, contract invoice payloads, API client, and existing test coverage
- **Explicitly out of scope:** SaaS plan billing at `/dashboard/subscription`
- **Backend limitation:** The uploaded package contains the Dashboard application but not the API and database source. Backend findings below that require confirmation are marked as verification tasks.

---

## 1. Objective

Correct the customer billing feature so that it is financially accurate, secure, permission-aware, scalable, understandable, and usable in English, French, and Arabic.

The work must prioritize:

1. Financial correctness
2. Data integrity
3. Access control
4. Reliable API contracts
5. Clear billing workflows
6. Responsive and accessible UI
7. Automated regression coverage

Visual redesign must not begin by hiding incorrect accounting behind more attractive cards. The financial model must be settled first.

---

## 2. Scope Definition

This plan covers rental-company billing involving:

- Customer invoices
- Rental charges
- Security deposits
- Payments received
- Outstanding balances
- Payment history
- Manual/offline payment recording
- Invoice and payment status
- Links to reservations and contracts
- Billing summaries, filtering, pagination, and export
- Menu, plan, and employee-role access

This plan does not cover:

- RentalDriveGo SaaS subscription checkout
- Subscription invoices
- Subscription renewal or cancellation
- Payment-provider credential setup
- Full accounting integrations
- General ledger accounting
- Tax filing
- Chargeback automation
- Bank reconciliation

---

## 3. Current Implementation Summary

The current billing page:

- Loads up to 100 reservations from `GET /reservations?pageSize=100`.
- Loads company payments from `GET /payments/company`.
- Joins reservations and payments in the browser.
- Calculates balance due as `totalAmount - paidAmount`.
- Shows four metrics:
  - Total billed
  - Collected
  - Outstanding
  - Open invoices
- Shows one wide table with 11 columns.
- Displays only the latest payment for each reservation.
- Allows manual payment recording through:
  - `POST /payments/reservations/:id/manual`
- Allows payment types:
  - `CHARGE`
  - `DEPOSIT`
- Uses a hard-coded `MAD` currency.
- Provides English, French, and Arabic copy inside the page component.
- Has no billing-specific automated tests.

The page is approximately 644 lines and combines data fetching, financial calculations, translation data, filtering, modal state, payment submission, and presentation.

---

## 4. Confirmed Problems

## 4.1 Critical: Deposit payments use the rental balance

Current behavior:

- The page enables payment only when `balanceDue > 0`.
- The modal defaults the amount to the rental balance.
- Both `CHARGE` and `DEPOSIT` are validated against the same rental balance.
- A deposit option is shown only because the reservation has a nonzero required deposit.

Consequences:

- A security deposit cannot be collected when the rental invoice is fully paid.
- A deposit amount may be limited by the wrong balance.
- The UI does not know how much deposit has already been collected or refunded.
- Rental revenue and refundable security money are treated as though they are the same liability.

Required correction:

Maintain separate authoritative amounts:

```text
Invoice
- invoiceTotal
- invoicePaid
- invoiceRefunded
- invoiceBalanceDue

Security deposit
- depositRequired
- depositCollected
- depositRefunded
- depositHeld
- depositOutstanding
```

`CHARGE` must be validated against `invoiceBalanceDue`.

`DEPOSIT` must be validated against `depositOutstanding`.

A customer with a paid invoice but an outstanding deposit must still be able to provide the deposit.

---

## 4.2 Critical: Financial truth is calculated in the browser

The page combines two broad API responses and derives billing rows locally.

Problems:

- The reservation query is capped at 100 records.
- Search, totals, and open-invoice counts only represent the loaded subset.
- Payment and reservation responses may be generated at different moments.
- The page assumes that `paidAmount` and payment events use compatible rules.
- There is no server-generated billing snapshot.
- Browser calculations can disagree with contracts, reports, or backend invoice logic.

Required correction:

Create a billing-specific API contract that returns authoritative invoice and deposit values from one consistent source.

The browser may format and display totals. It must not invent financial truth by reconstructing it from unrelated collections.

---

## 4.3 Critical: Currency is hard-coded to MAD

Observed behavior:

- Metric totals use `MAD`.
- Reservation totals use `MAD`.
- Deposits use `MAD`.
- Manual payments always submit `MAD`.
- Payment rows technically contain a currency, but reservation rows do not.

Risks:

- Incorrect display when company or invoice currency differs.
- Invalid manual payment submission.
- Nonsensical totals if invoices can contain multiple currencies.
- Currency is silently assumed rather than explicitly enforced.

Required correction:

- Add invoice currency to the billing response.
- Use the invoice currency for manual payments.
- If each company is restricted to one currency, enforce that rule in the API and database.
- If multiple currencies are permitted, group summary metrics by currency and prohibit cross-currency payment application.
- Use integer minor units consistently.

---

## 4.4 High: Billing role behavior is contradictory

Observed behavior:

- Billing is included in the Sidebar fallback for `MANAGER`.
- Team role descriptions state that Manager has “Full ops — no billing.”
- The route guard relies on the generated employee menu.
- The route guard fails open during some transient menu-load failures.
- The API source was not included, so endpoint-level role enforcement cannot yet be verified.

Required correction:

Freeze and document a billing permission matrix before implementation.

Recommended default:

| Capability | OWNER | MANAGER | AGENT |
|---|:---:|:---:|:---:|
| View billing summaries | Yes | No | No |
| View invoice/payment details | Yes | No | No |
| Record manual payment | Yes | No | No |
| Refund or void payment | Yes | No | No |
| Export billing data | Yes | No | No |

The platform Admin may assign the Billing menu to plans, but a visible menu item must not override role permissions.

If the intended product policy is that Managers may collect payments, update the role descriptions and create a granular `billing.record_payment` permission. Do not leave the current contradiction unresolved.

---

## 4.5 High: Admin menu control is not enough to secure billing

The platform Admin controls whether Billing appears for a subscription plan. This is navigation policy, not authorization.

Required checks:

```text
billing.view
billing.record_manual_payment
billing.refund
billing.export
billing.manage_adjustments
```

Effective access must require:

```text
Menu item globally enabled
AND assigned to active subscription plan
AND subscription status allows access
AND employee role permits action
AND company override does not disable it
AND API endpoint authorizes the action
```

The Dashboard must render the Admin-resolved menu. Every billing API endpoint must independently enforce permissions.

---

## 4.6 High: Manual payment submission needs stronger integrity controls

The current form submits:

- Amount
- Type
- Currency
- Payment method

Missing operational fields:

- Received date and time
- External reference or check number
- Internal note
- Recorded-by employee
- Idempotency key
- Optional evidence attachment
- Confirmation summary

Risks:

- Duplicate payment from retries
- No audit trail for cash, checks, or bank transfers
- No way to reconcile an offline payment
- Weak investigation path when a payment is disputed

Required correction:

Manual payment creation must be idempotent and audited.

Recommended payload:

```json
{
  "amountMinor": 125000,
  "currency": "MAD",
  "type": "CHARGE",
  "method": "BANK_TRANSFER",
  "receivedAt": "2026-06-29T18:00:00Z",
  "reference": "BANK-2026-00481",
  "note": "Received before vehicle return",
  "idempotencyKey": "client-generated-uuid"
}
```

The API must calculate the permitted maximum again. Client validation is only convenience.

---

## 4.7 High: Payment-provider and payment-method concepts are mixed

The local payment type only permits:

- `AMANPAY`
- `PAYPAL`

The page also records manual methods:

- Cash
- Check
- Bank transfer
- Card
- PayPal

A manual cash payment is not an AmanPay or PayPal provider payment. The current type definition is likely incomplete or misleading.

Required correction:

Separate:

```text
paymentChannel
- ONLINE
- OFFLINE
- TERMINAL

provider
- AMANPAY
- PAYPAL
- MANUAL
- EXTERNAL_TERMINAL
- null

method
- CASH
- CHECK
- BANK_TRANSFER
- CARD
- PAYPAL
- OTHER
```

Use shared API types instead of local string unions.

---

## 4.8 High: Pagination and filtering are not production-safe

Current behavior:

- Only 100 reservations are loaded.
- Search is client-side.
- Metrics are recomputed from filtered visible rows.
- There are no date, status, method, or balance filters.
- There is no pagination control.

Consequences:

- Companies with more than 100 reservations see incomplete financial totals.
- A search may falsely report no invoice because it is outside the loaded subset.
- Metric meaning changes silently when search text is entered.
- Large payment histories will become slow.

Required correction:

Use server-side:

- Pagination
- Search
- Date range
- Invoice status filter
- Payment status filter
- Payment method filter
- Outstanding-only filter
- Currency filter when required
- Sorting

Keep company-wide summary metrics separate from filtered-results metrics and label them explicitly.

---

## 4.9 Medium: The page shows only the latest payment

The current table displays a latest-payment snapshot and a count.

Missing:

- Full payment ledger
- Refund history
- Payment references
- Who recorded the payment
- Notes
- Deposit history
- Receipt access
- Failed-attempt details
- Event timestamps

Required correction:

Use a billing list plus an invoice detail drawer or page.

The detail view must show:

1. Invoice summary
2. Security deposit summary
3. Charges and adjustments
4. Complete payment timeline
5. Refunds
6. Audit information
7. Reservation and contract links

---

## 4.10 Medium: Failure and refresh behavior is fragile

Current behavior:

- `Promise.all` fails the entire screen if either request fails.
- The initial error is not clearly cleared before later reloads.
- Manual-payment refresh does not show a dedicated refreshing state.
- There is no retry button.
- There is no empty-state distinction between:
  - No invoices
  - No search results
  - Access denied
  - API failure

Required correction:

- Use one billing API response where possible.
- Add retry behavior.
- Preserve the current filters on retry.
- Show mutation success and failure separately from page-load errors.
- Keep the modal open if refresh fails after payment creation, but indicate whether payment creation succeeded.
- Prevent accidental resubmission after an uncertain network outcome by using idempotency.

---

## 4.11 Medium: Responsive and Arabic layouts are weak

The page uses an 11-column table with horizontal scrolling.

Problems:

- Poor mobile usability
- Important action is far to the right
- Physical `text-left`, `text-right`, and `items-end` classes do not fully adapt to RTL
- Dense payment content is difficult to scan
- Currency values and Latin identifiers need controlled bidirectional rendering

Required correction:

Desktop:

- Use a narrower invoice list.
- Move payment history and secondary details into a drawer.
- Keep key columns:
  - Invoice/customer
  - Rental period
  - Invoice amount
  - Paid
  - Balance
  - Status
  - Action

Mobile:

- Use invoice cards.
- Show the primary action without horizontal scrolling.
- Open details as a full-screen sheet.

Arabic:

- Use logical alignment.
- Use `dir="ltr"` for invoice numbers, references, email addresses, and currency-number groups where necessary.
- Test modal, drawer, table, cards, and pagination in true RTL.

---

## 4.12 Medium: Accessibility is incomplete

The manual-payment modal currently lacks a complete dialog implementation.

Required correction:

- Add `role="dialog"`.
- Add `aria-modal="true"`.
- Connect title and description IDs.
- Trap keyboard focus.
- Close on Escape unless submission is active.
- Return focus to the triggering button.
- Add an accessible label to the close button.
- Associate every label with an input ID.
- Announce errors and success states.
- Move focus to the first invalid field.
- Ensure status is not communicated by color alone.

---

## 4.13 Medium: Translation architecture is not maintainable

The page contains a large inline three-language dictionary.

Problems:

- Page size and cognitive load
- Repeated status maps
- Raw-enum fallback may leak untranslated values
- Count strings do not use proper plural rules
- Payment and invoice terminology may diverge from contract pages

Required correction:

- Move billing copy into the shared localization architecture.
- Centralize payment status, method, channel, and invoice-status translations.
- Use `Intl.PluralRules` or ICU-style messages.
- Keep immutable enum keys independent from translated labels.
- Reuse terminology across Billing, Contracts, Reservations, and Reports.

---

## 4.14 Medium: The feature has no focused test coverage

No billing-specific test file was found.

Required correction:

Add tests for:

- Money calculations
- Deposit and charge separation
- Currency rules
- Permission rules
- Pagination and filters
- Manual payment validation
- Idempotent retries
- Refund effects
- Status derivation
- RTL rendering
- Modal accessibility
- Admin menu visibility
- API authorization

---

## 5. Target Billing Model

## 5.1 Invoice model

Each invoice response should include:

```text
id
reservationId
invoiceNumber
contractNumber
customer
vehicle
rentalPeriod
currency
status
paymentStatus
issuedAt
dueAt
subtotal
taxTotal
discountTotal
adjustmentTotal
invoiceTotal
invoicePaid
invoiceRefunded
invoiceBalanceDue
```

## 5.2 Security deposit model

```text
depositRequired
depositCollected
depositRefunded
depositHeld
depositOutstanding
depositStatus
```

Recommended deposit statuses:

```text
NOT_REQUIRED
OUTSTANDING
PARTIALLY_COLLECTED
HELD
PARTIALLY_REFUNDED
REFUNDED
FORFEITED
```

## 5.3 Payment event model

```text
id
invoiceId
reservationId
amountMinor
currency
type
channel
provider
method
status
reference
note
receivedAt
paidAt
createdAt
recordedBy
refundedAmount
idempotencyKey
```

## 5.4 Money rules

- Store money as integers in minor units.
- Never use floating-point arithmetic for persisted financial values.
- A payment currency must equal the invoice currency.
- A charge payment cannot exceed invoice balance.
- A deposit payment cannot exceed deposit outstanding.
- A refund cannot exceed the refundable amount.
- Historical payment and invoice snapshots must remain immutable after pricing changes.

---

## 6. Recommended API Plan

## 6.1 Billing summary

```http
GET /billing/summary?dateFrom=&dateTo=&currency=
```

Returns authoritative totals:

```json
{
  "currency": "MAD",
  "totalInvoiced": 0,
  "totalCollected": 0,
  "totalRefunded": 0,
  "totalOutstanding": 0,
  "depositsHeld": 0,
  "openInvoiceCount": 0,
  "overdueInvoiceCount": 0
}
```

For multi-currency companies, return one summary per currency.

## 6.2 Billing invoices

```http
GET /billing/invoices?page=1&pageSize=25&search=&status=&paymentStatus=&dateFrom=&dateTo=&sort=
```

Returns:

```json
{
  "items": [],
  "page": 1,
  "pageSize": 25,
  "totalItems": 0,
  "totalPages": 0
}
```

## 6.3 Invoice details

```http
GET /billing/invoices/:invoiceId
```

Returns complete invoice, deposit, adjustments, and payment history.

## 6.4 Record manual payment

```http
POST /billing/invoices/:invoiceId/payments/manual
```

Requirements:

- Permission check
- Subscription entitlement check
- Idempotency
- Database transaction
- Server-side balance validation
- Audit record
- Authoritative updated invoice response

## 6.5 Refund or deposit return

Do not add this endpoint until refund behavior is approved.

Possible future routes:

```http
POST /billing/payments/:paymentId/refund
POST /billing/invoices/:invoiceId/deposit-return
```

Refunds must never be represented by deleting or editing the original payment.

---

## 7. Admin Menu and Subscription Behavior

The platform Admin controls whether the Billing menu is assigned to each subscription plan.

Admin controls:

- Globally enable or disable Billing
- Assign Billing to STARTER, GROWTH, and PRO
- Choose hidden or locked behavior
- Control menu order and translated description
- Preview by plan, employee role, and subscription status

Recommended safety rule:

Billing history must remain accessible in read-only recovery mode even when a plan is downgraded or suspended. A subscription paywall must not trap a company’s financial records.

Recommended capability split:

```text
billing.view
billing.record_manual_payment
billing.export
billing.refund
billing.adjust
```

The Admin may assign advanced capabilities by plan, but historical visibility and legally required records need a durable access policy.

---

## 8. Target Dashboard Experience

## 8.1 Page header

Include:

- Customer Billing title
- Clear distinction from Subscription Billing
- Date range
- Search
- Filters
- Export action when entitled
- Refresh state

## 8.2 Summary cards

Recommended:

- Total invoiced
- Collected
- Outstanding
- Deposits held
- Open invoices
- Overdue invoices

Each metric must identify:

- Date range
- Currency
- Whether it represents all records or filtered records

## 8.3 Invoice list

Desktop columns:

- Invoice and customer
- Vehicle
- Rental period
- Invoice total
- Collected
- Balance
- Deposit status
- Payment status
- Primary action

Secondary details belong in a drawer, not eleven permanent columns.

## 8.4 Invoice detail drawer

Tabs or sections:

- Overview
- Charges
- Payments
- Deposit
- Audit

Actions depend on permission:

- Record payment
- Return deposit
- Refund payment
- Open contract
- Open reservation
- Download receipt or invoice
- Export ledger

## 8.5 Manual payment form

Fields:

- Payment target: Invoice charge or security deposit
- Amount
- Currency, read-only from invoice
- Method
- Received date/time
- Reference
- Note
- Optional evidence
- Confirmation summary

Behavior:

- Show the correct remaining amount for the selected target.
- Recalculate the default amount when target changes.
- Do not close on validation failure.
- Prevent duplicate submission.
- Display the resulting payment reference after success.

---

## 9. Component Architecture

Recommended structure:

```text
src/app/(dashboard)/billing/
  page.tsx
  billing.types.ts
  billing.constants.ts
  billing.validation.ts
  billing.i18n.ts
  billing.permissions.ts

  components/
    BillingHeader.tsx
    BillingFilters.tsx
    BillingSummary.tsx
    BillingInvoiceTable.tsx
    BillingInvoiceCards.tsx
    BillingInvoiceDrawer.tsx
    InvoiceOverview.tsx
    InvoiceCharges.tsx
    InvoicePaymentLedger.tsx
    InvoiceDepositSummary.tsx
    InvoiceAuditTimeline.tsx
    ManualPaymentDialog.tsx
    BillingStatusBadge.tsx
    BillingEmptyState.tsx
    BillingErrorState.tsx
    BillingPagination.tsx
```

Use shared API types where available. Do not duplicate backend enums in the page.

---

## 10. Implementation Phases

## Phase 1: Freeze Financial Semantics

Decide and document:

- Whether `paidAmount` excludes deposits
- Whether deposits are refundable liabilities
- When an invoice is created
- When an invoice becomes due
- Overdue rules
- Charge, deposit, refund, and forfeiture semantics
- Company currency policy
- Manager billing permissions
- Subscription downgrade access
- Refund approval requirements

Exit criteria:

- Signed-off invoice and deposit state model
- Signed-off role and plan matrix
- No ambiguous use of `paidAmount`

## Phase 2: Audit the API and Database

Inspect:

- Reservation monetary fields
- Invoice generation
- Payment model
- Payment status derivation
- Deposit storage
- Refund records
- Manual payment endpoint
- Transactions and locking
- Idempotency
- Currency constraints
- Audit events
- Authorization guards

Exit criteria:

- Gap report mapping current fields to target fields
- Migration plan approved
- No financial mutation occurs without a transaction

## Phase 3: Add Authoritative Billing APIs

Implement:

- Billing summary endpoint
- Paginated invoice endpoint
- Invoice detail endpoint
- Correct manual-payment endpoint
- Permission and entitlement guards
- Idempotency
- Audit events

Exit criteria:

- Dashboard no longer joins broad reservation and payment collections
- Totals are authoritative and paginated
- Charge and deposit validation are separate

## Phase 4: Correct Access Control

Implement:

- Admin-controlled Billing menu assignment
- Explicit billing capabilities
- Owner/Manager/Agent policy
- Route-level denial
- Endpoint-level denial
- Recovery-mode access
- Consistent fallback navigation

Exit criteria:

- Menu visibility, route access, and API access agree
- A Manager cannot gain billing access because a fallback menu loaded
- Direct API calls cannot bypass permissions

## Phase 5: Refactor the Billing Dashboard

Implement:

- Billing page shell
- Summary
- Filters
- Paginated invoice list
- Responsive cards
- Invoice detail drawer
- Localized status components

Exit criteria:

- Page is no longer a 644-line monolith
- No 11-column mobile table
- Search covers the complete dataset

## Phase 6: Rebuild Manual Payment Workflow

Implement:

- Separate charge and deposit targets
- Correct remaining amounts
- Received date
- Reference
- Notes
- Idempotency
- Confirmation
- Success receipt
- Accessible dialog

Exit criteria:

- Fully paid invoice can still receive an outstanding deposit
- Payment cannot exceed its correct target balance
- Retry cannot create duplicate payment

## Phase 7: Add Ledger and Deposit History

Implement:

- Full payment timeline
- Deposit timeline
- Refund display
- Recorded-by employee
- References and notes
- Immutable audit events

Exit criteria:

- Every displayed total can be explained by visible events
- Historical events are not edited or deleted

## Phase 8: Localization, RTL, Accessibility, and Responsive Review

Implement:

- Shared EN/FR/AR copy
- Proper pluralization
- True RTL
- Focus management
- Screen-reader status announcements
- Mobile invoice cards
- Bidirectional formatting for identifiers

Exit criteria:

- Complete keyboard workflow
- No raw backend enum leakage
- Arabic is usable without horizontal navigation gymnastics

## Phase 9: Automated Tests and Reconciliation

Implement:

- Unit tests
- API integration tests
- Permission tests
- Idempotency tests
- Component tests
- E2E billing scenarios
- Data reconciliation checks

Exit criteria:

- All billing tests pass
- Summary equals invoice ledger totals
- Contract invoice, Billing page, and Reports use the same financial source

---

## 11. Required Test Scenarios

## Financial correctness

1. Unpaid invoice receives a partial charge.
2. Partial invoice receives the remaining charge.
3. Fully paid invoice rejects another charge.
4. Fully paid invoice accepts an outstanding deposit.
5. Deposit payment cannot exceed deposit outstanding.
6. Charge payment cannot exceed invoice balance.
7. Deposit refund does not reduce rental revenue.
8. Charge refund increases invoice balance correctly.
9. Failed and pending payments do not count as collected.
10. Refunded payments do not remain fully counted as collected.
11. Currency mismatch is rejected.
12. Minor-unit rounding is stable.

## Integrity and concurrency

13. Duplicate request with the same idempotency key creates one payment.
14. Two simultaneous attempts cannot overpay the invoice.
15. Two simultaneous deposit collections cannot exceed required deposit.
16. Network timeout followed by retry returns the original result.
17. Payment and invoice update occur in one transaction.

## Permissions

18. Owner with entitlement can view and record.
19. Manager is denied under the recommended default policy.
20. Agent is denied.
21. Hidden Billing menu does not authorize the endpoint.
22. Direct API call without capability is rejected.
23. Downgraded company can view historical records according to recovery policy.
24. Suspended company cannot create new payments unless recovery policy explicitly permits it.

## UI

25. Search operates across all server records.
26. Pagination preserves filters.
27. Empty search result differs from no billing records.
28. Modal traps focus and closes with Escape.
29. Arabic list, drawer, and modal render in RTL.
30. Mobile user can record a payment without horizontal scrolling.
31. Payment success is announced and displayed.
32. Failed refresh after a successful mutation does not invite duplicate payment.

---

## 12. Acceptance Criteria

The billing remediation is complete when:

1. Customer Billing and Subscription Billing are clearly separate.
2. Invoice charges and security deposits use separate balances.
3. Deposit collection works even when invoice balance is zero.
4. All money uses integer minor units.
5. Currency comes from the invoice or enforced company currency.
6. Billing totals come from authoritative backend responses.
7. The feature is not limited to the first 100 reservations.
8. Search and filters run server-side.
9. Billing history shows the complete payment ledger.
10. Manual payments include audit and reconciliation fields.
11. Manual payment requests are idempotent.
12. Concurrent requests cannot overpay.
13. The platform Admin controls menu-to-plan assignment.
14. Role permissions remain independent from subscription-plan access.
15. Menu visibility, route access, and API authorization are consistent.
16. The Manager billing contradiction is resolved.
17. Historical financial records remain visible under the approved retention policy.
18. The page is responsive without relying on an 11-column mobile table.
19. English, French, and Arabic are complete.
20. Arabic uses true RTL.
21. The manual-payment dialog meets accessibility requirements.
22. Billing, Contracts, and Reports use the same financial source.
23. No raw payment or status enum appears to end users.
24. Automated financial, permission, API, UI, and E2E tests pass.
25. No production billing migration occurs without reconciliation and rollback procedures.

---

## 13. Out of Scope for the First Remediation

Unless separately approved, the first implementation should not add:

- Full double-entry accounting
- Bank-feed integration
- Automated chargebacks
- Partial tax remittance
- Multi-entity consolidation
- Customer credit wallets
- Gift cards
- Installment financing
- Arbitrary invoice editing after issuance
- Deleting successful payments
- New online payment providers
- SaaS subscription changes

---

## 14. Execution Gate

No billing code changes should begin until these decisions are approved:

1. Invoice-versus-deposit accounting semantics
2. Money-unit convention
3. Single-currency or multi-currency policy
4. Owner, Manager, and Agent billing permissions
5. Admin plan assignments
6. Downgrade and suspension behavior
7. Refund and deposit-return rules
8. Overdue definition
9. Invoice issuance lifecycle
10. Audit retention requirements
11. Migration and reconciliation approach
12. Whether refunds are included in the first implementation
