Compare commits

...
10 Commits
Author SHA1 Message Date
Nick ShirokovandClaude Opus 4.7 7fa279c354 feat(skd-edit): clear-conditionalAppearance + multiline patch-query (доки)
- Новая операция clear-conditionalAppearance в стиле clear-selection/
  order/filter. Закрывает потребность "заменить набор правил оформления"
  через clear + re-add.
- patch-query: многострочные подстроки уже работали (string.Replace
  корректно обрабатывает \n). Зафиксировано в SKILL.md.
- add-total: shorthand-шаблон с тремя случаями (Func, Func(expr),
  identity-выражение) — после fix Bug 6 поведение нужно явно объяснить.
- Косметика: убрана утечка XML-внутренностей в комментарии примера
  set-field-role @period.
- Пример patch-query @once заменён на более типовой случай уникальной
  подстроки (КАК ВТ_СтароеИмя вместо ЛЕВОЕ СОЕДИНЕНИЕ).

Регресс: 33/33 PS, 33/33 PY, 33/33 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:39:24 +03:00
Nick ShirokovandClaude Opus 4.7 28a2a34c84 fix(skd-edit): add-total identity expression для не-аггрегатных функций
Раньше "DataPath: X" всегда заворачивалось в X(DataPath). Если X не
аггрегатная функция (например, имя другого ресурса или сам DataPath),
получалось некорректное выражение типа Проверка(Проверка).

Зеркалю логику из skd-compile: whitelist аггрегатных функций
(Сумма, Количество, Минимум, Максимум, Среднее + EN-варианты).
Для остального — identity (использовать funcPart как есть).

Сообщение [OK] теперь показывает фактически записанный expression.

Регресс: 32/32 PS, 32/32 PY, 32/32 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:16:27 +03:00
Nick ShirokovandClaude Opus 4.7 f0f1e88aaa feat(skd-edit): patch-query @once — assert ровно одно вхождение
Защищает от случайных замен в комментариях/совпадениях имён:

  "ЛЕВОЕ СОЕДИНЕНИЕ => ВНУТРЕННЕЕ СОЕДИНЕНИЕ @once"
  # fail, если в запросе 0 или 2+ вхождений

Без флага default — replace-all (как раньше, обратная совместимость).

При успехе сообщение содержит фактическое число вхождений
"(N occurrence(s))", помогает заметить неожиданную множественность
без явного @once.

Регресс: 31/31 PS, 31/31 PY, 31/31 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:00:55 +03:00
Nick ShirokovandClaude Opus 4.7 e7cbf306a0 feat(skd-edit): availableValue — список с replace-семантикой и в add-parameter
- Единый list-синтаксис: availableValue=v1[: p1], v2[: p2], ...
  Элементы через запятую, представление после двоеточия.
- Запятые/двоеточия внутри значений и представлений — в одинарных кавычках:
  availableValue=Окр1: 'руб., коп.', Окр1000: руб.
- add-parameter теперь принимает availableValue= и создаёт начальный список
  в одном вызове (раньше требовался последующий modify-parameter).
- modify-parameter availableValue=... ЗАМЕНЯЕТ весь список (раньше
  append). Согласуется с остальными modify-* для одиночных свойств.
- SKILL.md: добавлен shorthand-шаблон для modify-parameter,
  расширен для add-parameter [availableValue=список].

Существующие тесты мигрированы со старого ;;-batch на новый list-синтаксис.
Снапшоты сохранились (тесты стартовали с пустого списка — semantics
совпадает для greenfield).

Регресс: 29/29 PS, 29/29 PY, 29/29 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:37:56 +03:00
Nick ShirokovandClaude Opus 4.7 610720334b feat(skd-info): kv-параметры роли в детализации поля
В -Mode fields -Name <field> к сводке Role добавляются не-bool
параметры роли (balanceGroupName, balanceType, parentDimension,
accountTypeExpression и т.д.) в формате name=value.

Bool-флаги (@balance, @dimension, ...) отображаются как раньше.
False-значения по-прежнему скрыты.

Регресс: 6/6 PS, 6/6 PY (существующие snapshots не задеты).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:54:03 +03:00
Nick ShirokovandClaude Opus 4.7 5090deb5bc feat(skd-edit): set-field-role — управление ролями поля
Новая операция: полная замена <role>-блока поля dataSet.

- Shorthand: "<dataPath> [@флаги] [kv=значение]"
- Флаги (зеркало skd-compile): @balance, @dimension, @account, @period,
  @required, @autoOrder, @ignoreNullValues
- KV: balanceGroupName, balanceType, parentDimension, accountTypeExpression,
  orderType, expression, periodNumber, periodType
- Пустой spec (только dataPath) — снимает роль целиком
- Поддерживает пакетный режим

Закрывает потребность временного toggle off/on роли при отладке
(было: ручной Edit XML), а также корректировку balance/dimension
после add-total.

Регресс: 27/27 PS, 27/27 PY, 27/27 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:53:55 +03:00
Nick ShirokovandClaude Opus 4.7 8b0bcf0194 feat(skd-edit): флаги @hidden и @always для параметров
- @hidden — скрывает параметр от пользовательских настроек
  (useRestriction=true + availableAsField=false). Для констант-параметров.
- @always — параметр всегда подставляется в запрос (use=Always).
  Используется самостоятельно для видимых обязательных параметров.
- Композируются: @hidden @always одной строкой даёт типовой паттерн
  "скрытая константа всегда применяется".
- Поддержка в add-parameter и modify-parameter, идемпотентны.

Регресс: 25/25 PS, 25/25 PY, 25/25 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:14:19 +03:00
Nick ShirokovandClaude Opus 4.7 529a5cacae feat(skd-edit): modify-structure + фиксы set-structure/parameter/patch-query
- modify-structure: новая операция, меняет groupItems группы по @name=,
  сохраняя Selection/order/filter/conditionalAppearance (Bug 1)
- set-structure: shorthand поддерживает запятую для нескольких полей
  в одном уровне группировки (Bug 2)
- set-structure: @name= с обрамляющими кавычками (двойными/одинарными)
  снимает их при записи в <dcsset:name> (Bug 3)
- add-parameter: ссылочные типы (CatalogRef, ChartOfAccountsRef, …)
  пишут <value xsi:type="dcscor:DesignTimeValue">, не xs:string (Bug 4a)
- modify-parameter: namespace-aware lookup существующих свойств
  — обновляет inplace, не плодит дубли (Bug 4b)
- modify-parameter value=…: пересборка <value> с корректным xsi:type
  из <valueType> (попутно лечит ранее битый XML)
- patch-query: батч ;;-сегментов триммится по краям (Bug 5)
- skd-compile: симметричный фикс ссылочных типов в emit_value

Регресс: 23/23 PS, 23/23 PY (skd-edit), 21/21 PS+PY (skd-compile),
23/23 платформенный verify-snapshots.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:40:49 +03:00
Nick ShirokovandClaude Opus 4.7 8b0f55f1cc feat(form-validate): silent-skip числовых и UUID-DataPath в Check 5
В реальных выгрузках ERP/БП встречаются непрозрачные платформенные
DataPath, которые невозможно проверить из одного Form.xml:
- bare numeric ("10", "1000003") — внутренние индексы платформы
- "N/M:<uuid>" — ссылка на метаданные по UUID

Раньше Check 5 ругался на них "attribute not found". Теперь такие
пути пропускаются без счёта в paths checked и без ошибки.

Реалистичные пользовательские опечатки (кириллица в имени атрибута)
продолжают ловиться обычной проверкой attrMap.

Добавлен тест-кейс datapath-opaque-refs, версия v1.5 → v1.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:40:27 +03:00
Nick ShirokovandClaude Opus 4.7 54cbc69a59 feat(form-validate): резолв Items.<Table>.CurrentData.* и ~<Attr>.* в DataPath
В Check 5 раньше брался первый сегмент DataPath и искался в attrMap,
из-за чего ложно ругались реальные формы ERP/БП с путями вида
Items.<TableName>.CurrentData.<Field> (подвалы, инфо-панели) и
~<DynamicListAttr>.<Field> (текущая строка списка).

Теперь:
- ведущий ~ стрипается перед разбором сегментов;
- для Items.<Table>.CurrentData.* находим элемент-таблицу по name,
  берём её <DataPath> (атрибут DynamicList/TableSection) и проверяем
  его в attrMap. Если таблицы нет — Error; если третий сегмент не
  CurrentData — Warn.

Добавлен тест-кейс datapath-currentdata, версия скриптов v1.4 → v1.5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:38:56 +03:00
44 changed files with 2383 additions and 132 deletions
@@ -1,4 +1,4 @@
# form-validate v1.4 — Validate 1C managed form
# form-validate v1.6 — Validate 1C managed form
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -366,13 +366,51 @@ if (-not $stopped) {
$dataPath = $dpNode.InnerText.Trim()
if (-not $dataPath) { continue }
# Opaque platform-internal DataPath shapes — not validatable from Form.xml alone:
# - bare numeric (e.g. "10", "1000003") — internal index
# - "N/M:<uuid>" — metadata reference by UUID
if ($dataPath -match '^\d+$' -or $dataPath -match '^\d+/\d+:[0-9a-fA-F-]+$') {
continue
}
$pathChecked++
# Extract root segment of path, strip array indices like [0]
$cleanPath = $dataPath -replace '\[\d+\]', ''
# Strip leading '~' (current row of DynamicList: ~Список.Поле)
if ($cleanPath.StartsWith('~')) { $cleanPath = $cleanPath.Substring(1) }
$segments = $cleanPath -split '\.'
$rootAttr = $segments[0]
# Resolve Items.<TableName>.CurrentData.<Field>... — table element, not attribute
if ($rootAttr -eq 'Items') {
if ($segments.Count -lt 3 -or $segments[2] -ne 'CurrentData') {
Report-Warn "[$tag] '$elName': DataPath='$dataPath' — unknown Items.* shape, expected Items.<Table>.CurrentData.*"
continue
}
$tableName = $segments[1]
$tableEl = $null
foreach ($candidate in $allElements) {
if ($candidate.Tag -eq 'Table' -and $candidate.Name -eq $tableName) {
$tableEl = $candidate
break
}
}
if (-not $tableEl) {
Report-Error "[$tag] '$elName': DataPath='$dataPath' — table element '$tableName' not found"
$pathErrors++
continue
}
$tableDpNode = $tableEl.Node.SelectSingleNode("f:DataPath", $nsMgr)
if (-not $tableDpNode -or -not $tableDpNode.InnerText.Trim()) {
# Table without DataPath — can't resolve further, accept silently
continue
}
$tableDp = $tableDpNode.InnerText.Trim() -replace '\[\d+\]', ''
if ($tableDp.StartsWith('~')) { $tableDp = $tableDp.Substring(1) }
$rootAttr = ($tableDp -split '\.')[0]
}
if (-not $attrMap.ContainsKey($rootAttr)) {
Report-Error "[$tag] '$elName': DataPath='$dataPath' — attribute '$rootAttr' not found"
$pathErrors++
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# form-validate v1.4 — Validate 1C managed form
# form-validate v1.6 — Validate 1C managed form
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -376,12 +376,44 @@ def main():
if not data_path:
continue
# Opaque platform-internal DataPath shapes — not validatable from Form.xml alone:
# - bare numeric (e.g. "10", "1000003") — internal index
# - "N/M:<uuid>" — metadata reference by UUID
if re.match(r'^\d+$', data_path) or re.match(r'^\d+/\d+:[0-9a-fA-F-]+$', data_path):
continue
path_checked += 1
clean_path = re.sub(r'\[\d+\]', '', data_path)
# Strip leading '~' (current row of DynamicList: ~\u0421\u043f\u0438\u0441\u043e\u043a.\u041f\u043e\u043b\u0435)
if clean_path.startswith('~'):
clean_path = clean_path[1:]
segments = clean_path.split(".")
root_attr = segments[0]
# Resolve Items.<TableName>.CurrentData.<Field>... \u2014 table element, not attribute
if root_attr == 'Items':
if len(segments) < 3 or segments[2] != 'CurrentData':
report_warn(f"[{tag}] '{el_name}': DataPath='{data_path}' \u2014 unknown Items.* shape, expected Items.<Table>.CurrentData.*")
continue
table_name = segments[1]
table_el = None
for candidate in all_elements:
if candidate["Tag"] == 'Table' and candidate["Name"] == table_name:
table_el = candidate
break
if table_el is None:
report_error(f"[{tag}] '{el_name}': DataPath='{data_path}' \u2014 table element '{table_name}' not found")
path_errors += 1
continue
table_dp_node = table_el["Node"].find(f"{{{F_NS}}}DataPath")
if table_dp_node is None or not (table_dp_node.text or "").strip():
continue
table_dp = re.sub(r'\[\d+\]', '', (table_dp_node.text or "").strip())
if table_dp.startswith('~'):
table_dp = table_dp[1:]
root_attr = table_dp.split(".")[0]
if root_attr not in attr_map:
report_error(f"[{tag}] '{el_name}': DataPath='{data_path}' \u2014 attribute '{root_attr}' not found")
path_errors += 1
@@ -1,4 +1,4 @@
# skd-compile v1.21 — Compile 1C DCS from JSON
# skd-compile v1.22 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -1130,6 +1130,8 @@ function Emit-ParamValue {
X "$indent<value xsi:type=`"xs:decimal`">$(Esc-Xml $valStr)</value>"
} elseif ($type -match '^string') {
X "$indent<value xsi:type=`"xs:string`">$(Esc-Xml $valStr)</value>"
} elseif ($type -match '^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|BusinessProcessRef|TaskRef|ExchangePlanRef)\.') {
X "$indent<value xsi:type=`"dcscor:DesignTimeValue`">$(Esc-Xml $valStr)</value>"
} else {
# Guess from value
if ($valStr -match '^\d{4}-\d{2}-\d{2}T') {
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# skd-compile v1.21 — Compile 1C DCS from JSON
# skd-compile v1.22 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import json
@@ -811,6 +811,8 @@ def emit_param_value(lines, type_str, val, indent):
lines.append(f'{indent}<value xsi:type="xs:decimal">{esc_xml(val_str)}</value>')
elif type_str and re.match(r'^string', type_str):
lines.append(f'{indent}<value xsi:type="xs:string">{esc_xml(val_str)}</value>')
elif type_str and re.match(r'^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|BusinessProcessRef|TaskRef|ExchangePlanRef)\.', type_str):
lines.append(f'{indent}<value xsi:type="dcscor:DesignTimeValue">{esc_xml(val_str)}</value>')
else:
# Guess from value
if re.match(r'^\d{4}-\d{2}-\d{2}T', val_str):
+68 -10
View File
@@ -54,9 +54,12 @@ Shorthand: `"Имя [Заголовок]: тип @роль #ограничени
### add-total — добавить итог
Shorthand: `"<dataPath>: <выражение>"`. Если выражение — известная аггрегатная функция без скобок (`Сумма`, `Количество`, `Минимум`, `Максимум`, `Среднее`), оно автоматически оборачивается в `Func(dataPath)`. Если функция со скобками или произвольное выражение — используется как есть.
```
"Цена: Среднее"
"Стоимость: Сумма(Кол * Цена)"
"Цена: Среднее" # → Среднее(Цена)
"Стоимость: Сумма(Кол * Цена)" # → как есть
"Проверка: Проверка" # identity: выражение = Проверка
```
### add-calculated-field — добавить вычисляемое поле
@@ -80,24 +83,46 @@ Shorthand: `"Имя [Заголовок]: тип = Выражение #noFilter
"Организация: CatalogRef.Организации"
```
Shorthand: `"Имя [Заголовок]: тип = значение @флаги"`. `[Заголовок]` опциональный — добавляет `<title>`.
Shorthand: `"Имя [Заголовок]: тип = значение [availableValue=список] [@флаги]"`. `[Заголовок]` опциональный — добавляет `<title>`.
`@autoDates` генерирует пару скрытых параметров `ДатаНачала`/`ДатаОкончания` для StandardPeriod-параметра — для БСП-отчётов, чтобы получить пару полей «Начало/Конец» в панели быстрых настроек.
Флаги:
- `@autoDates` — генерирует пару скрытых параметров `ДатаНачала`/`ДатаОкончания` для StandardPeriod-параметра.
- `@hidden` — скрывает параметр от пользовательских настроек (для параметров-констант, используемых в запросе).
- `@always` — параметр всегда подставляется в запрос. Часто вместе с `@hidden`, но используется и отдельно (для видимых обязательных параметров типа отчётного периода).
```
"ПС: CatalogRef.Контрагенты = Справочник.Контрагенты.ПустаяСсылка @hidden"
"Период: StandardPeriod = LastMonth @always"
"ПСчет: ChartOfAccountsRef.Хозрасчетный = ПланСчетов.Хозрасчетный.X @hidden @always"
"Округление: EnumRef.Округления = Окр1 availableValue=Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс."
```
`availableValue=` задаёт начальный список допустимых значений. Формат списка: `v1[: p1], v2[: p2], ...` — элементы через `,`, представление после `:`. Если в значении или представлении встречается `,` или `:` — оборачивай в одинарные кавычки `'...'`:
```
"Округление: ... = Окр1 availableValue=Окр1_00: 'руб., коп.', Окр1: руб."
```
### modify-parameter — изменить существующий параметр
Находит параметр по имени, добавляет/обновляет свойства.
Shorthand: `"ИмяПараметра [Заголовок] [ключ=значение]... [@флаги]"`. Находит параметр по имени, обновляет указанные свойства.
```
"ПорядокОкругления use=Always"
"ПорядокОкругления [Округление сумм] denyIncompleteValues=true"
"ПериодОтчета [Отчетный период]" # только title
"ПорядокОкругления availableValue=Перечисление.Округления.Окр1 presentation=руб."
"ПорядокОкругления availableValue=Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс."
"СчетПС value=ПланСчетов.Хозрасчетный.КассаПредприятия"
"Контрагент @hidden @always"
```
`[Заголовок]` опциональный — устанавливает или заменяет `<title>`. Можно вызывать без других kv-пар, чтобы только обновить title.
`availableValue=` добавляет один элемент списка допустимых значений (можно несколько через `;;`). Тип значения определяется автоматически (DesignTimeValue для ссылок).
`availableValue=` **заменяет весь список** допустимых значений (старые удаляются). Формат и кавычки — те же, что в `add-parameter`.
`value=` заменяет значение параметра (тип значения подбирается автоматически по объявленному типу параметра).
Флаги `@hidden` / `@always` — те же, что и в `add-parameter`. Идемпотентны.
### rename-parameter — переименовать параметр
@@ -231,13 +256,17 @@ Value — имена ресурсов (как в полях/вычисляемы
### patch-query — точечная замена в тексте запроса
Shorthand: `"старое => новое"`. Заменяет все вхождения подстроки. Поддерживает пакетный режим и `-DataSet`.
Shorthand: `"старое => новое [@once]"`. По умолчанию заменяет все вхождения подстроки. Поддерживает пакетный режим и `-DataSet`.
```
"СубконтоДт1) В => СубконтоКт1) В"
"ЛЕВОЕ СОЕДИНЕНИЕ => ВНУТРЕННЕЕ СОЕДИНЕНИЕ"
"КАК ВТ_СтароеИмя => КАК ВТ_НовоеИмя @once"
```
`@once` — упасть с ошибкой, если в запросе не **ровно одно** вхождение. Защищает от случайных замен в комментариях и однотипных идентификаторах.
Многострочные подстроки поддерживаются — переводы строк в `старое`/`новое` сравниваются буквально (включая отступы).
### set-outputParameter — установить параметр вывода
```
@@ -249,16 +278,27 @@ Shorthand: `"старое => новое"`. Заменяет все вхожде
### set-structure — установить структуру варианта
Shorthand: `"Поле1 > Поле2 > details"`. `details`/`детали` — детальные записи. Заменяет всю структуру. Не поддерживает пакетный режим.
Shorthand: `"Поле1 > Поле2 > details"`. `>` — вложенный уровень группировки, `,` — несколько полей в одном уровне, `details` — детальные записи. **Заменяет всю структуру полностью** (включая Selection/order/filter/conditionalAppearance каждой группы). Для точечной модификации полей группировки с сохранением настроек — используй `modify-structure`. Не поддерживает пакетный режим.
```
"Организация > Номенклатура > details"
"Валюта, НаименованиеБанка, ИНН"
"details"
"СчетМеждународногоУчета @name=ДанныеОтчета"
```
`@name=Имя` — присваивает имя группировке (`<dcsset:name>`). Используется для привязки шаблонов через `groupName`.
### modify-structure — изменить поля группировки существующей группы
Тот же shorthand что и `set-structure`. Находит группу по `@name=`, заменяет только `<groupItems>` (поля группировки). Selection/order/filter/conditionalAppearance/outputParameters группы сохраняются. Без `@name=` — ошибка.
```
"Валюта @name=ДанныеОтчета"
"Валюта, НаименованиеБанка @name=ДанныеОтчета"
"details @name=ДанныеОтчета"
```
### modify-field — изменить существующее поле
Тот же shorthand что и `add-field`. Находит по dataPath, объединяет свойства (непустые переопределяют), сохраняет позицию.
@@ -267,6 +307,23 @@ Shorthand: `"Поле1 > Поле2 > details"`. `details`/`детали` — д
"Цена [Цена USD]: decimal(10,4) @dimension"
```
### set-field-role — установить роль поля
Shorthand: `"<dataPath> [@флаги] [kv=значение]"`. **Полностью заменяет** роль поля. Если в значении только dataPath без флагов/kv — удаляет роль.
```
"Сумма" # снять роль полностью
"СуммаОстаток @balance" # простая балансовая роль
"СуммаНач @balance balanceGroupName=Сумма balanceType=OpeningBalance" # с уточнением
"Контрагент @dimension parentDimension=Группа"
"Период @period" # роль периода
```
Флаги: `@balance`, `@dimension`, `@account`, `@period`, `@required`, `@autoOrder`, `@ignoreNullValues`.
KV: `balanceGroupName`, `balanceType` (OpeningBalance/ClosingBalance), `parentDimension`, `accountTypeExpression`, `orderType` (Asc/Desc), `expression`, `periodNumber`, `periodType`.
Поддерживает пакетный режим (`;;`).
### modify-filter — изменить существующий фильтр
Тот же shorthand что и `add-filter`. Находит по полю, обновляет оператор/значение/флаги. См. правило для `<use>` ниже.
@@ -294,6 +351,7 @@ Shorthand: `"Поле1 > Поле2 > details"`. `details`/`детали` — д
| `clear-selection` | `*` | Очищает все элементы selection |
| `clear-order` | `*` | Очищает все элементы order |
| `clear-filter` | `*` | Очищает все элементы filter |
| `clear-conditionalAppearance` | `*` | Очищает все правила условного оформления |
## Верификация
+533 -58
View File
@@ -1,4 +1,4 @@
# skd-edit v1.11 — Atomic 1C DCS editor
# skd-edit v1.18 — Atomic 1C DCS editor
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -11,9 +11,9 @@ param(
"add-dataParameter","add-order","add-selection","add-dataSetLink",
"add-dataSet","add-variant","add-conditionalAppearance","add-drilldown",
"set-query","patch-query","set-outputParameter","set-structure",
"modify-field","modify-filter","modify-dataParameter","modify-parameter",
"modify-field","modify-filter","modify-dataParameter","modify-parameter","modify-structure","set-field-role",
"rename-parameter","reorder-parameters",
"clear-selection","clear-order","clear-filter",
"clear-selection","clear-order","clear-filter","clear-conditionalAppearance",
"remove-field","remove-total","remove-calculated-field","remove-parameter","remove-filter")]
[string]$Operation,
@@ -238,14 +238,25 @@ function Read-FieldProperties($fieldEl) {
function Parse-TotalShorthand {
param([string]$s)
# "DataPath: Func" or "DataPath: Func(expr)" or "DataPath: ИмяРесурса" (identity)
$parts = $s -split ':', 2
$dataPath = $parts[0].Trim()
$funcPart = $parts[1].Trim()
# Known DCS aggregate functions (ru + en)
$aggFuncs = @('Сумма','Количество','Минимум','Максимум','Среднее',
'Sum','Count','Min','Max','Avg',
'Minimum','Maximum','Average')
if ($funcPart -match '^\w+\(') {
# Already has expression form: Func(expr)
return @{ dataPath = $dataPath; expression = $funcPart }
} else {
} elseif ($funcPart -in $aggFuncs) {
# Short: Func → Func(DataPath)
return @{ dataPath = $dataPath; expression = "$funcPart($dataPath)" }
} else {
# Identity or custom expression — use as-is
return @{ dataPath = $dataPath; expression = $funcPart }
}
}
@@ -297,13 +308,29 @@ function Parse-CalcShorthand {
function Parse-ParamShorthand {
param([string]$s)
$result = @{ name = ""; type = ""; value = $null; autoDates = $false; title = $null }
$result = @{ name = ""; type = ""; value = $null; autoDates = $false; title = $null; hidden = $false; always = $false; availableValues = @() }
# Extract availableValue=... (must be before main parse — captures to end of string)
if ($s -match '\s*availableValue=(.+)$') {
$result.availableValues = Parse-AvailableValueList $Matches[1].Trim()
$s = ($s -replace '\s*availableValue=.+$', '').Trim()
}
if ($s -match '@autoDates') {
$result.autoDates = $true
$s = $s -replace '\s*@autoDates', ''
}
if ($s -match '@hidden\b') {
$result.hidden = $true
$s = $s -replace '\s*@hidden\b', ''
}
if ($s -match '@always\b') {
$result.always = $true
$s = $s -replace '\s*@always\b', ''
}
# Extract optional [Title] (mirrors Parse-FieldShorthand)
if ($s -match '\[([^\]]*)\]') {
$result.title = $Matches[1].Trim()
@@ -581,15 +608,17 @@ function Parse-StructureShorthand {
$seg = $segments[$i].Trim()
$group = @{ type = "group" }
if ($seg -match '@name=(.+)') {
$group["name"] = $Matches[1].Trim()
$seg = ($seg -replace '\s*@name=.+', '').Trim()
if ($seg -match '@name=(?:"([^"]+)"|''([^'']+)''|(\S+))') {
$rawName = if ($Matches[1]) { $Matches[1] } elseif ($Matches[2]) { $Matches[2] } else { $Matches[3] }
$group["name"] = $rawName.Trim()
$seg = ($seg -replace '\s*@name=(?:"[^"]+"|''[^'']+''|\S+)', '').Trim()
}
if ($seg -match '^(?i)(details|детали)$') {
$group["groupBy"] = @()
} else {
$group["groupBy"] = @($seg)
$fields = @($seg -split '\s*,\s*' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
$group["groupBy"] = $fields
}
if ($null -ne $innermost) {
@@ -614,6 +643,75 @@ function Parse-OutputParamShorthand {
return @{ key = $s.Trim(); value = "" }
}
function Parse-AvailableValueList {
# Returns array of @{ value=...; presentation=... } from comma-separated list.
# Items can use 'single' or "double" quotes (stripped). Quoted spans preserve commas/colons.
param([string]$s)
$result = @()
if (-not $s) { return ,$result }
# Tokenize by ',' respecting quoted spans
$items = @()
$buf = New-Object System.Text.StringBuilder
$inQuote = $null
for ($i = 0; $i -lt $s.Length; $i++) {
$ch = $s[$i]
if ($inQuote) {
[void]$buf.Append($ch)
if ($ch -eq $inQuote) { $inQuote = $null }
} elseif ($ch -eq "'" -or $ch -eq '"') {
$inQuote = $ch
[void]$buf.Append($ch)
} elseif ($ch -eq ',') {
$items += $buf.ToString()
[void]$buf.Clear()
} else {
[void]$buf.Append($ch)
}
}
if ($buf.Length -gt 0) { $items += $buf.ToString() }
# For each item: split into value[:presentation], strip quotes
$stripQuotes = {
param($t)
$t = $t.Trim()
if ($t.Length -ge 2 -and (($t[0] -eq "'" -and $t[-1] -eq "'") -or ($t[0] -eq '"' -and $t[-1] -eq '"'))) {
return $t.Substring(1, $t.Length - 2)
}
return $t
}
foreach ($raw in $items) {
$item = $raw.Trim()
if (-not $item) { continue }
# Find first ':' outside quotes
$colonIdx = -1
$q = $null
for ($j = 0; $j -lt $item.Length; $j++) {
$c = $item[$j]
if ($q) {
if ($c -eq $q) { $q = $null }
} elseif ($c -eq "'" -or $c -eq '"') {
$q = $c
} elseif ($c -eq ':') {
$colonIdx = $j; break
}
}
if ($colonIdx -ge 0) {
$valPart = $item.Substring(0, $colonIdx)
$presPart = $item.Substring($colonIdx + 1)
$result += @{ value = (& $stripQuotes $valPart); presentation = (& $stripQuotes $presPart) }
} else {
$result += @{ value = (& $stripQuotes $item); presentation = "" }
}
}
return ,$result
}
# --- 4. Build-* functions (XML fragment generators) ---
function Build-ValueTypeXml {
@@ -804,6 +902,68 @@ function Build-CalcFieldFragment {
return $lines -join "`r`n"
}
function Build-ParamValueXml {
# Returns array of XML lines for a <value xsi:type=...>...</value> element (or StandardPeriod block).
# Selects xsi:type by declared type, then falls back to value pattern.
param([string]$type, [string]$value, [string]$indent, [string]$tagName = "value", [string]$tagNs = "")
$i = $indent
$valStr = "$value"
$open = if ($tagNs) { "$tagNs`:$tagName" } else { $tagName }
$lines = @()
if ($type -eq "StandardPeriod") {
$lines += "$i<$open xsi:type=`"v8:StandardPeriod`">"
$lines += "$i`t<v8:variant xsi:type=`"v8:StandardPeriodVariant`">$(Esc-Xml $valStr)</v8:variant>"
$lines += "$i`t<v8:startDate>0001-01-01T00:00:00</v8:startDate>"
$lines += "$i`t<v8:endDate>0001-01-01T00:00:00</v8:endDate>"
$lines += "$i</$open>"
return $lines
}
$xsi = $null
if ($type -match '^date') { $xsi = "xs:dateTime" }
elseif ($type -eq "boolean") { $xsi = "xs:boolean" }
elseif ($type -match '^decimal') { $xsi = "xs:decimal" }
elseif ($type -match '^string') { $xsi = "xs:string" }
elseif ($type -match '^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|BusinessProcessRef|TaskRef|ExchangePlanRef)\.') {
$xsi = "dcscor:DesignTimeValue"
}
else {
# Type unknown or empty — guess from value
if ($valStr -match '^\d{4}-\d{2}-\d{2}T') { $xsi = "xs:dateTime" }
elseif ($valStr -eq "true" -or $valStr -eq "false") { $xsi = "xs:boolean" }
elseif ($valStr -match '^(Перечисление|Справочник|ПланСчетов|Документ|ПланВидовХарактеристик|ПланВидовРасчета|БизнесПроцесс|Задача|РегистрСведений|ПланОбмена)\.' -or
$valStr -match '^(Catalog|Document|Enum|ChartOfAccounts|ChartOfCharacteristicTypes|ChartOfCalculationTypes|BusinessProcess|Task|InformationRegister|ExchangePlan)\.') {
$xsi = "dcscor:DesignTimeValue"
}
else { $xsi = "xs:string" }
}
$lines += "$i<$open xsi:type=`"$xsi`">$(Esc-Xml $valStr)</$open>"
return $lines
}
function Build-AvailableValueFragment {
# Returns XML lines (array) for a single <availableValue> block.
param($item, [string]$declaredType, [string]$indent)
$lines = @()
$lines += "$indent<availableValue>"
$valueLines = Build-ParamValueXml -type $declaredType -value $item.value -indent "$indent`t"
foreach ($vl in $valueLines) { $lines += $vl }
if ($item.presentation) {
$lines += "$indent`t<presentation xsi:type=`"v8:LocalStringType`">"
$lines += "$indent`t`t<v8:item>"
$lines += "$indent`t`t`t<v8:lang>ru</v8:lang>"
$lines += "$indent`t`t`t<v8:content>$(Esc-Xml $item.presentation)</v8:content>"
$lines += "$indent`t`t</v8:item>"
$lines += "$indent`t</presentation>"
}
$lines += "$indent</availableValue>"
return $lines
}
function Build-ParamFragment {
param($parsed, [string]$indent)
@@ -825,24 +985,26 @@ function Build-ParamFragment {
}
if ($null -ne $parsed.value) {
$valStr = "$($parsed.value)"
if ($parsed.type -eq "StandardPeriod") {
$lines += "$i`t<value xsi:type=`"v8:StandardPeriod`">"
$lines += "$i`t`t<v8:variant xsi:type=`"v8:StandardPeriodVariant`">$(Esc-Xml $valStr)</v8:variant>"
$lines += "$i`t`t<v8:startDate>0001-01-01T00:00:00</v8:startDate>"
$lines += "$i`t`t<v8:endDate>0001-01-01T00:00:00</v8:endDate>"
$lines += "$i`t</value>"
} elseif ($parsed.type -match '^date') {
$lines += "$i`t<value xsi:type=`"xs:dateTime`">$(Esc-Xml $valStr)</value>"
} elseif ($parsed.type -eq "boolean") {
$lines += "$i`t<value xsi:type=`"xs:boolean`">$(Esc-Xml $valStr)</value>"
} elseif ($parsed.type -match '^decimal') {
$lines += "$i`t<value xsi:type=`"xs:decimal`">$(Esc-Xml $valStr)</value>"
} else {
$lines += "$i`t<value xsi:type=`"xs:string`">$(Esc-Xml $valStr)</value>"
$valueLines = Build-ParamValueXml -type $parsed.type -value $parsed.value -indent "$i`t"
foreach ($vl in $valueLines) { $lines += $vl }
}
if ($parsed.hidden) {
$lines += "$i`t<useRestriction>true</useRestriction>"
$lines += "$i`t<availableAsField>false</availableAsField>"
}
if ($parsed.availableValues -and $parsed.availableValues.Count -gt 0) {
foreach ($av in $parsed.availableValues) {
$avLines = Build-AvailableValueFragment -item $av -declaredType $parsed.type -indent "$i`t"
foreach ($l in $avLines) { $lines += $l }
}
}
if ($parsed.always) {
$lines += "$i`t<use>Always</use>"
}
$lines += "$i</parameter>"
$fragments += ($lines -join "`r`n")
@@ -1565,10 +1727,10 @@ $corNs = "http://v8.1c.ru/8.1/data-composition-system/core"
# --- 7. Batch value splitting ---
if ($Operation -eq "set-query" -or $Operation -eq "set-structure" -or $Operation -eq "add-dataSet") {
if ($Operation -eq "set-query" -or $Operation -eq "set-structure" -or $Operation -eq "modify-structure" -or $Operation -eq "add-dataSet") {
$values = @($Value)
} elseif ($Operation -eq "patch-query") {
$values = @($Value -split ';;' | Where-Object { $_.Trim() })
$values = @($Value -split ';;' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
} elseif ($Operation -eq "add-drilldown") {
if ($Value.Contains(';;')) {
$values = @($Value -split ';;' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
@@ -1766,6 +1928,12 @@ switch ($Operation) {
$paramName = $parts[0].Trim()
$rest = if ($parts.Count -gt 1) { $parts[1].Trim() } else { "" }
# Extract @hidden / @always flags
$flagHidden = $false
$flagAlways = $false
if ($rest -match '@hidden\b') { $flagHidden = $true; $rest = ($rest -replace '\s*@hidden\b', '').Trim() }
if ($rest -match '@always\b') { $flagAlways = $true; $rest = ($rest -replace '\s*@always\b', '').Trim() }
# Find parameter element
$paramEl = Find-ElementByChildValue $xmlDoc.DocumentElement "parameter" "name" $paramName $schNs
if (-not $paramEl) {
@@ -1810,15 +1978,63 @@ switch ($Operation) {
$avPart = $rest.Substring($avIdx)
}
# Process simple key=value pairs (use, denyIncompleteValues, etc.)
# Process simple key=value pairs (use, denyIncompleteValues, value, etc.)
if ($simpleRest) {
$kvPairs = [regex]::Matches($simpleRest, '(\w+)=(\S+)')
foreach ($kv in $kvPairs) {
$key = $kv.Groups[1].Value
$value = $kv.Groups[2].Value
$existing = $paramEl.SelectSingleNode($key)
if ($existing) {
# Namespace-aware lookup (children live in $schNs)
$existing = $null
foreach ($ch in $paramEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq $key -and $ch.NamespaceURI -eq $schNs) {
$existing = $ch; break
}
}
if ($key -eq "value") {
# Special-case: rebuild <value> with correct xsi:type from <valueType>
$declaredType = ""
$vtEl = $null
foreach ($ch in $paramEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'valueType' -and $ch.NamespaceURI -eq $schNs) { $vtEl = $ch; break }
}
if ($vtEl) {
foreach ($tnode in $vtEl.ChildNodes) {
if ($tnode.NodeType -eq 'Element' -and $tnode.LocalName -eq 'Type') {
$declaredType = $tnode.InnerText.Trim() -replace '^d\d+p\d+:', ''
break
}
}
}
$valueLines = Build-ParamValueXml -type $declaredType -value $value -indent $childIndent
$fragXml = $valueLines -join "`r`n"
$wasExisting = ($null -ne $existing)
if ($existing) {
# Capture position by next-element sibling, then remove existing
$refNode = $existing.NextSibling
while ($refNode -and ($refNode.NodeType -eq 'Whitespace' -or $refNode.NodeType -eq 'SignificantWhitespace')) {
$refNode = $refNode.NextSibling
}
Remove-NodeWithWhitespace $existing
} else {
# Insert before useRestriction/availableValue/denyIncompleteValues/use
$refNode = $null
foreach ($child in $paramEl.ChildNodes) {
if ($child.NodeType -eq 'Element' -and $child.LocalName -in @('useRestriction','availableValue','denyIncompleteValues','use')) {
$refNode = $child; break
}
}
}
$nodes = Import-Fragment $xmlDoc $fragXml
foreach ($node in $nodes) {
Insert-BeforeElement $paramEl $node $refNode $childIndent
}
$verb = if ($wasExisting) { "updated" } else { "added" }
Write-Host "[OK] Parameter `"$paramName`": value $verb to $value"
} elseif ($existing) {
$existing.InnerText = $value
Write-Host "[OK] Parameter `"$paramName`": $key updated to $value"
} else {
@@ -1841,46 +2057,102 @@ switch ($Operation) {
}
}
# Process availableValue
# Process availableValue — replace whole list with new items
if ($avPart) {
$avRest = $avPart -replace '^availableValue=', ''
# Parse: "Перечисление...X presentation=текст с пробелами"
$avParts = $avRest -split '\s+presentation=', 2
$avValue = $avParts[0].Trim()
$avPresentation = if ($avParts.Count -gt 1) { $avParts[1].Trim() } else { "" }
$avRest = ($avPart -replace '^availableValue=', '').Trim()
$avItems = Parse-AvailableValueList $avRest
# Detect value type
$avType = "xs:string"
if ($avValue -match '^(Перечисление|Справочник|ПланСчетов|Документ|ПланВидовХарактеристик|ПланВидовРасчета)\.') {
$avType = "dcscor:DesignTimeValue"
# Detect value type: prefer declared <valueType> of the parameter, else guess from value
$declaredType = ""
$vtEl = $null
foreach ($ch in $paramEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'valueType' -and $ch.NamespaceURI -eq $schNs) { $vtEl = $ch; break }
}
if ($vtEl) {
foreach ($tnode in $vtEl.ChildNodes) {
if ($tnode.NodeType -eq 'Element' -and $tnode.LocalName -eq 'Type') {
$declaredType = $tnode.InnerText.Trim() -replace '^d\d+p\d+:', ''
break
}
}
}
$avLines = @()
$avLines += "$childIndent<availableValue>"
$avLines += "$childIndent`t<value xsi:type=`"$avType`">$(Esc-Xml $avValue)</value>"
if ($avPresentation) {
$avLines += "$childIndent`t<presentation xsi:type=`"v8:LocalStringType`">"
$avLines += "$childIndent`t`t<v8:item>"
$avLines += "$childIndent`t`t`t<v8:lang>ru</v8:lang>"
$avLines += "$childIndent`t`t`t<v8:content>$(Esc-Xml $avPresentation)</v8:content>"
$avLines += "$childIndent`t`t</v8:item>"
$avLines += "$childIndent`t</presentation>"
# Remove all existing <availableValue> elements
$toRemove = @()
foreach ($ch in $paramEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'availableValue' -and $ch.NamespaceURI -eq $schNs) {
$toRemove += $ch
}
}
$avLines += "$childIndent</availableValue>"
$fragXml = $avLines -join "`r`n"
foreach ($el in $toRemove) { Remove-NodeWithWhitespace $el }
# Insert before first of (denyIncompleteValues, use) in document order
# Insert each new <availableValue> before (denyIncompleteValues, use)
$refNode = $null
foreach ($child in $paramEl.ChildNodes) {
if ($child.NodeType -eq 'Element' -and ($child.LocalName -eq 'denyIncompleteValues' -or $child.LocalName -eq 'use')) {
$refNode = $child; break
}
}
$nodes = Import-Fragment $xmlDoc $fragXml
foreach ($node in $nodes) {
Insert-BeforeElement $paramEl $node $refNode $childIndent
foreach ($av in $avItems) {
$avLines = Build-AvailableValueFragment -item $av -declaredType $declaredType -indent $childIndent
$fragXml = $avLines -join "`r`n"
$nodes = Import-Fragment $xmlDoc $fragXml
foreach ($node in $nodes) {
Insert-BeforeElement $paramEl $node $refNode $childIndent
}
}
Write-Host "[OK] Parameter `"$paramName`": availableValue added"
Write-Host "[OK] Parameter `"$paramName`": availableValue set to $($avItems.Count) item(s)"
}
# Process @hidden / @always flags (idempotent)
if ($flagHidden) {
# useRestriction → true (insert after <value>, before <expression>/<availableAsField>/...)
$urEl = $null
foreach ($ch in $paramEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'useRestriction' -and $ch.NamespaceURI -eq $schNs) { $urEl = $ch; break }
}
if ($urEl) {
if ($urEl.InnerText.Trim() -ne 'true') { $urEl.InnerText = 'true' }
} else {
$refNode = $null
foreach ($child in $paramEl.ChildNodes) {
if ($child.NodeType -eq 'Element' -and $child.LocalName -in @('expression','availableAsField','availableValue','denyIncompleteValues','use')) { $refNode = $child; break }
}
$nodes = Import-Fragment $xmlDoc "$childIndent<useRestriction>true</useRestriction>"
foreach ($node in $nodes) { Insert-BeforeElement $paramEl $node $refNode $childIndent }
}
# availableAsField → false (insert after <expression>, before <availableValue>/<denyIncompleteValues>/<use>)
$afEl = $null
foreach ($ch in $paramEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'availableAsField' -and $ch.NamespaceURI -eq $schNs) { $afEl = $ch; break }
}
if ($afEl) {
if ($afEl.InnerText.Trim() -ne 'false') { $afEl.InnerText = 'false' }
} else {
$refNode = $null
foreach ($child in $paramEl.ChildNodes) {
if ($child.NodeType -eq 'Element' -and $child.LocalName -in @('availableValue','denyIncompleteValues','use')) { $refNode = $child; break }
}
$nodes = Import-Fragment $xmlDoc "$childIndent<availableAsField>false</availableAsField>"
foreach ($node in $nodes) { Insert-BeforeElement $paramEl $node $refNode $childIndent }
}
Write-Host "[OK] Parameter `"$paramName`": @hidden applied"
}
if ($flagAlways) {
$useEl = $null
foreach ($ch in $paramEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'use' -and $ch.NamespaceURI -eq $schNs) { $useEl = $ch; break }
}
if ($useEl) {
if ($useEl.InnerText.Trim() -ne 'Always') { $useEl.InnerText = 'Always' }
} else {
$nodes = Import-Fragment $xmlDoc "$childIndent<use>Always</use>"
foreach ($node in $nodes) { Insert-BeforeElement $paramEl $node $null $childIndent }
}
Write-Host "[OK] Parameter `"$paramName`": @always applied"
}
}
}
@@ -2211,6 +2483,12 @@ switch ($Operation) {
}
foreach ($val in $values) {
$once = $false
if ($val -match '@once\b') {
$once = $true
$val = ($val -replace '\s*@once\b', '').Trim()
}
$sepIdx = $val.IndexOf(" => ")
if ($sepIdx -lt 0) {
Write-Error "patch-query value must contain ' => ' separator: old => new"
@@ -2219,12 +2497,20 @@ switch ($Operation) {
$oldStr = $val.Substring(0, $sepIdx)
$newStr = $val.Substring($sepIdx + 4)
$queryText = $queryEl.InnerText
if (-not $queryText.Contains($oldStr)) {
$count = ([regex]::Matches($queryText, [regex]::Escape($oldStr))).Count
if ($count -eq 0) {
Write-Error "Substring not found in query of dataset '$dsName': $oldStr"
exit 1
}
if ($once -and $count -ne 1) {
Write-Error "@once: expected 1 occurrence of '$oldStr' in dataset '$dsName', found $count"
exit 1
}
$queryEl.InnerText = $queryText.Replace($oldStr, $newStr)
Write-Host "[OK] Query patched in dataset `"$dsName`": replaced '$oldStr'"
$suffix = if ($once) { " (1 occurrence)" } else { " ($count occurrence(s))" }
Write-Host "[OK] Query patched in dataset `"$dsName`": replaced '$oldStr'$suffix"
}
}
@@ -2289,6 +2575,102 @@ switch ($Operation) {
Write-Host "[OK] Structure set in variant `"$varName`": $Value"
}
"modify-structure" {
$settings = Resolve-VariantSettings
$varName = Get-VariantName
$structItems = Parse-StructureShorthand $Value
# Flatten parsed tree into (name, groupBy) targets
$targets = @()
$stack = New-Object System.Collections.Stack
foreach ($it in $structItems) { $stack.Push($it) }
while ($stack.Count -gt 0) {
$it = $stack.Pop()
if ($it["name"]) {
$targets += @{ name = $it["name"]; groupBy = $it["groupBy"] }
}
if ($it["children"]) {
foreach ($ch in $it["children"]) { $stack.Push($ch) }
}
}
if ($targets.Count -eq 0) {
Write-Error "modify-structure requires @name= for at least one group: $Value"
exit 1
}
$nsMgr = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable)
$nsMgr.AddNamespace("dcsset", $setNs)
$nsMgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
foreach ($t in $targets) {
$groupEl = $settings.SelectSingleNode(".//dcsset:item[@xsi:type='dcsset:StructureItemGroup'][dcsset:name='$($t.name)']", $nsMgr)
if (-not $groupEl) {
Write-Host "[WARN] Group with @name=`"$($t.name)`" not found — skipped"
continue
}
$giEl = $null
foreach ($ch in $groupEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'groupItems' -and $ch.NamespaceURI -eq $setNs) {
$giEl = $ch; break
}
}
$groupIndent = Get-ChildIndent $groupEl
if (-not $giEl) {
# Create <groupItems> after <name>, before <order>/<selection>/...
$nameEl = $null
$refAfterName = $null
foreach ($ch in $groupEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'name' -and $ch.NamespaceURI -eq $setNs) {
$nameEl = $ch
} elseif ($ch.NodeType -eq 'Element' -and $nameEl -and -not $refAfterName) {
$refAfterName = $ch; break
}
}
$giFrag = "$groupIndent<dcsset:groupItems></dcsset:groupItems>"
$nodes = Import-Fragment $xmlDoc $giFrag
foreach ($node in $nodes) {
Insert-BeforeElement $groupEl $node $refAfterName $groupIndent
}
# Re-find
foreach ($ch in $groupEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'groupItems' -and $ch.NamespaceURI -eq $setNs) {
$giEl = $ch; break
}
}
}
$toRemove = @()
foreach ($ch in $giEl.ChildNodes) {
if ($ch.NodeType -eq 'Element') { $toRemove += $ch }
}
foreach ($el in $toRemove) { Remove-NodeWithWhitespace $el }
$itemIndent = "$groupIndent`t"
foreach ($field in $t.groupBy) {
$lines = @()
$lines += "$itemIndent<dcsset:item xsi:type=`"dcsset:GroupItemField`">"
$lines += "$itemIndent`t<dcsset:field>$(Esc-Xml $field)</dcsset:field>"
$lines += "$itemIndent`t<dcsset:groupType>Items</dcsset:groupType>"
$lines += "$itemIndent`t<dcsset:periodAdditionType>None</dcsset:periodAdditionType>"
$lines += "$itemIndent`t<dcsset:periodAdditionBegin xsi:type=`"xs:dateTime`">0001-01-01T00:00:00</dcsset:periodAdditionBegin>"
$lines += "$itemIndent`t<dcsset:periodAdditionEnd xsi:type=`"xs:dateTime`">0001-01-01T00:00:00</dcsset:periodAdditionEnd>"
$lines += "$itemIndent</dcsset:item>"
$fragXml = $lines -join "`r`n"
$nodes = Import-Fragment $xmlDoc $fragXml
foreach ($node in $nodes) {
Insert-BeforeElement $giEl $node $null $itemIndent
}
}
$desc = if ($t.groupBy.Count -eq 0) { "details" } else { $t.groupBy -join ', ' }
Write-Host "[OK] Group `"$($t.name)`" groupItems updated: $desc"
}
}
"add-dataSetLink" {
foreach ($val in $values) {
$parsed = Parse-DataSetLinkShorthand $val
@@ -2476,6 +2858,18 @@ switch ($Operation) {
}
}
"clear-conditionalAppearance" {
$settings = Resolve-VariantSettings
$varName = Get-VariantName
$caEl = Find-FirstElement $settings @("conditionalAppearance") $setNs
if ($caEl) {
Clear-ContainerChildren $caEl
Write-Host "[OK] ConditionalAppearance cleared in variant `"$varName`""
} else {
Write-Host "[INFO] No conditionalAppearance section in variant `"$varName`""
}
}
"modify-filter" {
$settings = Resolve-VariantSettings
$varName = Get-VariantName
@@ -2675,6 +3069,87 @@ switch ($Operation) {
}
}
"set-field-role" {
$dsNode = Resolve-DataSet
$dsName = Get-DataSetName $dsNode
foreach ($val in $values) {
# Parse shorthand: "dataPath [@flag ...] [kv=value ...]"
$s = $val.Trim()
# Extract @flags
$flags = @()
$flagMatches = [regex]::Matches($s, '@(\w+)')
foreach ($m in $flagMatches) { $flags += $m.Groups[1].Value }
$s = [regex]::Replace($s, '\s*@\w+', '').Trim()
# Extract kv=value (value is non-whitespace)
$kv = [ordered]@{}
$kvMatches = [regex]::Matches($s, '(\w+)=(\S+)')
foreach ($m in $kvMatches) { $kv[$m.Groups[1].Value] = $m.Groups[2].Value }
$s = [regex]::Replace($s, '\s*\w+=\S+', '').Trim()
$dataPath = $s
if (-not $dataPath) {
Write-Host "[WARN] set-field-role: empty dataPath in `"$val`""
continue
}
$fieldEl = Find-ElementByChildValue $dsNode "field" "dataPath" $dataPath $schNs
if (-not $fieldEl) {
Write-Host "[WARN] Field `"$dataPath`" not found in dataset `"$dsName`""
continue
}
$fieldIndent = Get-ChildIndent $fieldEl
# Remove existing <role>
$oldRole = $null
foreach ($ch in $fieldEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -eq 'role' -and $ch.NamespaceURI -eq $schNs) { $oldRole = $ch; break }
}
if ($oldRole) { Remove-NodeWithWhitespace $oldRole }
# Empty spec — remove only
if ($flags.Count -eq 0 -and $kv.Count -eq 0) {
Write-Host "[OK] Field `"$dataPath`" role cleared"
continue
}
# Build new <role>
$lines = @()
$lines += "$fieldIndent<role>"
foreach ($flag in $flags) {
if ($flag -eq 'period') {
$lines += "$fieldIndent`t<dcscom:periodNumber>1</dcscom:periodNumber>"
$lines += "$fieldIndent`t<dcscom:periodType>Main</dcscom:periodType>"
} else {
$lines += "$fieldIndent`t<dcscom:$flag>true</dcscom:$flag>"
}
}
foreach ($k in $kv.Keys) {
$lines += "$fieldIndent`t<dcscom:$k>$(Esc-Xml $kv[$k])</dcscom:$k>"
}
$lines += "$fieldIndent</role>"
$fragXml = $lines -join "`r`n"
# Insert before <valueType>, else before <inputParameters>, else at end
$refNode = $null
foreach ($ch in $fieldEl.ChildNodes) {
if ($ch.NodeType -eq 'Element' -and $ch.LocalName -in @('valueType','inputParameters') -and $ch.NamespaceURI -eq $schNs) { $refNode = $ch; break }
}
$nodes = Import-Fragment $xmlDoc $fragXml
foreach ($node in $nodes) {
Insert-BeforeElement $fieldEl $node $refNode $fieldIndent
}
$desc = @()
if ($flags.Count -gt 0) { $desc += ($flags | ForEach-Object { "@$_" }) -join ' ' }
if ($kv.Count -gt 0) { $desc += ($kv.Keys | ForEach-Object { "$_=$($kv[$_])" }) -join ' ' }
Write-Host "[OK] Field `"$dataPath`" role set: $($desc -join ' ')"
}
}
"remove-field" {
$dsNode = Resolve-DataSet
$dsName = Get-DataSetName $dsNode
+422 -54
View File
@@ -1,4 +1,4 @@
# skd-edit v1.11 — Atomic 1C DCS editor (Python port)
# skd-edit v1.18 — Atomic 1C DCS editor (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -18,9 +18,9 @@ VALID_OPS = [
"add-dataParameter", "add-order", "add-selection", "add-dataSetLink",
"add-dataSet", "add-variant", "add-conditionalAppearance", "add-drilldown",
"set-query", "patch-query", "set-outputParameter", "set-structure",
"modify-field", "modify-filter", "modify-dataParameter", "modify-parameter",
"modify-field", "modify-filter", "modify-dataParameter", "modify-parameter", "modify-structure", "set-field-role",
"rename-parameter", "reorder-parameters",
"clear-selection", "clear-order", "clear-filter",
"clear-selection", "clear-order", "clear-filter", "clear-conditionalAppearance",
"remove-field", "remove-total", "remove-calculated-field", "remove-parameter", "remove-filter",
]
@@ -250,13 +250,21 @@ def read_field_properties(field_el):
def parse_total_shorthand(s):
# "DataPath: Func" or "DataPath: Func(expr)" or "DataPath: ИмяРесурса" (identity)
parts = s.split(":", 1)
data_path = parts[0].strip()
func_part = parts[1].strip()
agg_funcs = {'Сумма', 'Количество', 'Минимум', 'Максимум', 'Среднее',
'Sum', 'Count', 'Min', 'Max', 'Avg',
'Minimum', 'Maximum', 'Average'}
if re.match(r'^\w+\(', func_part):
return {"dataPath": data_path, "expression": func_part}
else:
elif func_part in agg_funcs:
return {"dataPath": data_path, "expression": f"{func_part}({data_path})"}
else:
return {"dataPath": data_path, "expression": func_part}
def parse_calc_shorthand(s):
@@ -299,12 +307,26 @@ def parse_calc_shorthand(s):
def parse_param_shorthand(s):
result = {"name": "", "type": "", "value": None, "autoDates": False, "title": None}
result = {"name": "", "type": "", "value": None, "autoDates": False, "title": None, "hidden": False, "always": False, "availableValues": []}
# Extract availableValue=... (must be before main parse — captures to end of string)
m_av = re.search(r'\s*availableValue=(.+)$', s)
if m_av:
result["availableValues"] = parse_available_value_list(m_av.group(1).strip())
s = re.sub(r'\s*availableValue=.+$', '', s).strip()
if re.search(r'@autoDates', s):
result["autoDates"] = True
s = re.sub(r'\s*@autoDates', '', s)
if re.search(r'@hidden\b', s):
result["hidden"] = True
s = re.sub(r'\s*@hidden\b', '', s)
if re.search(r'@always\b', s):
result["always"] = True
s = re.sub(r'\s*@always\b', '', s)
# Extract optional [Title] (mirrors parse_field_shorthand)
m = re.search(r'\[([^\]]*)\]', s)
if m:
@@ -545,15 +567,17 @@ def parse_structure_shorthand(s):
seg = segments[i].strip()
group = {"type": "group"}
name_m = re.search(r'\s*@name=(.+)', seg)
name_m = re.search(r'@name=(?:"([^"]+)"|\'([^\']+)\'|(\S+))', seg)
if name_m:
group["name"] = name_m.group(1).strip()
seg = re.sub(r'\s*@name=.+', '', seg).strip()
raw_name = name_m.group(1) or name_m.group(2) or name_m.group(3)
group["name"] = raw_name.strip()
seg = re.sub(r'\s*@name=(?:"[^"]+"|\'[^\']+\'|\S+)', '', seg).strip()
if re.match(r'^(details|\u0434\u0435\u0442\u0430\u043b\u0438)$', seg, re.IGNORECASE):
group["groupBy"] = []
else:
group["groupBy"] = [seg]
fields = [f.strip() for f in re.split(r'\s*,\s*', seg) if f.strip()]
group["groupBy"] = fields
if innermost is not None:
group["children"] = [innermost]
@@ -571,6 +595,80 @@ def parse_output_param_shorthand(s):
return {"key": s.strip(), "value": ""}
def parse_available_value_list(s):
"""Returns list of {value, presentation} from comma-separated list.
Items can use single/double quotes (stripped). Quoted spans preserve commas/colons."""
if not s:
return []
# Tokenize by ',' respecting quoted spans
items = []
buf = []
in_quote = None
for ch in s:
if in_quote:
buf.append(ch)
if ch == in_quote:
in_quote = None
elif ch in ("'", '"'):
in_quote = ch
buf.append(ch)
elif ch == ',':
items.append("".join(buf))
buf = []
else:
buf.append(ch)
if buf:
items.append("".join(buf))
def strip_quotes(t):
t = t.strip()
if len(t) >= 2 and ((t[0] == "'" and t[-1] == "'") or (t[0] == '"' and t[-1] == '"')):
return t[1:-1]
return t
result = []
for raw in items:
item = raw.strip()
if not item:
continue
# Find first ':' outside quotes
colon_idx = -1
q = None
for j, c in enumerate(item):
if q:
if c == q:
q = None
elif c in ("'", '"'):
q = c
elif c == ':':
colon_idx = j
break
if colon_idx >= 0:
val_part = item[:colon_idx]
pres_part = item[colon_idx + 1:]
result.append({"value": strip_quotes(val_part), "presentation": strip_quotes(pres_part)})
else:
result.append({"value": strip_quotes(item), "presentation": ""})
return result
def build_available_value_fragment(item, declared_type, indent):
"""Return XML lines for a single <availableValue> block."""
lines = [f"{indent}<availableValue>"]
for vl in build_param_value_xml(declared_type, item["value"], f"{indent}\t"):
lines.append(vl)
if item.get("presentation"):
lines.append(f'{indent}\t<presentation xsi:type="v8:LocalStringType">')
lines.append(f"{indent}\t\t<v8:item>")
lines.append(f"{indent}\t\t\t<v8:lang>ru</v8:lang>")
lines.append(f"{indent}\t\t\t<v8:content>{esc_xml(item['presentation'])}</v8:content>")
lines.append(f"{indent}\t\t</v8:item>")
lines.append(f"{indent}\t</presentation>")
lines.append(f"{indent}</availableValue>")
return lines
# ── 4. Build-* functions (XML fragment generators) ──────────
def build_value_type_xml(type_str, indent):
@@ -724,6 +822,47 @@ def build_calc_field_fragment(parsed, indent):
return "\r\n".join(lines)
def build_param_value_xml(type_str, value, indent, tag_name="value", tag_ns=""):
"""Return list of XML lines for <value xsi:type=...>...</value>."""
val_str = "" if value is None else str(value)
open_tag = f"{tag_ns}:{tag_name}" if tag_ns else tag_name
lines = []
if type_str == "StandardPeriod":
lines.append(f'{indent}<{open_tag} xsi:type="v8:StandardPeriod">')
lines.append(f'{indent}\t<v8:variant xsi:type="v8:StandardPeriodVariant">{esc_xml(val_str)}</v8:variant>')
lines.append(f"{indent}\t<v8:startDate>0001-01-01T00:00:00</v8:startDate>")
lines.append(f"{indent}\t<v8:endDate>0001-01-01T00:00:00</v8:endDate>")
lines.append(f"{indent}</{open_tag}>")
return lines
t = type_str or ""
xsi = None
if t.startswith("date"):
xsi = "xs:dateTime"
elif t == "boolean":
xsi = "xs:boolean"
elif t.startswith("decimal"):
xsi = "xs:decimal"
elif t.startswith("string"):
xsi = "xs:string"
elif re.match(r'^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|BusinessProcessRef|TaskRef|ExchangePlanRef)\.', t):
xsi = "dcscor:DesignTimeValue"
else:
if re.match(r'^\d{4}-\d{2}-\d{2}T', val_str):
xsi = "xs:dateTime"
elif val_str in ("true", "false"):
xsi = "xs:boolean"
elif re.match(r'^(Перечисление|Справочник|ПланСчетов|Документ|ПланВидовХарактеристик|ПланВидовРасчета|БизнесПроцесс|Задача|РегистрСведений|ПланОбмена)\.', val_str) or \
re.match(r'^(Catalog|Document|Enum|ChartOfAccounts|ChartOfCharacteristicTypes|ChartOfCalculationTypes|BusinessProcess|Task|InformationRegister|ExchangePlan)\.', val_str):
xsi = "dcscor:DesignTimeValue"
else:
xsi = "xs:string"
lines.append(f'{indent}<{open_tag} xsi:type="{xsi}">{esc_xml(val_str)}</{open_tag}>')
return lines
def build_param_fragment(parsed, indent):
i = indent
fragments = []
@@ -739,21 +878,19 @@ def build_param_fragment(parsed, indent):
lines.append(f"{i}\t</valueType>")
if parsed["value"] is not None:
val_str = str(parsed["value"])
if parsed.get("type") == "StandardPeriod":
lines.append(f'{i}\t<value xsi:type="v8:StandardPeriod">')
lines.append(f'{i}\t\t<v8:variant xsi:type="v8:StandardPeriodVariant">{esc_xml(val_str)}</v8:variant>')
lines.append(f"{i}\t\t<v8:startDate>0001-01-01T00:00:00</v8:startDate>")
lines.append(f"{i}\t\t<v8:endDate>0001-01-01T00:00:00</v8:endDate>")
lines.append(f"{i}\t</value>")
elif parsed.get("type", "").startswith("date"):
lines.append(f'{i}\t<value xsi:type="xs:dateTime">{esc_xml(val_str)}</value>')
elif parsed.get("type") == "boolean":
lines.append(f'{i}\t<value xsi:type="xs:boolean">{esc_xml(val_str)}</value>')
elif parsed.get("type", "").startswith("decimal"):
lines.append(f'{i}\t<value xsi:type="xs:decimal">{esc_xml(val_str)}</value>')
else:
lines.append(f'{i}\t<value xsi:type="xs:string">{esc_xml(val_str)}</value>')
for vl in build_param_value_xml(parsed.get("type", ""), parsed["value"], f"{i}\t"):
lines.append(vl)
if parsed.get("hidden"):
lines.append(f"{i}\t<useRestriction>true</useRestriction>")
lines.append(f"{i}\t<availableAsField>false</availableAsField>")
for av in parsed.get("availableValues", []) or []:
for l in build_available_value_fragment(av, parsed.get("type", ""), f"{i}\t"):
lines.append(l)
if parsed.get("always"):
lines.append(f"{i}\t<use>Always</use>")
lines.append(f"{i}</parameter>")
fragments.append("\r\n".join(lines))
@@ -1361,10 +1498,10 @@ xml_doc = tree.getroot()
# ── 7. Batch value splitting ────────────────────────────────
if operation in ("set-query", "set-structure", "add-dataSet"):
if operation in ("set-query", "set-structure", "modify-structure", "add-dataSet"):
values = [value_arg]
elif operation == "patch-query":
values = [v for v in value_arg.split(";;") if v.strip()]
values = [v.strip() for v in value_arg.split(";;") if v.strip()]
elif operation == "add-drilldown":
if ";;" in value_arg:
values = [v.strip() for v in value_arg.split(";;") if v.strip()]
@@ -1537,6 +1674,15 @@ elif operation == "modify-parameter":
param_name = parts[0].strip()
rest = parts[1].strip() if len(parts) > 1 else ""
flag_hidden = False
flag_always = False
if re.search(r'@hidden\b', rest):
flag_hidden = True
rest = re.sub(r'\s*@hidden\b', '', rest).strip()
if re.search(r'@always\b', rest):
flag_always = True
rest = re.sub(r'\s*@always\b', '', rest).strip()
param_el = find_element_by_child_value(xml_doc, "parameter", "name", param_name, SCH_NS)
if param_el is None:
print(f'[WARN] Parameter "{param_name}" not found -- skipped')
@@ -1568,8 +1714,33 @@ elif operation == "modify-parameter":
if simple_rest:
for m in re.finditer(r'(\w+)=(\S+)', simple_rest):
key, value = m.group(1), m.group(2)
existing = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) == key), None)
if existing is not None:
existing = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) == key and etree.QName(ch.tag).namespace == SCH_NS), None)
if key == "value":
# Rebuild <value> with correct xsi:type from <valueType>
declared_type = ""
vt_el = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) == "valueType" and etree.QName(ch.tag).namespace == SCH_NS), None)
if vt_el is not None:
for tnode in vt_el:
if isinstance(tnode.tag, str) and local_name(tnode) == "Type":
declared_type = re.sub(r'^d\d+p\d+:', '', (tnode.text or "").strip())
break
value_lines = build_param_value_xml(declared_type, value, child_indent)
frag_xml = "\r\n".join(value_lines)
was_existing = existing is not None
if existing is not None:
# Find next-element sibling as ref before removing
idx = list(param_el).index(existing)
ref_node = param_el[idx + 1] if idx + 1 < len(param_el) else None
remove_node_with_whitespace(existing)
else:
ref_node = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) in ("useRestriction", "availableValue", "denyIncompleteValues", "use")), None)
nodes = import_fragment(xml_doc, frag_xml)
for node in nodes:
insert_before_element(param_el, node, ref_node, child_indent)
verb = "updated" if was_existing else "added"
print(f'[OK] Parameter "{param_name}": value {verb} to {value}')
elif existing is not None:
existing.text = value
print(f'[OK] Parameter "{param_name}": {key} updated to {value}')
else:
@@ -1585,38 +1756,71 @@ elif operation == "modify-parameter":
# Process availableValue
if av_part:
av_rest = av_part[len("availableValue="):]
# Parse: "Перечисление...X presentation=текст с пробелами"
av_parts = re.split(r'\s+presentation=', av_rest, 1)
av_value = av_parts[0].strip()
av_presentation = av_parts[1].strip() if len(av_parts) > 1 else ""
av_rest = av_part[len("availableValue="):].strip()
av_items = parse_available_value_list(av_rest)
av_type = "xs:string"
if re.match(r'^(Перечисление|Справочник|ПланСчетов|Документ|ПланВидовХарактеристик|ПланВидовРасчета)\.', av_value):
av_type = "dcscor:DesignTimeValue"
# Prefer declared <valueType> of the parameter; fall back to value pattern
declared_type = ""
vt_el = None
for ch in param_el:
if isinstance(ch.tag, str) and local_name(ch) == "valueType" and etree.QName(ch.tag).namespace == SCH_NS:
vt_el = ch
break
if vt_el is not None:
for tnode in vt_el:
if isinstance(tnode.tag, str) and local_name(tnode) == "Type":
declared_type = re.sub(r'^d\d+p\d+:', '', (tnode.text or "").strip())
break
av_lines = [f"{child_indent}<availableValue>"]
av_lines.append(f'{child_indent}\t<value xsi:type="{av_type}">{esc_xml(av_value)}</value>')
if av_presentation:
av_lines.append(f'{child_indent}\t<presentation xsi:type="v8:LocalStringType">')
av_lines.append(f"{child_indent}\t\t<v8:item>")
av_lines.append(f"{child_indent}\t\t\t<v8:lang>ru</v8:lang>")
av_lines.append(f"{child_indent}\t\t\t<v8:content>{esc_xml(av_presentation)}</v8:content>")
av_lines.append(f"{child_indent}\t\t</v8:item>")
av_lines.append(f"{child_indent}\t</presentation>")
av_lines.append(f"{child_indent}</availableValue>")
frag_xml = "\r\n".join(av_lines)
# Remove all existing <availableValue>
to_remove = [ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) == "availableValue" and etree.QName(ch.tag).namespace == SCH_NS]
for el in to_remove:
remove_node_with_whitespace(el)
# Insert before first of (denyIncompleteValues, use) in document order
# Insert each new <availableValue> before (denyIncompleteValues, use)
ref_node = None
for child in param_el:
if isinstance(child.tag, str) and local_name(child) in ("denyIncompleteValues", "use"):
ref_node = child
break
nodes = import_fragment(xml_doc, frag_xml)
for node in nodes:
insert_before_element(param_el, node, ref_node, child_indent)
print(f'[OK] Parameter "{param_name}": availableValue added')
for av in av_items:
av_lines = build_available_value_fragment(av, declared_type, child_indent)
frag_xml = "\r\n".join(av_lines)
nodes = import_fragment(xml_doc, frag_xml)
for node in nodes:
insert_before_element(param_el, node, ref_node, child_indent)
print(f'[OK] Parameter "{param_name}": availableValue set to {len(av_items)} item(s)')
if flag_hidden:
ur_el = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) == "useRestriction" and etree.QName(ch.tag).namespace == SCH_NS), None)
if ur_el is not None:
if (ur_el.text or "").strip() != "true":
ur_el.text = "true"
else:
ref_node = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) in ("expression", "availableAsField", "availableValue", "denyIncompleteValues", "use")), None)
for node in import_fragment(xml_doc, f"{child_indent}<useRestriction>true</useRestriction>"):
insert_before_element(param_el, node, ref_node, child_indent)
af_el = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) == "availableAsField" and etree.QName(ch.tag).namespace == SCH_NS), None)
if af_el is not None:
if (af_el.text or "").strip() != "false":
af_el.text = "false"
else:
ref_node = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) in ("availableValue", "denyIncompleteValues", "use")), None)
for node in import_fragment(xml_doc, f"{child_indent}<availableAsField>false</availableAsField>"):
insert_before_element(param_el, node, ref_node, child_indent)
print(f'[OK] Parameter "{param_name}": @hidden applied')
if flag_always:
use_el = next((ch for ch in param_el if isinstance(ch.tag, str) and local_name(ch) == "use" and etree.QName(ch.tag).namespace == SCH_NS), None)
if use_el is not None:
if (use_el.text or "").strip() != "Always":
use_el.text = "Always"
else:
for node in import_fragment(xml_doc, f"{child_indent}<use>Always</use>"):
insert_before_element(param_el, node, None, child_indent)
print(f'[OK] Parameter "{param_name}": @always applied')
elif operation == "rename-parameter":
root = xml_doc
@@ -1868,6 +2072,11 @@ elif operation == "patch-query":
print(f"No <query> element found in dataset '{ds_name}'", file=sys.stderr)
sys.exit(1)
for val in values:
once = False
if re.search(r'@once\b', val):
once = True
val = re.sub(r'\s*@once\b', '', val).strip()
sep_idx = val.find(" => ")
if sep_idx < 0:
print("patch-query value must contain ' => ' separator: old => new", file=sys.stderr)
@@ -1875,11 +2084,18 @@ elif operation == "patch-query":
old_str = val[:sep_idx]
new_str = val[sep_idx + 4:]
query_text = query_el.text or ""
if old_str not in query_text:
count = query_text.count(old_str)
if count == 0:
print(f"Substring not found in query of dataset '{ds_name}': {old_str}", file=sys.stderr)
sys.exit(1)
if once and count != 1:
print(f"@once: expected 1 occurrence of '{old_str}' in dataset '{ds_name}', found {count}", file=sys.stderr)
sys.exit(1)
query_el.text = query_text.replace(old_str, new_str)
print(f'[OK] Query patched in dataset "{ds_name}": replaced \'{old_str}\'')
suffix = " (1 occurrence)" if once else f" ({count} occurrence(s))"
print(f'[OK] Query patched in dataset "{ds_name}": replaced \'{old_str}\'{suffix}')
elif operation == "set-outputParameter":
settings = resolve_variant_settings()
@@ -1922,6 +2138,85 @@ elif operation == "set-structure":
print(f'[OK] Structure set in variant "{var_name}": {value_arg}')
elif operation == "modify-structure":
settings = resolve_variant_settings()
var_name = get_variant_name()
struct_items = parse_structure_shorthand(value_arg)
# Flatten parsed tree into (name, groupBy) targets
targets = []
stack = list(struct_items)
while stack:
it = stack.pop()
if it.get("name"):
targets.append({"name": it["name"], "groupBy": it.get("groupBy", [])})
for ch in it.get("children", []) or []:
stack.append(ch)
if not targets:
print(f"modify-structure requires @name= for at least one group: {value_arg}", file=sys.stderr)
sys.exit(1)
ns = {"dcsset": SET_NS, "xsi": XSI_NS}
for t in targets:
xpath = f".//dcsset:item[@xsi:type='dcsset:StructureItemGroup'][dcsset:name='{t['name']}']"
group_el = settings.find(xpath, ns)
if group_el is None:
print(f'[WARN] Group with @name="{t["name"]}" not found — skipped')
continue
gi_el = None
for ch in group_el:
if isinstance(ch.tag, str) and local_name(ch) == "groupItems" and etree.QName(ch.tag).namespace == SET_NS:
gi_el = ch
break
group_indent = get_child_indent(group_el)
if gi_el is None:
# Insert <groupItems> after <name>, before first non-name sibling
ref_after_name = None
saw_name = False
for ch in group_el:
if not isinstance(ch.tag, str):
continue
if local_name(ch) == "name" and etree.QName(ch.tag).namespace == SET_NS:
saw_name = True
elif saw_name:
ref_after_name = ch
break
gi_frag = f"{group_indent}<dcsset:groupItems></dcsset:groupItems>"
for node in import_fragment(xml_doc, gi_frag):
insert_before_element(group_el, node, ref_after_name, group_indent)
for ch in group_el:
if isinstance(ch.tag, str) and local_name(ch) == "groupItems" and etree.QName(ch.tag).namespace == SET_NS:
gi_el = ch
break
to_remove = [ch for ch in gi_el if isinstance(ch.tag, str)]
for el in to_remove:
remove_node_with_whitespace(el)
item_indent = group_indent + "\t"
for field in t["groupBy"]:
lines = [
f'{item_indent}<dcsset:item xsi:type="dcsset:GroupItemField">',
f'{item_indent}\t<dcsset:field>{esc_xml(field)}</dcsset:field>',
f'{item_indent}\t<dcsset:groupType>Items</dcsset:groupType>',
f'{item_indent}\t<dcsset:periodAdditionType>None</dcsset:periodAdditionType>',
f'{item_indent}\t<dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>',
f'{item_indent}\t<dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>',
f'{item_indent}</dcsset:item>',
]
frag_xml = "\r\n".join(lines)
for node in import_fragment(xml_doc, frag_xml):
insert_before_element(gi_el, node, None, item_indent)
desc = "details" if not t["groupBy"] else ", ".join(t["groupBy"])
print(f'[OK] Group "{t["name"]}" groupItems updated: {desc}')
elif operation == "add-dataSetLink":
for val in values:
parsed = parse_data_set_link_shorthand(val)
@@ -2085,6 +2380,16 @@ elif operation == "clear-filter":
else:
print(f'[INFO] No filter section in variant "{var_name}"')
elif operation == "clear-conditionalAppearance":
settings = resolve_variant_settings()
var_name = get_variant_name()
ca_el = find_first_element(settings, ["conditionalAppearance"], SET_NS)
if ca_el is not None:
clear_container_children(ca_el)
print(f'[OK] ConditionalAppearance cleared in variant "{var_name}"')
else:
print(f'[INFO] No conditionalAppearance section in variant "{var_name}"')
elif operation == "modify-filter":
settings = resolve_variant_settings()
var_name = get_variant_name()
@@ -2237,6 +2542,69 @@ elif operation == "modify-field":
print(f'[OK] Field "{field_name}" modified in dataset "{ds_name}"')
elif operation == "set-field-role":
ds_node = resolve_data_set()
ds_name = get_data_set_name(ds_node)
for val in values:
s = val.strip()
flags = []
for m in re.finditer(r'@(\w+)', s):
flags.append(m.group(1))
s = re.sub(r'\s*@\w+', '', s).strip()
kv = []
for m in re.finditer(r'(\w+)=(\S+)', s):
kv.append((m.group(1), m.group(2)))
s = re.sub(r'\s*\w+=\S+', '', s).strip()
data_path = s
if not data_path:
print(f'[WARN] set-field-role: empty dataPath in "{val}"')
continue
field_el = find_element_by_child_value(ds_node, "field", "dataPath", data_path, SCH_NS)
if field_el is None:
print(f'[WARN] Field "{data_path}" not found in dataset "{ds_name}"')
continue
field_indent = get_child_indent(field_el)
# Remove existing <role>
old_role = next((ch for ch in field_el if isinstance(ch.tag, str) and local_name(ch) == "role" and etree.QName(ch.tag).namespace == SCH_NS), None)
if old_role is not None:
remove_node_with_whitespace(old_role)
# Empty spec — remove only
if not flags and not kv:
print(f'[OK] Field "{data_path}" role cleared')
continue
# Build new <role>
lines = [f"{field_indent}<role>"]
for flag in flags:
if flag == "period":
lines.append(f"{field_indent}\t<dcscom:periodNumber>1</dcscom:periodNumber>")
lines.append(f"{field_indent}\t<dcscom:periodType>Main</dcscom:periodType>")
else:
lines.append(f"{field_indent}\t<dcscom:{flag}>true</dcscom:{flag}>")
for k, v in kv:
lines.append(f"{field_indent}\t<dcscom:{k}>{esc_xml(v)}</dcscom:{k}>")
lines.append(f"{field_indent}</role>")
frag_xml = "\r\n".join(lines)
ref_node = next((ch for ch in field_el if isinstance(ch.tag, str) and local_name(ch) in ("valueType", "inputParameters") and etree.QName(ch.tag).namespace == SCH_NS), None)
for node in import_fragment(xml_doc, frag_xml):
insert_before_element(field_el, node, ref_node, field_indent)
parts = []
if flags:
parts.append(" ".join(f"@{f}" for f in flags))
if kv:
parts.append(" ".join(f"{k}={v}" for k, v in kv))
print(f'[OK] Field "{data_path}" role set: {" ".join(parts)}')
elif operation == "remove-field":
ds_node = resolve_data_set()
ds_name = get_data_set_name(ds_node)
+8 -2
View File
@@ -1,4 +1,4 @@
# skd-info v1.3 — Analyze 1C DCS structure
# skd-info v1.4 — Analyze 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory=$true)]
@@ -824,8 +824,14 @@ function Show-Fields {
$roleParts = @()
if ($role) {
foreach ($child in $role.ChildNodes) {
if ($child.NodeType -eq "Element" -and $child.InnerText -eq "true") {
if ($child.NodeType -ne "Element") { continue }
$txt = $child.InnerText.Trim()
if ($txt -eq "true") {
$roleParts += $child.LocalName
} elseif ($txt -eq "false") {
# skip default-false flags
} else {
$roleParts += "$($child.LocalName)=$txt"
}
}
}
+9 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# skd-info v1.3 — Analyze 1C DCS structure
# skd-info v1.4 — Analyze 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -777,8 +777,15 @@ def main():
role_parts = []
if role is not None:
for child in role:
if isinstance(child.tag, str) and (child.text or "").strip() == "true":
if not isinstance(child.tag, str):
continue
txt = (child.text or "").strip()
if txt == "true":
role_parts.append(localname(child))
elif txt == "false":
pass
else:
role_parts.append(f"{localname(child)}={txt}")
info["role"] = ", ".join(role_parts)
# UseRestriction
@@ -0,0 +1,5 @@
{
"name": "DataPath с Items.<Table>.CurrentData и ~Атрибут не вызывают ложных ошибок",
"setup": "fixture:datapath-currentdata",
"params": { "formPath": "DataProcessors/Spec/Forms/Форма" }
}
@@ -0,0 +1,5 @@
{
"name": "Числовые и UUID DataPath не вызывают ложных ошибок",
"setup": "fixture:datapath-opaque-refs",
"params": { "formPath": "DataProcessors/Opaque/Forms/Форма" }
}
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<Form xmlns="http://v8.1c.ru/8.3/xcf/logform" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Title>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест</v8:content>
</v8:item>
</Title>
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
<ChildItems>
<Table name="Список" id="1">
<DataPath>Список</DataPath>
<ContextMenu name="СписокКонтекстноеМеню" id="2"/>
<AutoCommandBar name="СписокКоманднаяПанель" id="3"/>
<SearchStringAddition name="СписокСтрокаПоиска" id="4"/>
<ViewStatusAddition name="СписокСостояниеПросмотра" id="5"/>
<SearchControlAddition name="СписокУправлениеПоиском" id="6"/>
<ChildItems>
<InputField name="Ссылка" id="7">
<DataPath>Список.Ссылка</DataPath>
<ContextMenu name="СсылкаКонтекстноеМеню" id="8"/>
<ExtendedTooltip name="СсылкаРасширеннаяПодсказка" id="9"/>
</InputField>
</ChildItems>
</Table>
<InputField name="ТекущаяСсылка" id="10">
<DataPath>Items.Список.CurrentData.Ссылка</DataPath>
<ContextMenu name="ТекущаяСсылкаКонтекстноеМеню" id="11"/>
<ExtendedTooltip name="ТекущаяСсылкаРасширеннаяПодсказка" id="12"/>
</InputField>
<InputField name="ВыбраннаяСсылка" id="13">
<DataPath>~Список.Ссылка</DataPath>
<ContextMenu name="ВыбраннаяСсылкаКонтекстноеМеню" id="14"/>
<ExtendedTooltip name="ВыбраннаяСсылкаРасширеннаяПодсказка" id="15"/>
</InputField>
</ChildItems>
<Attributes>
<Attribute name="Список" id="16">
<Type>
<v8:Type>cfg:DynamicList</v8:Type>
</Type>
<MainAttribute>true</MainAttribute>
</Attribute>
</Attributes>
</Form>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<Form xmlns="http://v8.1c.ru/8.3/xcf/logform" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Title>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест</v8:content>
</v8:item>
</Title>
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
<ChildItems>
<InputField name="ПривязкаПоUUID" id="1">
<DataPath>1/0:a917a122-f663-4c45-8de0-fd5104007de3</DataPath>
<ContextMenu name="ПривязкаПоUUIDКонтекстноеМеню" id="2"/>
<ExtendedTooltip name="ПривязкаПоUUIDРасширеннаяПодсказка" id="3"/>
</InputField>
<LabelField name="ЧисловаяПривязка" id="4">
<DataPath>10</DataPath>
<ContextMenu name="ЧисловаяПривязкаКонтекстноеМеню" id="5"/>
<ExtendedTooltip name="ЧисловаяПривязкаРасширеннаяПодсказка" id="6"/>
</LabelField>
<InputField name="Нормальное" id="7">
<DataPath>Объект.Наименование</DataPath>
<ContextMenu name="НормальноеКонтекстноеМеню" id="8"/>
<ExtendedTooltip name="НормальноеРасширеннаяПодсказка" id="9"/>
</InputField>
</ChildItems>
<Attributes>
<Attribute name="Объект" id="10">
<Type>
<v8:Type>cfg:DataProcessorObject.Opaque</v8:Type>
</Type>
<MainAttribute>true</MainAttribute>
</Attribute>
</Attributes>
</Form>
@@ -0,0 +1,21 @@
{
"name": "add-parameter @hidden @always: useRestriction+availableAsField+use=Always",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т",
"fields": ["Поле: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "add-parameter",
"value": "Контрагент: CatalogRef.Контрагенты = Справочник.Контрагенты.ПустаяСсылка @hidden @always"
}
}
@@ -0,0 +1,21 @@
{
"name": "add-parameter: ссылочный тип → xsi:type=dcscor:DesignTimeValue",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Счет ИЗ Регистр КАК Т",
"fields": ["Счет: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "add-parameter",
"value": "Контрагент: CatalogRef.Контрагенты = Справочник.Контрагенты.ПустаяСсылка"
}
}
@@ -0,0 +1,21 @@
{
"name": "add-parameter с initial availableValue list (с запятой в кавычках)",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т",
"fields": ["Поле: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "add-parameter",
"value": "Округление: EnumRef.Округления = Окр1_00 availableValue=Перечисление.Округления.Окр1_00: 'руб., коп.', Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс. руб."
}
}
@@ -0,0 +1,21 @@
{
"name": "add-total: 'X: X' — identity expression (без обёртки в Func)",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Проверка ИЗ Регистр КАК Т",
"fields": ["Проверка: decimal(15,2)"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "add-total",
"value": "Проверка: Проверка"
}
}
@@ -0,0 +1,25 @@
{
"name": "clear-conditionalAppearance: очистить все правила оформления варианта",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Сумма ИЗ Регистр КАК Т",
"fields": ["Сумма: decimal(15,2)"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
},
{
"script": "skd-edit/scripts/skd-edit",
"args": { "-TemplatePath": "{workDir}/Template.xml", "-Operation": "add-conditionalAppearance", "-Value": "ЦветТекста = web:Red when Сумма < 0 ;; ЦветФона = web:LightGreen when Сумма > 1000" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "clear-conditionalAppearance",
"value": "*"
}
}
@@ -0,0 +1,25 @@
{
"name": "modify-parameter availableValue: replace whole list (старый список удалён, новый добавлен)",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т",
"fields": ["Поле: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
},
{
"script": "skd-edit/scripts/skd-edit",
"args": { "-TemplatePath": "{workDir}/Template.xml", "-Operation": "add-parameter", "-Value": "Округление: EnumRef.Округления = Окр1_00 availableValue=Перечисление.Округления.Окр1_00: ст1, Перечисление.Округления.Окр1: ст2, Перечисление.Округления.Окр1000: ст3" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "modify-parameter",
"value": "Округление availableValue=Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс., Перечисление.Округления.Окр1000000: млн."
}
}
@@ -17,6 +17,6 @@
"params": {
"templatePath": "Template.xml",
"operation": "modify-parameter",
"value": "ПорядокОкругления denyIncompleteValues=true use=Always availableValue=Перечисление.Округления.Окр1_00 presentation=руб. коп ;; ПорядокОкругления availableValue=Перечисление.Округления.Окр1 presentation=руб. ;; ПорядокОкругления availableValue=Перечисление.Округления.Окр1000 presentation=тыс. руб"
"value": "ПорядокОкругления denyIncompleteValues=true use=Always availableValue=Перечисление.Округления.Окр1_00: руб. коп, Перечисление.Округления.Окр1: руб., Перечисление.Округления.Окр1000: тыс. руб"
}
}
@@ -0,0 +1,29 @@
{
"name": "modify-parameter @hidden @always: идемпотентность",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т",
"fields": ["Поле: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
},
{
"script": "skd-edit/scripts/skd-edit",
"args": { "-TemplatePath": "{workDir}/Template.xml", "-Operation": "add-parameter", "-Value": "Контрагент: CatalogRef.Контрагенты = Справочник.Контрагенты.ПустаяСсылка" }
},
{
"script": "skd-edit/scripts/skd-edit",
"args": { "-TemplatePath": "{workDir}/Template.xml", "-Operation": "modify-parameter", "-Value": "Контрагент @hidden @always" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "modify-parameter",
"value": "Контрагент @hidden @always"
}
}
@@ -0,0 +1,25 @@
{
"name": "modify-parameter value=... обновляет существующий <value> (не дублирует)",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Счет ИЗ Регистр КАК Т",
"fields": ["Счет: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
},
{
"script": "skd-edit/scripts/skd-edit",
"args": { "-TemplatePath": "{workDir}/Template.xml", "-Operation": "add-parameter", "-Value": "Контрагент: CatalogRef.Контрагенты = Справочник.Контрагенты.ПустаяСсылка" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "modify-parameter",
"value": "Контрагент value=Справочник.Контрагенты.НашаОрганизация"
}
}
@@ -17,6 +17,6 @@
"params": {
"templatePath": "Template.xml",
"operation": "modify-parameter",
"value": "ПорядокОкругления use=Always ;; ПорядокОкругления denyIncompleteValues=true ;; ПорядокОкругления availableValue=Перечисление.Округления.Окр1_00 presentation=руб. коп ;; ПорядокОкругления availableValue=Перечисление.Округления.Окр1 presentation=руб."
"value": "ПорядокОкругления use=Always ;; ПорядокОкругления denyIncompleteValues=true ;; ПорядокОкругления availableValue=Перечисление.Округления.Окр1_00: руб. коп, Перечисление.Округления.Окр1: руб."
}
}
@@ -0,0 +1,29 @@
{
"name": "modify-structure меняет groupItems, сохраняет Selection",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Счет, Т.Сумма, Т.Валюта ИЗ Регистр КАК Т",
"fields": ["Счет: string", "Сумма: decimal(15,2)", "Валюта: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
},
{
"script": "skd-edit/scripts/skd-edit",
"args": { "-TemplatePath": "{workDir}/Template.xml", "-Operation": "set-structure", "-Value": "Счет @name=ДанныеОтчета" }
},
{
"script": "skd-edit/scripts/skd-edit",
"args": { "-TemplatePath": "{workDir}/Template.xml", "-Operation": "add-selection", "-Value": "Счет @group=ДанныеОтчета ;; Сумма @group=ДанныеОтчета" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "modify-structure",
"value": "Валюта @name=ДанныеОтчета"
}
}
@@ -0,0 +1,21 @@
{
"name": "patch-query ;;-batch: сегменты триммятся по краям",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.СтароеИмя1, Т.СтароеИмя2 ИЗ Регистр КАК Т",
"fields": ["СтароеИмя1: string", "СтароеИмя2: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "patch-query",
"value": "СтароеИмя1 => НовоеИмя1 ;; СтароеИмя2 => НовоеИмя2"
}
}
@@ -0,0 +1,22 @@
{
"name": "patch-query @once: множественные вхождения — ошибка",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Поле1, Т.Поле2 ИЗ Регистр КАК Т ГДЕ Т.Поле1 = Т.Поле2",
"fields": ["Поле1: string", "Поле2: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "patch-query",
"value": "Поле1 => Новое @once"
},
"expectError": "expected 1 occurrence"
}
@@ -0,0 +1,21 @@
{
"name": "patch-query @once: 1 вхождение — успешная замена",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.УникальноеИмя ИЗ Регистр КАК Т",
"fields": ["УникальноеИмя: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "patch-query",
"value": "УникальноеИмя => НовоеИмя @once"
}
}
@@ -0,0 +1,21 @@
{
"name": "set-field-role: установить балансовую роль с уточнением",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Сумма ИЗ Регистр КАК Т",
"fields": ["Сумма: decimal(15,2)"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "set-field-role",
"value": "Сумма @balance balanceGroupName=Сумма balanceType=OpeningBalance"
}
}
@@ -0,0 +1,21 @@
{
"name": "set-field-role: пустой spec — снимает роль",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Сумма ИЗ Регистр КАК Т",
"fields": ["Сумма: decimal(15,2) @balance"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "set-field-role",
"value": "Сумма"
}
}
@@ -0,0 +1,21 @@
{
"name": "set-structure: запятая в shorthand → несколько GroupItemField",
"preRun": [
{
"script": "skd-compile/scripts/skd-compile",
"input": {
"dataSets": [{
"name": "Основной",
"query": "ВЫБРАТЬ Т.Валюта, Т.Банк, Т.ИНН ИЗ Регистр КАК Т",
"fields": ["Валюта: string", "Банк: string", "ИНН: string"]
}]
},
"args": { "-DefinitionFile": "{inputFile}", "-OutputPath": "{workDir}/Template.xml" }
}
],
"params": {
"templatePath": "Template.xml",
"operation": "set-structure",
"value": "Валюта, Банк, ИНН @name=ДанныеОтчета"
}
}
@@ -0,0 +1,54 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Поле</dataPath>
<field>Поле</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т</query>
</dataSet>
<parameter>
<name>Контрагент</name>
<valueType>
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:CatalogRef.Контрагенты</v8:Type>
</valueType>
<value xsi:type="dcscor:DesignTimeValue">Справочник.Контрагенты.ПустаяСсылка</value>
<useRestriction>true</useRestriction>
<availableAsField>false</availableAsField>
<use>Always</use>
</parameter>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,51 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Счет</dataPath>
<field>Счет</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Счет ИЗ Регистр КАК Т</query>
</dataSet>
<parameter>
<name>Контрагент</name>
<valueType>
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:CatalogRef.Контрагенты</v8:Type>
</valueType>
<value xsi:type="dcscor:DesignTimeValue">Справочник.Контрагенты.ПустаяСсылка</value>
</parameter>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,78 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Поле</dataPath>
<field>Поле</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т</query>
</dataSet>
<parameter>
<name>Округление</name>
<valueType>
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:EnumRef.Округления</v8:Type>
</valueType>
<value xsi:type="dcscor:DesignTimeValue">Окр1_00</value>
<availableValue>
<value xsi:type="dcscor:DesignTimeValue">Перечисление.Округления.Окр1_00</value>
<presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>руб., коп.</v8:content>
</v8:item>
</presentation>
</availableValue>
<availableValue>
<value xsi:type="dcscor:DesignTimeValue">Перечисление.Округления.Окр1</value>
<presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>руб.</v8:content>
</v8:item>
</presentation>
</availableValue>
<availableValue>
<value xsi:type="dcscor:DesignTimeValue">Перечисление.Округления.Окр1000</value>
<presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>тыс. руб.</v8:content>
</v8:item>
</presentation>
</availableValue>
</parameter>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,49 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Проверка</dataPath>
<field>Проверка</field>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>15</v8:Digits>
<v8:FractionDigits>2</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Проверка ИЗ Регистр КАК Т</query>
</dataSet>
<totalField>
<dataPath>Проверка</dataPath>
<expression>Проверка</expression>
</totalField>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,47 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Сумма</dataPath>
<field>Сумма</field>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>15</v8:Digits>
<v8:FractionDigits>2</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Сумма ИЗ Регистр КАК Т</query>
</dataSet>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:conditionalAppearance>
</dcsset:conditionalAppearance>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,78 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Поле</dataPath>
<field>Поле</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т</query>
</dataSet>
<parameter>
<name>Округление</name>
<valueType>
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:EnumRef.Округления</v8:Type>
</valueType>
<value xsi:type="dcscor:DesignTimeValue">Окр1_00</value>
<availableValue>
<value xsi:type="dcscor:DesignTimeValue">Перечисление.Округления.Окр1</value>
<presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>руб.</v8:content>
</v8:item>
</presentation>
</availableValue>
<availableValue>
<value xsi:type="dcscor:DesignTimeValue">Перечисление.Округления.Окр1000</value>
<presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>тыс.</v8:content>
</v8:item>
</presentation>
</availableValue>
<availableValue>
<value xsi:type="dcscor:DesignTimeValue">Перечисление.Округления.Окр1000000</value>
<presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>млн.</v8:content>
</v8:item>
</presentation>
</availableValue>
</parameter>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,54 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Поле</dataPath>
<field>Поле</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Поле ИЗ Регистр КАК Т</query>
</dataSet>
<parameter>
<name>Контрагент</name>
<valueType>
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:CatalogRef.Контрагенты</v8:Type>
</valueType>
<value xsi:type="dcscor:DesignTimeValue">Справочник.Контрагенты.ПустаяСсылка</value>
<useRestriction>true</useRestriction>
<availableAsField>false</availableAsField>
<use>Always</use>
</parameter>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,51 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Счет</dataPath>
<field>Счет</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Счет ИЗ Регистр КАК Т</query>
</dataSet>
<parameter>
<name>Контрагент</name>
<valueType>
<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:CatalogRef.Контрагенты</v8:Type>
</valueType>
<value xsi:type="dcscor:DesignTimeValue">Справочник.Контрагенты.НашаОрганизация</value>
</parameter>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,83 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Счет</dataPath>
<field>Счет</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<field xsi:type="DataSetFieldField">
<dataPath>Сумма</dataPath>
<field>Сумма</field>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>15</v8:Digits>
<v8:FractionDigits>2</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
</field>
<field xsi:type="DataSetFieldField">
<dataPath>Валюта</dataPath>
<field>Валюта</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Счет, Т.Сумма, Т.Валюта ИЗ Регистр КАК Т</query>
</dataSet>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:name>ДанныеОтчета</dcsset:name>
<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:item xsi:type="dcsset:SelectedItemField">
<dcsset:field>Счет</dcsset:field>
</dcsset:item>
<dcsset:item xsi:type="dcsset:SelectedItemField">
<dcsset:field>Сумма</dcsset:field>
</dcsset:item>
</dcsset:selection>
</dcsset:item>
<dcsset:selection>
</dcsset:selection>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,55 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>СтароеИмя1</dataPath>
<field>СтароеИмя1</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<field xsi:type="DataSetFieldField">
<dataPath>СтароеИмя2</dataPath>
<field>СтароеИмя2</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.НовоеИмя1, Т.НовоеИмя2 ИЗ Регистр КАК Т</query>
</dataSet>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,44 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>УникальноеИмя</dataPath>
<field>УникальноеИмя</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.НовоеИмя ИЗ Регистр КАК Т</query>
</dataSet>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,50 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Сумма</dataPath>
<field>Сумма</field>
<role>
<dcscom:balance>true</dcscom:balance>
<dcscom:balanceGroupName>Сумма</dcscom:balanceGroupName>
<dcscom:balanceType>OpeningBalance</dcscom:balanceType>
</role>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>15</v8:Digits>
<v8:FractionDigits>2</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Сумма ИЗ Регистр КАК Т</query>
</dataSet>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,45 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Сумма</dataPath>
<field>Сумма</field>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>15</v8:Digits>
<v8:FractionDigits>2</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Сумма ИЗ Регистр КАК Т</query>
</dataSet>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
</dcsset:selection>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto" />
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto" />
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -0,0 +1,90 @@
<?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">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>Основной</name>
<field xsi:type="DataSetFieldField">
<dataPath>Валюта</dataPath>
<field>Валюта</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<field xsi:type="DataSetFieldField">
<dataPath>Банк</dataPath>
<field>Банк</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<field xsi:type="DataSetFieldField">
<dataPath>ИНН</dataPath>
<field>ИНН</field>
<valueType>
<v8:Type>xs:string</v8:Type>
<v8:StringQualifiers>
<v8:Length>0</v8:Length>
<v8:AllowedLength>Variable</v8:AllowedLength>
</v8:StringQualifiers>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ Т.Валюта, Т.Банк, Т.ИНН ИЗ Регистр КАК Т</query>
</dataSet>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:name>ДанныеОтчета</dcsset:name>
<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: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: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>
<dcsset:selection>
</dcsset:selection>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>