diff --git a/.claude/skills/skd-compile/scripts/skd-compile.ps1 b/.claude/skills/skd-compile/scripts/skd-compile.ps1 index 5111da16d..85f7175ac 100644 --- a/.claude/skills/skd-compile/scripts/skd-compile.ps1 +++ b/.claude/skills/skd-compile/scripts/skd-compile.ps1 @@ -1,4 +1,4 @@ -# skd-compile v1.123 — Compile 1C DCS from JSON +# skd-compile v1.124 — Compile 1C DCS from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills [CmdletBinding(PositionalBinding=$false)] param( @@ -474,9 +474,44 @@ function Emit-ValueType { if (-not $typeStr) { return } - # Multi-type: iterate and emit each type with its qualifiers + # Составной тип: по XSD TypeDescription сначала все Type, затем TypeSet, затем квалификаторы + # (Number, String, Date, BinaryData) — а не «тип со своими квалификаторами» подряд. Каждый тип + # пишем во временный буфер и раскладываем строки по разделам; квалификатор вида — один. if ($typeStr -is [array] -or $typeStr -is [System.Collections.IList]) { - foreach ($t in $typeStr) { Emit-SingleValueType -typeStr "$t" -indent $indent } + $saved = $script:xml + $types = New-Object System.Collections.ArrayList + $typeSets = New-Object System.Collections.ArrayList + $quals = [ordered]@{ 'NumberQualifiers' = $null; 'StringQualifiers' = $null; 'DateQualifiers' = $null; 'BinaryDataQualifiers' = $null } + try { + foreach ($t in $typeStr) { + $script:xml = New-Object System.Text.StringBuilder + Emit-SingleValueType -typeStr "$t" -indent $indent + $lines = $script:xml.ToString() -split "`r?`n" | Where-Object { $_ -ne '' } + $cur = $null + foreach ($ln in $lines) { + if ($cur) { + [void]$cur.Add($ln) + if ($ln -eq "$indent") { $cur = $null } + continue + } + if ($ln.StartsWith("$indent$') + if ($qm.Success -and $quals.Contains($qm.Groups[1].Value)) { + $curKind = $qm.Groups[1].Value + $cur = New-Object System.Collections.ArrayList + [void]$cur.Add($ln) + if ($null -eq $quals[$curKind]) { $quals[$curKind] = $cur } + continue + } + [void]$types.Add($ln) + } + } + } finally { + $script:xml = $saved + } + foreach ($ln in $types) { X $ln } + foreach ($ln in $typeSets) { X $ln } + foreach ($k in $quals.Keys) { if ($quals[$k]) { foreach ($ln in $quals[$k]) { X $ln } } } return } @@ -1105,6 +1140,18 @@ function Emit-InputParameters { X "$indent" } +# Флаги ограничения использования — в порядке XSD FieldUseRestriction (field condition group order), +# а не в порядке ввода: чтение по схеме (XDTO) отвергает нарушенный порядок. Имена — XML-имена +# флагов; дубли (noFilter и noCondition дают один condition) схлопываются. +function Emit-RestrictionFlags { + param([object[]]$names, [string]$indent) + $flagOrder = @('field', 'condition', 'group', 'order') + $given = @($names | ForEach-Object { "$_" } | Where-Object { $_ }) + foreach ($n in $flagOrder) { + if ($given -contains $n) { X "$indent<$n>true" } + } +} + function Emit-Field { param($fieldDef, [string]$indent) @@ -1193,24 +1240,14 @@ function Emit-Field { } if ($f.restrict.Count -gt 0) { X "$indent`t" - foreach ($r in $f.restrict) { - $xmlName = $restrictMap["$r"] - if ($xmlName) { - X "$indent`t`t<$xmlName>true" - } - } + Emit-RestrictionFlags -names @($f.restrict | ForEach-Object { $restrictMap["$_"] }) -indent "$indent`t`t" X "$indent`t" } # AttributeUseRestriction if ($f["attrRestrict"] -and $f["attrRestrict"].Count -gt 0) { X "$indent`t" - foreach ($r in $f["attrRestrict"]) { - $xmlName = $restrictMap["$r"] - if ($xmlName) { - X "$indent`t`t<$xmlName>true" - } - } + Emit-RestrictionFlags -names @($f["attrRestrict"] | ForEach-Object { $restrictMap["$_"] }) -indent "$indent`t`t" X "$indent`t" } @@ -1237,7 +1274,12 @@ function Emit-Field { X "$indent`t" } - # OrderExpression — после role, до valueType. Допустим массив (multi-sort). + # PresentationExpression — сразу после role, до orderExpression (порядок XSD DataSetFieldField) + if ($f["presentationExpression"]) { + X "$indent`t$(Esc-XmlText $f["presentationExpression"])" + } + + # OrderExpression — после presentationExpression, до valueType. Допустим массив (multi-sort). if ($f["orderExpression"]) { $oeRaw = $f["orderExpression"] if ($oeRaw -is [System.Collections.IDictionary]) { @@ -1266,27 +1308,6 @@ function Emit-Field { X "$indent`t" } - # AvailableValues — list of allowed values with optional multilang presentation - if ($f["availableValues"]) { - foreach ($av in $f["availableValues"]) { - X "$indent`t" - $avVal = $av.value - $avType = if ($av.valueType) { "$($av.valueType)" } else { '' } - if (-not $avType) { - if ($avVal -is [bool]) { $avType = 'xs:boolean' } - elseif ($avVal -is [int] -or $avVal -is [long] -or $avVal -is [double]) { $avType = 'xs:decimal' } - elseif ("$avVal" -match '^\d{4}-\d{2}-\d{2}T') { $avType = 'xs:dateTime' } - else { $avType = 'xs:string' } - } - $avStr = if ($avVal -is [bool]) { "$avVal".ToLower() } else { Esc-XmlText "$avVal" } - X "$indent`t`t$avStr" - if ($av.presentation) { - Emit-MLText -tag "presentation" -text $av.presentation -indent "$indent`t`t" - } - X "$indent`t" - } - } - # Appearance if ($f.appearance -and $f.appearance.Count -gt 0) { X "$indent`t" @@ -1305,9 +1326,25 @@ function Emit-Field { X "$indent`t" } - # PresentationExpression - if ($f["presentationExpression"]) { - X "$indent`t$(Esc-XmlText $f["presentationExpression"])" + # AvailableValues — после appearance (порядок XSD); список значений с необязательным представлением + if ($f["availableValues"]) { + foreach ($av in $f["availableValues"]) { + X "$indent`t" + $avVal = $av.value + $avType = if ($av.valueType) { "$($av.valueType)" } else { '' } + if (-not $avType) { + if ($avVal -is [bool]) { $avType = 'xs:boolean' } + elseif ($avVal -is [int] -or $avVal -is [long] -or $avVal -is [double]) { $avType = 'xs:decimal' } + elseif ("$avVal" -match '^\d{4}-\d{2}-\d{2}T') { $avType = 'xs:dateTime' } + else { $avType = 'xs:string' } + } + $avStr = if ($avVal -is [bool]) { "$avVal".ToLower() } else { Esc-XmlText "$avVal" } + X "$indent`t`t$avStr" + if ($av.presentation) { + Emit-MLText -tag "presentation" -text $av.presentation -indent "$indent`t`t" + } + X "$indent`t" + } } # InputParameters — в конце field @@ -1458,25 +1495,14 @@ function Emit-CalcFields { if ($title) { Emit-MLText -tag "title" -text $title -indent "`t`t" } - if ($typeStr) { - X "`t`t" - Emit-ValueType -typeStr $typeStr -indent "`t`t`t" - X "`t`t" - } if ($restrictObj -or $restrictTokens.Count -gt 0) { X "`t`t" if ($restrictObj) { - foreach ($prop in $restrictObj.PSObject.Properties) { - if ($prop.Value -eq $true) { - X "`t`t`t<$($prop.Name)>true" - } - } + $flagNames = @($restrictObj.PSObject.Properties | Where-Object { $_.Value -eq $true } | ForEach-Object { $_.Name }) } else { - foreach ($r in $restrictTokens) { - $xmlName = $restrictMap["$r"] - if ($xmlName) { X "`t`t`t<$xmlName>true" } - } + $flagNames = @($restrictTokens | ForEach-Object { $restrictMap["$_"] }) } + Emit-RestrictionFlags -names $flagNames -indent "`t`t`t" X "`t`t" } if ($appearance) { @@ -1494,6 +1520,12 @@ function Emit-CalcFields { } X "`t`t" } + # valueType — последним: после useRestriction и appearance (порядок XSD CalculatedField) + if ($typeStr) { + X "`t`t" + Emit-ValueType -typeStr $typeStr -indent "`t`t`t" + X "`t`t" + } X "`t" } @@ -1792,7 +1824,8 @@ function Emit-ParamValue { if ($val.Contains('endDate')) { $edStr = "$($val['endDate'])" } } } - $valStr = if ($variantStr) { $variantStr } else { "$val" } + # JSON-булево: "$val" даёт True/False, а xs:boolean — только true/false/1/0 + $valStr = if ($variantStr) { $variantStr } elseif ($val -is [bool]) { "$val".ToLower() } else { "$val" } if ($type -eq "StandardPeriod") { # Platform-pattern: startDate/endDate эмитятся ТОЛЬКО для variant=Custom. @@ -1809,7 +1842,7 @@ function Emit-ParamValue { } elseif ($type -match '^date') { X "$indent$(Esc-XmlText $valStr)" } elseif ($type -eq "boolean") { - X "$indent$(Esc-XmlText $valStr)" + X "$indent$(Esc-XmlText $valStr.ToLower())" } elseif ($type -match '^decimal') { X "$indent$(Esc-XmlText $valStr)" } elseif ($type -match '^string') { @@ -1821,7 +1854,7 @@ function Emit-ParamValue { if ($valStr -match '^\d{4}-\d{2}-\d{2}T') { X "$indent$(Esc-XmlText $valStr)" } elseif ($valStr -eq "true" -or $valStr -eq "false") { - X "$indent$(Esc-XmlText $valStr)" + X "$indent$(Esc-XmlText $valStr.ToLower())" } elseif ($valStr -match '^(ПланСчетов|Справочник|Перечисление|Документ|ПланВидовХарактеристик|ПланВидовРасчета|БизнесПроцесс|Задача|РегистрСведений|ПланОбмена)\.' -or $valStr -match '^(ChartOfAccounts|Catalog|Enum|Document|ChartOfCharacteristicTypes|ChartOfCalculationTypes|BusinessProcess|Task|InformationRegister|ExchangePlan)\.') { X "$indent$(Esc-XmlText $valStr)" } else { @@ -2684,6 +2717,7 @@ function Emit-AppearanceValue { } else { if ($innerVal.Contains($attrName)) { $av = $innerVal[$attrName] } } + if ($av -is [bool]) { $av = "$av".ToLower() } if ($null -ne $av) { $attrParts += "$attrName=`"$(Esc-Xml "$av")`"" } } X "$indent`t" @@ -2691,7 +2725,8 @@ function Emit-AppearanceValue { # Multilang dict ({"ru": "...", "en": "..."}) → LocalStringType независимо от ключа. Emit-MLText -tag "dcscor:value" -text $innerVal -indent "$indent`t" } else { - $actualVal = "$innerVal" + # JSON-булево: "$innerVal" даёт True/False, а xs:boolean — только true/false + $actualVal = if ($innerVal -is [bool]) { "$innerVal".ToLower() } else { "$innerVal" } # Параметр-специфичный тип для известных appearance keys $keyTypeMap = @{ 'Размещение' = 'dcscor:DataCompositionTextPlacementType' @@ -2709,7 +2744,7 @@ function Emit-AppearanceValue { # локальный xmlns не нужен — эмитим short form. X "$indent`t$(Esc-XmlText $actualVal)" } elseif ($actualVal -eq "true" -or $actualVal -eq "false") { - X "$indent`t$actualVal" + X "$indent`t$($actualVal.ToLower())" } elseif ($key -eq "Текст" -or $key -eq "Заголовок" -or $key -eq "Формат") { # Строковые ключи, традиционно эмитятся как LocalStringType (даже если только ru). Emit-MLText -tag "dcscor:value" -text $actualVal -indent "$indent`t" @@ -2879,10 +2914,11 @@ function Emit-OutputParametersSubItem { X "$indent`t`t" if ($subUseFalse) { X "$indent`t`t`tfalse" } X "$indent`t`t`t$(Esc-XmlText $subName)" + $subStr = if ($subVal -is [bool]) { "$subVal".ToLower() } else { "$subVal" } if ($subUri) { - X "$indent`t`t`t$(Esc-XmlText "$subVal")" + X "$indent`t`t`t$(Esc-XmlText $subStr)" } else { - X "$indent`t`t`t$(Esc-XmlText "$subVal")" + X "$indent`t`t`t$(Esc-XmlText $subStr)" } X "$indent`t`t" } @@ -2956,13 +2992,16 @@ function Emit-OutputParameters { } else { if ($rawVal.Contains($attrName)) { $av = $rawVal[$attrName] } } + if ($av -is [bool]) { $av = "$av".ToLower() } if ($null -ne $av) { $attrParts += "$attrName=`"$(Esc-Xml "$av")`"" } } X "$indent`t`t" } elseif ($ptype -eq "mltext") { Emit-MLText -tag "dcscor:value" -text $rawVal -indent "$indent`t`t" } else { - X "$indent`t`t$(Esc-XmlText "$rawVal")" + # JSON-булево: "$rawVal" даёт True/False, а xs:boolean — только true/false + $rawStr = if ($rawVal -is [bool]) { "$rawVal".ToLower() } else { "$rawVal" } + X "$indent`t`t$(Esc-XmlText $rawStr)" } # Nested sub-параметры (ТипДиаграммы.ВидПодписей и т.п.) — эмитим между value и extras. # valueType: строка → xsi:type=string, объект {uri, name} → локальный xmlns:dN + xsi:type=dN:name. @@ -3360,6 +3399,9 @@ function Emit-StructureItem { # Платформа на группировке (плоской и вложенной в ось, short/explicit) всегда пишет # order+selection; при отсутствии ключа кладёт Auto. Ключ присутствует (в т.ч. пустой []) # — уважаем как задано (blockViewMode/userSettingID имеют смысл только при явном order). + # filter — до order/selection (порядок XSD StructureItemGroup: groupItems filter order selection) + Emit-Filter -items $item.filter -indent "$indent`t" + $hasGrpOrderKey = $item.PSObject.Properties.Match('order').Count -gt 0 $grpOrderItems = if ($hasGrpOrderKey) { $item.order } else { @('Auto') } Emit-Order -items $grpOrderItems -indent "$indent`t" -blockViewMode $item.orderViewMode -blockUserSettingID $item.orderUserSettingID @@ -3367,8 +3409,6 @@ function Emit-StructureItem { $grpSelItems = if ($hasGrpSelKey) { $item.selection } else { @('Auto') } Emit-Selection -items $grpSelItems -indent "$indent`t" - Emit-Filter -items $item.filter -indent "$indent`t" - if ($item.conditionalAppearance) { Emit-ConditionalAppearance -items $item.conditionalAppearance -indent "$indent`t" } @@ -3447,13 +3487,6 @@ function Emit-StructureItem { if ($item.outputParameters) { Emit-OutputParameters -params $item.outputParameters -indent "$indent`t" } - # columnsViewMode / rowsViewMode — axis-level режим доступности (после rows/columns) - if ($item.columnsViewMode) { - X "$indent`t$(Esc-XmlText "$($item.columnsViewMode)")" - } - if ($item.rowsViewMode) { - X "$indent`t$(Esc-XmlText "$($item.rowsViewMode)")" - } # viewMode / userSettingID / userSettingPresentation / itemsViewMode на самой таблице if ($item.viewMode) { X "$indent`t$(Esc-XmlText "$($item.viewMode)")" @@ -3465,6 +3498,13 @@ function Emit-StructureItem { if ($item.userSettingPresentation) { Emit-MLText -tag "dcsset:userSettingPresentation" -text $item.userSettingPresentation -indent "$indent`t" } + # columnsViewMode / rowsViewMode — axis-level режим доступности: после viewMode/userSettingID (порядок XSD и платформы) + if ($item.columnsViewMode) { + X "$indent`t$(Esc-XmlText "$($item.columnsViewMode)")" + } + if ($item.rowsViewMode) { + X "$indent`t$(Esc-XmlText "$($item.rowsViewMode)")" + } if ($item.itemsViewMode) { X "$indent`t$(Esc-XmlText "$($item.itemsViewMode)")" } @@ -3529,13 +3569,6 @@ function Emit-StructureItem { Emit-OutputParameters -params $item.outputParameters -indent "$indent`t" } - # pointsViewMode / seriesViewMode — axis-level режим доступности (после points/series) - if ($item.pointsViewMode) { - X "$indent`t$(Esc-XmlText "$($item.pointsViewMode)")" - } - if ($item.seriesViewMode) { - X "$indent`t$(Esc-XmlText "$($item.seriesViewMode)")" - } # viewMode / userSettingID / userSettingPresentation / itemsViewMode на самой диаграмме if ($item.viewMode) { X "$indent`t$(Esc-XmlText "$($item.viewMode)")" @@ -3547,6 +3580,13 @@ function Emit-StructureItem { if ($item.userSettingPresentation) { Emit-MLText -tag "dcsset:userSettingPresentation" -text $item.userSettingPresentation -indent "$indent`t" } + # pointsViewMode / seriesViewMode — axis-level режим доступности: после viewMode/userSettingID (порядок XSD и платформы) + if ($item.pointsViewMode) { + X "$indent`t$(Esc-XmlText "$($item.pointsViewMode)")" + } + if ($item.seriesViewMode) { + X "$indent`t$(Esc-XmlText "$($item.seriesViewMode)")" + } if ($item.itemsViewMode) { X "$indent`t$(Esc-XmlText "$($item.itemsViewMode)")" } @@ -3645,24 +3685,7 @@ function Emit-SettingsVariants { Emit-Filter -items $s.filter -indent "`t`t`t" -blockViewMode $fvm -blockUserSettingID $fusid } - # Order - $ovm = Get-BlockVM 'order'; $ousid = Get-BlockUSID 'order' - if ($s.order -or $null -ne $ovm -or $null -ne $ousid) { - Emit-Order -items $s.order -indent "`t`t`t" -blockViewMode $ovm -blockUserSettingID $ousid - } - - # ConditionalAppearance - $cavm = Get-BlockVM 'conditionalAppearance'; $causid = Get-BlockUSID 'conditionalAppearance' - if ($s.conditionalAppearance -or $null -ne $cavm -or $null -ne $causid) { - Emit-ConditionalAppearance -items $s.conditionalAppearance -indent "`t`t`t" -blockViewMode $cavm -blockUserSettingID $causid - } - - # OutputParameters (platform does NOT emit on this block) - if ($s.outputParameters) { - Emit-OutputParameters -params $s.outputParameters -indent "`t`t`t" - } - - # DataParameters + # DataParameters — сразу после filter, до order (порядок XSD Settings; иначе XDTO: «нарушен порядок») if ($s.dataParameters -eq 'auto') { # Auto-generate dataParameters for all non-hidden params. # Pattern follows 1C Designer / ERP persistence: @@ -3711,6 +3734,23 @@ function Emit-SettingsVariants { Emit-DataParameters -items $s.dataParameters -indent "`t`t`t" } + # Order + $ovm = Get-BlockVM 'order'; $ousid = Get-BlockUSID 'order' + if ($s.order -or $null -ne $ovm -or $null -ne $ousid) { + Emit-Order -items $s.order -indent "`t`t`t" -blockViewMode $ovm -blockUserSettingID $ousid + } + + # ConditionalAppearance + $cavm = Get-BlockVM 'conditionalAppearance'; $causid = Get-BlockUSID 'conditionalAppearance' + if ($s.conditionalAppearance -or $null -ne $cavm -or $null -ne $causid) { + Emit-ConditionalAppearance -items $s.conditionalAppearance -indent "`t`t`t" -blockViewMode $cavm -blockUserSettingID $causid + } + + # OutputParameters (platform does NOT emit on this block) + if ($s.outputParameters) { + Emit-OutputParameters -params $s.outputParameters -indent "`t`t`t" + } + # Structure (supports string shorthand: "Организация > details") if ($s.structure) { $structItems = $s.structure @@ -3722,12 +3762,7 @@ function Emit-SettingsVariants { } } - # on — emit only if explicitly set - if ($s.itemsViewMode) { - X "`t`t`t$(Esc-XmlText "$($s.itemsViewMode)")" - } - - # — key/value свойства варианта + # — key/value свойства варианта; до itemsViewMode (порядок XSD) if ($s.additionalProperties) { X "`t`t`t" foreach ($prop in $s.additionalProperties.PSObject.Properties) { @@ -3738,6 +3773,11 @@ function Emit-SettingsVariants { X "`t`t`t" } + # on — emit only if explicitly set + if ($s.itemsViewMode) { + X "`t`t`t$(Esc-XmlText "$($s.itemsViewMode)")" + } + X "`t`t" X "`t" } diff --git a/.claude/skills/skd-compile/scripts/skd-compile.py b/.claude/skills/skd-compile/scripts/skd-compile.py index 8f7ec6283..6170b32dd 100644 --- a/.claude/skills/skd-compile/scripts/skd-compile.py +++ b/.claude/skills/skd-compile/scripts/skd-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# skd-compile v1.123 — Compile 1C DCS from JSON +# skd-compile v1.124 — Compile 1C DCS from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -457,10 +457,39 @@ def emit_value_type(lines, type_spec, indent): if not type_spec: return - # Multi-type: iterate and emit each type with its qualifiers + # Составной тип: по XSD TypeDescription сначала все Type, затем TypeSet, затем квалификаторы + # (Number, String, Date, BinaryData) — а не «тип со своими квалификаторами» подряд. Каждый тип + # пишем во временный список и раскладываем строки по разделам; квалификатор вида — один. if isinstance(type_spec, list): + types, type_sets = [], [] + quals = {'NumberQualifiers': None, 'StringQualifiers': None, 'DateQualifiers': None, 'BinaryDataQualifiers': None} for t in type_spec: - emit_single_value_type(lines, str(t), indent) + buf = [] + emit_single_value_type(buf, str(t), indent) + cur = None + cur_kind = None + for ln in buf: + if cur is not None: + cur.append(ln) + if ln == f'{indent}': + cur = None + continue + if ln.startswith(f'{indent}$', ln) + if qm and qm.group(1) in quals: + cur_kind = qm.group(1) + cur = [ln] + if quals[cur_kind] is None: + quals[cur_kind] = cur + continue + types.append(ln) + lines.extend(types) + lines.extend(type_sets) + for k in quals: + if quals[k]: + lines.extend(quals[k]) return emit_single_value_type(lines, str(type_spec), indent) @@ -999,6 +1028,16 @@ def emit_input_parameters(lines, ip, indent): lines.append(f'{indent}') +# Флаги ограничения использования — в порядке XSD FieldUseRestriction (field condition group order), +# а не в порядке ввода: чтение по схеме (XDTO) отвергает нарушенный порядок. Имена — XML-имена +# флагов; дубли (noFilter и noCondition дают один condition) схлопываются. +def emit_restriction_flags(lines, names, indent): + given = [str(n).lower() for n in names if n] + for n in ('field', 'condition', 'group', 'order'): + if n in given: + lines.append(f'{indent}<{n}>true') + + def emit_field(lines, field_def, indent): if isinstance(field_def, str): f = parse_field_shorthand(field_def) @@ -1071,19 +1110,13 @@ def emit_field(lines, field_def, indent): } if f.get('restrict') and len(f['restrict']) > 0: lines.append(f'{indent}\t') - for r in f['restrict']: - xml_name = restrict_map.get(str(r)) - if xml_name: - lines.append(f'{indent}\t\t<{xml_name}>true') + emit_restriction_flags(lines, [restrict_map.get(str(r)) for r in f['restrict']], f'{indent}\t\t') lines.append(f'{indent}\t') # AttributeUseRestriction if f.get('attrRestrict') and len(f['attrRestrict']) > 0: lines.append(f'{indent}\t') - for r in f['attrRestrict']: - xml_name = restrict_map.get(str(r)) - if xml_name: - lines.append(f'{indent}\t\t<{xml_name}>true') + emit_restriction_flags(lines, [restrict_map.get(str(r)) for r in f['attrRestrict']], f'{indent}\t\t') lines.append(f'{indent}\t') # Role @@ -1104,7 +1137,11 @@ def emit_field(lines, field_def, indent): lines.append(f'{indent}\t\t{esc_xml_text(str(v))}') lines.append(f'{indent}\t') - # OrderExpression — после role, до valueType + # PresentationExpression — сразу после role, до orderExpression (порядок XSD DataSetFieldField) + if f.get('presentationExpression'): + lines.append(f'{indent}\t{esc_xml_text(f["presentationExpression"])}') + + # OrderExpression — после presentationExpression, до valueType. Допустим массив (multi-sort). if f.get('orderExpression'): oe_raw = f['orderExpression'] oe_list = oe_raw if isinstance(oe_raw, list) else [oe_raw] @@ -1125,7 +1162,21 @@ def emit_field(lines, field_def, indent): emit_value_type(lines, f['type'], f'{indent}\t\t') lines.append(f'{indent}\t') - # AvailableValues — list of allowed values with optional multilang presentation + # Appearance + if f.get('appearance') and len(f['appearance']) > 0: + lines.append(f'{indent}\t') + for key, val in f['appearance'].items(): + # \u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e xsi:type, \u043d\u0435 \u0441\u0442\u0440\u043e\u043a\u0430 + if key == '\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435' and not isinstance(val, dict): + lines.append(f'{indent}\t\t') + lines.append(f'{indent}\t\t\t{esc_xml_text(key)}') + lines.append(f'{indent}\t\t\t{esc_xml_text(str(val))}') + lines.append(f'{indent}\t\t') + else: + emit_appearance_value(lines, key, val, f'{indent}\t\t') + lines.append(f'{indent}\t') + + # AvailableValues — после appearance (порядок XSD); список значений с необязательным представлением if f.get('availableValues'): for av in f['availableValues']: lines.append(f'{indent}\t') @@ -1146,24 +1197,6 @@ def emit_field(lines, field_def, indent): emit_mltext(lines, f'{indent}\t\t', 'presentation', av['presentation']) lines.append(f'{indent}\t') - # Appearance - if f.get('appearance') and len(f['appearance']) > 0: - lines.append(f'{indent}\t') - for key, val in f['appearance'].items(): - # \u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e xsi:type, \u043d\u0435 \u0441\u0442\u0440\u043e\u043a\u0430 - if key == '\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435' and not isinstance(val, dict): - lines.append(f'{indent}\t\t') - lines.append(f'{indent}\t\t\t{esc_xml_text(key)}') - lines.append(f'{indent}\t\t\t{esc_xml_text(str(val))}') - lines.append(f'{indent}\t\t') - else: - emit_appearance_value(lines, key, val, f'{indent}\t\t') - lines.append(f'{indent}\t') - - # PresentationExpression - if f.get('presentationExpression'): - lines.append(f'{indent}\t{esc_xml_text(f["presentationExpression"])}') - # InputParameters — в конце field if f.get('inputParameters'): emit_input_parameters(lines, f['inputParameters'], f'{indent}\t') @@ -1298,21 +1331,13 @@ def emit_calc_fields(lines, defn): if title: emit_mltext(lines, '\t\t', 'title', title) - if type_str: - lines.append('\t\t') - emit_value_type(lines, type_str, '\t\t\t') - lines.append('\t\t') if restrict_obj or restrict_tokens: lines.append('\t\t') if restrict_obj: - for xml_name, flag in restrict_obj.items(): - if flag: - lines.append(f'\t\t\t<{esc_xml_text(str(xml_name))}>true') + flag_names = [xml_name for xml_name, flag in restrict_obj.items() if flag is True] else: - for r in restrict_tokens: - xml_name = restrict_map.get(str(r)) - if xml_name: - lines.append(f'\t\t\t<{xml_name}>true') + flag_names = [restrict_map.get(str(r)) for r in restrict_tokens] + emit_restriction_flags(lines, flag_names, '\t\t\t') lines.append('\t\t') if appearance: lines.append('\t\t') @@ -1325,6 +1350,11 @@ def emit_calc_fields(lines, defn): else: emit_appearance_value(lines, k, v, '\t\t\t') lines.append('\t\t') + # valueType — последним: после useRestriction и appearance (порядок XSD CalculatedField) + if type_str: + lines.append('\t\t') + emit_value_type(lines, type_str, '\t\t\t') + lines.append('\t\t') lines.append('\t') @@ -1414,7 +1444,8 @@ def emit_param_value(lines, type_str, val, indent, value_list_allowed=False): variant_str = str(val.get('variant')) if val.get('variant') is not None else None sd_str = str(val['startDate']) if 'startDate' in val else None ed_str = str(val['endDate']) if 'endDate' in val else None - val_str = variant_str if variant_str else str(val) + # JSON-булево: str(False) даёт "False", а xs:boolean — только true/false/1/0 + val_str = variant_str if variant_str else (str(val).lower() if isinstance(val, bool) else str(val)) if type_str == 'StandardPeriod': # Platform-pattern: startDate/endDate ТОЛЬКО для variant=Custom. @@ -1429,7 +1460,7 @@ def emit_param_value(lines, type_str, val, indent, value_list_allowed=False): elif type_str and re.match(r'^date', type_str): lines.append(f'{indent}{esc_xml_text(val_str)}') elif type_str == 'boolean': - lines.append(f'{indent}{esc_xml_text(val_str)}') + lines.append(f'{indent}{esc_xml_text(val_str.lower())}') elif type_str and re.match(r'^decimal', type_str): lines.append(f'{indent}{esc_xml_text(val_str)}') elif type_str and re.match(r'^string', type_str): @@ -1440,8 +1471,8 @@ def emit_param_value(lines, type_str, val, indent, value_list_allowed=False): # Guess from value if re.match(r'^\d{4}-\d{2}-\d{2}T', val_str): lines.append(f'{indent}{esc_xml_text(val_str)}') - elif val_str == 'true' or val_str == 'false': - lines.append(f'{indent}{esc_xml_text(val_str)}') + elif val_str.lower() in ('true', 'false'): + lines.append(f'{indent}{esc_xml_text(val_str.lower())}') elif re.match(r'^(ПланСчетов|Справочник|Перечисление|Документ|ПланВидовХарактеристик|ПланВидовРасчета|БизнесПроцесс|Задача|РегистрСведений|ПланОбмена|ChartOfAccounts|Catalog|Enum|Document|ChartOfCharacteristicTypes|ChartOfCalculationTypes|BusinessProcess|Task|InformationRegister|ExchangePlan)\.', val_str): lines.append(f'{indent}{esc_xml_text(val_str)}') else: @@ -2340,12 +2371,15 @@ def emit_appearance_value(lines, key, val, indent): attr_parts = [] for attr_name in ('ref', 'faceName', 'height', 'bold', 'italic', 'underline', 'strikeout', 'kind', 'scale'): if attr_name in inner_val: - attr_parts.append(f'{attr_name}="{esc_xml(str(inner_val[attr_name]))}"') + av = inner_val[attr_name] + av = str(av).lower() if isinstance(av, bool) else str(av) + attr_parts.append(f'{attr_name}="{esc_xml(av)}"') lines.append(f'{indent}\t') elif isinstance(inner_val, dict): emit_mltext(lines, f'{indent}\t', 'dcscor:value', inner_val) else: - actual_val = str(inner_val) if inner_val is not None else '' + # JSON-булево: str(True) даёт "True", а xs:boolean — только true/false + actual_val = (str(inner_val).lower() if isinstance(inner_val, bool) else str(inner_val)) if inner_val is not None else '' # \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440-\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0439 \u0442\u0438\u043f \u0434\u043b\u044f \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0445 appearance keys key_type_map = { '\u0420\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435': 'dcscor:DataCompositionTextPlacementType', @@ -2362,8 +2396,8 @@ def emit_appearance_value(lines, key, val, indent): # Внутри префиксы style:/web:/win:/sys: уже объявлены на корне, # локальный xmlns не нужен — эмитим short form. lines.append(f'{indent}\t{esc_xml_text(actual_val)}') - elif actual_val == 'true' or actual_val == 'false': - lines.append(f'{indent}\t{actual_val}') + elif actual_val.lower() in ('true', 'false'): + lines.append(f'{indent}\t{actual_val.lower()}') elif key in ('\u0422\u0435\u043a\u0441\u0442', '\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a', '\u0424\u043e\u0440\u043c\u0430\u0442'): emit_mltext(lines, f'{indent}\t', 'dcscor:value', actual_val) elif re.match(r'^-?\d+(\.\d+)?$', actual_val): @@ -2494,12 +2528,16 @@ def emit_output_parameters(lines, params, indent): attr_parts = [] for attr_name in ('ref', 'faceName', 'height', 'bold', 'italic', 'underline', 'strikeout', 'kind', 'scale'): if attr_name in val: - attr_parts.append(f'{attr_name}="{esc_xml(str(val[attr_name]))}"') + av = val[attr_name] + av = str(av).lower() if isinstance(av, bool) else str(av) + attr_parts.append(f'{attr_name}="{esc_xml(av)}"') lines.append(f'{indent}\t\t') elif ptype == 'mltext': emit_mltext(lines, f'{indent}\t\t', 'dcscor:value', val) else: - lines.append(f'{indent}\t\t{esc_xml_text(str(val))}') + # JSON-булево: str(True) даёт "True", а xs:boolean — только true/false + raw_str = str(val).lower() if isinstance(val, bool) else str(val) + lines.append(f'{indent}\t\t{esc_xml_text(raw_str)}') # Nested sub-параметры (ТипДиаграммы.ВидПодписей и т.п.). # valueType: строка → xsi:type=string, объект {uri, name} → локальный xmlns:dN. if wrap_items and isinstance(wrap_items, dict): @@ -2525,10 +2563,11 @@ def emit_output_parameters(lines, params, indent): if sub_use_false: lines.append(f'{indent}\t\t\tfalse') lines.append(f'{indent}\t\t\t{esc_xml_text(sub_name)}') + sub_str = str(sub_val).lower() if isinstance(sub_val, bool) else str(sub_val) if sub_uri: - lines.append(f'{indent}\t\t\t{esc_xml_text(str(sub_val))}') + lines.append(f'{indent}\t\t\t{esc_xml_text(sub_str)}') else: - lines.append(f'{indent}\t\t\t{esc_xml_text(str(sub_val))}') + lines.append(f'{indent}\t\t\t{esc_xml_text(sub_str)}') lines.append(f'{indent}\t\t') if wrap_vm: lines.append(f'{indent}\t\t{esc_xml_text(str(wrap_vm))}') @@ -2820,13 +2859,14 @@ def emit_structure_item(lines, item, indent, short_group=False): # Платформа на группировке (плоской и вложенной в ось, short/explicit) всегда пишет # order+selection; при отсутствии ключа кладёт Auto. Ключ присутствует (в т.ч. пустой []) # — уважаем как задано (blockViewMode/userSettingID имеют смысл только при явном order). + # filter — до order/selection (порядок XSD StructureItemGroup: groupItems filter order selection) + emit_filter(lines, item.get('filter'), f'{indent}\t') + grp_order_items = item['order'] if 'order' in item else ['Auto'] emit_order(lines, grp_order_items, f'{indent}\t', block_view_mode=item.get('orderViewMode'), block_user_setting_id=item.get('orderUserSettingID')) grp_sel_items = item['selection'] if 'selection' in item else ['Auto'] emit_selection(lines, grp_sel_items, f'{indent}\t') - emit_filter(lines, item.get('filter'), f'{indent}\t') - if item.get('conditionalAppearance'): emit_conditional_appearance(lines, item['conditionalAppearance'], f'{indent}\t') @@ -2882,11 +2922,6 @@ def emit_structure_item(lines, item, indent, short_group=False): emit_conditional_appearance(lines, item['conditionalAppearance'], f'{indent}\t') if item.get('outputParameters'): emit_output_parameters(lines, item['outputParameters'], f'{indent}\t') - # columnsViewMode / rowsViewMode — axis-level режим доступности - if item.get('columnsViewMode'): - lines.append(f'{indent}\t{esc_xml_text(str(item["columnsViewMode"]))}') - if item.get('rowsViewMode'): - lines.append(f'{indent}\t{esc_xml_text(str(item["rowsViewMode"]))}') # viewMode / userSettingID / userSettingPresentation / itemsViewMode на самой таблице if item.get('viewMode'): lines.append(f'{indent}\t{esc_xml_text(str(item["viewMode"]))}') @@ -2895,6 +2930,11 @@ def emit_structure_item(lines, item, indent, short_group=False): lines.append(f'{indent}\t{esc_xml_text(gid)}') if item.get('userSettingPresentation'): emit_mltext(lines, f'{indent}\t', 'dcsset:userSettingPresentation', item['userSettingPresentation']) + # columnsViewMode / rowsViewMode — axis-level режим доступности: после viewMode/userSettingID (порядок XSD и платформы) + if item.get('columnsViewMode'): + lines.append(f'{indent}\t{esc_xml_text(str(item["columnsViewMode"]))}') + if item.get('rowsViewMode'): + lines.append(f'{indent}\t{esc_xml_text(str(item["rowsViewMode"]))}') if item.get('itemsViewMode'): lines.append(f'{indent}\t{esc_xml_text(str(item["itemsViewMode"]))}') @@ -2936,11 +2976,6 @@ def emit_structure_item(lines, item, indent, short_group=False): if item.get('outputParameters'): emit_output_parameters(lines, item['outputParameters'], f'{indent}\t') - # pointsViewMode / seriesViewMode — axis-level режим доступности - if item.get('pointsViewMode'): - lines.append(f'{indent}\t{esc_xml_text(str(item["pointsViewMode"]))}') - if item.get('seriesViewMode'): - lines.append(f'{indent}\t{esc_xml_text(str(item["seriesViewMode"]))}') # viewMode / userSettingID / userSettingPresentation / itemsViewMode на самой диаграмме if item.get('viewMode'): lines.append(f'{indent}\t{esc_xml_text(str(item["viewMode"]))}') @@ -2949,6 +2984,11 @@ def emit_structure_item(lines, item, indent, short_group=False): lines.append(f'{indent}\t{esc_xml_text(gid)}') if item.get('userSettingPresentation'): emit_mltext(lines, f'{indent}\t', 'dcsset:userSettingPresentation', item['userSettingPresentation']) + # pointsViewMode / seriesViewMode — axis-level режим доступности: после viewMode/userSettingID (порядок XSD и платформы) + if item.get('pointsViewMode'): + lines.append(f'{indent}\t{esc_xml_text(str(item["pointsViewMode"]))}') + if item.get('seriesViewMode'): + lines.append(f'{indent}\t{esc_xml_text(str(item["seriesViewMode"]))}') if item.get('itemsViewMode'): lines.append(f'{indent}\t{esc_xml_text(str(item["itemsViewMode"]))}') @@ -3023,19 +3063,7 @@ def emit_settings_variants(lines, defn): if s.get('filter') or fvm is not None or fusid is not None: emit_filter(lines, s.get('filter'), '\t\t\t', block_view_mode=fvm, block_user_setting_id=fusid) - ovm, ousid = _block_vm('order'), _block_usid('order') - if s.get('order') or ovm is not None or ousid is not None: - emit_order(lines, s.get('order'), '\t\t\t', block_view_mode=ovm, block_user_setting_id=ousid) - - cavm, causid = _block_vm('conditionalAppearance'), _block_usid('conditionalAppearance') - if s.get('conditionalAppearance') or cavm is not None or causid is not None: - emit_conditional_appearance(lines, s.get('conditionalAppearance'), '\t\t\t', block_view_mode=cavm, block_user_setting_id=causid) - - # OutputParameters (platform does NOT emit on this block) - if s.get('outputParameters'): - emit_output_parameters(lines, s['outputParameters'], '\t\t\t') - - # DataParameters + # DataParameters — сразу после filter, до order (порядок XSD Settings; иначе XDTO: «нарушен порядок») if s.get('dataParameters') == 'auto': # Auto-generate dataParameters for all non-hidden params. # Pattern follows 1C Designer / ERP persistence: @@ -3078,6 +3106,18 @@ def emit_settings_variants(lines, defn): elif s.get('dataParameters'): emit_data_parameters(lines, s['dataParameters'], '\t\t\t') + ovm, ousid = _block_vm('order'), _block_usid('order') + if s.get('order') or ovm is not None or ousid is not None: + emit_order(lines, s.get('order'), '\t\t\t', block_view_mode=ovm, block_user_setting_id=ousid) + + cavm, causid = _block_vm('conditionalAppearance'), _block_usid('conditionalAppearance') + if s.get('conditionalAppearance') or cavm is not None or causid is not None: + emit_conditional_appearance(lines, s.get('conditionalAppearance'), '\t\t\t', block_view_mode=cavm, block_user_setting_id=causid) + + # OutputParameters (platform does NOT emit on this block) + if s.get('outputParameters'): + emit_output_parameters(lines, s['outputParameters'], '\t\t\t') + # Structure (supports string shorthand) if s.get('structure'): struct_items = s['structure'] @@ -3088,11 +3128,7 @@ def emit_settings_variants(lines, defn): for item in struct_items: emit_structure_item(lines, item, '\t\t\t') - # on settings — emit only if explicitly set - if s.get('itemsViewMode'): - lines.append(f'\t\t\t{esc_xml_text(str(s["itemsViewMode"]))}') - - # — key/value свойства варианта + # — key/value свойства варианта; до itemsViewMode (порядок XSD) if s.get('additionalProperties'): lines.append('\t\t\t') for k, v in s['additionalProperties'].items(): @@ -3101,6 +3137,10 @@ def emit_settings_variants(lines, defn): lines.append('\t\t\t\t') lines.append('\t\t\t') + # on settings — emit only if explicitly set + if s.get('itemsViewMode'): + lines.append(f'\t\t\t{esc_xml_text(str(s["itemsViewMode"]))}') + lines.append('\t\t') lines.append('\t') diff --git a/.claude/skills/skd-edit/scripts/skd-edit.ps1 b/.claude/skills/skd-edit/scripts/skd-edit.ps1 index 273a58d4e..676dfbdc5 100644 --- a/.claude/skills/skd-edit/scripts/skd-edit.ps1 +++ b/.claude/skills/skd-edit/scripts/skd-edit.ps1 @@ -1,4 +1,4 @@ -# skd-edit v1.41 — Atomic 1C DCS editor +# skd-edit v1.42 — Atomic 1C DCS editor # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # NB: парный .py собирает выражения автодат вне f-string ради совместимости с python 3.9 (PEP 701). [CmdletBinding(PositionalBinding=$false)] @@ -1175,11 +1175,12 @@ function Build-RestrictionXml { "noGroup" = "group"; "noOrder" = "order" } + # Флаги — в порядке XSD FieldUseRestriction (field condition group order), не в порядке ввода + $given = @($restrict | ForEach-Object { $restrictMap["$_"] } | Where-Object { $_ }) $lines = @() $lines += "$indent" - foreach ($r in $restrict) { - $xmlName = $restrictMap["$r"] - if ($xmlName) { + foreach ($xmlName in @('field', 'condition', 'group', 'order')) { + if ($given -contains $xmlName) { $lines += "$indent`t<$xmlName>true" } } @@ -1209,30 +1210,42 @@ function Build-FieldFragment { $lines += (Build-MLTextXml -tag "title" -text $parsed.title -indent "$i`t") } + # Остальные части собираем как (место по XSD, xml) и выводим по месту: сохранённые как есть + # узлы (attributeUseRestriction, presentationExpression, orderExpression, appearance, …) + # встают на своё место, а не в хвост после valueType. Незнакомые — в конец, как раньше. + $fieldOrder = [string[]]$script:XsdChildOrder['DataSetFieldField'] + $parts = New-Object System.Collections.ArrayList if ($parsed.restrict -and $parsed.restrict.Count -gt 0) { - $lines += (Build-RestrictionXml -restrict $parsed.restrict -indent "$i`t") + [void]$parts.Add(@([array]::IndexOf($fieldOrder, 'useRestriction'), (Build-RestrictionXml -restrict $parsed.restrict -indent "$i`t"))) } $roleXml = Build-RoleXml -roles $parsed.roles -indent "$i`t" - if ($roleXml) { $lines += $roleXml } + if ($roleXml) { [void]$parts.Add(@([array]::IndexOf($fieldOrder, 'role'), $roleXml)) } + $vtRank = [array]::IndexOf($fieldOrder, 'valueType') if ($parsed.rawValueType) { # Preserve original verbatim — keeps qualifiers (StringQualifiers, # NumberQualifiers, DateQualifiers, …) that aren't expressible via shorthand. - $lines += "$i`t" + $parsed.rawValueType + [void]$parts.Add(@($vtRank, ("$i`t" + $parsed.rawValueType))) } elseif ($parsed.type) { - $lines += "$i`t" - $lines += (Build-ValueTypeXml -typeStr $parsed.type -indent "$i`t`t") - $lines += "$i`t" + $vt = @("$i`t") + @(Build-ValueTypeXml -typeStr $parsed.type -indent "$i`t`t") + @("$i`t") + [void]$parts.Add(@($vtRank, ($vt -join "`n"))) } # Defense in depth: re-emit OuterXml of unknown children (e.g. , # , custom extensions) that Read-FieldProperties captured. if ($parsed._unknownChildren) { foreach ($raw in $parsed._unknownChildren) { - $lines += "$i`t" + $raw + $m = [regex]::Match($raw, '^<(?:[\w.-]+:)?([\w.-]+)') + $r = if ($m.Success) { [array]::IndexOf($fieldOrder, $m.Groups[1].Value) } else { -1 } + if ($r -lt 0) { $r = $fieldOrder.Count } + [void]$parts.Add(@($r, ("$i`t" + $raw))) } } + # Устойчивая сортировка по месту: при равенстве — порядок добавления + $idx = 0 + $sorted = $parts | ForEach-Object { [pscustomobject]@{ r = $_[0]; n = $idx++; x = $_[1] } } | Sort-Object r, n + foreach ($p in $sorted) { $lines += $p.x } $lines += "$i" return $lines -join "`n" @@ -2172,7 +2185,47 @@ function Resolve-VariantSettings { exit 1 } -function Ensure-SettingsChild($settings, [string]$childName, [string[]]$afterSiblings) { +# Порядок детей по XSD схемы компоновки: чтение по схеме (XDTO) отвергает нарушенный порядок, +# поэтому новый узел встаёт перед первым соседом, который по схеме идёт позже. Ключ — вид +# контейнера: settings, поле набора или xsi:type элемента структуры (без xsi:type — группа). +$script:XsdChildOrder = @{ + 'settings' = @('userFields','selection','filter','dataParameters','order','conditionalAppearance','outputParameters', + 'item','additionalProperties','itemsViewMode','itemsUserSettingID','itemsUserSettingPresentation') + 'StructureItemGroup' = @('use','name','groupItems','filter','order','selection','conditionalAppearance','outputParameters', + 'item','id','viewMode','userSettingID','userSettingPresentation','itemsViewMode','itemsUserSettingID','itemsUserSettingPresentation','groupState') + 'StructureItemTable' = @('use','name','column','row','selection','conditionalAppearance','outputParameters', + 'id','viewMode','userSettingID','userSettingPresentation','columnsViewMode','columnsUserSettingID','columnsUserSettingPresentation', + 'rowsViewMode','rowsUserSettingID','rowsUserSettingPresentation') + 'StructureItemChart' = @('use','name','point','series','selection','conditionalAppearance','outputParameters', + 'id','viewMode','userSettingID','userSettingPresentation','pointsViewMode','pointsUserSettingID','pointsUserSettingPresentation', + 'seriesViewMode','seriesUserSettingID','seriesUserSettingPresentation') + 'DataSetFieldField' = @('dataPath','field','title','useRestriction','attributeUseRestriction','role','presentationExpression', + 'orderExpression','inHierarchyDataSet','inHierarchyDataSetParameter','valueType','appearance','availableValue','inputParameters') +} + +function Get-XsdChildOrder($container) { + if ($container.LocalName -eq 'settings') { return $script:XsdChildOrder['settings'] } + if ($container.LocalName -eq 'field') { return $script:XsdChildOrder['DataSetFieldField'] } + $xt = $container.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance") + $xt = ($xt -split ':')[-1] + if ($xt -and $script:XsdChildOrder.ContainsKey($xt)) { return $script:XsdChildOrder[$xt] } + return $script:XsdChildOrder['StructureItemGroup'] +} + +# Первый сосед, который по XSD идёт после $childName; $null — вставлять в конец +function Find-OrderedInsertRef($container, [string]$childName) { + $order = [string[]](Get-XsdChildOrder $container) + $rank = [array]::IndexOf($order, $childName) + if ($rank -lt 0) { return $null } + foreach ($ch in $container.ChildNodes) { + if ($ch.NodeType -ne 'Element') { continue } + $r = [array]::IndexOf($order, [string]$ch.LocalName) + if ($r -gt $rank) { return $ch } + } + return $null +} + +function Ensure-SettingsChild($settings, [string]$childName) { $el = Find-FirstElement $settings @($childName) $setNs if ($el) { return $el } @@ -2180,18 +2233,7 @@ function Ensure-SettingsChild($settings, [string]$childName, [string[]]$afterSib $fragXml = "$indent" $nodes = Import-Fragment $xmlDoc $fragXml - $refNode = $null - foreach ($sibName in $afterSiblings) { - $sib = Find-FirstElement $settings @($sibName) $setNs - if ($sib) { - $refNode = $sib.NextSibling - while ($refNode -and ($refNode.NodeType -eq 'Whitespace' -or $refNode.NodeType -eq 'SignificantWhitespace')) { - $refNode = $refNode.NextSibling - } - break - } - } - + $refNode = Find-OrderedInsertRef $settings $childName foreach ($node in $nodes) { Insert-BeforeElement $settings $node $refNode $indent } @@ -2309,7 +2351,7 @@ switch ($Operation) { if (-not $NoSelection) { $settings = Resolve-VariantSettings $varName = Get-VariantName - $selection = Ensure-SettingsChild $settings "selection" @() + $selection = Ensure-SettingsChild $settings "selection" $existingSel = Find-ElementByChildValue $selection "item" "field" $parsed.dataPath $setNs if ($existingSel) { Write-Host "[INFO] Field `"$($parsed.dataPath)`" already in selection — skipped" @@ -2395,7 +2437,7 @@ switch ($Operation) { if (-not $NoSelection) { $settings = Resolve-VariantSettings $varName = Get-VariantName - $selection = Ensure-SettingsChild $settings "selection" @() + $selection = Ensure-SettingsChild $settings "selection" $existingSel = Find-ElementByChildValue $selection "item" "field" $parsed.dataPath $setNs if ($existingSel) { Write-Host "[INFO] Field `"$($parsed.dataPath)`" already in selection — skipped" @@ -2956,7 +2998,7 @@ switch ($Operation) { foreach ($val in $values) { $parsed = Parse-FilterShorthand $val - $filterEl = Ensure-SettingsChild $settings "filter" @("selection") + $filterEl = Ensure-SettingsChild $settings "filter" $filterIndent = Get-ContainerChildIndent $filterEl $fragXml = Build-FilterItemFragment -parsed $parsed -indent $filterIndent @@ -2976,7 +3018,7 @@ switch ($Operation) { foreach ($val in $values) { $parsed = Parse-DataParamShorthand $val - $dpEl = Ensure-SettingsChild $settings "dataParameters" @("outputParameters","conditionalAppearance","order","filter","selection") + $dpEl = Ensure-SettingsChild $settings "dataParameters" $dpIndent = Get-ContainerChildIndent $dpEl $fragXml = Build-DataParamFragment -parsed $parsed -indent $dpIndent @@ -2996,7 +3038,7 @@ switch ($Operation) { foreach ($val in $values) { $parsed = Parse-OrderShorthand $val - $orderEl = Ensure-SettingsChild $settings "order" @("filter","selection") + $orderEl = Ensure-SettingsChild $settings "order" $orderIndent = Get-ContainerChildIndent $orderEl # Duplicate check @@ -3063,7 +3105,7 @@ switch ($Operation) { $targetEl = $settings } - $selection = Ensure-SettingsChild $targetEl "selection" @() + $selection = Ensure-SettingsChild $targetEl "selection" # Dedup: skip if SelectedItemAuto already exists if ($fieldName -eq "Auto") { @@ -3160,7 +3202,7 @@ switch ($Operation) { foreach ($val in $values) { $parsed = Parse-OutputParamShorthand $val - $outputEl = Ensure-SettingsChild $settings "outputParameters" @("conditionalAppearance","order","filter","selection") + $outputEl = Ensure-SettingsChild $settings "outputParameters" $outputIndent = Get-ContainerChildIndent $outputEl # Remove existing parameter with same key if present @@ -3199,9 +3241,8 @@ switch ($Operation) { $structItems = Parse-StructureShorthand $Value $settingsIndent = Get-ChildIndent $settings - # Find insertion point — before outputParameters/dataParameters/conditionalAppearance/order/filter/selection or at end - $refNode = Find-FirstElement $settings @("outputParameters","dataParameters","conditionalAppearance","order","filter","selection","item") $setNs - if (-not $refNode) { $refNode = $null } + # Место по XSD: после outputParameters и прочих блоков, до additionalProperties/itemsViewMode + $refNode = Find-OrderedInsertRef $settings "item" foreach ($structItem in $structItems) { $fragXml = Build-StructureItemFragment -item $structItem -indent $settingsIndent @@ -3445,7 +3486,7 @@ switch ($Operation) { foreach ($val in $values) { $parsed = Parse-ConditionalAppearanceShorthand $val - $caEl = Ensure-SettingsChild $settings "conditionalAppearance" @("outputParameters","order","filter","selection") + $caEl = Ensure-SettingsChild $settings "conditionalAppearance" $caIndent = Get-ContainerChildIndent $caEl $fragXml = Build-ConditionalAppearanceItemFragment -parsed $parsed -indent $caIndent @@ -3801,11 +3842,8 @@ switch ($Operation) { $lines += "$fieldIndent" $fragXml = $lines -join "`n" - # Insert before , else before , 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 } - } + # Место по XSD: после attributeUseRestriction, до presentationExpression/orderExpression/valueType + $refNode = Find-OrderedInsertRef $fieldEl "role" $nodes = Import-Fragment $xmlDoc $fragXml foreach ($node in $nodes) { Insert-BeforeElement $fieldEl $node $refNode $fieldIndent diff --git a/.claude/skills/skd-edit/scripts/skd-edit.py b/.claude/skills/skd-edit/scripts/skd-edit.py index 65c0993cc..ad10055ff 100644 --- a/.claude/skills/skd-edit/scripts/skd-edit.py +++ b/.claude/skills/skd-edit/scripts/skd-edit.py @@ -1,4 +1,4 @@ -# skd-edit v1.41 — Atomic 1C DCS editor (Python port) +# skd-edit v1.42 — Atomic 1C DCS editor (Python port) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import json @@ -1163,10 +1163,11 @@ def build_restriction_xml(restrict, indent): if not restrict: return "" restrict_map = {"noField": "field", "noFilter": "condition", "noCondition": "condition", "noGroup": "group", "noOrder": "order"} + # Флаги — в порядке XSD FieldUseRestriction (field condition group order), не в порядке ввода + given = [restrict_map.get(r) for r in restrict] lines = [f"{indent}"] - for r in restrict: - xml_name = restrict_map.get(r) - if xml_name: + for xml_name in ("field", "condition", "group", "order"): + if xml_name in given: lines.append(f"{indent}\t<{xml_name}>true") lines.append(f"{indent}") return "\n".join(lines) @@ -1189,25 +1190,35 @@ def build_field_fragment(parsed, indent): elif parsed.get("title"): lines.append(build_mltext_xml("title", parsed["title"], f"{i}\t")) + # Остальные части собираем как (место по XSD, xml) и выводим по месту: сохранённые как есть + # узлы (attributeUseRestriction, presentationExpression, orderExpression, appearance, …) + # встают на своё место, а не в хвост после valueType. Незнакомые — в конец, как раньше. + field_order = XSD_CHILD_ORDER['DataSetFieldField'] + parts = [] if parsed.get("restrict"): - lines.append(build_restriction_xml(parsed["restrict"], f"{i}\t")) + parts.append((field_order.index('useRestriction'), build_restriction_xml(parsed["restrict"], f"{i}\t"))) role_xml = build_role_xml(parsed.get("roles"), f"{i}\t") if role_xml: - lines.append(role_xml) + parts.append((field_order.index('role'), role_xml)) + vt_rank = field_order.index('valueType') if parsed.get("rawValueType"): # Preserve original verbatim — keeps qualifiers (StringQualifiers, # NumberQualifiers, DateQualifiers, …) that aren't expressible via shorthand. - lines.append(f"{i}\t" + parsed["rawValueType"]) + parts.append((vt_rank, f"{i}\t" + parsed["rawValueType"])) elif parsed.get("type"): - lines.append(f"{i}\t") - lines.append(build_value_type_xml(parsed["type"], f"{i}\t\t")) - lines.append(f"{i}\t") + vt = [f"{i}\t", build_value_type_xml(parsed["type"], f"{i}\t\t"), f"{i}\t"] + parts.append((vt_rank, "\n".join(vt))) # Defense in depth: re-emit OuterXml of unknown children captured by Read. for raw in (parsed.get("_unknownChildren") or []): - lines.append(f"{i}\t" + raw) + m = re.match(r'^<(?:[\w.-]+:)?([\w.-]+)', raw) + r = field_order.index(m.group(1)) if m and m.group(1) in field_order else len(field_order) + parts.append((r, f"{i}\t" + raw)) + # Устойчивая сортировка по месту: при равенстве — порядок добавления + for _, x in sorted(parts, key=lambda t: t[0]): + lines.append(x) lines.append(f"{i}") return "\n".join(lines) @@ -1986,7 +1997,54 @@ def resolve_variant_settings(): sys.exit(1) -def ensure_settings_child(settings, child_name, after_siblings): +# Порядок детей по XSD схемы компоновки: чтение по схеме (XDTO) отвергает нарушенный порядок, +# поэтому новый узел встаёт перед первым соседом, который по схеме идёт позже. Ключ — вид +# контейнера: settings, поле набора или xsi:type элемента структуры (без xsi:type — группа). +XSD_CHILD_ORDER = { + 'settings': ['userFields', 'selection', 'filter', 'dataParameters', 'order', 'conditionalAppearance', 'outputParameters', + 'item', 'additionalProperties', 'itemsViewMode', 'itemsUserSettingID', 'itemsUserSettingPresentation'], + 'StructureItemGroup': ['use', 'name', 'groupItems', 'filter', 'order', 'selection', 'conditionalAppearance', 'outputParameters', + 'item', 'id', 'viewMode', 'userSettingID', 'userSettingPresentation', 'itemsViewMode', 'itemsUserSettingID', + 'itemsUserSettingPresentation', 'groupState'], + 'StructureItemTable': ['use', 'name', 'column', 'row', 'selection', 'conditionalAppearance', 'outputParameters', + 'id', 'viewMode', 'userSettingID', 'userSettingPresentation', 'columnsViewMode', 'columnsUserSettingID', + 'columnsUserSettingPresentation', 'rowsViewMode', 'rowsUserSettingID', 'rowsUserSettingPresentation'], + 'StructureItemChart': ['use', 'name', 'point', 'series', 'selection', 'conditionalAppearance', 'outputParameters', + 'id', 'viewMode', 'userSettingID', 'userSettingPresentation', 'pointsViewMode', 'pointsUserSettingID', + 'pointsUserSettingPresentation', 'seriesViewMode', 'seriesUserSettingID', 'seriesUserSettingPresentation'], + 'DataSetFieldField': ['dataPath', 'field', 'title', 'useRestriction', 'attributeUseRestriction', 'role', 'presentationExpression', + 'orderExpression', 'inHierarchyDataSet', 'inHierarchyDataSetParameter', 'valueType', 'appearance', + 'availableValue', 'inputParameters'], +} + + +def get_xsd_child_order(container): + if local_name(container) == 'settings': + return XSD_CHILD_ORDER['settings'] + if local_name(container) == 'field': + return XSD_CHILD_ORDER['DataSetFieldField'] + xt = (container.get('{http://www.w3.org/2001/XMLSchema-instance}type') or '').split(':')[-1] + if xt in XSD_CHILD_ORDER: + return XSD_CHILD_ORDER[xt] + return XSD_CHILD_ORDER['StructureItemGroup'] + + +def find_ordered_insert_ref(container, child_name): + """Первый сосед, который по XSD идёт после child_name; None — вставлять в конец.""" + order = get_xsd_child_order(container) + if child_name not in order: + return None + rank = order.index(child_name) + for ch in container: + if not isinstance(ch.tag, str): + continue + ln = local_name(ch) + if ln in order and order.index(ln) > rank: + return ch + return None + + +def ensure_settings_child(settings, child_name): el = find_first_element(settings, [child_name], SET_NS) if el is not None: return el @@ -1995,19 +2053,7 @@ def ensure_settings_child(settings, child_name, after_siblings): frag_xml = f"{indent}" nodes = import_fragment(xml_doc, frag_xml) - ref_node = None - for sib_name in after_siblings: - sib = find_first_element(settings, [sib_name], SET_NS) - if sib is not None: - # Get next element sibling - found = False - for ch in settings: - if found and isinstance(ch.tag, str): - ref_node = ch - break - if ch is sib: - found = True - break + ref_node = find_ordered_insert_ref(settings, child_name) for node in nodes: insert_before_element(settings, node, ref_node, indent) @@ -2108,7 +2154,7 @@ if operation == "add-field": if not no_selection: settings = resolve_variant_settings() var_name = get_variant_name() - selection = ensure_settings_child(settings, "selection", []) + selection = ensure_settings_child(settings, "selection") existing_sel = find_element_by_child_value(selection, "item", "field", parsed["dataPath"], SET_NS) if existing_sel is not None: print(f'[INFO] Field "{parsed["dataPath"]}" already in selection -- skipped') @@ -2186,7 +2232,7 @@ elif operation == "add-calculated-field": if not no_selection: settings = resolve_variant_settings() var_name = get_variant_name() - selection = ensure_settings_child(settings, "selection", []) + selection = ensure_settings_child(settings, "selection") existing_sel = find_element_by_child_value(selection, "item", "field", parsed["dataPath"], SET_NS) if existing_sel is not None: print(f'[INFO] Field "{parsed["dataPath"]}" already in selection -- skipped') @@ -2582,7 +2628,7 @@ elif operation == "add-filter": var_name = get_variant_name() for val in values: parsed = parse_filter_shorthand(val) - filter_el = ensure_settings_child(settings, "filter", ["selection"]) + filter_el = ensure_settings_child(settings, "filter") filter_indent = get_container_child_indent(filter_el) frag_xml = build_filter_item_fragment(parsed, filter_indent) nodes = import_fragment(xml_doc, frag_xml) @@ -2595,7 +2641,7 @@ elif operation == "add-dataParameter": var_name = get_variant_name() for val in values: parsed = parse_data_param_shorthand(val) - dp_el = ensure_settings_child(settings, "dataParameters", ["outputParameters", "conditionalAppearance", "order", "filter", "selection"]) + dp_el = ensure_settings_child(settings, "dataParameters") dp_indent = get_container_child_indent(dp_el) frag_xml = build_data_param_fragment(parsed, dp_indent) nodes = import_fragment(xml_doc, frag_xml) @@ -2608,7 +2654,7 @@ elif operation == "add-order": var_name = get_variant_name() for val in values: parsed = parse_order_shorthand(val) - order_el = ensure_settings_child(settings, "order", ["filter", "selection"]) + order_el = ensure_settings_child(settings, "order") order_indent = get_container_child_indent(order_el) if parsed["field"] == "Auto": @@ -2665,7 +2711,7 @@ elif operation == "add-selection": else: target_el = settings - selection = ensure_settings_child(target_el, "selection", []) + selection = ensure_settings_child(target_el, "selection") # Dedup: skip if SelectedItemAuto already exists if field_name == "Auto": @@ -2737,7 +2783,7 @@ elif operation == "set-outputParameter": var_name = get_variant_name() for val in values: parsed = parse_output_param_shorthand(val) - output_el = ensure_settings_child(settings, "outputParameters", ["conditionalAppearance", "order", "filter", "selection"]) + output_el = ensure_settings_child(settings, "outputParameters") output_indent = get_container_child_indent(output_el) existing_param = find_element_by_child_value(output_el, "item", "parameter", parsed["key"], COR_NS) @@ -2763,7 +2809,8 @@ elif operation == "set-structure": struct_items = parse_structure_shorthand(value_arg) settings_indent = get_child_indent(settings) - ref_node = find_first_element(settings, ["outputParameters", "dataParameters", "conditionalAppearance", "order", "filter", "selection", "item"], SET_NS) + # Место по XSD: после outputParameters и прочих блоков, до additionalProperties/itemsViewMode + ref_node = find_ordered_insert_ref(settings, "item") for struct_item in struct_items: frag_xml = build_structure_item_fragment(struct_item, settings_indent) @@ -2967,7 +3014,7 @@ elif operation == "add-conditionalAppearance": var_name = get_variant_name() for val in values: parsed = parse_conditional_appearance_shorthand(val) - ca_el = ensure_settings_child(settings, "conditionalAppearance", ["outputParameters", "order", "filter", "selection"]) + ca_el = ensure_settings_child(settings, "conditionalAppearance") ca_indent = get_container_child_indent(ca_el) frag_xml = build_conditional_appearance_item_fragment(parsed, ca_indent) nodes = import_fragment(xml_doc, frag_xml) @@ -3256,7 +3303,8 @@ elif operation == "set-field-role": lines.append(f"{field_indent}") frag_xml = "\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) + # Место по XSD: после attributeUseRestriction, до presentationExpression/orderExpression/valueType + ref_node = find_ordered_insert_ref(field_el, "role") for node in import_fragment(xml_doc, frag_xml): insert_before_element(field_el, node, ref_node, field_indent) diff --git a/tests/skills/cases/skd-compile/snapshots/calc-shorthand-extended/Template.xml b/tests/skills/cases/skd-compile/snapshots/calc-shorthand-extended/Template.xml index b81b79dde..6ae5a7bbf 100644 --- a/tests/skills/cases/skd-compile/snapshots/calc-shorthand-extended/Template.xml +++ b/tests/skills/cases/skd-compile/snapshots/calc-shorthand-extended/Template.xml @@ -42,6 +42,12 @@ Имя ресурса + + true + true + true + true + xs:string @@ -49,12 +55,6 @@ Variable - - true - true - true - true - Маржа diff --git a/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml b/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml index 35d79bc68..a24c9d11f 100644 --- a/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml +++ b/tests/skills/cases/skd-compile/snapshots/empty-param-values/Template.xml @@ -165,11 +165,11 @@ СоставнойТип xs:string + d5p1:CatalogRef.ПлоскийПростой 10 Fixed - d5p1:CatalogRef.ПлоскийПростой false diff --git a/tests/skills/cases/skd-compile/snapshots/field-appearance-and-presentation/Template.xml b/tests/skills/cases/skd-compile/snapshots/field-appearance-and-presentation/Template.xml index 0c833063d..ca3f1c880 100644 --- a/tests/skills/cases/skd-compile/snapshots/field-appearance-and-presentation/Template.xml +++ b/tests/skills/cases/skd-compile/snapshots/field-appearance-and-presentation/Template.xml @@ -42,6 +42,7 @@ Описание + ТекстСообщения d5p1:CatalogRef.Организации @@ -51,7 +52,6 @@ Right - ТекстСообщения ИсточникДанных1 ЖурналОшибок diff --git a/tests/skills/cases/skd-compile/snapshots/field-restrictions/Template.xml b/tests/skills/cases/skd-compile/snapshots/field-restrictions/Template.xml index 7c6752d1d..9fc918ddb 100644 --- a/tests/skills/cases/skd-compile/snapshots/field-restrictions/Template.xml +++ b/tests/skills/cases/skd-compile/snapshots/field-restrictions/Template.xml @@ -59,9 +59,9 @@ Служебное Служебное + true true true - true xs:string diff --git a/tests/skills/cases/skd-compile/snapshots/xsd-order-calc-field/Template.xml b/tests/skills/cases/skd-compile/snapshots/xsd-order-calc-field/Template.xml new file mode 100644 index 000000000..71a7ee32c --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/xsd-order-calc-field/Template.xml @@ -0,0 +1,107 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Количество + Количество + + xs:decimal + + 15 + 3 + Any + + + + + Цена + Цена + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Количество, Т.Цена ИЗ Регистр КАК Т + + + Итого + Количество * Цена + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Итого</v8:content> + </v8:item> + + + true + true + + + + Формат + + + ru + ЧДЦ=2 + + + + + + xs:decimal + + 15 + 2 + Any + + + + + Удвоенное + Количество * 2 + + true + true + + + xs:decimal + + 10 + 0 + Any + + + + + Основной + + + ru + Основной + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-compile/snapshots/xsd-order-dataset-field/Template.xml b/tests/skills/cases/skd-compile/snapshots/xsd-order-dataset-field/Template.xml new file mode 100644 index 000000000..4bc0f5445 --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/xsd-order-dataset-field/Template.xml @@ -0,0 +1,112 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Вид + Вид + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Вид операции</v8:content> + </v8:item> + + + true + true + true + true + + + true + true + + + true + + ВЫБОР КОГДА Вид = 1 ТОГДА "Доход" ИНАЧЕ "Расход" КОНЕЦ + + Вид + Desc + false + + + xs:decimal + + 1 + 0 + Any + + + + + Формат + + + ru + ЧН=- + + + + + + 1 + + + ru + Доход + + + + + 2 + + + ru + Расход + + + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т + + + Основной + + + ru + Основной + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-compile/snapshots/xsd-order-group-filter/Template.xml b/tests/skills/cases/skd-compile/snapshots/xsd-order-group-filter/Template.xml new file mode 100644 index 000000000..1210e088f --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/xsd-order-group-filter/Template.xml @@ -0,0 +1,86 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Организация + Организация + + d5p1:CatalogRef.Организации + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Организация, Т.Сумма ИЗ Регистр КАК Т + + + Основной + + + ru + Основной + + + + + + Сумма + + + + + + Организация + Items + None + 0001-01-01T00:00:00 + 0001-01-01T00:00:00 + + + + + Сумма + Greater + 0 + + + + + + + + + + + + Сумма + Less + 1000 + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-compile/snapshots/xsd-order-settings/Template.xml b/tests/skills/cases/skd-compile/snapshots/xsd-order-settings/Template.xml new file mode 100644 index 000000000..ba7dc9564 --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/xsd-order-settings/Template.xml @@ -0,0 +1,155 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Организация + Организация + + d5p1:CatalogRef.Организации + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + + Активна + Активна + + xs:boolean + + + ИсточникДанных1 + ВЫБРАТЬ Т.Организация, Т.Сумма, Т.Активна ИЗ Регистр КАК Т + + + Период + + v8:StandardPeriod + + + LastMonth + + false + + + Основной + + + ru + Основной + + + + + + Организация + + + Сумма + + + + + Активна + Equal + true + + + + + Период + + LastMonth + + UUID-001 + + + + + Сумма + Desc + + + + + + + + Сумма + Less + 0 + + + + + ЦветТекста + web:Red + + + Видимость + false + + + + + + + Заголовок + + + ru + Отчёт + + + + + + + + Организация + Items + None + 0001-01-01T00:00:00 + 0001-01-01T00:00:00 + + + + + Сумма + Greater + 0 + + + + + Сумма + Desc + + + + + + + + + Основной + + + Normal + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-compile/snapshots/xsd-order-table-chart/Template.xml b/tests/skills/cases/skd-compile/snapshots/xsd-order-table-chart/Template.xml new file mode 100644 index 000000000..9f5b157fd --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/xsd-order-table-chart/Template.xml @@ -0,0 +1,147 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Организация + Организация + + d5p1:CatalogRef.Организации + + + + Период + Период + + xs:dateTime + + Date + + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Организация, Т.Период, Т.Сумма ИЗ Регистр КАК Т + + + Основной + + + ru + Основной + + + + + + Сумма + + + + Таблица + + + + Период + Items + None + 0001-01-01T00:00:00 + 0001-01-01T00:00:00 + + + + + + + + + + + + + Организация + Items + None + 0001-01-01T00:00:00 + 0001-01-01T00:00:00 + + + + + + + + + + Normal + + + ru + Таблица + + + Normal + QuickAccess + + + + + + Организация + Items + None + 0001-01-01T00:00:00 + 0001-01-01T00:00:00 + + + + + + + + + + + + + Период + Items + None + 0001-01-01T00:00:00 + 0001-01-01T00:00:00 + + + + + + + + + + + + Сумма + + + Normal + Normal + Inaccessible + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-compile/snapshots/xsd-values-bool-composite/Template.xml b/tests/skills/cases/skd-compile/snapshots/xsd-values-bool-composite/Template.xml new file mode 100644 index 000000000..830fa9d49 --- /dev/null +++ b/tests/skills/cases/skd-compile/snapshots/xsd-values-bool-composite/Template.xml @@ -0,0 +1,109 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Число + Число + + xs:string + xs:decimal + xs:dateTime + d5p1:CatalogRef.Организации + d5p1:DocumentRef + + 10 + 2 + Any + + + 10 + Variable + + + Date + + + + ИсточникДанных1 + ВЫБРАТЬ 1 КАК Число + + + Выключен + + xs:boolean + + false + false + + + Включен + + xs:boolean + + true + false + + + БезТипа + false + false + + + Составной + + xs:decimal + xs:string + d5p1:CatalogRef.Организации + + 10 + 2 + Any + + + 20 + Variable + + + + false + + + Основной + + + ru + Основной + + + + + + Число + + + + + Выключен + false + + + Включен + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-compile/xsd-order-calc-field.json b/tests/skills/cases/skd-compile/xsd-order-calc-field.json new file mode 100644 index 000000000..c74d66bf9 --- /dev/null +++ b/tests/skills/cases/skd-compile/xsd-order-calc-field.json @@ -0,0 +1,24 @@ +{ + "name": "Вычисляемое поле с типом, ограничениями и оформлением — valueType последним", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ Т.Количество, Т.Цена ИЗ Регистр КАК Т", + "fields": ["Количество: decimal(15,3)", "Цена: decimal(15,2)"] + }], + "calculatedFields": [ + { + "dataPath": "Итого", + "expression": "Количество * Цена", + "title": "Итого", + "type": "decimal(15,2)", + "restrict": ["noOrder", "noGroup"], + "appearance": { "Формат": "ЧДЦ=2" } + }, + "Удвоенное: decimal(10) = Количество * 2 #noGroup #noField" + ] + }, + "validatePath": "Template.xml", + "expect": { "files": ["Template.xml"] } +} diff --git a/tests/skills/cases/skd-compile/xsd-order-dataset-field.json b/tests/skills/cases/skd-compile/xsd-order-dataset-field.json new file mode 100644 index 000000000..4406ed7db --- /dev/null +++ b/tests/skills/cases/skd-compile/xsd-order-dataset-field.json @@ -0,0 +1,31 @@ +{ + "name": "Поле набора со всеми частями — порядок по XSD, флаги ограничений не в порядке ввода", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т", + "fields": [ + { + "dataPath": "Вид", + "field": "Вид", + "title": "Вид операции", + "type": "decimal(1)", + "role": { "dimension": true }, + "restrict": ["noOrder", "noGroup", "noFilter", "noField"], + "attrRestrict": ["noGroup", "noField"], + "appearance": { "Формат": "ЧН=-" }, + "presentationExpression": "ВЫБОР КОГДА Вид = 1 ТОГДА \"Доход\" ИНАЧЕ \"Расход\" КОНЕЦ", + "orderExpression": { "expression": "Вид", "orderType": "Desc", "autoOrder": false }, + "availableValues": [ + { "value": 1, "presentation": "Доход" }, + { "value": 2, "presentation": "Расход" } + ] + }, + "Сумма: decimal(15,2)" + ] + }] + }, + "validatePath": "Template.xml", + "expect": { "files": ["Template.xml"] } +} diff --git a/tests/skills/cases/skd-compile/xsd-order-group-filter.json b/tests/skills/cases/skd-compile/xsd-order-group-filter.json new file mode 100644 index 000000000..a38a322eb --- /dev/null +++ b/tests/skills/cases/skd-compile/xsd-order-group-filter.json @@ -0,0 +1,23 @@ +{ + "name": "Группировка с отбором, порядком и полями — filter до order и selection", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ Т.Организация, Т.Сумма ИЗ Регистр КАК Т", + "fields": ["Организация: CatalogRef.Организации", "Сумма: decimal(15,2)"] + }], + "settingsVariants": [{ + "name": "Основной", + "settings": { + "selection": ["Сумма"], + "structure": [ + { "type": "group", "groupBy": ["Организация"], "filter": ["Сумма > 0"], + "children": [{ "type": "group", "filter": ["Сумма < 1000"] }] } + ] + } + }] + }, + "validatePath": "Template.xml", + "expect": { "files": ["Template.xml"] } +} diff --git a/tests/skills/cases/skd-compile/xsd-order-settings.json b/tests/skills/cases/skd-compile/xsd-order-settings.json new file mode 100644 index 000000000..c2aad71df --- /dev/null +++ b/tests/skills/cases/skd-compile/xsd-order-settings.json @@ -0,0 +1,32 @@ +{ + "name": "Настройки варианта со всеми блоками и группировкой с отбором — порядок по XSD", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ Т.Организация, Т.Сумма, Т.Активна ИЗ Регистр КАК Т", + "fields": ["Организация: CatalogRef.Организации", "Сумма: decimal(15,2)", "Активна: boolean"] + }], + "parameters": ["Период: StandardPeriod = LastMonth"], + "settingsVariants": [{ + "name": "Основной", + "settings": { + "selection": ["Организация", "Сумма"], + "filter": ["Активна = true"], + "order": ["Сумма desc"], + "conditionalAppearance": [ + { "filter": ["Сумма < 0"], "appearance": { "ЦветТекста": "web:Red", "Видимость": false } } + ], + "outputParameters": { "Заголовок": "Отчёт" }, + "dataParameters": ["Период = LastMonth @user"], + "structure": [ + { "type": "group", "groupBy": ["Организация"], "filter": ["Сумма > 0"], "order": ["Сумма desc"], "selection": ["Auto"] } + ], + "itemsViewMode": "Normal", + "additionalProperties": { "ВариантНаименование": "Основной" } + } + }] + }, + "validatePath": "Template.xml", + "expect": { "files": ["Template.xml"] } +} diff --git a/tests/skills/cases/skd-compile/xsd-order-table-chart.json b/tests/skills/cases/skd-compile/xsd-order-table-chart.json new file mode 100644 index 000000000..777b13d49 --- /dev/null +++ b/tests/skills/cases/skd-compile/xsd-order-table-chart.json @@ -0,0 +1,40 @@ +{ + "name": "Таблица и диаграмма с режимами доступности — viewMode до columns/pointsViewMode", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ Т.Организация, Т.Период, Т.Сумма ИЗ Регистр КАК Т", + "fields": ["Организация: CatalogRef.Организации", "Период: date", "Сумма: decimal(15,2)"] + }], + "settingsVariants": [{ + "name": "Основной", + "settings": { + "selection": ["Сумма"], + "structure": [ + { + "type": "table", + "name": "Таблица", + "rows": [{ "groupBy": ["Организация"] }], + "columns": [{ "groupBy": ["Период"] }], + "viewMode": "Normal", + "userSettingPresentation": "Таблица", + "columnsViewMode": "Normal", + "rowsViewMode": "QuickAccess" + }, + { + "type": "chart", + "points": { "groupBy": ["Организация"] }, + "series": { "groupBy": ["Период"] }, + "selection": ["Сумма"], + "viewMode": "Normal", + "pointsViewMode": "Normal", + "seriesViewMode": "Inaccessible" + } + ] + } + }] + }, + "validatePath": "Template.xml", + "expect": { "files": ["Template.xml"] } +} diff --git a/tests/skills/cases/skd-compile/xsd-values-bool-composite.json b/tests/skills/cases/skd-compile/xsd-values-bool-composite.json new file mode 100644 index 000000000..6c92c40eb --- /dev/null +++ b/tests/skills/cases/skd-compile/xsd-values-bool-composite.json @@ -0,0 +1,27 @@ +{ + "name": "Булевы значения из JSON и составной тип — true/false строчными, сначала типы, потом квалификаторы", + "params": { "outputPath": "Template.xml" }, + "input": { + "dataSets": [{ + "name": "Основной", + "query": "ВЫБРАТЬ 1 КАК Число", + "fields": [{ "dataPath": "Число", "field": "Число", "type": ["string(10)", "decimal(10,2)", "date", "CatalogRef.Организации", "DocumentRef"] }] + }], + "parameters": [ + { "name": "Выключен", "type": "boolean", "value": false }, + { "name": "Включен", "type": "boolean", "value": true }, + { "name": "БезТипа", "value": false }, + { "name": "Составной", "type": ["decimal(10,2)", "string(20)", "CatalogRef.Организации"] } + ], + "settingsVariants": [{ + "name": "Основной", + "settings": { + "selection": ["Число"], + "dataParameters": ["Выключен = false", "Включен = true"], + "structure": "details" + } + }] + }, + "validatePath": "Template.xml", + "expect": { "files": ["Template.xml"] } +} diff --git a/tests/skills/cases/skd-decompile/snapshots/calc-total-params/Template.xml b/tests/skills/cases/skd-decompile/snapshots/calc-total-params/Template.xml index 76c8cc15e..5ba557059 100644 --- a/tests/skills/cases/skd-decompile/snapshots/calc-total-params/Template.xml +++ b/tests/skills/cases/skd-decompile/snapshots/calc-total-params/Template.xml @@ -58,6 +58,12 @@ Служебное "" + + true + true + true + true + xs:string @@ -65,12 +71,6 @@ Variable - - true - true - true - true - Цена diff --git a/tests/skills/cases/skd-decompile/snapshots/fields-types-and-restrictions/Template.xml b/tests/skills/cases/skd-decompile/snapshots/fields-types-and-restrictions/Template.xml index 6930dedb4..311e65627 100644 --- a/tests/skills/cases/skd-decompile/snapshots/fields-types-and-restrictions/Template.xml +++ b/tests/skills/cases/skd-decompile/snapshots/fields-types-and-restrictions/Template.xml @@ -140,10 +140,10 @@ СВыражениемПредставления СВыражениемПредставления + Представление(СВыражениемПредставления) d5p1:CatalogRef.Номенклатура - Представление(СВыражениемПредставления) ИсточникДанных1 ВЫБРАТЬ * ИЗ Справочник.Номенклатура diff --git a/tests/skills/cases/skd-decompile/snapshots/variant-full/Template.xml b/tests/skills/cases/skd-decompile/snapshots/variant-full/Template.xml index 284a84d01..67d1c9f7d 100644 --- a/tests/skills/cases/skd-decompile/snapshots/variant-full/Template.xml +++ b/tests/skills/cases/skd-decompile/snapshots/variant-full/Template.xml @@ -307,6 +307,20 @@ + + + Период + + LastMonth + + UUID-002 + + + Активные + true + UUID-003 + + Сумма @@ -332,7 +346,7 @@ Большие суммы Normal - UUID-002 + UUID-004 @@ -346,20 +360,6 @@ - - - Период - - LastMonth - - UUID-003 - - - Активные - true - UUID-004 - - diff --git a/tests/skills/cases/skd-edit/snapshots/add-calculated-field-restrict/Template.xml b/tests/skills/cases/skd-edit/snapshots/add-calculated-field-restrict/Template.xml index 54e2b2945..f36bbf333 100644 --- a/tests/skills/cases/skd-edit/snapshots/add-calculated-field-restrict/Template.xml +++ b/tests/skills/cases/skd-edit/snapshots/add-calculated-field-restrict/Template.xml @@ -38,8 +38,8 @@ "" true - true true + true xs:string diff --git a/tests/skills/cases/skd-edit/snapshots/modify-structure-preserves-selection/Template.xml b/tests/skills/cases/skd-edit/snapshots/modify-structure-preserves-selection/Template.xml index 85435476c..40cb0d933 100644 --- a/tests/skills/cases/skd-edit/snapshots/modify-structure-preserves-selection/Template.xml +++ b/tests/skills/cases/skd-edit/snapshots/modify-structure-preserves-selection/Template.xml @@ -52,6 +52,9 @@ + + + ДанныеОтчета @@ -76,9 +79,6 @@ - - - \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/snapshots/set-structure-multi-field/Template.xml b/tests/skills/cases/skd-edit/snapshots/set-structure-multi-field/Template.xml index d7e93fbd9..33fe1b35c 100644 --- a/tests/skills/cases/skd-edit/snapshots/set-structure-multi-field/Template.xml +++ b/tests/skills/cases/skd-edit/snapshots/set-structure-multi-field/Template.xml @@ -51,6 +51,9 @@ + + + ДанныеОтчета @@ -83,9 +86,6 @@ - - - \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/snapshots/set-structure-named/Template.xml b/tests/skills/cases/skd-edit/snapshots/set-structure-named/Template.xml index 2bdb57d94..32546e388 100644 --- a/tests/skills/cases/skd-edit/snapshots/set-structure-named/Template.xml +++ b/tests/skills/cases/skd-edit/snapshots/set-structure-named/Template.xml @@ -65,6 +65,9 @@ + + + ДанныеОтчета @@ -104,9 +107,6 @@ - - - \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/snapshots/xsd-order-add-conditionalAppearance/Template.xml b/tests/skills/cases/skd-edit/snapshots/xsd-order-add-conditionalAppearance/Template.xml new file mode 100644 index 000000000..de18c436f --- /dev/null +++ b/tests/skills/cases/skd-edit/snapshots/xsd-order-add-conditionalAppearance/Template.xml @@ -0,0 +1,95 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Вид + Вид + + xs:decimal + + 1 + 0 + Any + + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т + + + Основной + + + ru + Основной + + + + + + Сумма + + + + + Сумма + Desc + + + + + + + + Сумма + Less + 0 + + + + + ЦветТекста + web:Red + + + + + + + Заголовок + + + ru + Отчёт + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/snapshots/xsd-order-add-dataParameter/Template.xml b/tests/skills/cases/skd-edit/snapshots/xsd-order-add-dataParameter/Template.xml new file mode 100644 index 000000000..6e227b758 --- /dev/null +++ b/tests/skills/cases/skd-edit/snapshots/xsd-order-add-dataParameter/Template.xml @@ -0,0 +1,123 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Вид + Вид + + xs:decimal + + 1 + 0 + Any + + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т + + + Период + + v8:StandardPeriod + + + LastMonth + + false + + + Основной + + + ru + Основной + + + + + + Сумма + + + + + Сумма + Greater + 0 + + + + + Период + + LastMonth + 0001-01-01T00:00:00 + 0001-01-01T00:00:00 + + UUID-001 + + + + + Сумма + Desc + + + + + + + + Сумма + Less + 0 + + + + + ЦветТекста + web:Red + + + + + + + Заголовок + + + ru + Отчёт + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/snapshots/xsd-order-add-selection-first/Template.xml b/tests/skills/cases/skd-edit/snapshots/xsd-order-add-selection-first/Template.xml new file mode 100644 index 000000000..3ae9c7c3a --- /dev/null +++ b/tests/skills/cases/skd-edit/snapshots/xsd-order-add-selection-first/Template.xml @@ -0,0 +1,71 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Вид + Вид + + xs:decimal + + 1 + 0 + Any + + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т + + + Основной + + + ru + Основной + + + + + + Сумма + + + + + Заголовок + + + ru + Отчёт + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/snapshots/xsd-order-modify-field/Template.xml b/tests/skills/cases/skd-edit/snapshots/xsd-order-modify-field/Template.xml new file mode 100644 index 000000000..98b060f7f --- /dev/null +++ b/tests/skills/cases/skd-edit/snapshots/xsd-order-modify-field/Template.xml @@ -0,0 +1,109 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Вид + Вид + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Вид операции</v8:content> + </v8:item> + + + true + true + + + true + + + true + + ВЫБОР КОГДА Вид = 1 ТОГДА "Доход" ИНАЧЕ "Расход" КОНЕЦ + + Вид + Desc + false + + + xs:decimal + + 2 + 0 + Any + + + + + Формат + + + ru + ЧН=- + + + + + + 1 + + + ru + Доход + + + + + 2 + + + ru + Расход + + + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т + + + Основной + + + ru + Основной + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/snapshots/xsd-order-set-field-role/Template.xml b/tests/skills/cases/skd-edit/snapshots/xsd-order-set-field-role/Template.xml new file mode 100644 index 000000000..563ec6f0a --- /dev/null +++ b/tests/skills/cases/skd-edit/snapshots/xsd-order-set-field-role/Template.xml @@ -0,0 +1,105 @@ + + + + ИсточникДанных1 + Local + + + Основной + + Вид + Вид + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Вид</v8:content> + </v8:item> + + + true + + + true + + ВЫБОР КОГДА Вид = 1 ТОГДА "Доход" ИНАЧЕ "Расход" КОНЕЦ + + Вид + Desc + false + + + xs:decimal + + 1 + 0 + Any + + + + + Формат + + + ru + ЧН=- + + + + + + 1 + + + ru + Доход + + + + + 2 + + + ru + Расход + + + + + + Сумма + Сумма + + xs:decimal + + 15 + 2 + Any + + + + ИсточникДанных1 + ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т + + + Основной + + + ru + Основной + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/skd-edit/xsd-order-add-conditionalAppearance.json b/tests/skills/cases/skd-edit/xsd-order-add-conditionalAppearance.json new file mode 100644 index 000000000..2a95e2fc0 --- /dev/null +++ b/tests/skills/cases/skd-edit/xsd-order-add-conditionalAppearance.json @@ -0,0 +1,46 @@ +{ + "name": "add-conditionalAppearance при order и outputParameters — до outputParameters", + "preRun": [ + { + "script": "skd-compile/scripts/skd-compile", + "input": { + "dataSets": [ + { + "name": "Основной", + "query": "ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т", + "fields": [ + "Вид: decimal(1)", + "Сумма: decimal(15,2)" + ] + } + ], + "settingsVariants": [ + { + "name": "Основной", + "settings": { + "selection": [ + "Сумма" + ], + "order": [ + "Сумма desc" + ], + "outputParameters": { + "Заголовок": "Отчёт" + }, + "structure": "details" + } + } + ] + }, + "args": { + "-DefinitionFile": "{inputFile}", + "-OutputPath": "{workDir}/Template.xml" + } + } + ], + "params": { + "templatePath": "Template.xml", + "operation": "add-conditionalAppearance", + "value": "ЦветТекста = web:Red when Сумма < 0" + } +} diff --git a/tests/skills/cases/skd-edit/xsd-order-add-dataParameter.json b/tests/skills/cases/skd-edit/xsd-order-add-dataParameter.json new file mode 100644 index 000000000..4151726ec --- /dev/null +++ b/tests/skills/cases/skd-edit/xsd-order-add-dataParameter.json @@ -0,0 +1,62 @@ +{ + "name": "add-dataParameter в заполненные настройки — сразу после filter, до order", + "preRun": [ + { + "script": "skd-compile/scripts/skd-compile", + "input": { + "dataSets": [ + { + "name": "Основной", + "query": "ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т", + "fields": [ + "Вид: decimal(1)", + "Сумма: decimal(15,2)" + ] + } + ], + "parameters": [ + "Период: StandardPeriod = LastMonth" + ], + "settingsVariants": [ + { + "name": "Основной", + "settings": { + "selection": [ + "Сумма" + ], + "filter": [ + "Сумма > 0" + ], + "order": [ + "Сумма desc" + ], + "conditionalAppearance": [ + { + "filter": [ + "Сумма < 0" + ], + "appearance": { + "ЦветТекста": "web:Red" + } + } + ], + "outputParameters": { + "Заголовок": "Отчёт" + }, + "structure": "details" + } + } + ] + }, + "args": { + "-DefinitionFile": "{inputFile}", + "-OutputPath": "{workDir}/Template.xml" + } + } + ], + "params": { + "templatePath": "Template.xml", + "operation": "add-dataParameter", + "value": "Период = LastMonth @user" + } +} diff --git a/tests/skills/cases/skd-edit/xsd-order-add-selection-first.json b/tests/skills/cases/skd-edit/xsd-order-add-selection-first.json new file mode 100644 index 000000000..266297bfa --- /dev/null +++ b/tests/skills/cases/skd-edit/xsd-order-add-selection-first.json @@ -0,0 +1,40 @@ +{ + "name": "add-selection в вариант без selection — перед outputParameters и структурой, а не в конец", + "preRun": [ + { + "script": "skd-compile/scripts/skd-compile", + "input": { + "dataSets": [ + { + "name": "Основной", + "query": "ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т", + "fields": [ + "Вид: decimal(1)", + "Сумма: decimal(15,2)" + ] + } + ], + "settingsVariants": [ + { + "name": "Основной", + "settings": { + "outputParameters": { + "Заголовок": "Отчёт" + }, + "structure": "details" + } + } + ] + }, + "args": { + "-DefinitionFile": "{inputFile}", + "-OutputPath": "{workDir}/Template.xml" + } + } + ], + "params": { + "templatePath": "Template.xml", + "operation": "add-selection", + "value": "Сумма" + } +} diff --git a/tests/skills/cases/skd-edit/xsd-order-modify-field.json b/tests/skills/cases/skd-edit/xsd-order-modify-field.json new file mode 100644 index 000000000..730ee5a18 --- /dev/null +++ b/tests/skills/cases/skd-edit/xsd-order-modify-field.json @@ -0,0 +1,56 @@ +{ + "name": "modify-field пересобирает поле — сохранённые части на своих местах по XSD", + "preRun": [ + { + "script": "skd-compile/scripts/skd-compile", + "input": { + "dataSets": [ + { + "name": "Основной", + "query": "ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т", + "fields": [ + { + "dataPath": "Вид", + "field": "Вид", + "title": "Вид", + "type": "decimal(1)", + "attrRestrict": [ + "noGroup" + ], + "presentationExpression": "ВЫБОР КОГДА Вид = 1 ТОГДА \"Доход\" ИНАЧЕ \"Расход\" КОНЕЦ", + "orderExpression": { + "expression": "Вид", + "orderType": "Desc", + "autoOrder": false + }, + "appearance": { + "Формат": "ЧН=-" + }, + "availableValues": [ + { + "value": 1, + "presentation": "Доход" + }, + { + "value": 2, + "presentation": "Расход" + } + ] + }, + "Сумма: decimal(15,2)" + ] + } + ] + }, + "args": { + "-DefinitionFile": "{inputFile}", + "-OutputPath": "{workDir}/Template.xml" + } + } + ], + "params": { + "templatePath": "Template.xml", + "operation": "modify-field", + "value": "Вид [Вид операции]: decimal(2) @dimension #noOrder #noField" + } +} diff --git a/tests/skills/cases/skd-edit/xsd-order-set-field-role.json b/tests/skills/cases/skd-edit/xsd-order-set-field-role.json new file mode 100644 index 000000000..2e5217b64 --- /dev/null +++ b/tests/skills/cases/skd-edit/xsd-order-set-field-role.json @@ -0,0 +1,56 @@ +{ + "name": "set-field-role на поле с presentationExpression и orderExpression — role перед ними", + "preRun": [ + { + "script": "skd-compile/scripts/skd-compile", + "input": { + "dataSets": [ + { + "name": "Основной", + "query": "ВЫБРАТЬ Т.Вид, Т.Сумма ИЗ Регистр КАК Т", + "fields": [ + { + "dataPath": "Вид", + "field": "Вид", + "title": "Вид", + "type": "decimal(1)", + "attrRestrict": [ + "noGroup" + ], + "presentationExpression": "ВЫБОР КОГДА Вид = 1 ТОГДА \"Доход\" ИНАЧЕ \"Расход\" КОНЕЦ", + "orderExpression": { + "expression": "Вид", + "orderType": "Desc", + "autoOrder": false + }, + "appearance": { + "Формат": "ЧН=-" + }, + "availableValues": [ + { + "value": 1, + "presentation": "Доход" + }, + { + "value": 2, + "presentation": "Расход" + } + ] + }, + "Сумма: decimal(15,2)" + ] + } + ] + }, + "args": { + "-DefinitionFile": "{inputFile}", + "-OutputPath": "{workDir}/Template.xml" + } + } + ], + "params": { + "templatePath": "Template.xml", + "operation": "set-field-role", + "value": "Вид @dimension" + } +}