# Task D.4 Implementation Summary

## Completed

- extended `crm_enquiries` with official won/lost lifecycle fields
- added `crm_enquiry_attachments` for purchase order files
- seeded `crm_lost_reason` master data
- added permissions:
  - `crm.enquiry.mark_won`
  - `crm.enquiry.mark_lost`
  - `crm.enquiry.reopen`
- added outcome service operations for:
  - mark won
  - mark lost
  - reopen lost opportunity
- added API routes for outcome transitions and PO attachment upload/view/download
- added enquiry detail outcome card with:
  - open / won / lost state
  - PO data
  - lost data
  - closed by / closed date
  - mark won / mark lost / reopen actions
  - PO attachment upload and retrieval
- removed quotation-status-driven mutation of enquiry pipeline outcome
- migrated dashboard summary/funnel/sales won revenue to enquiry outcome helpers
- added reporting helpers:
  - `getWonRevenue()`
  - `getLostRevenue()`
  - `getLostByReason()`
  - `getLostByCompetitor()`
  - `getWinRate()`

## Verification

- `npm exec tsc --noEmit`

## Notes

- marketing users still receive outcome state, but PO amount is redacted server-side unless commercial pricing visibility exists
- PO attachment endpoints are also restricted to commercial-data viewers
- revenue analytics cards still use existing quotation-attribution views for top-party ranking, but won/lost headline KPI and sales won revenue now follow the D.4 lifecycle rule
