feat(skd-decompile): компактный JSON-сериализатор + расширенный shorthand totalFields

Заменил ConvertTo-Json (PS5.1) на собственный ConvertTo-CompactJson:
- 2-пробельный indent (вместо 4 + выравнивание keys по длине)
- Массивы примитивов (string/number/bool/null) — inline `[a, b, c]`
- Массивы с объектами/nested arrays — multi-line как раньше
- Кириллица в UTF-8 (без \uXXXX-escapes)
- Корректный escape строк (\\", \\, \n, \r, \t, \uXXXX для control chars)

Build-TotalField: shorthand "name: expr" для любого однострочного
expression. Раньше object form применялась когда expression не Func(arg).
Теперь — только когда есть group или expression многострочный.
Compile принимает любой shorthand вида "dataPath: expression" (Parse-
TotalShorthand делает split по первому ":").

Save-UserStyles тоже использует новый сериализатор.

Все 16 декомпиляционных snapshot'ов обновлены (косметика — JSON
структурно тот же, тесты round-trip проходят).

На реальном отчёте (целевой корпус): 405 → 264 строк (-35%).
v0.18 → v0.19.
This commit is contained in:
Nick Shirokov
2026-05-21 20:50:34 +03:00
parent e0ee927156
commit 55b80fdc08
18 changed files with 604 additions and 648 deletions
@@ -1,4 +1,4 @@
# skd-decompile v0.18 — Decompile 1C DCS Template.xml to JSON DSL (draft) # skd-decompile v0.19 — Decompile 1C DCS Template.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)]
@@ -107,6 +107,88 @@ function New-Sentinel {
# --- 3. Helpers --- # --- 3. Helpers ---
# Custom JSON serializer — компактный, 2-пробельный indent, массивы примитивов inline.
# В отличие от ConvertTo-Json (PS5.1):
# - не выравнивает ключи объекта по самому длинному
# - не разворачивает массивы примитивов на отдельные строки
# - кириллица в UTF-8 (без \uXXXX-escapes)
function Convert-StringToJsonLiteral {
param([string]$s)
if ($null -eq $s) { return 'null' }
$sb = New-Object System.Text.StringBuilder
[void]$sb.Append('"')
foreach ($ch in $s.ToCharArray()) {
$code = [int]$ch
if ($code -eq 0x22) { [void]$sb.Append('\"') }
elseif ($code -eq 0x5C) { [void]$sb.Append('\\') }
elseif ($code -eq 0x08) { [void]$sb.Append('\b') }
elseif ($code -eq 0x09) { [void]$sb.Append('\t') }
elseif ($code -eq 0x0A) { [void]$sb.Append('\n') }
elseif ($code -eq 0x0C) { [void]$sb.Append('\f') }
elseif ($code -eq 0x0D) { [void]$sb.Append('\r') }
elseif ($code -lt 0x20) { [void]$sb.AppendFormat('\u{0:x4}', $code) }
else { [void]$sb.Append($ch) }
}
[void]$sb.Append('"')
return $sb.ToString()
}
function ConvertTo-CompactJson {
param($obj, [int]$depth = 0, [string]$indentUnit = ' ')
$indent = $indentUnit * $depth
$childIndent = $indentUnit * ($depth + 1)
if ($null -eq $obj) { return 'null' }
if ($obj -is [bool]) { if ($obj) { return 'true' } else { return 'false' } }
if ($obj -is [string]) { return (Convert-StringToJsonLiteral $obj) }
if ($obj -is [int] -or $obj -is [long]) { return "$obj" }
if ($obj -is [double] -or $obj -is [single] -or $obj -is [decimal]) {
# .NET ToString с invariant culture, чтобы не было запятой
return ([System.Convert]::ToString($obj, [System.Globalization.CultureInfo]::InvariantCulture))
}
# Hashtable / OrderedDictionary / PSCustomObject — объект
if ($obj -is [System.Collections.IDictionary]) {
$keys = @($obj.Keys)
if ($keys.Count -eq 0) { return '{}' }
$parts = @()
foreach ($k in $keys) {
$val = ConvertTo-CompactJson -obj $obj[$k] -depth ($depth + 1) -indentUnit $indentUnit
$parts += "$childIndent$(Convert-StringToJsonLiteral "$k"): $val"
}
return "{`n" + ($parts -join ",`n") + "`n$indent}"
}
if ($obj -is [System.Management.Automation.PSCustomObject]) {
$props = @($obj.PSObject.Properties)
if ($props.Count -eq 0) { return '{}' }
$parts = @()
foreach ($p in $props) {
$val = ConvertTo-CompactJson -obj $p.Value -depth ($depth + 1) -indentUnit $indentUnit
$parts += "$childIndent$(Convert-StringToJsonLiteral "$($p.Name)"): $val"
}
return "{`n" + ($parts -join ",`n") + "`n$indent}"
}
# Array / IList
if ($obj -is [array] -or $obj -is [System.Collections.IList]) {
$items = @($obj)
if ($items.Count -eq 0) { return '[]' }
$allPrimitive = $true
foreach ($it in $items) {
if ($it -is [System.Collections.IDictionary] -or $it -is [System.Management.Automation.PSCustomObject] -or $it -is [array] -or $it -is [System.Collections.IList]) {
$allPrimitive = $false
break
}
}
if ($allPrimitive) {
$parts = @($items | ForEach-Object { ConvertTo-CompactJson -obj $_ -depth $depth -indentUnit $indentUnit })
return '[' + ($parts -join ', ') + ']'
}
$parts = @($items | ForEach-Object { "$childIndent$(ConvertTo-CompactJson -obj $_ -depth ($depth + 1) -indentUnit $indentUnit)" })
return "[`n" + ($parts -join ",`n") + "`n$indent]"
}
# Fallback
return (Convert-StringToJsonLiteral "$obj")
}
function Get-Text { function Get-Text {
param($node, [string]$xpath) param($node, [string]$xpath)
if (-not $node) { return $null } if (-not $node) { return $null }
@@ -489,25 +571,26 @@ function Build-TotalField {
param($tfNode) param($tfNode)
$dataPath = Get-Text $tfNode "r:dataPath" $dataPath = Get-Text $tfNode "r:dataPath"
$expression = Get-Text $tfNode "r:expression" $expression = Get-Text $tfNode "r:expression"
# Detect Func(<dataPath>) → shorthand "name: Func"
if ($expression -match '^(\w+)\(([^)]*)\)$') {
$func = $matches[1]
$inner = $matches[2].Trim()
if ($inner -eq $dataPath) {
return "$dataPath`: $func"
}
# "name: Func(expr)" form — also a valid shorthand
return "$dataPath`: $func($inner)"
}
# group attachment via groupItem — Ring 2 / object form
$groupNodes = $tfNode.SelectNodes("r:group", $ns) $groupNodes = $tfNode.SelectNodes("r:group", $ns)
$obj = [ordered]@{ dataPath = $dataPath; expression = $expression } $hasGroups = $groupNodes -and $groupNodes.Count -gt 0
if ($groupNodes -and $groupNodes.Count -gt 0) {
$groups = @() # Object form — только если есть group или expression многострочный
foreach ($g in $groupNodes) { $groups += $g.InnerText } if ($hasGroups -or ($expression -match "[`r`n]")) {
$obj['group'] = $groups $obj = [ordered]@{ dataPath = $dataPath; expression = $expression }
if ($hasGroups) {
$groups = @()
foreach ($g in $groupNodes) { $groups += $g.InnerText }
$obj['group'] = $groups
}
return $obj
} }
return $obj
# Shorthand: "Func(dataPath)" → "name: Func" (агрегат с очевидным аргументом)
if ($expression -match '^(\w+)\((\w+)\)$' -and $matches[2] -eq $dataPath) {
return "$dataPath`: $($matches[1])"
}
# Любой другой однострочный expression → "name: expression" (compile берёт всё после ":" как expression)
return "$dataPath`: $expression"
} }
# Detect StandardPeriod variant from <value> node # Detect StandardPeriod variant from <value> node
@@ -875,8 +958,7 @@ function Save-UserStyles {
$out[$name] = $script:customStylesAccumulator[$name] $out[$name] = $script:customStylesAccumulator[$name]
} }
if ($out.Count -eq 0) { return } if ($out.Count -eq 0) { return }
$json = $out | ConvertTo-Json -Depth 8 $json = ConvertTo-CompactJson -obj $out
$json = [regex]::Replace($json, '\\u([0-9a-fA-F]{4})', { param($m) [char][int]("0x" + $m.Groups[1].Value) })
$enc = New-Object System.Text.UTF8Encoding($false) $enc = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($stylesPath, $json, $enc) [System.IO.File]::WriteAllText($stylesPath, $json, $enc)
[Console]::Error.WriteLine("Saved skd-styles.json (custom styles: $($script:customStylesAccumulator.Count))") [Console]::Error.WriteLine("Saved skd-styles.json (custom styles: $($script:customStylesAccumulator.Count))")
@@ -1878,13 +1960,7 @@ if ($settingsVariants.Count -gt 0) { $out['settingsVariants'] = $settingsVariant
# --- 7. Serialize --- # --- 7. Serialize ---
$json = $out | ConvertTo-Json -Depth 32 $json = ConvertTo-CompactJson -obj $out
# Unescape \uXXXX → UTF-8 literals
$json = [regex]::Replace($json, '\\u([0-9a-fA-F]{4})', {
param($m)
[char][int]("0x" + $m.Groups[1].Value)
})
if ($OutputPath) { if ($OutputPath) {
$enc = New-Object System.Text.UTF8Encoding($false) $enc = New-Object System.Text.UTF8Encoding($false)
@@ -1,40 +1,38 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
"fields": [ "fields": [
{ {
"field": "ДатаДокумента", "field": "ДатаДокумента",
"type": "date", "type": "date",
"appearance": { "appearance": {
"Формат": { "Формат": {
"ru": "ДЛФ=D", "ru": "ДЛФ=D",
"en": "DLF=D" "en": "DLF=D"
} }
} }
} }
] ]
} }
], ],
"settingsVariants": [ "settingsVariants": [
{ {
"name": "Основной", "name": "Основной",
"settings": { "settings": {
"conditionalAppearance": [ "conditionalAppearance": [
{ {
"selection": [ "selection": ["ДатаДокумента"],
"ДатаДокумента" "appearance": {
], "Формат": {
"appearance": { "ru": "ДЛФ=DT",
"Формат": { "en": "DLF=DT"
"ru": "ДЛФ=DT", }
"en": "DLF=DT" }
} }
} ]
} }
] }
} ]
}
]
} }
@@ -1,42 +1,32 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура", "query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура",
"fields": [ "fields": ["Цена: decimal(15,2)", "Закупка: decimal(15,2)"]
"Цена: decimal(15,2)", }
"Закупка: decimal(15,2)" ],
] "calculatedFields": ["Маржа = Цена - Закупка", "Наценка [Наценка, %]: decimal(10,2) = Маржа / Закупка * 100", "Служебное: string = \"\" #noField #noFilter #noGroup #noOrder"],
} "totalFields": ["Цена: Сумма", "Маржа: Сумма(Цена - Закупка)"],
], "parameters": [
"calculatedFields": [ "Период [Отчетный период]: StandardPeriod = LastMonth @autoDates",
"Маржа = Цена - Закупка", "Организация: CatalogRef.Организации",
"Наценка [Наценка, %]: decimal(10,2) = Маржа / Закупка * 100", "СписокДокументов: CatalogRef.Документы @valueList",
"Служебное: string = \"\" #noField #noFilter #noGroup #noOrder" "СлужебныйПар: string @hidden",
], {
"totalFields": [ "name": "ПорядокОкругления",
"Цена: Сумма", "type": "EnumRef.Округления",
"Маржа: Сумма(Цена - Закупка)" "value": "Перечисление.Округления.Окр1",
], "availableValues": [
"parameters": [ {
"Период [Отчетный период]: StandardPeriod = LastMonth @autoDates", "value": "Перечисление.Округления.Окр1_00",
"Организация: CatalogRef.Организации", "presentation": "руб. коп"
"СписокДокументов: CatalogRef.Документы @valueList", },
"СлужебныйПар: string @hidden", {
{ "value": "Перечисление.Округления.Окр1",
"name": "ПорядокОкругления", "presentation": "руб."
"type": "EnumRef.Округления", }
"value": "Перечисление.Округления.Окр1", ]
"availableValues": [ }
{ ]
"value": "Перечисление.Округления.Окр1_00",
"presentation": "руб. коп"
},
{
"value": "Перечисление.Округления.Окр1",
"presentation": "руб."
}
]
}
]
} }
@@ -1,26 +1,26 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
"fields": [ "fields": [
"Период: date", "Период: date",
{ {
"field": "СальдоНаНачалоПериода", "field": "СальдоНаНачалоПериода",
"folder": true, "folder": true,
"title": "Сальдо на начало периода" "title": "Сальдо на начало периода"
}, },
"СальдоНаНачалоПериода.Дт: decimal(15,2)", "СальдоНаНачалоПериода.Дт: decimal(15,2)",
"СальдоНаНачалоПериода.Кт: decimal(15,2)" "СальдоНаНачалоПериода.Кт: decimal(15,2)"
] ]
} }
], ],
"settingsVariants": [ "settingsVariants": [
{ {
"name": "Основной", "name": "Основной",
"settings": { "settings": {
"structure": "Auto > Период" "structure": "Auto > Период"
} }
} }
] ]
} }
@@ -1,13 +1,9 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "ПродажиПоПериодам", "name": "ПродажиПоПериодам",
"query": "@ПродажиПоПериодам.sql", "query": "@ПродажиПоПериодам.sql",
"fields": [ "fields": ["Номенклатура: CatalogRef.Номенклатура @dimension", "Количество: decimal(15,3)", "Сумма: decimal(15,2)"]
"Номенклатура: CatalogRef.Номенклатура @dimension", }
"Количество: decimal(15,3)", ]
"Сумма: decimal(15,2)"
]
}
]
} }
@@ -1,38 +1,29 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Запрос1", "name": "Запрос1",
"query": "ВЫБРАТЬ Номенклатура.Наименование КАК Имя ИЗ Справочник.Номенклатура КАК Номенклатура", "query": "ВЫБРАТЬ Номенклатура.Наименование КАК Имя ИЗ Справочник.Номенклатура КАК Номенклатура",
"fields": [ "fields": ["Имя: string"]
"Имя: string" },
] {
}, "name": "Журнал",
{ "objectName": "ЖурналОшибок",
"name": "Журнал", "fields": ["Сообщение: string(150)", "Уровень: string"]
"objectName": "ЖурналОшибок", },
"fields": [ {
"Сообщение: string(150)", "name": "Объединение",
"Уровень: string" "items": [
] {
}, "name": "Часть1",
{ "query": "ВЫБРАТЬ 1 КАК Поле",
"name": "Объединение", "fields": ["Поле: decimal(10,2)"]
"items": [ },
{ {
"name": "Часть1", "name": "Часть2",
"query": "ВЫБРАТЬ 1 КАК Поле", "query": "ВЫБРАТЬ 2 КАК Поле",
"fields": [ "fields": ["Поле: decimal(10,2)"]
"Поле: decimal(10,2)" }
] ]
}, }
{ ]
"name": "Часть2",
"query": "ВЫБРАТЬ 2 КАК Поле",
"fields": [
"Поле: decimal(10,2)"
]
}
]
}
]
} }
@@ -1,66 +1,61 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
"fields": [ "fields": [
{ {
"field": "СегментНоменклатуры", "field": "СегментНоменклатуры",
"type": "CatalogRef.СегментыНоменклатуры", "type": "CatalogRef.СегментыНоменклатуры",
"inputParameters": [ "inputParameters": [
{ {
"parameter": "ПараметрыВыбора", "parameter": "ПараметрыВыбора",
"choiceParameters": [ "choiceParameters": [
{ {
"name": "Отбор.СпособФормирования", "name": "Отбор.СпособФормирования",
"values": [ "values": ["Перечисление.СпособыФормированияСегментов.ФормироватьВручную", "Перечисление.СпособыФормированияСегментов.ПериодическиОбновлять"]
"Перечисление.СпособыФормированияСегментов.ФормироватьВручную", }
"Перечисление.СпособыФормированияСегментов.ПериодическиОбновлять" ]
] }
} ]
] },
} {
] "field": "Сотрудник",
}, "type": "CatalogRef.Сотрудники",
{ "inputParameters": [
"field": "Сотрудник", {
"type": "CatalogRef.Сотрудники", "parameter": "СвязиПараметровВыбора",
"inputParameters": [ "choiceParameterLinks": [
{ {
"parameter": "СвязиПараметровВыбора", "name": "Отбор.ТекущаяОрганизация",
"choiceParameterLinks": [ "value": "Организация",
{ "mode": "Clear"
"name": "Отбор.ТекущаяОрганизация", },
"value": "Организация", {
"mode": "Clear" "name": "Отбор.ТекущееПодразделение",
}, "value": "Подразделение",
{ "mode": "Clear"
"name": "Отбор.ТекущееПодразделение", }
"value": "Подразделение", ]
"mode": "Clear" }
} ]
] },
} {
] "field": "ПростоЕА",
}, "type": "CatalogRef.Сотрудники",
{ "inputParameters": [
"field": "ПростоЕА", {
"type": "CatalogRef.Сотрудники", "parameter": "ПараметрыВыбора",
"inputParameters": [ "choiceParameters": []
{ },
"parameter": "ПараметрыВыбора", {
"choiceParameters": [ "parameter": "БыстрыйВыбор",
"use": false,
] "value": true
}, }
{ ]
"parameter": "БыстрыйВыбор", }
"use": false, ]
"value": true }
} ]
]
}
]
}
]
} }
@@ -1,19 +1,19 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.ВидыРасчета", "query": "ВЫБРАТЬ * ИЗ Справочник.ВидыРасчета",
"fields": [ "fields": [
{ {
"field": "ВидРасчета", "field": "ВидРасчета",
"type": "CatalogRef.ВидыРасчета", "type": "CatalogRef.ВидыРасчета",
"orderExpression": { "orderExpression": {
"expression": "ЕстьNULL(ВидРасчета.Порядок, 10000)", "expression": "ЕстьNULL(ВидРасчета.Порядок, 10000)",
"orderType": "Asc", "orderType": "Asc",
"autoOrder": false "autoOrder": false
} }
} }
] ]
} }
] ]
} }
@@ -1,14 +1,9 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ РегистрНакопления.Остатки", "query": "ВЫБРАТЬ * ИЗ РегистрНакопления.Остатки",
"fields": [ "fields": ["Период: date @period", "Контрагент: CatalogRef.Контрагенты @dimension @required", "СуммаНач: decimal(15,2) @balance balanceGroupName=Сумма balanceType=OpeningBalance", "СуммаКон: decimal(15,2) @balance balanceGroupName=Сумма balanceType=ClosingBalance"]
"Период: date @period", }
"Контрагент: CatalogRef.Контрагенты @dimension @required", ]
"СуммаНач: decimal(15,2) @balance balanceGroupName=Сумма balanceType=OpeningBalance",
"СуммаКон: decimal(15,2) @balance balanceGroupName=Сумма balanceType=ClosingBalance"
]
}
]
} }
@@ -1,46 +1,43 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура", "query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура",
"fields": [ "fields": [
"Наименование", "Наименование",
"Количество: decimal(15,2)", "Количество: decimal(15,2)",
"Организация: CatalogRef.Организации @dimension", "Организация: CatalogRef.Организации @dimension",
"Служебное: string #noField #noFilter", "Служебное: string #noField #noFilter",
"СтрокаФикс: string(50,fix)", "СтрокаФикс: string(50,fix)",
"Положительное: decimal(10,nonneg)", "Положительное: decimal(10,nonneg)",
"Дата1: date", "Дата1: date",
{ {
"field": "СПояснением", "field": "СПояснением",
"title": "Поле с пояснением", "title": "Поле с пояснением",
"type": "decimal(15,2)", "type": "decimal(15,2)",
"appearance": { "appearance": {
"ГоризонтальноеПоложение": "Right", "ГоризонтальноеПоложение": "Right",
"МинимальнаяШирина": "80" "МинимальнаяШирина": "80"
} }
}, },
{ {
"field": "Многоязычное", "field": "Многоязычное",
"title": { "title": {
"ru": "Русский", "ru": "Русский",
"en": "English" "en": "English"
}, },
"type": "string" "type": "string"
}, },
{ {
"field": "СоставноеПоле", "field": "СоставноеПоле",
"type": [ "type": ["CatalogRef.Организации", "CatalogRef.Валюты"]
"CatalogRef.Организации", },
"CatalogRef.Валюты" {
] "field": "СВыражениемПредставления",
}, "type": "CatalogRef.Номенклатура",
{ "presentationExpression": "Представление(СВыражениемПредставления)"
"field": "СВыражениемПредставления", }
"type": "CatalogRef.Номенклатура", ]
"presentationExpression": "Представление(СВыражениемПредставления)" }
} ]
]
}
]
} }
@@ -1,11 +1,9 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "НаборДанных1", "name": "НаборДанных1",
"query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура", "query": "ВЫБРАТЬ Номенклатура.Наименование КАК Наименование ИЗ Справочник.Номенклатура КАК Номенклатура",
"fields": [ "fields": ["Наименование"]
"Наименование" }
] ]
}
]
} }
@@ -1,80 +1,70 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "DSОбъединение", "name": "DSОбъединение",
"items": [ "items": [
{ {
"name": "Часть1", "name": "Часть1",
"objectName": "ДанныеЧасть1" "objectName": "ДанныеЧасть1"
}, },
{ {
"name": "Часть2", "name": "Часть2",
"objectName": "ДанныеЧасть2" "objectName": "ДанныеЧасть2"
} }
], ],
"fields": [ "fields": ["Период: date", "ВидРасчета: CatalogRef.ВидыРасчета", "Сумма: decimal(15,2)", "Подразделение: CatalogRef.Подразделения"]
"Период: date", }
"ВидРасчета: CatalogRef.ВидыРасчета", ],
"Сумма: decimal(15,2)", "settingsVariants": [
"Подразделение: CatalogRef.Подразделения" {
] "name": "Основной",
} "settings": {
], "selection": [
"settingsVariants": [ "Период",
{ {
"name": "Основной", "field": "Сумма",
"settings": { "title": "Итого"
"selection": [ },
"Период", {
{ "folder": "Группа итогов",
"field": "Сумма", "items": [
"title": "Итого" "ВидРасчета",
}, {
{ "field": "Сумма",
"folder": "Группа итогов", "title": "Сумма с расшифровкой"
"items": [ },
"ВидРасчета", {
{ "folder": "Подгруппа",
"field": "Сумма", "items": ["Подразделение"]
"title": "Сумма с расшифровкой" }
}, ]
{ }
"folder": "Подгруппа", ],
"items": [ "structure": [
"Подразделение" {
] "name": "Группа1",
} "groupFields": [
] {
} "field": "Период",
], "periodAdditionType": "Day"
"structure": [ },
{ {
"name": "Группа1", "field": "Подразделение",
"groupFields": [ "groupType": "Hierarchy"
{ }
"field": "Период", ],
"periodAdditionType": "Day" "children": [
}, {
{ "type": "nestedObject",
"field": "Подразделение", "objectID": "ДанныеЧасть1",
"groupType": "Hierarchy" "settings": {
} "selection": ["ВидРасчета", "Сумма"]
], }
"children": [ }
{ ]
"type": "nestedObject", }
"objectID": "ДанныеЧасть1", ]
"settings": { }
"selection": [ }
"ВидРасчета", ]
"Сумма"
]
}
}
]
}
]
}
}
]
} }
@@ -1,22 +1,18 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
"fields": [ "fields": ["Поле: string"]
"Поле: string" }
] ],
} "templates": [
], {
"templates": [ "name": "Заголовок",
{ "style": "myHeader",
"name": "Заголовок", "rows": [
"style": "myHeader", ["A"]
"rows": [ ]
[ }
"A" ]
]
]
}
]
} }
@@ -1,15 +1,15 @@
{ {
"myHeader": { "myHeader": {
"font": "Calibri", "font": "Calibri",
"fontSize": 11, "fontSize": 11,
"bold": false, "bold": false,
"italic": false, "italic": false,
"hAlign": "Center", "hAlign": "Center",
"vAlign": "Center", "vAlign": "Center",
"wrap": false, "wrap": false,
"bgColor": "style:ReportHeaderBackColor", "bgColor": "style:ReportHeaderBackColor",
"textColor": null, "textColor": null,
"borderColor": "style:ReportLineColor", "borderColor": "style:ReportLineColor",
"borders": true "borders": true
} }
} }
@@ -1,27 +1,25 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
"fields": [ "fields": ["Поле: string"]
"Поле: string" }
] ],
} "templates": [
], {
"templates": [ "name": "СмешанныйМакет",
{ "style": "data",
"name": "СмешанныйМакет", "rows": [
"style": "data", [
"rows": [ "A",
[ {
"A", "value": "B",
{ "style": "header"
"value": "B", },
"style": "header" "C"
}, ]
"C" ]
] }
] ]
}
]
} }
@@ -1,28 +1,19 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники", "query": "ВЫБРАТЬ * ИЗ Справочник.Сотрудники",
"fields": [ "fields": ["Поле1: string", "Поле2: string"]
"Поле1: string", }
"Поле2: string" ],
] "templates": [
} {
], "name": "БезСтиля",
"templates": [ "style": "none",
{ "widths": ["7", "7"],
"name": "БезСтиля", "rows": [
"style": "none", ["A", "B"]
"widths": [ ]
"7", }
"7" ]
],
"rows": [
[
"A",
"B"
]
]
}
]
} }
@@ -1,81 +1,48 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура", "query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура",
"fields": [ "fields": ["Имя: string", "Сумма: decimal(15,2)"]
"Имя: string", }
"Сумма: decimal(15,2)" ],
] "templates": [
} {
], "name": "Шапка",
"templates": [ "style": "header",
{ "widths": ["20", "30", "25", "25"],
"name": "Шапка", "rows": [
"style": "header", ["Имя", "Сумма", "Поступление", ">"],
"widths": [ ["|", "|", "из произв.", "со сч.40"],
"20", ["К1", "К2", "К3", "К4"]
"30", ]
"25", },
"25" {
], "name": "Данные",
"rows": [ "style": "data",
[ "widths": ["20", "30", "25", "25"],
"Имя", "rows": [
"Сумма", ["{Имя}", "{Сумма}", "{Поступление}", "{СчетПрочее}"]
"Поступление", ],
">" "parameters": [
], {
[ "name": "Имя",
"|", "expression": "Имя"
"|", },
"из произв.", {
"со сч.40" "name": "Сумма",
], "expression": "Сумма"
[ },
"К1", {
"К2", "name": "Поступление",
"К3", "expression": "СуммаПоступления",
"К4" "drilldown": "СуммаПоступления"
] },
] {
}, "name": "СчетПрочее",
{ "expression": "СчетПрочее"
"name": "Данные", }
"style": "data", ]
"widths": [ }
"20", ]
"30",
"25",
"25"
],
"rows": [
[
"{Имя}",
"{Сумма}",
"{Поступление}",
"{СчетПрочее}"
]
],
"parameters": [
{
"name": "Имя",
"expression": "Имя"
},
{
"name": "Сумма",
"expression": "Сумма"
},
{
"name": "Поступление",
"expression": "СуммаПоступления",
"drilldown": "СуммаПоступления"
},
{
"name": "СчетПрочее",
"expression": "СчетПрочее"
}
]
}
]
} }
@@ -1,87 +1,65 @@
{ {
"dataSets": [ "dataSets": [
{ {
"name": "Тест", "name": "Тест",
"query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура", "query": "ВЫБРАТЬ * ИЗ Справочник.Номенклатура",
"fields": [ "fields": ["Организация: CatalogRef.Организации @dimension", "Номенклатура: CatalogRef.Номенклатура @dimension", "Сумма: decimal(15,2)", "Количество: decimal(15,3)", "Статус: string"]
"Организация: CatalogRef.Организации @dimension", }
"Номенклатура: CatalogRef.Номенклатура @dimension", ],
"Сумма: decimal(15,2)", "parameters": ["Период: StandardPeriod = LastMonth @autoDates", "Активные: boolean = true"],
"Количество: decimal(15,3)", "templates": [
"Статус: string" {
] "name": "Шапка",
} "style": "header",
], "rows": [
"parameters": [ ["Орг", "Сум"]
"Период: StandardPeriod = LastMonth @autoDates", ]
"Активные: boolean = true" }
], ],
"templates": [ "groupTemplates": [
{ {
"name": "Шапка", "groupName": "ДанныеОтчета",
"style": "header", "templateType": "GroupHeader",
"rows": [ "template": "Шапка"
[ }
"Орг", ],
"Сум" "settingsVariants": [
] {
] "name": "Основной",
} "title": "Основной вариант",
], "settings": {
"groupTemplates": [ "selection": [
{ "Организация",
"groupName": "ДанныеОтчета", {
"templateType": "GroupHeader", "folder": "Объёмы",
"template": "Шапка" "items": ["Сумма", "Количество"]
} }
], ],
"settingsVariants": [ "filter": [
{ "Организация = _ @off @user",
"name": "Основной", {
"title": "Основной вариант", "group": "Or",
"settings": { "items": ["Статус = Активен", "Сумма > 1000"]
"selection": [ }
"Организация", ],
{ "order": ["Сумма desc"],
"folder": "Объёмы", "conditionalAppearance": [
"items": [ {
"Сумма", "filter": ["Сумма > 10000"],
"Количество" "appearance": {
] "ЦветТекста": "style:НегативныйТекстЦвет"
} },
], "presentation": "Большие суммы",
"filter": [ "viewMode": "Normal",
"Организация = _ @off @user", "userSettingID": "auto"
{ }
"group": "Or", ],
"items": [ "outputParameters": {
"Статус = Активен", "Заголовок": "Сводка по организациям"
"Сумма > 1000" },
] "dataParameters": "auto",
} "structure": "Организация > Номенклатура > details"
], }
"order": [ }
"Сумма desc" ]
],
"conditionalAppearance": [
{
"filter": [
"Сумма > 10000"
],
"appearance": {
"ЦветТекста": "style:НегативныйТекстЦвет"
},
"presentation": "Большие суммы",
"viewMode": "Normal",
"userSettingID": "auto"
}
],
"outputParameters": {
"Заголовок": "Сводка по организациям"
},
"dataParameters": "auto",
"structure": "Организация > Номенклатура > details"
}
}
]
} }