# Dashboard Refactor — Service Reuse Survey

What already exists that the new dashboard can lean on, what it must not touch, and what
is a genuine candidate for centralisation. Companion to `RULES.md`.

Legend: 🟢 use as-is · 🟡 use, but wrap/adapt · 🔴 do not touch or extend · 🔵 needs a decision

---

## 🟢 Use as-is

| Service | Path | Where it serves the refactor |
|---|---|---|
| `ReportsAgingCustomerService` | `Modules/Reports/Services/ReportsAgingCustomerService.php` | `getGrandTotalSummary()` returns receivables split across dynamic aging buckets, already backed by the materialised `report_customer_aging` table. This is **the** Receivables card and the "invoices past due" alert. |
| `RetrievingCurrentFinancialYearService` | `Modules/Settings/Services/` | Current FY for every period-scoped card. |
| `RetrievingSettingsService` / `GeneralSettingsRepository::getLast()` | `Modules/Settings/` | `taxable`, `currency`, `country`, brand name/logo. Gate for the VAT alert. |
| `RetrievingTenantCurrencyService` | `Modules/Settings/Services/` | Currency code → drives SAR-icon vs ISO-code rendering. |
| `CompanyInfo::scopeZatcaComply()` | `Modules/Tenant/Models/CompanyInfo.php:175` | Gate for the ZATCA alert card. |
| `SubscriptionReportStatusService` | `Modules/Reports/Services/` | Package/addon gating pattern; already used by every v2 report controller. |
| `PreparingDataService` | `Modules/Reports/Services/` | Shared account-tree / fiscal-year prep the v2 report services all consume. |
| `ReportKpiCard.vue` | `resources/js/components/` | KPI tile, already carries SAR-icon vs ISO-code logic. |
| `ReportV2EmptyState.vue` | `Modules/Reports/Resources/assets/js/components/` | Error / empty / hint states per card. |
| `ReportMonetaryOutput` | `Modules/Reports/Support/` | Consistent money formatting on the backend. |

---

## 🟡 Use, but wrap

| Service | Why it needs a wrapper |
|---|---|
| `NewTaxesReportService` (637 lines) | Computes output/input VAT across invoices, returns, bills, expenses, assets and synced orders — exactly the VAT Position card. But `execute()` takes a full `TaxesReportRequestEntity` and returns a report-shaped array. Wrap it in a thin dashboard service that feeds it a period and reduces the result to `{ output, input, net }`. **Do not modify it.** |
| `IncomeStatementService` | Feeds Net Profit. Already wrapped once by `IncomeStatementChartService` for the legacy dashboard. Follow that precedent with a new, leaner wrapper rather than reusing the chart wrapper. |
| `SalesSummaryReportV2Service` / `PurchasesSummaryReportV2Service` | Both are `execute(RequestEntity, ?array $tableQuery)` and return paginated report payloads. Usable for Total Sales / Total Purchases and Top Customers, but only through a wrapper that asks for totals, not pages. |
| `InsightsCalculationService` | `Modules/CompanyUser/Services/Insights/` — already computes weekly period-over-period deltas and caches them into `weekly_insights`. Overlaps the prototype's "▲ 6.1% vs Jul" deltas. Worth reading before writing new delta maths; **but it is weekly and cached**, so it is not a drop-in for a month/quarter/year selector. |

---

## 🔴 Do not touch or extend

| Service | Why |
|---|---|
| `Modules\Settings\Services\Dashboard\RetrievingDataForDashboardService` | 340 lines. Hydrates **every** invoice, bill, return and expense of the fiscal year into memory and groups them in PHP (`->get()->groupBy()->map()`), five times over, on every dashboard load. It is the legacy dashboard's data layer and nothing else uses it. Leave it running for `/companyuser`; let the new per-card endpoints replace it piece by piece; delete it only at the final URL swap. |
| `GetGenralSettingsCountService`, `GetAccountingSettingsCountService` | Same folder, same fate. Only the legacy blade consumes them. |
| The `--ard-*` token blocks duplicated across 6+ v2 report components | Real duplication, real temptation. Centralising it would touch every shipped v2 report. **Copy the values into a dashboard-local block instead** (rule 1.2). |
| The `extra-styles` / `extra_styles` section-name mismatch across ~18 CompanyUser views | Fixing it centrally switches on ~18 dormant stylesheets at once. See `RULES.md` §3. |

---

## 🔵 Flagged for your decision — centralisation candidates

These are the things I'd *want* to extract. None of them are safe unilaterally, so none are
being done without a yes from you.

### 1. A shared `DashboardCardController` base + JSON envelope — **low risk, recommend yes**

Every v2 report controller repeats the same block: package gate → validator → JSON envelope
`{ status, data, errors, success }`. The dashboard will have one endpoint per card, so that
block would be repeated a dozen times.

Proposal: a **new** `Modules\CompanyUser\Http\Controllers\Dashboard\BaseDashboardCardController`
that only new dashboard controllers extend. Nothing existing changes. Zero blast radius.

### 2. A shared Vue `<dashboard-card>` shell — **low risk, recommend yes**

Skeleton + error state + empty state + title + the fetch/generation-counter dance are
identical for every card. One new shell component, new file, consumed only by new cards.
Existing report components keep their own copies.

### 3. Aging buckets for **payables** — **medium, needs a product answer**

`report_customer_aging` + `ReportsAgingCustomerService` exist for receivables. There is
**no supplier equivalent** anywhere in the codebase. The prototype's Payables card needs
the same aging breakdown for bills.

Options: (a) compute it live from `purchase_bills` for the dashboard only — cheap now, a
second implementation later; (b) build a `report_supplier_aging` mirror + populate job —
correct, but that is its own project and well outside a dashboard phase.
**My read: (a) for the dashboard, and file (b) as separate work.** Your call.

### 4. A money-formatting helper shared between backend and frontend — **flag only**

Formatting currently lives in `ReportMonetaryOutput` (PHP) and is re-implemented inside
each Vue component. Consolidating would touch shipped reports. I'd leave it and copy.

---

## Frontend reference implementations to copy from

* Async fetch + out-of-order guard: `Modules/Reports/Resources/assets/js/components/CashFlowDirectReportV2.vue:520-580`
* Skeleton markup + CSS: `Modules/Reports/Resources/assets/js/components/CashFlowDirectReportDataV2.vue:3-9, 388-413`
* Card / hero surface CSS: `Modules/Reports/Resources/assets/js/components/AccountStatementReportTable.vue:540-610`
* Blade → component wiring (props, `@js()`, `@json()`): `Modules/Reports/Resources/views/cash_flow_direct_v2/cash-flow-direct-v2.blade.php`
* Controller shape (index + data + gating): `Modules/Reports/Http/Controllers/CashFlowDirectReportControllerV2.php`
* Component registration: `resources/js/app.js` (explicit `Vue.component(...)` per component; the auto-registration block at `:59-60` is commented out — register new components explicitly)
