Status: accepted Context: Task D.2 introduced separate `Billing Customer` and `Project Parties` data entry in CRM enquiries and quotations. Task J.0 froze KPI definitions and confirmed that dashboard/reporting behavior must not drift without an explicit governance decision. Task D.2.1 freezes how revenue attribution and relationship reporting work across dashboard, report center, exports, and future analytics features. Decision: - Freeze `Revenue Owner = End Customer`. - Determine `Revenue Owner` from project-party role code `end_customer`. - If a record has no `end_customer`, fallback to `billing_customer` for revenue-owner attribution only. - Freeze `Billing Revenue` as quotation revenue grouped by project-party role `billing_customer`. - Freeze `Contractor Revenue` as quotation revenue grouped by project-party role `contractor`. - Freeze `Consultant Revenue` as quotation revenue grouped by project-party role `consultant`. - Use project-party relationships as the reporting authority, not bare `crm_customers` references alone. - Prefer quotation project parties for reporting. If quotation project parties are absent, fallback to enquiry project parties for the linked enquiry. - When multiple parties share the same reporting role on one quotation, each party receives full quotation attribution. - Do not prorate relationship analytics across multiple parties because this model is for CRM relationship reporting, not accounting allocation. - Exclude cancelled quotations from revenue attribution by default unless an explicit reporting filter intentionally includes them. Consequences: - Dashboard KPI, report center, exports, and ad hoc analytics can share one attribution rule set. - `Top End Customers`, `Top Contractors`, `Top Consultants`, and `Top Billing Customers` can be built from the same reusable service layer. - A single quotation may contribute full value to more than one customer in relationship analytics when multiple parties share a role. - Revenue attribution and accounting allocation remain intentionally separate concerns. - Legacy or incomplete quotations without project-party rows may not attribute revenue until project-party data is synchronized or backfilled. Future: - add a unified reporting view or materialized projection if revenue analytics queries become heavy - add explicit lifecycle timestamps for won/lost stage reporting precision - decide whether approved snapshots should become the long-term reporting source for historically locked documents - add backfill tooling if legacy quotations are found without authoritative project-party rows