# FastReport — Настройка и решение проблем

> Назначение: ответы на типовые вопросы по настройке FastReport и работе с отчётами.
> Связан с: [администрированием отчётов](https://help.1forma.ru/domains/reports/admin.md).

## 1. Архитектура отчётов

FastReport — движок генерации отчётов в 1Форме. Пользователь запускает отчёт через веб-интерфейс, API вызывает FastReport Engine, который выполняет SQL-запрос и формирует документ.

![Запуск отчёта через поиск: вкладка «Отчёты» со списком доступных отчётов](https://help.1forma.ru/help-images/reports/main_search_report.png)

```
Пользователь → Веб-интерфейс → API (reports/view/{id}) → FastReport Engine → SQL Server / PG → Готовый отчёт
                                                                ↑
                                                    Reports.ContentXml (шаблон)
```

1Ф поддерживает два способа создания отчётов через FastReport:

- **Win-дизайнер** (десктопное приложение) — полный функционал, требует установки
- **Онлайн-дизайнер** (в браузере) — ограниченный функционал, не требует установки

## 2. Предварительные требования для Win-дизайнера

Что нужно для работы Win-дизайнера:

1. **FastReport Designer** — поставляется в ZIP-архиве из категории «Репозиторий версий приложения» (не скачивается из интерфейса)
2. **.NET Framework 4.7.1** или выше — [скачать](https://www.microsoft.com/ru-ru/download/details.aspx?id=56480)
3. **Сетевой доступ к SQL Server** — дизайнер подключается напрямую к БД

| Ресурс | Порт | Зачем |
|--------|------|-------|
| SQL Server 1Ф | 1433 (TCP) | Дизайнер подключается к БД для получения данных |
| Сервер 1Ф (web) | 443/80 | Для сохранения шаблона обратно в 1Ф |

Дизайнер использует connection string из 1Ф. Два варианта:

1. **Windows Authentication** — учётная запись Windows пользователя должна иметь доступ к БД 1Ф (`db_datareader` минимум)
2. **SQL Authentication** — логин/пароль SQL Server (задаётся в connection string отчёта)

**Важно**: учётная запись дизайнера должна иметь:

- `SELECT` на таблицы, которые используются в отчётах
- `EXECUTE` на хранимые процедуры, если отчёт их вызывает
- Рекомендуемая роль: `db_datareader` + точечные `EXECUTE` на нужные SP



**Совместимость сборки дизайнера.** Дизайнер поставляется в составе платформы; сторонние библиотеки, от которых он зависит, поставляются вместе с ним в согласованных версиях. Отдельно доустанавливать пакеты для запуска дизайнера не требуется. Если при развёртывании дизайнера на рабочем месте возникают ошибки загрузки библиотек, обращайтесь в техническую поддержку 1Формы.## 3. Настройка в 1Ф (пошагово)

**Администрирование → Отчёты → Создать отчёт**

| Поле | Описание |
|------|----------|
| **Название** | Отображаемое имя отчёта |
| **Режим** | `FastReports` (для FastReport-шаблонов) |
| **Контекст** | Откуда доступен: Задача, Категория, Раздел, Пользователь, Группа |
| **Блок** | Группировка в интерфейсе |
| **Скрытый** | Если `true` — не показывается пользователям |

**Администрирование → Отчёты → [отчёт] → Права**

Права настраиваются по группам:

| Право | Описание |
|-------|----------|
| **Просмотр** | Кто видит отчёт в списке и может генерировать |
| **Аннотация** | Кто может редактировать описание |
| **Специальные** | Полный доступ (администратор отчёта) |

Если права не назначены — отчёт виден только администраторам.

Контекст определяет, какие параметры автоматически доступны в шаблоне:

| Контекст | Автопараметр | Где отображается |
|----------|-------------|------------------|
| **Задача** | `taskId` | В карточке задачи |
| **Категория** | `categoryId` | В гриде категории |
| **Раздел** | — | В разделе |
| **Пользователь** | `userId` | В профиле пользователя |
| **Группа** | `groupId` | В настройках группы |

Параметр `CurrentUserId` доступен всегда — ID текущего пользователя.

Фильтры позволяют пользователю задавать параметры перед генерацией. Настраиваются в **Администрирование → Отчёты → [отчёт] → Фильтр**.

## 4. Работа с Win-дизайнером

Порядок работы с Win-дизайнером:

1. Распаковать ZIP-архив дизайнера
2. Запустить `TCReportDesigner.exe`
3. В списке отчётов выбрать нужный → «Win-дизайнер»
4. Дизайнер скачает шаблон и откроется

В дизайнере доступны:

- **Таблицы БД** — прямой доступ к таблицам 1Ф
- **SQL-запросы** — произвольные SELECT
- **Хранимые процедуры** — с параметрами
- **Несколько Connection** — можно подключить дополнительные БД

Connection string подставляется автоматически из настроек 1Ф. Таймаут SQL-команд: **120 секунд** (настройка `FastReportCommandTimeoutSeconds`).

При сохранении дизайнер отправляет XML-шаблон обратно в 1Ф через маршрут `~/MVC/ReportDesigner/Save`. Шаблон записывается в `Reports.ContentXml`.

## Онлайн-дизайнер и форматы экспорта

Онлайн-дизайнер доступен из интерфейса 1Формы (**Отчёты → [отчёт] → Онлайн-дизайнер**) и требует **права администратора**. Ограничения по сравнению с Win-дизайнером: нет полного набора компонентов, нет прямого доступа к connection strings, не все форматы экспорта доступны.

### Форматы экспорта

FastReport поддерживает экспорт отчётов в несколько форматов: PDF, Word, Excel, PowerPoint, RTF и другие.

| Формат | Расширение | Особенности |
|--------|-----------|-------------|
| PDF | .pdf | Основной формат. Встраивание шрифтов, сжатие |
| Word | .docx | Несколько режимов: WYSIWYG, постраничный, абзацный |
| Excel | .xlsx | Режимы: постраничный, бесшовный, только данные |
| PowerPoint | .pptx | Изображения в PNG или JPEG |
| RTF | .rtf | С разрывами страниц |
| HTML, CSV, XML, TXT, DBF, ODS, ODT | — | Дополнительные форматы |

**Кодировка CSV.** Файл CSV — при выгрузке из интерфейса и при формировании файла отчёта — сохраняется в кодировке UTF-8 с меткой BOM, поэтому Excel открывает кириллицу без искажений.

## 7. Типичные проблемы и решения

### 7.1 «Не могу подключить дизайнер к БД»

**Симптом**: при открытии Win-дизайнера ошибка подключения к SQL Server.

**Проверить**:

1. **Сеть**: с компьютера пользователя `telnet sql-server 1433` — порт должен быть открыт
2. **Учётная запись**: если Windows Auth — пользователь должен быть в домене и иметь доступ к БД. Если SQL Auth — проверить логин/пароль
3. **Firewall**: SQL Server может слушать на нестандартном порту или блокировать внешние подключения
4. **Named Pipes vs TCP/IP**: проверить что TCP/IP включен в SQL Server Configuration Manager

**Проверить**:

1. `Reports.IsHidden` — не скрыт ли отчёт?
2. Права — назначены ли группе пользователя права на просмотр?
3. Контекст — если отчёт привязан к контексту (задача/категория), он отображается только в этом контексте

### 7.3 «Отчёт генерируется медленно или с ошибкой таймаута»

**Проверить**:

1. SQL-запросы в шаблоне — оптимизировать (добавить индексы, упростить)
2. Таймаут — по умолчанию 120 секунд. Увеличить `FastReportCommandTimeoutSeconds` в конфигурации
3. Объём данных — при большом объёме использовать фильтры для ограничения выборки

- Win-дизайнер доступен только для отчётов с `Mode = FastReports`
- Требуется роль администратора

Дизайнер поставляется в ZIP-архиве из категории **«Репозиторий версий приложения»** в 1Ф. Ссылка для скачивания из интерфейса убрана.

### 7.4 «Report template failed» при итогах в отчёте с детализацией

**Симптом:** отчёт с первым уровнем и страницей детализации перестаёт строиться, как только в шаблоне появляется итог или агрегатное выражение; падает тот уровень, к которому итог не относится.

**Проверить:** на какую полосу данных указывает `Evaluator` итога — она должна принадлежать той же странице, что и сам итог. Итог по данным первого уровня считается на первом уровне, итог по данным страницы детализации — на ней.

**Решение:** поправить привязку итога. Ссылка на полосу другого уровня построение не ломает — ячейка останется пустой, а в составном выражении чужая часть заменится нулём; ссылка на несуществующую полосу даёт ошибку конфигурации с именем итога, страницы, набора и полосы. Правило целиком — в [Отчёты — администрирование](https://help.1forma.ru/domains/reports/admin.md).

### 7.5 «Источники отчёта разошлись с шаблоном»

**Симптом:** в отчёте с внешней отрисовкой не хватает наборов данных или колонок — источники настроены не полностью либо их карты имён отстали от шаблона.

**Проверить:** что объявлено в шаблоне и что настроено в отчёте — сводку отдаёт `GET api/admin/reports/{reportId}/datasources/template-state`.

**Решение:** выполнить синхронизацию с шаблоном (`POST api/admin/reports/{reportId}/datasources/sync-template`). Операция создаёт недостающие источники, дополняет карты имён и перестраивает таблицы. Она отклоняется, если отчёт не в режиме внешней отрисовки, если в шаблоне повторяются внутренние имена наборов данных, нет ни одного соединения с данными или новая таблица не привязана к единственному соединению. Конфликт возвращается, когда шаблон изменился с момента чтения — тогда отчёт надо перечитать и повторить операцию.

### 7.6 Детализация не отбирает данные по кликнутой ячейке

**Симптом:** клик по ссылке открывает вкладку детализации, но показывает весь набор данных вместо строк по выбранной ячейке; иногда отбор молча пропадает совсем — при ссылке в первой колонке заголовок строки пуст и прежний разбор значений не находит ничего.

**Проверить** по порядку:

1. У ячейки в шаблоне заполнены **оба** свойства — `Hyperlink.Expression` и `Hyperlink.ReportParameter`. Без любого из них ссылка строится как раньше, и клиент берёт значения из раскладки таблицы.
2. Имя из `Hyperlink.ReportParameter` совпадает с полем «Имя ячейки» в записи сопоставления источника страницы детализации, а вид значения у записи — «Значение из ячейки набора».
3. Если значение составное, в той же записи заполнены «Разделитель» и «Номер части» — вместе, номером части с 1; неполная пара блокирует сохранение сопоставлений.
4. Ссылка в разметке имеет вид `#report-drill/<страница>?<имя>=<значение>`, и имя страницы в адресе не содержит query — иначе откроется вкладка с именем, которого нет в шаблоне.

**Решение:** привести сопоставление и шаблон к паре «имя параметра в ссылке ↔ Имя ячейки в записи». Правила целиком — в [Отчёты — администрирование](https://help.1forma.ru/domains/reports/admin.md).

### 7.7 Экспорт отчёта на сервисе внешней отрисовки останавливает процесс на секунды

**Симптом:** выгрузка тяжёлого отчёта или печатной формы приостанавливает сервис отрисовки на секунды; в трейсе видно принудительную сборку мусора (`GC.Collect(2)`).

**Причина:** движок FastReport по умолчанию выполняет полную сборку мусора в конце каждой выгрузки. Свойство `FastReport.Utils.Config.UseGcCollect` выключается отдельно в каждом процессе, который строит отчёты.

**Проверить:** что в сборке есть версия с выключенным свойством — в сервисе отрисовки оно снимается при старте процесса-воркера. На живом стенде снять трейс при экспорте и убедиться, что принудительных сборок с этим стеком нет.

**Решение:** обновиться до сборки с исправлением. Содержимое выгружаемых файлов при этом не меняется.

### 7.8 Экспорт отчёта или печатной формы останавливает веб-ноду

**Симптом:** каждая выгрузка отчёта или печатной формы приостанавливает веб-ноду примерно на 2 секунды. Если пауза попадает в открытую транзакцию, вместе с этой нодой ждут остальные ноды кластера: видны цепочки ожиданий SQL 6–21 секунды, а внешние автоматизации с коротким таймаутом (например, телефония) теряют вызовы.

**Причина:** движок FastReport в конце каждой выгрузки выполняет полную сборку мусора. Свойство `FastReport.Utils.Config.UseGcCollect` включено, пока его не выключит процесс, который строит отчёты; в процессе ядра оно выключается при инициализации отчётов, до первого обращения к движку.

**Проверить:** снять на ноде трейс `dotnet-trace` с профилем `gc-verbose` в момент выгрузки отчёта. Признак дефекта — сборки с признаком принудительного запуска и стеком `FastReport.Export.ExportBase.DeleteTempFiles`; фаза остановки потоков при этом близка к нулю, то есть пауза не связана с загрузкой хоста. Обычные сборки в том же окне укладываются в сотни миллисекунд, фоновая сборка второго поколения — около 70 миллисекунд.

**Решение:** обновиться до сборки с исправлением. Состав и содержимое выгружаемых файлов при этом не меняются.

**Не путать:** принудительные сборки дают и другие вызывающие — задание `GCCollectJob` (полная сборка с уплотнением большой кучи, раз в 2 часа) и полная перезагрузка кэша локализации. Они закрываются отдельными работами, и после обновления такие паузы в трейсе остаются.

### 7.9 Пустая детализация падает с ошибкой о несовпадении состава колонок

**Симптом:** отчёт с внешней отрисовкой или его страница детализации падает с сообщением вида «набор задания не совпадает с шаблоном по колонкам», когда отбор не вернул ни одной строки. При непустом отборе тот же отчёт строится.

**Причина:** набор данных с пустым результатом уходил в службу отрисовки без колонок, а служба требует все колонки, объявленные в шаблоне.

**Решение:** обновиться до сборки с исправлением — для пустого результата зарегистрированного источника без карты имён состав колонок берётся из объявлений шаблона, типы — из каталога. Детализация строится пустой, без ошибки. Источники с картой имён и непустые результаты работают как прежде.

**Если ошибка осталась:** проверить, что в шаблоне у нужного источника данных объявлены колонки и что источник сопоставлен по внутреннему имени набора и псевдониму — см. [Отчёты — администрирование](https://help.1forma.ru/domains/reports/admin.md), раздел «Источники данных отчёта и карта имён».

## 8. Таблицы БД

Основные поля таблицы `Reports`:

| Поле | Тип | Описание |
|------|-----|----------|
| `id` | int | PK |
| `Description` | varchar(500) | Название отчёта |
| `ContentXml` | varchar(max) | XML-шаблон FastReport |
| `Context` | int | Тип контекста (0=Task, 1=Subcat, 2=Category, 3=User, 4=Group) |
| `Mode` | int | Режим (0=ExtForms, 2=FastReports) |
| `IsHidden` | bit | Скрытый |
| `IsSystemReport` | bit | Системный |
| `ExternalObjectId` | uniqueidentifier | FK на ExternalObjects (права) |
| `UserID` | int | Владелец |
| `Block` | varchar(200) | Группа в интерфейсе |
| `ExportSettings` | nvarchar(max) | JSON настроек экспорта |
| `GUID` | uniqueidentifier | Уникальный ID |

| Таблица | Описание |
|---------|----------|
| `ReportContextObjects` | Привязка отчёта к контексту (категория, задача и т.д.) |
| `ReportFilterLinks` | Привязка фильтров к отчёту |
| `ExternalObjects` + `ExternalObjectsViewRights` | Права доступа к отчёту |

## 9. Диагностические SQL-запросы

Готовые запросы для диагностики отчётов:

```sql
set transaction isolation level read uncommitted;

-- Все FastReport-отчёты
select
        r.id,
        r.Description,
        r.Context,
        r.IsHidden,
        r.IsSystemReport,
        r.UserID,
        u.FullName as Владелец,
        len(r.ContentXml) as ШаблонSize
from dbo.Reports r with (nolock)
        left join dbo.Users u with (nolock)
            on u.UserID = r.UserID
where r.Mode = 2
order by r.Description;

-- Права на отчёт
select
        r.Description as Отчёт,
        g.Name as Группа,
        eovr.RightType
from dbo.Reports r with (nolock)
        join dbo.ExternalObjects eo with (nolock)
            on eo.GUID = r.ExternalObjectId
        join dbo.ExternalObjectsViewRights eovr with (nolock)
            on eovr.ExternalObjectId = eo.Id
        join dbo.Groups g with (nolock)
            on g.GroupID = eovr.GroupID
where r.id = @ReportId
order by g.Name;

-- Контекст отчёта
select
        r.Description as Отчёт,
        rco.ContextObjectType,
        rco.ContextObjectId
from dbo.Reports r with (nolock)
        join dbo.ReportContextObjects rco with (nolock)
            on rco.ReportId = r.id
where r.id = @ReportId;
```

## 10. Маршруты API

REST API для управления отчётами и генерации: просмотр, создание, обновление, копирование и удаление отчётов через административные маршруты.

| Маршрут | Метод | Описание |
|----------|-------|----------|
| `reports/view/{id}` | GET/POST | Генерация отчёта |
| `reportdesigner/{id}` | GET | Открытие Win-дизайнера |
| `api/admin/reports` | GET | Список отчётов (админ) |
| `api/admin/reports` | POST | Создание отчёта (админ) |
| `api/admin/reports/{id}` | POST | Обновление отчёта (админ) |
| `api/admin/reports/{id}` | DELETE | Удаление отчёта (админ) |
| `api/admin/reports/{id}/copy` | POST | Копирование отчёта (админ) |
| `api/admin/reports/{reportId}/datasources/template-state` | GET | Сверка шаблона отчёта с настроенными источниками, только чтение (админ) |
| `api/admin/reports/{reportId}/datasources/sync-template` | POST | Синхронизация источников отчёта с шаблоном (админ) |

## 11. Экспорт в XLSX — настройки и типичные проблемы

FastReport поддерживает 4 режима экспорта в Excel, настраиваемые через ExportSettings отчёта (API: `PUT /app/v1.1/api/reports/{id}/exportSettings`):

| Режим | Поле настроек | Поведение |
|-------|----------|-----------|
| **Wysiwyg** | `Wysiwyg: true` | Точное визуальное воспроизведение. FR воссоздаёт позиции элементов через объединённые ячейки. Дефолт |
| **DataOnly** | `DataOnly: true` | Только данные без форматирования. Без объединённых ячеек. Подходит для дальнейшей обработки |
| **Seamless** | `Seamless: true` | Без разрывов страниц, непрерывная таблица |
| **PrintOptimized** | `PrintOptimized: true` | Оптимизация для печати (отступы, масштаб) |

**Причина:** режим Wysiwyg (по умолчанию). FastReport позиционирует каждый элемент шаблона абсолютно (X, Y, Width, Height). При экспорте в XLSX координаты конвертируются в ячейки сетки. Если элементы не выровнены по единой сетке — FR создаёт дополнительные колонки/строки и объединяет ячейки для сохранения визуального расположения.

**Решения:**

1. **DataOnly=true** — убирает все объединённые ячейки. Подходит если нужны только данные
2. **Выравнивание элементов в шаблоне** — в FR Designer включить привязку к сетке, выровнять все элементы по одной сетке колонок. Чем меньше уникальных X-координат — тем меньше объединённых ячеек
3. **Table-объект вместо свободных Band-элементов** — Table в FR не создаёт лишних колонок
4. **SplitPages=false** — если объединённые ячейки появляются на границах страниц

```json
{
  "xlsxExportSettings": {
    "wysiwyg": true,
    "pageBreaks": false,
    "splitPages": false,
    "dataOnly": false,
    "seamless": false,
    "printOptimized": false
  }
}
```

Таблица БД: `Reports.ExportSettings` (NVARCHAR MAX, JSON). Миграция v2.178.
