# Phase 3 — Milestone Invoiceability Report

**Status:** Complete — awaiting approval to start Phase 4  
**Date:** 2026-10-07  
**Scope:** Eligibility, invoiced/remaining amounts, over-invoicing prevention. No create-invoice API/UI.

---

## What was implemented

### Service

`MilestoneInvoiceabilityService` (+ interface)

| Method | Behavior |
|--------|----------|
| `isEligible` | Only `approved` milestones |
| `invoicedAmount` | Sum of allocations on **non-cancelled** invoices |
| `remainingAmount` | `amount − invoiced` (floor 0) |
| `summarize` | Snapshot for API/UI later |
| `assertCanAllocate` | amount > 0, same contract, approved, ≤ remaining |
| `assertCanAllocateMany` | Batch validation for multi-milestone invoices |

### Repository

`ContractMilestoneRepository` — find + `sumInvoicedAmount` (excludes cancelled invoices; optional `excludeInvoiceId` for future edits).

### Approval integration (this phase)

- Invoice eligibility is gated on `ContractMilestoneStatus::Approved`.
- Platform ApprovalEngine wiring (submit/approve request → status flip) deferred to milestone CRUD/approval work in Phase 4/5 prep — **status gate is the invoiceability contract**.

### Binding

Registered in `ProjectServiceProvider`.

---

## Tests

`Modules/Project/tests/Unit/MilestoneInvoiceabilityServiceTest.php` — **10 passed**

Covers master scenarios relevant to Phase 3:

- Partial remaining (40k → 60k left)
- Multiple partials to zero
- Over-invoicing fail
- Unapproved / draft / rejected fail
- Fully invoiced fail
- Cancelled invoice frees remaining
- Wrong-contract milestone fail
- Multi-allocation batch validate

---

## Explicitly NOT done

- Manual invoice create API (Phase 4)
- Auto-invoice on approval (Phase 5)
- Milestone CRUD / ApprovalEngine submit endpoints
- Contract-wise remaining vs `contract_value` cap (still open; not milestone-scoped)
- Payment (Phase 7)

---

## STOP

Phase 3 complete. **Awaiting explicit approval for Phase 4 — Manual Invoice.**
