---
title: Reports and dashboard
description: Read the dashboard summary and branch comparison, then run inventory, purchases, sales, pharmacist, and VAT reports.
---

You read the dashboard from `apps/server/src/features/dashboard/route.ts` and the five reports from `apps/server/src/features/reports/route.ts` with helpers under `apps/server/src/features/reports/queries/`. Dashboard endpoints need authentication only, while every report requires the `admin`, `branch_manager`, or `auditor` role.

### Read the daily summary

Call `GET /dashboard/summary` for the morning screen. Pass `branch_id` to scope to one branch, or omit it for the whole organisation. You get `today_sales_count`, `today_revenue`, `today_vat`, and `revenue_trend`, the percentage change against yesterday (0 when yesterday had no revenue).

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8000/api/v1/dashboard/summary?branch_id=BRANCH_ID"
```

The same payload carries `sparkline_30d` (daily revenue totals for the last 30 days), `low_stock_count`, `out_of_stock_count`, `expiring_90_count`, `expiring_30_count`, `expired_count`, and `total_medicines`. Expiring counts exclude recalled and quarantined batches, so the numbers reflect sellable risk only.

### Compare branches

Call `GET /dashboard/branch-comparison` to rank every active branch by revenue with `sales_count` and `share_pct`, the branch share of total revenue rounded to one decimal. Branches with no sales still appear with zero revenue.

```bash
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8000/api/v1/dashboard/branch-comparison
```

Use the ranking to spot an underperforming branch, then drill into its own summary by passing its id as `branch_id` to the summary endpoint.

### Set the report window

The sales, purchases, pharmacist, and VAT reports all take `from_date` and `to_date` in `YYYY-MM-DD` format and default to the last 30 days up to today, resolved by `dateWindow` in `apps/server/src/features/reports/queries/shared.ts`. An invalid format or a `from_date` after `to_date` returns a 400. Pass `branch_id` to scope any report to one branch.

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8000/api/v1/reports/sales?from_date=2026-08-28&to_date=2026-09-27"
```

### Run sales and inventory reports

`GET /reports/sales` returns totals plus `by_day` (daily total and count), `by_payment` (count and total per method), a top-10 `top_selling` list with `gross_profit` and `margin_pct` per medicine, and the 8 most `recent` sales with pharmacist names. A zero-revenue medicine yields a `margin_pct` of 0 rather than a division error.

`GET /reports/sales/by-pharmacist` breaks the same window down per user with transaction count, revenue, VAT, and average transaction value, grouped by user and branch and ordered by revenue descending.

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8000/api/v1/reports/sales/by-pharmacist?from_date=2026-08-28&to_date=2026-09-27&branch_id=BRANCH_ID"
```

`GET /reports/inventory` needs no date window. It returns total medicines, low-stock count, total inventory value at selling price, a `by_category` breakdown sorted by value, and a 20-item `low_stock_list` sorted with the emptiest shelves first. Pass `branch_id` and the branch stock figure comes from `sumStockByMedicine` in `apps/server/src/features/reports/queries/inventory.ts`, the same ledger sum the rest of the app uses.

### Run purchases and VAT reports

`GET /reports/purchases` totals `qty_received * unit_cost` across batches received in the window, broken down `by_supplier` (batch count and spend, highest spend first) and `by_medicine` (top 20 by spend with units and batch counts). Use it with the reorder suggestions in `/operations/suppliers-and-finance` to decide what to order next.

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8000/api/v1/reports/purchases?from_date=2026-08-28&to_date=2026-09-27"
```

`GET /reports/vat` groups by month (`YYYY-MM`, newest first) with `taxable_0`, `taxable_18` (also aliased as `taxable_15`), `vat_collected`, and `grand_total`. Cross-check the current month against the `today_vat` figure on the dashboard before filing.

### Next steps

**[Printing and settings](/operations/printing-and-settings)**

Confirm the tax rate and receipt layout match what the VAT report assumes.

**[Compliance](/operations/compliance)**

Turn the same sales data into regulator-ready books and fiscal previews.
