## 1. Report summary

- [x] 1.1 In `LunchOrderController::ordersReport()`, when `limit` is set, clone the grouped query (without ORDER BY) and aggregate it through a derived table into `total_people`, `total_orders`, `total_amount` (cast to int/int/float, nulls as 0)
- [x] 1.2 Return `array_merge($paginator->toArray(), ['summary' => $summary])` for the paginated branch; leave the `get()` branch unchanged
- [x] 1.3 Update the OpenAPI annotation of `ordersReport()` to document `summary` (present only when `limit` is sent)

## 2. Item price contract

- [x] 2.1 Confirm `price` is in the OpenAPI response docs of `LunchMenuController::show()` (`items[].price`) and `LunchItemController::getList()` (`price`), nullable; add it where missing

## 3. Report sort

- [x] 3.1 In `ordersReport()`, accept `sort` (`total_amount`) and `order` (`asc`/`desc`), default `total_amount desc`, tie-break by `number_orders desc` then `account_id asc`; document both parameters in the OpenAPI annotation
- [x] 3.2 Verify default, `asc` and `desc` orderings and that `summary` is unchanged

## 4. Verification

- [x] 4.1 Lint changed files (`php -l`, PHP 7.4 in the app container)
- [x] 4.2 Report with `limit` over several pages → `summary` identical on every page; `total_people` equals pagination `total`; sums match a manual SQL check
- [x] 4.3 Report with `department_id` / `q` / `from`-`to` filters → `summary` narrows accordingly; no matches → all zeros
- [x] 4.4 Report without `limit` → plain array, no `summary`
- [x] 4.5 `GET /admin/lunch-menus/{id}` and `GET /admin/public/lunch-items` (with and without `limit`) → each item has `price`; an item with null price returns `null`, an item priced 0 returns `0`
