---
name: edt-skd
description: Проектирование и генерация отчётов на Системе компоновки данных (СКД / DCS) для «1С:Предприятие» в проектах 1C:EDT — структура файла схемы .dcs, наборы данных, роли полей, ресурсы, вычисляемые поля, параметры, связи наборов, настройки/варианты и программная компоновка из BSL. Использовать при создании или правке любого отчёта СКД, в т.ч. через MCP-сервер EDT_MCP (инструменты create_data_composition_schema / add_dcs_*).
---

# СКД — построение отчётов Системы компоновки данных в 1C:EDT

Практический справочник по **СКД** (Система компоновки данных, англ. DCS — Data Composition System) — декларативному механизму отчётов «1С:Предприятие». Скилл — компаньон к [edt-mcp](../edt-mcp/SKILL.md): edt-mcp описывает MCP-инструменты и их баги, **этот** скилл — доменные паттерны СКД и реальный формат файла схемы `.dcs`.

## Модель СКД — как это работает

Разработчик НЕ строит таблицу отчёта вручную. Он декларативно описывает **схему компоновки данных** (источники, поля, ресурсы, параметры) и **настройки** (структуру группировок, отбор, сортировку, оформление); платформа сама генерирует запрос, считает итоги, рисует таблицу/диаграмму, обрабатывает расшифровку.

Этапы компоновки (в каждый можно вмешаться из BSL):
1. Разработчик создаёт **схему** + стандартные настройки.
2. `КомпоновщикМакетаКомпоновкиДанных` соединяет схему и настройки → **макет компоновки**.
3. `ПроцессорКомпоновкиДанных` извлекает и агрегирует данные → **результат**.
4. `ПроцессорВыводаРезультата…` выводит результат в табличный документ / дерево / таблицу значений.

Ключевые сущности схемы:
- **Набор данных** — источник: `Запрос` (язык запросов + расширения СКД), `Объект` (внешние данные из BSL), `Объединение` (контейнер нескольких наборов).
- **Связь наборов** — соединение наборов по полю; в СКД всегда **левое внешнее соединение**.
- **Вычисляемое поле** — поле по формуле на языке выражений СКД.
- **Ресурс** (totalField) — поле, по которому считаются групповые/общие итоги. Для таблиц и диаграмм ресурсы **обязательны**.
- **Параметр** — критерий получения данных (период, отбор).
- **Роль поля** — пометка `Измерение`/`Период`/`Остаток`/`Счёт`, по которой СКД правильно считает остатки и обороты.
- **Настройки / варианты** — стартовая структура отчёта; у отчёта может быть несколько вариантов.

## Файл схемы: `.dcs`

В формате 1C:EDT схема хранится как **макет объекта Report**:

```
src/Reports/<Отчёт>/Templates/<ИмяМакета>/Template.dcs
```

- Стандартное имя макета основной схемы в типовых конфигурациях — **`ОсновнаяСхемаКомпоновкиДанных`** (тогда из BSL: `ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных")`). MCP-инструмент `create_data_composition_schema` принимает `templateName` (default может отличаться — проверь и при необходимости задай явно). Имя макета в `.mdo` отчёта и в `ПолучитьМакет(...)` должны совпадать.
- Один отчёт почти всегда = одна схема; несколько `.dcs` у одного отчёта — редкое исключение.
- Кодировка — **UTF-8 без BOM**. Правки делать Edit-инструментом или MCP, **не** PowerShell `Set-Content` (ломает кириллицу — см. edt-mcp).

### Корень и пространства имён (фиксированы)

```xml
<?xml version="1.0" encoding="UTF-8"?>
<DataCompositionSchema xmlns="http://v8.1c.ru/8.1/data-composition-system/schema"
    xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common"
    xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core"
    xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings"
    xmlns:v8="http://v8.1c.ru/8.1/data/core"
    xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
```

`dcscom` — роли полей; `dcscor` — параметры/значения; `dcsset` — настройки вариантов; `v8`/`v8ui` — типы данных и UI. Локально (на конкретных элементах) объявляются `dcsat` (макеты областей) и `style/sys/web/win` (на `<dcsset:settings>`).

### Порядок дочерних элементов корня

```
dataSource → dataSet(s) → calculatedField* → totalField* → parameter* → template* → nestedSchema* → dataSetLink* → settingsVariant+
```

`dataSource` первым, `settingsVariant` последним — строго. Порядок средних элементов EDT-валидатор переносит мягко (в реальных схемах `dataSetLink` встречается и до, и после `totalField`), и EDT всё равно нормализует файл при сохранении. При ручной правке держись порядка из уже работающего файла.

### Карта элементов

| Элемент | Назначение |
|---|---|
| `<dataSource>` | Источник: `<name>` + `<dataSourceType>Local</dataSourceType>`. Обычно один. |
| `<dataSet xsi:type="DataSetQuery">` | Набор-запрос: `<name>`, список `<field>`, `<dataSource>`, `<query>`. |
| `<dataSet xsi:type="DataSetObject">` | Набор-объект: вместо `<query>` — `<objectName>` (данные передаются из BSL). |
| `<dataSet xsi:type="DataSetUnion">` | Объединение: общие `<field>` + вложенные `<item xsi:type="DataSetQuery">`. |
| `<calculatedField>` | Вычисляемое поле: `<dataPath>`, `<expression>`, `<title>`, `<appearance>`. |
| `<totalField>` | Ресурс (итог): `<dataPath>`, `<expression>`; опц. `<groupItems>`. |
| `<parameter>` | Параметр схемы: `<name>`, `<valueType>`, `<value>`, `<useRestriction>`, опц. `<expression>`, `<use>`. |
| `<dataSetLink>` | Связь наборов: `<sourceDataSet>`, `<destinationDataSet>`, `<sourceExpression>`, `<destinationExpression>`. |
| `<nestedSchema>` | Вложенная схема: `<name>`, `<title>`, `<schema>` (полная вложенная `.dcs`). |
| `<template>` | Предопределённый макет области оформления (`dcsat:AreaTemplate`). |
| `<settingsVariant>` | Вариант отчёта: `<dcsset:name>`, `<dcsset:presentation>`, `<dcsset:settings>`. |

### Текст запроса — это plain text, НЕ CDATA

`<query>` — обычный текстовый узел. Спецсимволы экранируются XML-сущностями:

- `<`  →  `&lt;`     `>`  →  `&gt;`     `&`  →  `&amp;`
- параметр запроса `&Параметр`  →  в XML  `&amp;Параметр`
- `<>` (не равно)  →  `&lt;&gt;`

Переводы строк сохраняются буквально. MCP-инструменты экранирование делают сами — экранировать вручную надо только при прямой правке `.dcs` Edit-инструментом.

## Рабочий процесс через EDT_MCP

MCP-сервер покрывает СКД одиннадцатью инструментами (точные аргументы — в [edt-mcp](../edt-mcp/SKILL.md)):

| Что покрыто | Инструмент |
|---|---|
| Создать схему-макет у отчёта | `create_data_composition_schema` |
| Набор-запрос с текстом запроса | `add_dcs_data_set_query` |
| Поле набора данных | `add_dcs_field` |
| Параметр схемы | `add_dcs_parameter` |
| Вычисляемое поле | `add_dcs_calculated_field` |
| Ресурс (итоговое поле) | `add_dcs_total_field` |
| Связь наборов | `add_dcs_dataset_link` |
| Переписать текст запроса набора | `set_dcs_query_text` |
| Группировка в `settingsVariant` (Items/Hierarchy) | `add_dcs_setting_grouping` |
| Условие отбора в `settingsVariant` | `add_dcs_setting_filter` |
| Значение параметра в `settingsVariant` | `set_dcs_setting_parameter_value` |

**Чего инструментов НЕТ — правится прямой Edit-правкой `.dcs`:**
- наборы `DataSetObject` и `DataSetUnion`;
- роли полей (`<role>` — `dimension`, `period`, `balance`);
- структура `settingsVariant` за пределами grouping/filter/parameter-value: выбранные поля (`selection`), сортировка (`order`), условное оформление (`conditionalAppearance`), параметры вывода (`outputParameters`);
- производные параметры (`<expression>&Период.ДатаНачала`), типы `StandardPeriod`;
- предопределённые макеты `<template>`, вложенные схемы `<nestedSchema>`.

MCP-инструменты создают **минимальную** валидную схему — selection/order/conditionalAppearance в `settingsVariant` и роли полей почти всегда дописываются вручную. После генерации **всегда читай `.dcs` с диска** и дорабатывай.

### Базовый рецепт (один набор, период, ресурс)

```jsonc
[
  { "tool": "create_md_object", "args": { "project": "X", "kind": "Report", "name": "МойОтчет" } },
  { "tool": "create_data_composition_schema", "args": {
      "project": "X", "reportFqn": "Report.МойОтчет",
      "templateName": "ОсновнаяСхемаКомпоновкиДанных" } },
  { "tool": "add_dcs_data_set_query", "args": {
      "project": "X", "reportFqn": "Report.МойОтчет", "dataSetName": "НаборДанных",
      "query": "ВЫБРАТЬ РАЗРЕШЕННЫЕ Т.Номенклатура КАК Номенклатура, Т.КоличествоОборот КАК Количество ИЗ РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Т" } },
  { "tool": "add_dcs_parameter", "args": {
      "project": "X", "reportFqn": "Report.МойОтчет", "parameterName": "НачалоПериода", "valueType": "Date" } },
  { "tool": "add_dcs_parameter", "args": {
      "project": "X", "reportFqn": "Report.МойОтчет", "parameterName": "КонецПериода", "valueType": "Date" } },
  { "tool": "add_dcs_total_field", "args": {
      "project": "X", "reportFqn": "Report.МойОтчет", "dataPath": "Количество", "expression": "Сумма(Количество)" } }
]
```

Затем — прочитать `.dcs`, при необходимости вписать `settingsVariant` со структурой группировок и параметр-период `StandardPeriod` (см. П2), затем `check_run` + деплой.

### ⚠️ Текст запроса — только по фактическим метаданным

**`check_run` ошибки в тексте запроса СКД НЕ ловит.** «Поле не найдено» / «Таблица не найдена» всплывут только в рантайме 1С при открытии отчёта. Перед написанием любого `query` сверь по `.mdo` (через `list_project_files` + Read), что КАЖДАЯ таблица, реквизит, измерение/ресурс регистра и стандартный реквизит реально существуют. Не угадывай «стандартные» имена: реквизит-контрагент бывает `Контрагент`/`Партнёр`/`Клиент`; `ЭтоГруппа`/`Родитель` есть только у иерархических справочников.

---

# Паттерн-каталог

Каждый паттерн: **когда** → **как** (схема/запрос/настройки) → **подводные камни**.

## П1. Отчёт «один набор-запрос» (база)

**Когда:** простой отчёт из одного источника ИБ. Фундаментальный паттерн — подавляющее большинство отчётов строятся так.

**Как:** один `DataSetQuery`; текст запроса с `ВЫБРАТЬ РАЗРЕШЕННЫЕ` (учёт прав RLS); поля набора при автозаполнении выводятся из запроса; ресурсы — на `<totalField>`; структуру (группировки) — в `settingsVariant`.

**Камни:** `ВЫБРАТЬ РАЗРЕШЕННЫЕ` почти обязательно для прикладных отчётов. Поля группировок можно не дублировать в выбранных полях — выводятся автополем.

## П2. Параметры периода

**Когда:** почти любой отчёт строится за период.

**Как (канон — `СтандартныйПериод`):** пользователь выбирает «Этот месяц» / «Прошлый месяц». В `.dcs` три параметра: видимый `Период` типа `StandardPeriod` + два **производных** `НачалоПериода`/`КонецПериода`, вычисляемых через `<expression>`:

```xml
<parameter>
  <name>Период</name>
  <title xsi:type="v8:LocalStringType"><v8:item><v8:lang>ru</v8:lang><v8:content>Период</v8:content></v8:item></title>
  <valueType><v8:Type>v8:StandardPeriod</v8:Type></valueType>
  <value xsi:type="v8:StandardPeriod">
    <v8:variant xsi:type="v8:StandardPeriodVariant">Custom</v8:variant>
    <v8:startDate>0001-01-01T00:00:00</v8:startDate>
    <v8:endDate>0001-01-01T00:00:00</v8:endDate>
  </value>
  <useRestriction>false</useRestriction>
  <use>Always</use>
</parameter>
<parameter>
  <name>НачалоПериода</name>
  <valueType><v8:Type>xs:dateTime</v8:Type>
    <v8:DateQualifiers><v8:DateFractions>Date</v8:DateFractions></v8:DateQualifiers></valueType>
  <value xsi:type="xs:dateTime">0001-01-01T00:00:00</value>
  <useRestriction>true</useRestriction>
  <expression>&amp;Период.ДатаНачала</expression>
</parameter>
<!-- КонецПериода — аналогично, expression = &amp;Период.ДатаОкончания -->
```

В тексте запроса использовать `&НачалоПериода` / `&КонецПериода`. В `settingsVariant` задать значение по умолчанию через `<dcsset:dataParameters>` (например `ThisMonth`).

**Камни:**
- `СтандартныйПериод`: `ДатаНачала` = `00:00:00`, `ДатаОкончания` = `23:59:59` — последний день включается, поправка не нужна.
- Если используется простой параметр `Дата` (без StandardPeriod) с `Состав даты = Дата` — интервал считается до `00:00:00` последнего дня, данные последнего дня выпадают. Лечение — `<expression>` параметра `КонецПериода`: `КонецПериода(&КонецПериода, "День")`.
- `<use>` = `Always` (используется всегда, флажка у пользователя нет) или `Auto` (флажок виден).

## П3. Ресурсы — итоговые поля (`<totalField>`)

**Когда:** нужны групповые/общие итоги. Для таблиц и диаграмм — **обязательно**.

**Как:** `<totalField>` с `<dataPath>` (имя поля) и `<expression>` (агрегат): `Сумма(Сумма)`, `Количество(Различные Контрагент)`, `Максимум(Цена)`, `Среднее(Цена)`. Опциональный `<groupItems>` ограничивает группировки, по которым считается ресурс (используется редко — обычно ресурсы глобальные). MCP: `add_dcs_total_field` (`dataPath`, `expression`, `groupKeys`).

**Камни:**
- Простое `Сумма(...)` не всегда верно. Для производных величин задавай своё выражение: `Сумма(Собрано) * (Среднее(ЦенаПродажи) - Среднее(ЦенаЗакупки))`.
- Одно поле может быть ресурсом несколько раз — разные формулы для разных группировок (через `groupItems`). Разные формулы одного поля для **одной** группировки недопустимы.
- Для числовых ресурсов платформа сама создаёт подчинённые `ПроцентВГруппе`, `ПроцентВИерархии`, `ПроцентОбщий` — их можно выводить как обычные поля.

## П4. Вычисляемые поля (`<calculatedField>`)

**Когда:** поле получается формулой над полями набора (`Прибыль = Выручка - Себестоимость`).

**Как:** `<calculatedField>` с `<dataPath>` (имя поля), `<expression>` (язык выражений СКД), опц. `<title>` и `<appearance>` (формат, выравнивание). MCP: `add_dcs_calculated_field`.

```xml
<calculatedField>
  <dataPath>ПрибыльПолная</dataPath>
  <expression>ВЫБОР КОГДА ОстатокКОплате = 0 ТОГДА Выручка - Себестоимость ИНАЧЕ 0 КОНЕЦ</expression>
  <title xsi:type="v8:LocalStringType"><v8:item><v8:lang>ru</v8:lang><v8:content>Прибыль полная</v8:content></v8:item></title>
  <appearance>
    <dcscor:item xsi:type="dcsset:SettingsParameterValue">
      <dcscor:parameter>Формат</dcscor:parameter>
      <dcscor:value xsi:type="v8:LocalStringType"><v8:item><v8:lang>ru</v8:lang><v8:content>ЧДЦ=2</v8:content></v8:item></dcscor:value>
    </dcscor:item>
  </appearance>
</calculatedField>
```

**Камни:** в выражении вычисляемого поля **нельзя** использовать другие вычисляемые поля. Можно: поля наборов, конструкции языка выражений СКД, экспортные функции общих модулей. Вычисляемое поле можно сделать ресурсом (добавить `<totalField>` с тем же `dataPath`).

## П5. Связь наборов данных (`<dataSetLink>`)

**Когда:** связанные данные из 2+ наборов — когда удобнее не одним сложным запросом.

**Как:** два набора-запроса; на каждую пару связуемых полей — отдельный `<dataSetLink>`:

```xml
<dataSetLink>
  <sourceDataSet>Структура</sourceDataSet>
  <destinationDataSet>Суммы</destinationDataSet>
  <sourceExpression>Документ</sourceExpression>
  <destinationExpression>Документ</destinationExpression>
</dataSetLink>
```

MCP: `add_dcs_dataset_link` (`source`, `destination`, `sourceExpression`, `destinationExpression`).

**Камни:**
- Связь СКД — всегда **левое внешнее соединение**: source = родительский набор (все его записи попадут в отчёт), destination = зависимый. Выбор «кто source» критичен.
- Связь по нескольким полям = несколько `<dataSetLink>` с одинаковыми source/destination.
- **Итоги.** При связи наборов СКД каждая запись учитывается в итоге один раз — итог верный. При соединении в самом запросе (`ЛЕВОЕ СОЕДИНЕНИЕ` внутри `<query>`) дублирующиеся строки **задваивают** общий итог. ⇒ для корректных итогов из нескольких источников — связывать наборами, а не соединять в запросе.
- Глобальный отбор по полю зависимого набора превращает все связи во **внутренние** соединения.

## П6. Связь наборов по периодам

**Когда:** совместить остатки (помесячно) и обороты (за тот же месяц) из разных регистров.

**Как:** СКД связывает только по полям ⇒ в обоих наборах должны быть поля `НачалоПериода`/`КонецПериода`. В наборе остатков их добавляют через `КОНЕЦПЕРИОДА(Т.Период, МЕСЯЦ)`; в наборе оборотов — как `&Параметр КАК НачалоПериода`. Создать `<dataSetLink>` по `Номенклатура` + `НачалоПериода` + `КонецПериода`. Значения дат из родительского набора подставляются в параметры виртуальной таблицы зависимого (через колонку «Параметр» связи; MCP `add_dcs_dataset_link` имеет аргумент `parameter`).

**Камни:** если у зависимого набора-запроса с виртуальной таблицей оставить **Автозаполнение**, параметры ВТ заполнятся отчётным периодом целиком, а не значениями связи → данные не разобьются по месяцам и задвоятся. Лечение — выключить автозаполнение, задать поля и роли вручную секцией `{ВЫБРАТЬ ...}`.

## П7. Набор-объединение (`DataSetUnion`)

**Когда:** в отчёт нужны ВСЕ записи из нескольких источников без связывания (поступления + продажи рядом).

**Как:** `<dataSet xsi:type="DataSetUnion">` содержит сначала **общие поля** объединения, затем дочерние наборы-члены `<item xsi:type="DataSetQuery">` (или `DataSetObject`) — каждый со своим `<name>`, полями, источником и запросом. Поля членов сопоставляются по позиции/имени; имена приводят к согласованным (`Количество` → `Поступило` / `Продано`).

**Камни:** объединение ≠ связь. Связь даёт записи зависимого набора только по условию; объединение — все записи всех членов. MCP-инструмента для Union нет — собирать прямой Edit-правкой `.dcs` по образцу.

## П8. Набор-объект (`DataSetObject`) + программная компоновка

**Когда:** данные — не из запроса к ИБ, а из BSL (таблица значений, табличная часть, результат произвольного кода); печатные формы.

**Как:** `<dataSet xsi:type="DataSetObject">`: вместо `<query>` — `<objectName>` (имя, под которым данные передаются из BSL). Поля **описываются вручную** (`<field>`), их имена обязаны совпасть с именами полей в передаваемых данных. Компоновка — программная, см. П14.

**Камни:** имя в `<objectName>` = ключ структуры `ВнешниеНаборыДанных` в коде. Оформление (формат) полю набора-объекта напрямую задать нельзя — поле дублируют в родительский набор-объединение и оформляют там.

## П9. Роли полей и корректные остатки/обороты ⚠️

**Когда:** отчёт по регистру накопления/бухгалтерии с полями остатка или с детализацией. **Неверные роли → молча неверные числа.**

**Как:** роли пишутся в `<role>` поля, namespace `dcscom`:

```xml
<role><dcscom:dimension>true</dcscom:dimension></role>                  <!-- измерение -->
<role><dcscom:dimension>true</dcscom:dimension>
      <dcscom:required>true</dcscom:required></role>                    <!-- обязательное измерение -->
<role><dcscom:periodNumber>1</dcscom:periodNumber>
      <dcscom:periodType>Main</dcscom:periodType></role>                <!-- поле-период -->
<role><dcscom:balance>true</dcscom:balance>
      <dcscom:balanceGroupName>Количество</dcscom:balanceGroupName>
      <dcscom:balanceType>ClosingBalance</dcscom:balanceType></role>    <!-- балансовое поле -->
```

Правила корректности остатков:
- **Измерение** — все поля, в разрезе которых берётся остаток, помечать `dimension`. Реквизит измерения (`Номенклатура.ВидНоменклатуры`) — тоже `dimension`, и в запросе должно присутствовать само измерение (`Номенклатура`).
- **Период** — `periodNumber` нумеруется непрерывно с 1; меньший номер = более точный период (`Регистратор` < `ПериодСекунда` < `ПериодДень` < … < `ПериодГод`). `periodType`: `Main` / `Additional`. При выборе поля-периода в запросе должно присутствовать его родительское поле-период.
- **Остаток/баланс** — парные поля (`...НачальныйОстаток` / `...КонечныйОстаток`) должны иметь **одинаковый** `balanceGroupName`; непарные — разные. В запросе обязательно должно быть **парное** поле остатка. `balanceType`: `OpeningBalance` / `ClosingBalance`.
- **Обязательное** (`required`) — поле всегда включается в результирующий запрос, даже если не выведено в настройках. Нужно для измерений, от которых зависят вычисляемые поля/ресурсы: СКД выбрасывает из запроса поля, не участвующие в настройках → без `required` суммы могут «схлопнуться».

**Камни:** при включённом Автозаполнении набора-запроса роли проставляются автоматически. Ручная установка нужна для наборов-объектов и при неверном автозаполнении. `check_run` неверные роли не ловит — проверяется только рантайм-сверкой чисел.

## П10. Характеристики

**Когда:** вывести/отбирать произвольные пользовательские свойства объекта (план видов характеристик + регистр сведений со значениями).

**Как:** секция-расширение в тексте запроса:

```
{ХАРАКТЕРИСТИКИ
  ТИП(Справочник.Контрагенты)
  ВИДЫХАРАКТЕРИСТИК ПланВидовХарактеристик.ВидыХарактеристик
  ПОЛЕКЛЮЧА Ссылка ПОЛЕИМЕНИ Наименование ПОЛЕТИПАЗНАЧЕНИЯ ТипЗначения
  ЗНАЧЕНИЯХАРАКТЕРИСТИК РегистрСведений.ДополнительныеХарактеристики
  ПОЛЕОБЪЕКТА Объект ПОЛЕВИДА ВидХарактеристики ПОЛЕЗНАЧЕНИЯ ЗначениеХарактеристики}
```

Альтернатива — описать характеристики в свойстве `Характеристики` самого объекта конфигурации (универсально для всех отчётов). Для характеристик-флагов (наличие признака) — опустить `ПОЛЕТИПАЗНАЧЕНИЯ` (→ `Булево`) и `ПОЛЕЗНАЧЕНИЯ` (→ `Истина`, если запись есть).

**Камни:** поля-характеристики появляются только в режиме 1С:Предприятие (после выполнения запроса характеристик) — в Конфигураторе/EDT их не видно. Настройки по характеристикам сохраняются лишь в отдельном пользовательском варианте отчёта.

## П11. Иерархия

**Стандартная:** у группировки в `<dcsset:groupItems>` поле с `<dcsset:groupType>Hierarchy</dcsset:groupType>` (вместо `Items`) — промежуточные итоги по группам справочника.

**Произвольная (иерархия по своему полю / для неиерархического объекта):** отдельный набор «Иерархия» с полями `текущий` и `родитель`; `<dataSetLink>` набора **к самому себе** (`sourceExpression` = поле-родитель, `destinationExpression` = поле-элемент), для иерархии детальных записей — с `<startExpression>` (корень дерева, например `""` или `Значение(Справочник.X.ПустаяСсылка)`):

```xml
<dataSetLink>
  <sourceDataSet>Иерархия</sourceDataSet>
  <destinationDataSet>Иерархия</destinationDataSet>
  <sourceExpression>ИдентификаторРодителя</sourceExpression>
  <destinationExpression>ИдентификаторСтроки</destinationExpression>
  <startExpression>""</startExpression>
</dataSetLink>
```

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

## П12. Структура отчёта и настройки (`settingsVariant`)

**Когда:** всегда — `settingsVariant` определяет, как отчёт выглядит при открытии. Минимум один вариант обязателен.

**Структура** `<dcsset:settings>` (порядок важен): `selection` → `filter` → `order` → `dataParameters` → `outputParameters` → `conditionalAppearance` → элементы структуры (`StructureItem*`).

Элементы структуры отчёта:
- **`dcsset:StructureItemGroup`** — группировка (линейный вывод по строкам, итоги по вертикали).
- **`dcsset:StructureItemTable`** — таблица (группировки по строкам и колонкам, ресурсы на пересечении).
- **`dcsset:StructureItemChart`** — диаграмма.

Группировка с вложенными группировками (реальный фрагмент: Документ → Контрагент → Договор):

```xml
<dcsset:item xsi:type="dcsset:StructureItemGroup">
  <dcsset:groupItems>
    <dcsset:item xsi:type="dcsset:GroupItemField">
      <dcsset:field>Документ</dcsset:field>
      <dcsset:groupType>Items</dcsset:groupType>
      <dcsset:periodAdditionType>None</dcsset:periodAdditionType>
      <dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>
      <dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>
    </dcsset:item>
  </dcsset:groupItems>
  <dcsset:order><dcsset:item xsi:type="dcsset:OrderItemAuto"/></dcsset:order>
  <dcsset:selection><dcsset:item xsi:type="dcsset:SelectedItemAuto"/></dcsset:selection>
  <!-- вложенная группировка — снова <dcsset:item xsi:type="dcsset:StructureItemGroup"> -->
  <dcsset:itemsViewMode>Normal</dcsset:itemsViewMode>
</dcsset:item>
```

- Группировка без полей (`groupItems` пуст) = «Детальные записи». `groupType`: `Items` (только элементы) / `Hierarchy` / `HierarchyOnly`.
- `<dcsset:selection>` с `<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>` — автополе (все доступные поля). Конкретное поле — `dcsset:SelectedItemField` + `<dcsset:field>Имя</dcsset:field>`.
- Системные поля — через `<dcsset:field>` со спец-именами: `SystemFields.SerialNumber` (№ п/п), `SystemFields.Level`.
- Параметры значений — `<dcsset:dataParameters>`; параметры вывода (`Заголовок`, `ВыводитьЗаголовок`, `ВертикальноеРасположениеОбщихИтогов`) — `<dcsset:outputParameters>`. Каждый настраиваемый элемент несёт `<dcsset:userSettingID>` (GUID — генерировать при ручном добавлении).

**Несколько вариантов:** добавить ещё `<settingsVariant>` с другим `<dcsset:name>` — те же наборы/ресурсы/параметры, другая структура.

## П13. Условное оформление

**Когда:** подсветить строки по условию (просрочка — красным). Широко распространено.

**Как:** `<dcsset:conditionalAppearance>` внутри `<dcsset:settings>`, каждый `<dcsset:item>` содержит: `<dcsset:selection>` (оформляемые поля, пусто = все), `<dcsset:filter>` (условие), `<dcsset:appearance>` (оформление), `<dcsset:presentation>` (имя для пользователя):

```xml
<dcsset:conditionalAppearance>
  <dcsset:item>
    <dcsset:selection/>
    <dcsset:filter>
      <dcsset:item xsi:type="dcsset:FilterItemComparison">
        <dcsset:left xsi:type="dcscor:Field">ДолгПросрочен</dcsset:left>
        <dcsset:comparisonType>Greater</dcsset:comparisonType>
        <dcsset:right xsi:type="xs:decimal">0</dcsset:right>
      </dcsset:item>
    </dcsset:filter>
    <dcsset:appearance>
      <dcscor:item xsi:type="dcsset:SettingsParameterValue">
        <dcscor:parameter>ЦветТекста</dcscor:parameter>
        <dcscor:value xsi:type="v8ui:Color">web:red</dcscor:value>
      </dcscor:item>
    </dcsset:appearance>
    <dcsset:presentation xsi:type="v8:LocalStringType">
      <v8:item><v8:lang>ru</v8:lang><v8:content>Просрочка</v8:content></v8:item>
    </dcsset:presentation>
  </dcsset:item>
</dcsset:conditionalAppearance>
```

**Камни:** всегда задавай `<dcsset:presentation>` — иначе пользователь видит сырое условие. `comparisonType`: `Equal`/`NotEqual`/`Greater`/`GreaterOrEqual`/`Less`/`LessOrEqual`/`InList`/`InHierarchy`. Правое значение: `dcscor:DesignTimeValue` (выражение-конструктор: `Перечисление.X.Значение`), `xs:decimal`, `v8:ValueListType` (список).

## П14. Программная компоновка из BSL

**Когда:** вывод в нестандартный формат, печатные формы, наборы-объекты, фоновое формирование.

**Канонический цикл** (модуль отчёта / обработки):

```bsl
// 1. Схема и настройки
СхемаКД = Отчеты.МойОтчет.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаКД.НастройкиПоУмолчанию;

// 2. Внешние наборы (только для DataSetObject) — ключ = <objectName> в схеме
ВнешниеНаборы = Новый Структура;
ВнешниеНаборы.Вставить("ДанныеПоиска", ТаблицаЗначений);

// 3. Объект расшифровки (опционально)
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;

// 4. Макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКД, Настройки, ДанныеРасшифровки);

// 5. Процессор компоновки
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКомпоновки, ВнешниеНаборы, ДанныеРасшифровки);

// 6. Вывод в табличный документ
ДокументРезультат = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(Процессор);
```

**Вывод в дерево/таблицу значений** (для программной обработки данных):
- в `КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"))`;
- `ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений` + `.УстановитьОбъект(ДеревоЗначений)` (без `УстановитьОбъект` → таблица значений).
- Ограничение: в настройках допускаются только группировки и детальные записи (без таблиц/диаграмм/вложенных отчётов); условное оформление и предопределённые макеты игнорируются.

**Установка параметров из формы отчёта:**
- `ПередЗагрузкойВариантаНаСервере(Настройки)` — `Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", '20240101')`;
- `ПередЗагрузкойПользовательскихНастроекНаСервере(Настройки)` — `Настройки.Элементы[0].Значение = …; Настройки.Элементы[0].Использование = Истина;` (нужно, если настройка вынесена в быстрые пользовательские и пользователь её менял).

**Авто-формирование / фон:** в `ПриСозданииНаСервере` — `Параметры.СформироватьПриОткрытии = Истина`; фон — `СкомпоноватьРезультат(РежимКомпоновкиРезультата.Фоновый)`.

## П15. Вложенная схема (`<nestedSchema>`)

**Когда:** для каждой строки основного отчёта показать блок из другого готового отчёта. Редкий паттерн.

**Как:** `<nestedSchema>` несёт `<name>`, `<title>` и `<schema>` с полной вложенной `.dcs` внутри. В структуре основного отчёта добавить элемент «Вложенный отчёт», связать по общему полю через отбор `ОбъектНастройки.Владелец.<Поле>`.

---

# Язык запросов СКД — расширения `{...}`

Часть текста запроса в **фигурных скобках** интерпретируется СКД отдельно от обычного запроса:

- `{ВЫБРАТЬ Поле1, Поле2, Поле.*}` — список полей набора, доступных в настройках (`Поле.*` — поле и все его реквизиты). Нужен при выключенном Автозаполнении.
- `{ГДЕ Условие}` — пользовательский отбор: условие применяется, только если пользователь задал значение параметра.
- `{(Поле1).*, (Поле2).*}` в параметрах виртуальной таблицы — поля, по которым разрешён отбор на ВТ.
- `{&ИмяПараметра}` в позиции параметра ВТ — параметр компоновки (управляется из настроек), в отличие от обычного `&Параметр`.
- `{ХАРАКТЕРИСТИКИ ...}` — см. П10.

Виртуальные таблицы: периодичность задаётся параметром (`РегистрНакопления.Продажи.Обороты(&Начало, &Конец, Месяц, ...)`) — от неё зависит доступность поля `Период`. Без периодичности группировка по периодам невозможна.

# Язык выражений СКД

Отдельный от BSL язык — для вычисляемых полей, ресурсов, условного оформления. Подмножество выражений + спец-функции:

- Агрегатные: `Сумма(...)`, `Количество(...)`, `Количество(Различные ...)`, `Максимум`, `Минимум`, `Среднее`.
- `ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ` (в XML `<>` → `&lt;&gt;`).
- `ВычислитьВыражение("Сумма(Стоимость)", "Контрагент", "ОбщийИтог")` — расчёт в контексте другой группировки/области. Области: `"ОбщийИтог"`, имя группировки, `"Иерархия"`; границы записей: `"Первая"`, `"Текущая"`, `"Последняя"` (накопительные итоги).
- `ВычислитьВыражениеСГруппировкойМассив("Сумма(...)", "Номенклатура")` — массив значений по вложенной группировке.
- `Массив(Различные Поле)` — список значений в ячейке.
- Можно вызывать **экспортные** функции общих модулей (в вычисляемых полях и ресурсах; в пользовательских полях — нельзя).

Типовые приёмы: процент к родителю — `Сумма(Стоимость)*100 / ВычислитьВыражение("Сумма(Стоимость)", "Контрагент")`; накопительный итог — `ВычислитьВыражение("Сумма(Стоимость)", , , "Первая", "Текущая")`.

---

# Функциональные опции ERP скрывают поля отчёта

В 1С:ERP/УТ видимость многих реквизитов документов и справочников управляется **функциональными опциями** (ФО). Если ФО выключена в ИБ, реквизит скрыт — и **платформа автоматически убирает из доступных полей отчёта СКД любое поле/группировку, построенное на реквизите, закрытом ФО**. Поле молча пропадает из «Выбора поля отчёта», группировки и выбранные поля со ссылкой на него отбрасываются. `check_run` это НЕ ловит — проявляется только в рантайме при открытии отчёта.

Бьёт по кастомным отчётам жёстко: корректное поле схемы просто не появляется — **независимо от архитектуры схемы** (один набор / связь наборов / прямая колонка — без разницы). Легко потерять часы, перебирая схему, хотя причина вне отчёта.

**Пример — `Контрагент`.** Реквизит `Document.РеализацияТоваровУслуг.Attribute.Контрагент` (и ~80 др. объектов) входит в Состав ФО `ИспользоватьПартнеровИКонтрагентов`. Если ИБ в режиме «партнёры как контрагенты» (эта ФО выкл.), поле `Контрагент` в отчёте исчезает. Решение — строить отчёт на реквизите `Партнер` (в продажах он и отображается как «Клиент»).

Механизм двухслойный:
1. **Платформа (главное):** реквизит в Составе ФО → ФО выкл. → реквизит скрыт → платформа выкидывает поле из доступных полей отчёта.
2. **Код конфигурации (доп.):** `ОбщийМодуль.ОтчетыУТПереопределяемый.НастроитьПараметрыОтборыПоФункциональнымОпциям` (вызывается из `ПередЗагрузкойВариантаНаСервере` для КАЖДОГО отчёта, включая отчёты расширений) дополнительно вычищает из настроек любого отчёта отборы/группировки/параметры по этим полям через `КомпоновкаДанныхСервер.Удалить*ИзВсехНастроекОтчета(...)`.

**Поля, которые ERP убирает из отчётов по ФО** (перечень — из процедуры `НастроитьПараметрыОтборыПоФункциональнымОпциям` и Составов ФО):

| Поле отчёта | Функциональная опция |
|---|---|
| `Контрагент`, `АналитикаОборотов.Контрагент` | `ИспользоватьПартнеровИКонтрагентов`, `ИспользоватьПартнеровКакКонтрагентов` |
| `Договор` | `ИспользоватьДоговорыСКлиентами`, `ИспользоватьДоговорыСПоставщиками` |
| `Организация`, `СтруктураПредприятия.Организация` | `ИспользоватьНесколькоОрганизаций` |
| `Подразделение`, `АналитикаОборотов.Подразделение` | `ИспользоватьПодразделения` |
| `Склад`, `СтруктураПредприятия.Склад` | `ИспользоватьНесколькоСкладов` |
| `Касса` | `ИспользоватьНесколькоКасс` |
| `БанковскийСчет` | `ИспользоватьНесколькоРасчетныхСчетов` |
| `Характеристика`, `АналитикаНоменклатуры.Характеристика` | `ИспользоватьХарактеристикиНоменклатуры` |
| `Серия`, `АналитикаНоменклатуры.Серия` | `ИспользоватьСерииНоменклатуры` |
| `Валюта` | `ИспользоватьНесколькоВалют` (отчёты без себестоимости), `БазоваяВерсия` |
| `ВидЦены` | `ИспользоватьНесколькоВидовЦен` |
| `ЕдиницыКоличества` | `ИспользоватьЕдиницыИзмеренияДляОтчетов` |
| `НаправлениеДеятельности` | учёт по направлениям деятельности |

**Диагностика:** поле есть в `.dcs`, схема валидна, `check_run` чист — но поле не появляется в отчёте в рантайме → почти наверняка ФО. Быстрая проверка: переименовать поле или сменить реквизит-источник; заработало → дело в ФО.

**Решение:** строить отчёт на реквизите, не закрытом выключенной ФО (вместо `Контрагент` → `Партнер`; вместо `Договор` при выкл. ФО договоров — другой разрез); либо включить нужную ФО (меняет режим всей ИБ — согласовывать с заказчиком).

---

# Отбор по вычисляемому полю проваливается в параметр виртуальной таблицы ⚠️

Если поле набора вычисляется выражением над **регистратором/ссылкой** виртуальной таблицы (например `ВЫБОР … ТОГДА Регистратор.ДокументОснование.Менеджер ИНАЧЕ Регистратор.Менеджер КОНЕЦ КАК Менеджер` над `…Обороты(...)`), и по этому полю задаётся отбор, СКД-оптимизатор проталкивает отбор в 4-й параметр (условие) виртуальной таблицы: `…Обороты(&Нач, &Кон, Регистратор, (Менеджер) = &П)`. При этом он подставляет **голое ИМЯ поля**, игнорируя выражение `ВЫБОР`. Если имя поля совпадает с **реквизитом регистратора** (`Менеджер` есть у документов-регистраторов), платформа в условии ВТ резолвит `(Менеджер)` как `Регистратор.Менеджер` — а это ДРУГОЕ значение (у корректировки реализации собственный `Менеджер` пуст, правильный — в документе-основании). Строки молча пропадают из отчёта при включении отбора. Особенно коварно, когда поле **только в отборе** и не выводится: оптимизатор вообще выкидывает выражение из выборки и оставляет лишь протолкнутое условие.

**Симптом:** без отбора строка в отчёте есть, при включении отбора по полю — исчезает; при этом само поле в выводе показывает правильное значение. `check_run` не ловит — только рантайм/сверка.

**Что НЕ помогает** (проверено программной компоновкой): вложенный подзапрос, временная таблица (`ПОМЕСТИТЬ`), материализация поля в ВТ, явный `ЛЕВОЕ СОЕДИНЕНИЕ`. СКД анализирует зависимости выражения и проталкивает имя в параметр ВТ через любую обёртку тела запроса.

**Решение — разорвать совпадение имени.** Переименовать поле-псевдоним в схеме так, чтобы оно НЕ совпадало с реквизитом регистратора: `КАК Менеджер` → `КАК МенеджерПродажи`. В `.dcs`: у `<field>` поменять `<dataPath>` и `<field>` на новое имя, а прежний заголовок сохранить через `<title>` («Менеджер» — пользователь видит привычное имя); обновить `<totalField><group>` и все места настроек, где поле использовалось. Тогда платформа не находит реквизит с таким именем у регистратора, СКД не может протолкнуть отбор в параметр ВТ — он ложится на выражение (с `ДокументОснование`), и всё считается верно. Тело запроса можно оставить простым (ВТ/JOIN не нужны).

**Диагностика:** программно скомпоновать отчёт с нужным отбором (`КомпоновщикМакетаКомпоновкиДанных.Выполнить(Схема, Настройки, …)`) и сериализовать макет в XML — `СериализаторXDTO.ЗаписатьXML(Запись, Макет)`; в сгенерированном `<query>` набора виден проброс `(Поле) = &П` прямо в параметр виртуальной таблицы. Выполнить компоновку в `ТаблицаЗначений` (через `ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений`) без и с отбором и сравнить наличие строки — быстрый регресс-тест.

---

# Подводные камни

1. **`check_run` не проверяет текст запроса СКД и роли полей.** Ошибки «Поле не найдено», задвоенные итоги, неверные остатки всплывают только в рантайме при открытии отчёта. Проверять — сверкой запроса с `.mdo` и реальным прогоном.
2. **Текст запроса в `.dcs` — plain text с XML-экранированием** (`&lt; &gt; &amp;`). При ручной Edit-правке экранировать самому; MCP-инструменты — сами.
3. **MCP-инструменты создают минимальную схему.** `settingsVariant` со структурой, роли полей, наборы Object/Union, производные параметры, условное оформление — дописывать прямой правкой `.dcs`. После генерации всегда читай `.dcs` с диска.
4. **Итоги из нескольких источников** — связывать наборами (`<dataSetLink>`), а не соединять в `<query>`: соединение в запросе задваивает общий итог.
5. **Остатки** — в запросе всегда брать парные поля остатков + все родительские поля-периоды + сами измерения (не только их реквизиты); проверять роли.
6. **Имена элементов EDT-формата** не интуитивны: `<parameter>` (не `dataParameter`), `<nestedSchema>` (не `nestedDataCompositionSchema`), `<field xsi:type="DataSetFieldField">`. Полиморфизм — через `xsi:type`, его нельзя опускать.
7. **Ссылочные типы** в `<valueType>` пишутся с локальным namespace: `<v8:Type xmlns:d4p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d4p1:CatalogRef.Валюты</v8:Type>`.
8. **`userSettingID`** (GUID) — у каждого настраиваемого элемента отбора/параметра. При ручном добавлении генерировать новый.
9. **Кодировка** `.dcs` — UTF-8 без BOM. Править Edit-инструментом или MCP, не PowerShell `Set-Content`.
10. **Имя макета схемы** в `.mdo` отчёта, в папке `Templates/` и в `ПолучитьМакет(...)` должны совпадать.
11. **Отбор по вычисляемому полю над регистратором ВТ** может проваливаться в параметр виртуальной таблицы по совпадению имени поля с реквизитом регистратора → строки молча теряются. Лечение — переименовать поле-псевдоним (сохранив `<title>`). См. одноимённый раздел выше.

# Чек-лист построения отчёта СКД

1. Определить данные: какие таблицы/регистры, разрезы, итоги, период. **Сверить имена по `.mdo`.**
2. `create_md_object` kind=Report → `create_data_composition_schema`.
3. `add_dcs_data_set_query` — набор(ы) с текстом запроса (`ВЫБРАТЬ РАЗРЕШЕННЫЕ`).
4. `add_dcs_parameter` — параметры (период и др.); для канона периода дописать `StandardPeriod` + производные в `.dcs`.
5. `add_dcs_total_field` — ресурсы (для таблиц/диаграмм обязательно).
6. `add_dcs_calculated_field` — вычисляемые поля при необходимости.
7. `add_dcs_dataset_link` — связи, если наборов несколько.
8. Прочитать `.dcs` с диска. Дописать роли полей (`<role>`), `settingsVariant` со структурой группировок/выбранных полей/отбора, условное оформление.
9. `check_run` + `check_list_markers` — фиксить только BLOCKER (см. edt-mcp).
10. Деплой, открыть отчёт в 1С, проверить числа и состав колонок в рантайме.
