diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index 2359557e..109aa352 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -1,4 +1,4 @@ -# meta-compile v1.36 — Compile 1C metadata object from JSON +# meta-compile v1.37 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -257,7 +257,7 @@ $script:validEnumValues = @{ "FillChecking" = @("DontCheck","ShowError","ShowWarning") "Indexing" = @("DontIndex","Index","IndexWithAdditionalOrder") "SubordinationUse" = @("ToItems","ToFolders","ToFoldersAndItems") - "CodeSeries" = @("WholeCatalog","WithinSubordination","WithinOwnerSubordination","WholeCharacteristicKind") + "CodeSeries" = @("WholeCatalog","WithinSubordination","WithinOwnerSubordination","WholeCharacteristicKind","WholeChartOfAccounts") "ChoiceMode" = @("BothWays","QuickChoice","FromForm") "CreateOnInput" = @("Auto","Use","DontUse") "ChoiceHistoryOnInput" = @("Auto","DontUse") @@ -630,6 +630,8 @@ $script:fillEmptyRefWords = @('emptyref','пустаяссылка') $script:fillEnumValWords = @('enumvalue','значениеперечисления') $script:fillBoolTrue = @('true','истина','да') $script:fillBoolFalse = @('false','ложь','нет') +# Значения платформенного перечисления ВидСчета (ent:AccountType) — FillValue стандартного реквизита Тип у Плана счетов. +$script:accountTypeValues = @('Active','Passive','ActivePassive') # XxxRef (тип реквизита) → корень DTR-пути (для разворота короткой записи значения). $script:fillRefKindRoot = @{ 'catalogref'='Catalog'; 'documentref'='Document'; 'enumref'='Enum'; @@ -1018,7 +1020,7 @@ $script:standardAttributesByType = @{ "AccumulationRegister" = @("Active","LineNumber","Recorder","Period") "AccountingRegister" = @("Active","Period","Recorder","LineNumber","Account") "CalculationRegister" = @("Active","Recorder","LineNumber","RegistrationPeriod","CalculationType","ReversingEntry") - "ChartOfAccounts" = @("PredefinedDataName","Predefined","Ref","DeletionMark","Description","Code","Parent","Order","Type","OffBalance") + "ChartOfAccounts" = @("PredefinedDataName","Order","OffBalance","Type","Description","Code","Parent","Predefined","DeletionMark","Ref") "ChartOfCharacteristicTypes" = @("PredefinedDataName","Predefined","Ref","DeletionMark","Description","Code","Parent","ValueType") "ChartOfCalculationTypes" = @("PredefinedDataName","Predefined","Ref","DeletionMark","Description","Code","ActionPeriodIsBasic") "BusinessProcess" = @("Ref","DeletionMark","Date","Number","Started","Completed","HeadTask") @@ -1047,6 +1049,13 @@ $script:stdAttrProfile = @{ "Description" = @{ FillChecking = "ShowError" } "Parent" = @{ FillFromFillingValue = "true" } } + # ChartOfAccounts: Наименование/Код → FillChecking=ShowError (3/3), Родитель → FFV=true (3/3). Тип (АктивПассив) + # и FillValue Родителя (self EmptyRef) кастомизируются пообъектно → захват override, не профиль. + "ChartOfAccounts" = @{ + "Description" = @{ FillChecking = "ShowError" } + "Code" = @{ FillChecking = "ShowError" } + "Parent" = @{ FillFromFillingValue = "true" } + } } # $ov — hashtable переопределений (профиль + DSL) для полей: FillChecking, FillFromFillingValue, @@ -1107,7 +1116,7 @@ function Emit-StandardAttribute { # Прочие типы (не в множестве) → блок эмитится всегда (текущее поведение, пока их правило не выведено). # - stdAttrProfile[тип]: профиль материализованного блока (пусто = schema-дефолт), поверх — DSL-override. # Миграция типа = добавить его в stdAttrConditionalTypes + stdAttrProfile и переснять снэпшоты; КОД НЕ ТРОГАЕМ. -$script:stdAttrConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes') +$script:stdAttrConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts') function Emit-StandardAttributes { param([string]$indent, [string]$objectType) $attrs = $script:standardAttributesByType[$objectType] @@ -1321,6 +1330,7 @@ function Normalize-ChoiceValue { if ($s -match '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$') { return @{ XsiType='xs:dateTime'; Text=$s } } $ref = Normalize-FillRef $s if ($ref) { return @{ XsiType='xr:DesignTimeRef'; Text=$ref } } + if ($script:accountTypeValues -contains $s) { return @{ XsiType='ent:AccountType'; Text=$s } } return @{ XsiType='xs:string'; Text=$s } } @@ -1521,8 +1531,10 @@ function Emit-MinMaxValue { } function Emit-Attribute { - param([string]$indent, $parsed, [string]$context) - # $context: "catalog", "document", "object", "processor", "tabular", "processor-tabular", "register" + param([string]$indent, $parsed, [string]$context, [string]$elemTag = "Attribute") + # $context: "catalog", "document", "object", "processor", "tabular", "processor-tabular", "register", + # "account" (реквизит Плана счетов: как catalog, но без ), "account-flag" (признак учёта ПС: + # как account, но без /, тип по умолчанию Boolean; $elemTag = AccountingFlag/ExtDimensionAccountingFlag) $attrName = $parsed.name $ctxReserved = $script:reservedByContext[$context] if ($ctxReserved) { @@ -1538,7 +1550,7 @@ function Emit-Attribute { Write-Warning "Attribute '$attrName' conflicts with a standard attribute name. This may cause errors when loading into 1C." } $uuid = New-Guid-String - X "$indent" + X "$indent<$elemTag uuid=`"$uuid`">" X "$indent`t" X "$indent`t`t$(Esc-Xml $parsed.name)" Emit-MLText "$indent`t`t" "Synonym" $parsed.synonym @@ -1548,6 +1560,11 @@ function Emit-Attribute { $typeStr = $parsed.type if ($typeStr) { Emit-ValueType "$indent`t`t" $typeStr + } elseif ($context -eq "account-flag") { + # Признак учёта — по умолчанию Boolean. + X "$indent`t`t" + X "$indent`t`t`txs:boolean" + X "$indent`t`t" } else { # Default: unqualified string X "$indent`t`t" @@ -1607,14 +1624,17 @@ function Emit-Attribute { # Indexing/FullTextSearch/DataHistory — not for non-stored objects (processor, processor-tabular) if ($context -notin @("processor", "processor-tabular")) { - $indexing = "DontIndex" - if ($parsed.flags -contains "index") { $indexing = "Index" } - if ($parsed.flags -contains "indexadditional") { $indexing = "IndexWithAdditionalOrder" } - if ($parsed.indexing) { $indexing = $parsed.indexing } - X "$indent`t`t$indexing" + # Признаки учёта ПС (account-flag) не имеют /, но имеют . + if ($context -ne "account-flag") { + $indexing = "DontIndex" + if ($parsed.flags -contains "index") { $indexing = "Index" } + if ($parsed.flags -contains "indexadditional") { $indexing = "IndexWithAdditionalOrder" } + if ($parsed.indexing) { $indexing = $parsed.indexing } + X "$indent`t`t$indexing" - $fts = if ($parsed.fullTextSearch) { $parsed.fullTextSearch } else { "Use" } - X "$indent`t`t$fts" + $fts = if ($parsed.fullTextSearch) { $parsed.fullTextSearch } else { "Use" } + X "$indent`t`t$fts" + } # DataHistory — not for Chart* types and non-InformationRegister register family if ($context -notin @("chart", "register-other")) { $dh = if ($parsed.dataHistory) { $parsed.dataHistory } else { "Use" } @@ -1623,7 +1643,7 @@ function Emit-Attribute { } X "$indent`t" - X "$indent" + X "$indent" } # команды — структурный блок (зеркало form-compile). Дефолт LoadTransparent=true (конвенция @@ -2721,87 +2741,111 @@ function Emit-ChartOfAccountsProperties { X "$i$(Esc-Xml $objName)" Emit-MLText $i "Synonym" $synonym - X "$i" - X "$itrue" + if ($def.comment) { X "$i$(Esc-XmlText "$($def.comment)")" } else { X "$i" } + $useStdCmd = if (Get-BoolProp "useStandardCommands" $true) { "true" } else { "false" } + X "$i$useStdCmd" + $inclHelp = if (Get-BoolProp "includeHelpInContents" $false) { "true" } else { "false" } + X "$i$inclHelp" + Emit-BasedOn $i $def.basedOn - # ExtDimensionTypes - $extDimTypes = if ($def.extDimensionTypes) { "$($def.extDimensionTypes)" } else { "" } - if ($extDimTypes) { X "$i$extDimTypes" } - else { X "$i" } + # ExtDimensionTypes — ссылка на ПВХ видов субконто (прощающий ввод: ПланВидовХарактеристик.X → ChartOfCharacteristicTypes.X). + $extDimTypes = "" + if ($def.extDimensionTypes) { + $extDimTypes = "$($def.extDimensionTypes)" + if ($extDimTypes.Contains('.')) { + $edtDot = $extDimTypes.IndexOf('.'); $edtPfx = $extDimTypes.Substring(0, $edtDot); $edtSfx = $extDimTypes.Substring($edtDot + 1) + if ($script:objectTypeSynonyms.ContainsKey($edtPfx)) { $edtPfx = $script:objectTypeSynonyms[$edtPfx] } + $extDimTypes = "$edtPfx.$edtSfx" + } + } + if ($extDimTypes) { X "$i$(Esc-Xml $extDimTypes)" } else { X "$i" } $maxExtDim = if ($null -ne $def.maxExtDimensionCount) { "$($def.maxExtDimensionCount)" } else { "3" } X "$i$maxExtDim" - $codeMask = if ($def.codeMask) { "$($def.codeMask)" } else { "" } - if ($codeMask) { X "$i$codeMask" } else { X "$i" } - - $codeLength = if ($null -ne $def.codeLength) { "$($def.codeLength)" } else { "8" } - $descriptionLength = if ($null -ne $def.descriptionLength) { "$($def.descriptionLength)" } else { "120" } - $codeSeries = if ($def.codeSeries) { "$($def.codeSeries)" } else { "WholeChartOfAccounts" } - $autoOrder = if ($def.autoOrderByCode -eq $false) { "false" } else { "true" } - $orderLength = if ($null -ne $def.orderLength) { "$($def.orderLength)" } else { "5" } + if ($def.codeMask) { X "$i$(Esc-XmlText "$($def.codeMask)")" } else { X "$i" } + $codeLength = if ($null -ne $def.codeLength) { "$($def.codeLength)" } else { "9" } + $descriptionLength = if ($null -ne $def.descriptionLength) { "$($def.descriptionLength)" } else { "25" } X "$i$codeLength" X "$i$descriptionLength" - X "$i$codeSeries" - X "$ifalse" - X "$iAsDescription" - X "$i$autoOrder" - X "$i$orderLength" - - X "$iInDialog" + X "$i$(Get-EnumProp 'CodeSeries' 'codeSeries' 'WholeChartOfAccounts')" + $checkUnique = if ($def.checkUnique -eq $false) { "false" } else { "true" } + X "$i$checkUnique" + X "$i$(Get-EnumProp 'DefaultPresentation' 'defaultPresentation' 'AsCode')" Emit-StandardAttributes $i "ChartOfAccounts" + Emit-Characteristics $i $def.characteristics - # StandardTabularSections — ExtDimensionTypes + # StandardTabularSections — ExtDimensionTypes (обёртка платформенно-константна: Synonym с пустым lang «Виды субконто», + # Comment/ToolTip/FillChecking; вложены 4 стандартных реквизита all-default). Кастомизация — не выведена (см. WORKFLOW). X "$i" X "$i`t" + X "$i`t`t" + X "$i`t`t`t" + X "$i`t`t`t`t" + X "$i`t`t`t`tВиды субконто" + X "$i`t`t`t" + X "$i`t`t" + X "$i`t`t" + X "$i`t`t" + X "$i`t`tDontCheck" X "$i`t`t" foreach ($stAttr in @("TurnoversOnly","Predefined","ExtDimensionType","LineNumber")) { - Emit-StandardAttribute "$i`t`t`t" $stAttr + $stOv = if ($stAttr -eq "ExtDimensionType") { @{ FillChecking = "ShowError" } } else { $null } + Emit-StandardAttribute "$i`t`t`t" $stAttr $stOv } X "$i`t`t" X "$i`t" X "$i" - X "$i" - X "$iAuto" + X "$i$(Get-EnumProp 'PredefinedDataUpdate' 'predefinedDataUpdate' 'Auto')" + X "$i$(Get-EnumProp 'EditType' 'editType' 'InDialog')" $quickChoice = if ($def.quickChoice -eq $true) { "true" } else { "false" } X "$i$quickChoice" - X "$iBothWays" - X "$i" - X "$i`tChartOfAccounts.$objName.StandardAttribute.Description" - X "$i`tChartOfAccounts.$objName.StandardAttribute.Code" - X "$i" - X "$iBegin" + X "$i$(Get-EnumProp 'ChoiceMode' 'choiceMode' 'BothWays')" + + # InputByString: override ЛИБО дефолт [Descr при D>0]+[Code при C>0] (prefix ChartOfAccounts). + if (Test-DefKey 'inputByString') { + $ibFields = @($def.inputByString | ForEach-Object { Expand-DataPath "$_" }) + } else { + $ibFields = @() + if ([int]$descriptionLength -gt 0) { $ibFields += "ChartOfAccounts.$objName.StandardAttribute.Description" } + if ([int]$codeLength -gt 0) { $ibFields += "ChartOfAccounts.$objName.StandardAttribute.Code" } + } + Emit-FieldBlock $i "InputByString" $ibFields + X "$i$(Get-EnumProp 'SearchStringModeOnInputByString' 'searchStringModeOnInputByString' 'Begin')" X "$iDontUse" X "$iDirectly" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$i" - X "$ifalse" - X "$i" - X "$i" + X "$i$(Get-EnumProp 'CreateOnInput' 'createOnInput' 'DontUse')" + X "$i$(Get-EnumProp 'ChoiceHistoryOnInput' 'choiceHistoryOnInput' 'Auto')" + Emit-FormRef $i "DefaultObjectForm" $def.defaultObjectForm + Emit-FormRef $i "DefaultListForm" $def.defaultListForm + Emit-FormRef $i "DefaultChoiceForm" $def.defaultChoiceForm + Emit-FormRef $i "AuxiliaryObjectForm" $def.auxiliaryObjectForm + Emit-FormRef $i "AuxiliaryListForm" $def.auxiliaryListForm + Emit-FormRef $i "AuxiliaryChoiceForm" $def.auxiliaryChoiceForm - $dataLockControlMode = Get-EnumProp "DataLockControlMode" "dataLockControlMode" "Automatic" - X "$i$dataLockControlMode" + $autoOrder = if ($def.autoOrderByCode -eq $false) { "false" } else { "true" } + X "$i$autoOrder" + $orderLength = if ($null -ne $def.orderLength) { "$($def.orderLength)" } else { "9" } + X "$i$orderLength" - $fullTextSearch = Get-EnumProp "FullTextSearch" "fullTextSearch" "Use" - X "$i$fullTextSearch" + $dlFields = if (Test-DefKey 'dataLockFields') { @($def.dataLockFields | ForEach-Object { Expand-DataPath "$_" }) } else { @() } + Emit-FieldBlock $i "DataLockFields" $dlFields + X "$i$(Get-EnumProp 'DataLockControlMode' 'dataLockControlMode' 'Automatic')" + X "$i$(Get-EnumProp 'FullTextSearch' 'fullTextSearch' 'Use')" + X "$i$(Get-EnumProp 'DataHistory' 'dataHistory' 'DontUse')" + $updDH = if (Get-BoolProp "updateDataHistoryImmediatelyAfterWrite" $false) { "true" } else { "false" } + X "$i$updDH" + $execDH = if (Get-BoolProp "executeAfterWriteDataHistoryVersionProcessing" $false) { "true" } else { "false" } + X "$i$execDH" Emit-MLText $i "ObjectPresentation" $def.objectPresentation Emit-MLText $i "ExtendedObjectPresentation" $def.extendedObjectPresentation Emit-MLText $i "ListPresentation" $def.listPresentation Emit-MLText $i "ExtendedListPresentation" $def.extendedListPresentation Emit-MLText $i "Explanation" $def.explanation - X "$iDontUse" - X "$iAuto" - X "$iDontUse" - X "$ifalse" - X "$ifalse" } function Emit-AccountingRegisterProperties { @@ -3190,74 +3234,6 @@ function Emit-Column { X "$indent" } -function Emit-AccountingFlag { - param([string]$indent, [string]$flagName) - $uuid = New-Guid-String - $flagSynonym = Split-CamelCase $flagName - - X "$indent" - X "$indent`t" - X "$indent`t`t$(Esc-Xml $flagName)" - Emit-MLText "$indent`t`t" "Synonym" $flagSynonym - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`t`txs:boolean" - X "$indent`t`t" - X "$indent`t`tfalse" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tfalse" - X "$indent`t`t" - X "$indent`t`tfalse" - X "$indent`t`tfalse" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tDontCheck" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tAuto" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tAuto" - X "$indent`t" - X "$indent" -} - -function Emit-ExtDimensionAccountingFlag { - param([string]$indent, [string]$flagName) - $uuid = New-Guid-String - $flagSynonym = Split-CamelCase $flagName - - X "$indent" - X "$indent`t" - X "$indent`t`t$(Esc-Xml $flagName)" - Emit-MLText "$indent`t`t" "Synonym" $flagSynonym - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`t`txs:boolean" - X "$indent`t`t" - X "$indent`t`tfalse" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tfalse" - X "$indent`t`t" - X "$indent`t`tfalse" - X "$indent`t`tfalse" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tDontCheck" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tAuto" - X "$indent`t`t" - X "$indent`t`t" - X "$indent`t`tAuto" - X "$indent`t" - X "$indent" -} - function Emit-URLTemplate { param([string]$indent, [string]$tmplName, $tmplDef) $uuid = New-Guid-String @@ -3526,12 +3502,13 @@ if ($objType -in $typesWithAttrTS) { } } - # ChartOfAccounts: AccountingFlags + ExtDimensionAccountingFlags + # ChartOfAccounts: AccountingFlags + ExtDimensionAccountingFlags (признаки учёта — структурно как реквизит, + # но без Indexing/FullTextSearch/Use; тип по умолчанию Boolean). Парсим как реквизиты. $acctFlags = @() $extDimFlags = @() if ($objType -eq "ChartOfAccounts") { - if ($def.accountingFlags) { $acctFlags = @($def.accountingFlags) } - if ($def.extDimensionAccountingFlags) { $extDimFlags = @($def.extDimensionAccountingFlags) } + if ($def.accountingFlags) { foreach ($af in $def.accountingFlags) { $acctFlags += Parse-AttributeShorthand $af } } + if ($def.extDimensionAccountingFlags) { foreach ($edf in $def.extDimensionAccountingFlags) { $extDimFlags += Parse-AttributeShorthand $edf } } } # Task: AddressingAttributes @@ -3558,7 +3535,8 @@ if ($objType -in $typesWithAttrTS) { "Document" { "document" } { $_ -in @("DataProcessor","Report") } { "processor" } "ChartOfCharacteristicTypes" { "catalog" } # реквизиты ПВХ структурно как у справочника (Use/FillFromFillingValue/DataHistory) - { $_ -in @("ChartOfAccounts","ChartOfCalculationTypes") } { "chart" } + "ChartOfAccounts" { "account" } # как catalog, но БЕЗ (реквизиты ПС не иерархичны как справочник) + "ChartOfCalculationTypes" { "chart" } default { "object" } } foreach ($a in $attrs) { @@ -3569,12 +3547,10 @@ if ($objType -in $typesWithAttrTS) { Emit-TabularSection "`t`t`t" $tsName $tsE.columns $objType $objName $tsE.synonym $tsE.tooltip $tsE.comment $tsE.lineNumber } foreach ($af in $acctFlags) { - $afName = if ($af.name) { $af.name } else { "$af" } - Emit-AccountingFlag "`t`t`t" $afName + Emit-Attribute "`t`t`t" $af "account-flag" "AccountingFlag" } foreach ($edf in $extDimFlags) { - $edfName = if ($edf.name) { $edf.name } else { "$edf" } - Emit-ExtDimensionAccountingFlag "`t`t`t" $edfName + Emit-Attribute "`t`t`t" $edf "account-flag" "ExtDimensionAccountingFlag" } foreach ($aa in $addrAttrs) { Emit-AddressingAttribute "`t`t`t" $aa @@ -3827,6 +3803,82 @@ function Build-PredefinedXml { return $sb.ToString() } +# --- Предопределённые СЧЕТА Плана счетов (отдельная грамматика: AccountType/OffBalance/Order/AccountingFlags/ +# ExtDimensionTypes/ChildItems). Флаги перечисляем по def-порядку списков признаков плана; в DSL — только TRUE. --- +$script:predefAccGet = { param($o, [string[]]$keys) foreach ($k in $keys) { if ($o -is [System.Collections.IDictionary]) { if ($o.Contains($k)) { return $o[$k] } } elseif ($o.PSObject -and $o.PSObject.Properties[$k]) { return $o.$k } } return $null } +function Emit-PredefAccountFlags { + param($sb, [string]$indent, [string]$tag, [string]$refKind, [string]$objName, [string[]]$flagNames, $trueSet) + if (-not $flagNames -or $flagNames.Count -eq 0) { [void]$sb.Append("$indent<$tag/>`n"); return } + $set = @{}; if ($trueSet) { foreach ($t in @($trueSet)) { $set["$t"] = $true } } + [void]$sb.Append("$indent<$tag>`n") + foreach ($fn in $flagNames) { + $v = if ($set.ContainsKey($fn)) { 'true' } else { 'false' } + [void]$sb.Append("$indent`t$v`n") + } + [void]$sb.Append("$indent`n") +} +function Emit-PredefAccount { + param($sb, $val, [string]$indent, [string]$objName, [string[]]$acctFlagNames, [string[]]$extDimFlagNames) + $gv = $script:predefAccGet + $name = "$(& $gv $val @('name','имя'))" + $codeV = & $gv $val @('code','код'); $code = if ($null -ne $codeV) { "$codeV" } else { '' } + $hasDesc = ($val -is [System.Collections.IDictionary] -and ($val.Contains('description') -or $val.Contains('наименование'))) -or ($val.PSObject -and ($val.PSObject.Properties['description'] -or $val.PSObject.Properties['наименование'])) + $descV = & $gv $val @('description','наименование') + $desc = if ($hasDesc) { "$descV" } else { Split-CamelCase $name } + $acctType = "$(& $gv $val @('accountType','видСчета','вид'))"; if (-not $acctType) { $acctType = 'ActivePassive' } + $offV = & $gv $val @('offBalance','забалансовый'); $off = if ($offV -eq $true) { 'true' } else { 'false' } + $order = "$(& $gv $val @('order','порядок'))" + $flags = & $gv $val @('flags','признаки') + $subconto = & $gv $val @('subconto','extDimensionTypes','видыСубконто') + $children = & $gv $val @('childItems','подчиненные') + + [void]$sb.Append("$indent`n") + [void]$sb.Append("$indent`t$(Esc-XmlText $name)`n") + if (-not $code) { [void]$sb.Append("$indent`t`n") } else { [void]$sb.Append("$indent`t$(Esc-XmlText $code)`n") } + if ($desc -eq '') { [void]$sb.Append("$indent`t`n") } else { [void]$sb.Append("$indent`t$(Esc-XmlText $desc)`n") } + [void]$sb.Append("$indent`t$acctType`n") + [void]$sb.Append("$indent`t$off`n") + [void]$sb.Append("$indent`t$(Esc-XmlText $order)`n") + Emit-PredefAccountFlags $sb "$indent`t" 'AccountingFlags' 'AccountingFlag' $objName $acctFlagNames $flags + # ExtDimensionTypes — субконто: пусто → self-close; иначе список с Turnover + признаками. + $subArr = @(); if ($subconto) { $subArr = @($subconto) } + if ($subArr.Count -eq 0) { [void]$sb.Append("$indent`t`n") } + else { + [void]$sb.Append("$indent`t`n") + foreach ($sc in $subArr) { + $scType = "$(& $gv $sc @('type','тип'))" + if ($scType.Contains('.')) { + $scDot = $scType.IndexOf('.'); $scPfx = $scType.Substring(0, $scDot); $scSfx = $scType.Substring($scDot + 1) + if ($script:objectTypeSynonyms.ContainsKey($scPfx)) { $scPfx = $script:objectTypeSynonyms[$scPfx] } + $scType = "$scPfx.$scSfx" + } + $scTurnV = & $gv $sc @('turnover','оборотный'); $scTurn = if ($scTurnV -eq $true) { 'true' } else { 'false' } + $scFlags = & $gv $sc @('flags','признаки') + [void]$sb.Append("$indent`t`t`n") + [void]$sb.Append("$indent`t`t`t$scTurn`n") + Emit-PredefAccountFlags $sb "$indent`t`t`t" 'AccountingFlags' 'ExtDimensionAccountingFlag' $objName $extDimFlagNames $scFlags + [void]$sb.Append("$indent`t`t`n") + } + [void]$sb.Append("$indent`t`n") + } + $childArr = @(); if ($children) { $childArr = @($children) } + if ($childArr.Count -gt 0) { + [void]$sb.Append("$indent`t`n") + foreach ($c in $childArr) { Emit-PredefAccount $sb $c "$indent`t`t" $objName $acctFlagNames $extDimFlagNames } + [void]$sb.Append("$indent`t`n") + } + [void]$sb.Append("$indent`n") +} +function Build-PredefinedAccountXml { + param($items, [string]$objName, [string[]]$acctFlagNames, [string[]]$extDimFlagNames) + $sb = New-Object System.Text.StringBuilder + [void]$sb.Append("`n") + [void]$sb.Append("`n") + foreach ($it in $items) { Emit-PredefAccount $sb $it "`t" $objName $acctFlagNames $extDimFlagNames } + [void]$sb.Append("`n") + return $sb.ToString() +} + $extDir = Join-Path $objSubDir "Ext" if (-not (Test-Path $typeDir)) { @@ -3927,7 +3979,16 @@ if ($objType -eq "BusinessProcess") { # Предопределённые элементы (Ext/Predefined.xml). Root-элемент — по типу. Пусто/нет ключа → файл не создаём. $predefRootByType = @{ 'Catalog' = 'CatalogPredefinedItems'; 'ChartOfCharacteristicTypes' = 'PlanOfCharacteristicKindPredefinedItems' } -if ($predefRootByType.ContainsKey($objType) -and $def.predefined -and @($def.predefined).Count -gt 0) { +if ($objType -eq 'ChartOfAccounts' -and $def.predefined -and @($def.predefined).Count -gt 0) { + # Предопределённые СЧЕТА — отдельная грамматика (флаги разворачиваются по def-порядку признаков плана). + Ensure-ExtDir + $afNames = @(); if ($def.accountingFlags) { foreach ($af in $def.accountingFlags) { $afNames += (Parse-AttributeShorthand $af).name } } + $edfNames = @(); if ($def.extDimensionAccountingFlags) { foreach ($edf in $def.extDimensionAccountingFlags) { $edfNames += (Parse-AttributeShorthand $edf).name } } + $predefXml = Build-PredefinedAccountXml @($def.predefined) $objName $afNames $edfNames + $predefPath = Join-Path $extDir "Predefined.xml" + [System.IO.File]::WriteAllText($predefPath, $predefXml, $enc) + $modulesCreated += $predefPath +} elseif ($predefRootByType.ContainsKey($objType) -and $def.predefined -and @($def.predefined).Count -gt 0) { Ensure-ExtDir $catCodeType = if ($def.codeType) { "$($def.codeType)" } else { 'String' } $predefXml = Build-PredefinedXml @($def.predefined) $predefRootByType[$objType] $catCodeType diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 296dd1b3..884b1be9 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-compile v1.36 — Compile 1C metadata object from JSON +# meta-compile v1.37 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -374,7 +374,7 @@ valid_enum_values = { 'FillChecking': ['DontCheck', 'ShowError', 'ShowWarning'], 'Indexing': ['DontIndex', 'Index', 'IndexWithAdditionalOrder'], 'SubordinationUse': ['ToItems', 'ToFolders', 'ToFoldersAndItems'], - 'CodeSeries': ['WholeCatalog', 'WithinSubordination', 'WithinOwnerSubordination', 'WholeCharacteristicKind'], + 'CodeSeries': ['WholeCatalog', 'WithinSubordination', 'WithinOwnerSubordination', 'WholeCharacteristicKind', 'WholeChartOfAccounts'], 'ChoiceMode': ['BothWays', 'QuickChoice', 'FromForm'], 'CreateOnInput': ['Auto', 'Use', 'DontUse'], 'ChoiceHistoryOnInput': ['Auto', 'DontUse'], @@ -660,6 +660,8 @@ fill_empty_ref_words = ('emptyref', 'пустаяссылка') fill_enum_val_words = ('enumvalue', 'значениеперечисления') fill_bool_true = ('true', 'истина', 'да') fill_bool_false = ('false', 'ложь', 'нет') +# Значения платформенного перечисления ВидСчета (ent:AccountType) — FillValue реквизита Тип у Плана счетов. +ACCOUNT_TYPE_VALUES = ('Active', 'Passive', 'ActivePassive') # XxxRef (тип реквизита) → корень DTR-пути (для разворота короткой записи значения). fill_ref_kind_root = { 'catalogref': 'Catalog', 'documentref': 'Document', 'enumref': 'Enum', @@ -1035,7 +1037,7 @@ standard_attributes_by_type = { 'AccumulationRegister': ['Active', 'LineNumber', 'Recorder', 'Period'], 'AccountingRegister': ['Active', 'Period', 'Recorder', 'LineNumber', 'Account'], 'CalculationRegister': ['Active', 'Recorder', 'LineNumber', 'RegistrationPeriod', 'CalculationType', 'ReversingEntry'], - 'ChartOfAccounts': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'Parent', 'Order', 'Type', 'OffBalance'], + 'ChartOfAccounts': ['PredefinedDataName', 'Order', 'OffBalance', 'Type', 'Description', 'Code', 'Parent', 'Predefined', 'DeletionMark', 'Ref'], 'ChartOfCharacteristicTypes': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'Parent', 'ValueType'], 'ChartOfCalculationTypes': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'ActionPeriodIsBasic'], 'BusinessProcess': ['Ref', 'DeletionMark', 'Date', 'Number', 'Started', 'Completed', 'HeadTask'], @@ -1061,6 +1063,12 @@ std_attr_profile = { 'Description': {'FillChecking': 'ShowError'}, 'Parent': {'FillFromFillingValue': 'true'}, }, + # ChartOfAccounts: Наименование/Код → FillChecking=ShowError (3/3), Родитель → FFV=true (3/3). + 'ChartOfAccounts': { + 'Description': {'FillChecking': 'ShowError'}, + 'Code': {'FillChecking': 'ShowError'}, + 'Parent': {'FillFromFillingValue': 'true'}, + }, } # ov — dict переопределений (профиль + DSL): FillChecking, FillFromFillingValue, Synonym, @@ -1126,7 +1134,7 @@ def emit_standard_attribute(indent, attr_name, ov=None): # Единый эмиттер блока StandardAttributes — поведение правят ДАННЫЕ, не форк кода (см. коммент в .ps1). # std_attr_conditional_types: типы, где блок только при кастомизации (DSL-ключ standardAttributes). # Прочие типы → блок всегда (текущее поведение). Миграция типа = +строчка в оба справочника + снэпшоты. -std_attr_conditional_types = {'Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes'} +std_attr_conditional_types = {'Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts'} def emit_standard_attributes(indent, object_type): attrs = standard_attributes_by_type.get(object_type) if not attrs: @@ -1402,6 +1410,8 @@ def normalize_choice_value(value): ref = normalize_fill_ref(s) if ref: return ('xr:DesignTimeRef', ref) + if s in ACCOUNT_TYPE_VALUES: + return ('ent:AccountType', s) return ('xs:string', s) def convert_from_ch_param_shorthand(s): @@ -1597,7 +1607,10 @@ def emit_min_max_value(indent, tag, val): t = 'xs:string' if isinstance(val, str) else 'xs:decimal' X(f'{indent}<{tag} xsi:type="{t}">{esc_xml(str(val))}') -def emit_attribute(indent, parsed, context): +def emit_attribute(indent, parsed, context, elem_tag='Attribute'): + # context: "catalog", "document", "object", "processor", "tabular", "processor-tabular", "register", + # "account" (реквизит Плана счетов: как catalog, но без ), "account-flag" (признак учёта ПС: + # как account, но без /, тип по умолчанию Boolean; elem_tag = AccountingFlag/ExtDimensionAccountingFlag) attr_name = parsed['name'] ctx_reserved = RESERVED_BY_CONTEXT.get(context) if ctx_reserved is not None: @@ -1607,7 +1620,7 @@ def emit_attribute(indent, parsed, context): elif context not in ('tabular', 'processor-tabular') and (attr_name in RESERVED_ATTR_NAMES or attr_name in RESERVED_ATTR_NAMES_RU): print(f"WARNING: Attribute '{attr_name}' conflicts with a standard attribute name. This may cause errors when loading into 1C.", file=sys.stderr) uid = new_uuid() - X(f'{indent}') + X(f'{indent}<{elem_tag} uuid="{uid}">') X(f'{indent}\t') X(f'{indent}\t\t{esc_xml(parsed["name"])}') emit_mltext(f'{indent}\t\t', 'Synonym', parsed['synonym']) @@ -1618,6 +1631,10 @@ def emit_attribute(indent, parsed, context): type_str = parsed['type'] if type_str: emit_value_type(f'{indent}\t\t', type_str) + elif context == 'account-flag': + X(f'{indent}\t\t') + X(f'{indent}\t\t\txs:boolean') + X(f'{indent}\t\t') else: X(f'{indent}\t\t') X(f'{indent}\t\t\txs:string') @@ -1663,20 +1680,22 @@ def emit_attribute(indent, parsed, context): if context == 'catalog': X(f'{indent}\t\t{parsed.get("use") or "ForItem"}') if context not in ('processor', 'processor-tabular'): - indexing = 'DontIndex' - if 'index' in parsed.get('flags', []): - indexing = 'Index' - if 'indexadditional' in parsed.get('flags', []): - indexing = 'IndexWithAdditionalOrder' - if parsed.get('indexing'): - indexing = parsed['indexing'] - X(f'{indent}\t\t{indexing}') - X(f'{indent}\t\t{parsed.get("fullTextSearch") or "Use"}') + # Признаки учёта ПС (account-flag) не имеют /, но имеют . + if context != 'account-flag': + indexing = 'DontIndex' + if 'index' in parsed.get('flags', []): + indexing = 'Index' + if 'indexadditional' in parsed.get('flags', []): + indexing = 'IndexWithAdditionalOrder' + if parsed.get('indexing'): + indexing = parsed['indexing'] + X(f'{indent}\t\t{indexing}') + X(f'{indent}\t\t{parsed.get("fullTextSearch") or "Use"}') # DataHistory — not for Chart* types and non-InformationRegister register family if context not in ('chart', 'register-other'): X(f'{indent}\t\t{parsed.get("dataHistory") or "Use"}') X(f'{indent}\t') - X(f'{indent}') + X(f'{indent}') # --------------------------------------------------------------------------- # 9. TabularSection emitter @@ -2615,77 +2634,104 @@ def emit_chart_of_accounts_properties(indent): i = indent X(f'{i}{esc_xml(obj_name)}') emit_mltext(i, 'Synonym', synonym) - X(f'{i}') - X(f'{i}true') - ext_dim_types = str(defn['extDimensionTypes']) if defn.get('extDimensionTypes') else '' + if defn.get('comment'): + X(f'{i}{esc_xml_text(str(defn["comment"]))}') + else: + X(f'{i}') + X(f'{i}{"true" if get_bool_prop("useStandardCommands", True) else "false"}') + X(f'{i}{"true" if get_bool_prop("includeHelpInContents", False) else "false"}') + emit_based_on(i, defn.get('basedOn')) + # ExtDimensionTypes — ссылка на ПВХ видов субконто (прощающий ввод: ПланВидовХарактеристик.X → ChartOfCharacteristicTypes.X). + ext_dim_types = '' + if defn.get('extDimensionTypes'): + ext_dim_types = str(defn['extDimensionTypes']) + if '.' in ext_dim_types: + edt_pfx, edt_sfx = ext_dim_types.split('.', 1) + if edt_pfx in object_type_synonyms: + edt_pfx = object_type_synonyms[edt_pfx] + ext_dim_types = f'{edt_pfx}.{edt_sfx}' if ext_dim_types: - X(f'{i}{ext_dim_types}') + X(f'{i}{esc_xml(ext_dim_types)}') else: X(f'{i}') max_ext_dim = str(defn['maxExtDimensionCount']) if defn.get('maxExtDimensionCount') is not None else '3' X(f'{i}{max_ext_dim}') - code_mask = str(defn['codeMask']) if defn.get('codeMask') else '' - if code_mask: - X(f'{i}{code_mask}') + if defn.get('codeMask'): + X(f'{i}{esc_xml_text(str(defn["codeMask"]))}') else: X(f'{i}') - code_length = str(defn['codeLength']) if defn.get('codeLength') is not None else '8' - description_length = str(defn['descriptionLength']) if defn.get('descriptionLength') is not None else '120' - code_series = str(defn['codeSeries']) if defn.get('codeSeries') else 'WholeChartOfAccounts' - auto_order = 'false' if defn.get('autoOrderByCode') is False else 'true' - order_length = str(defn['orderLength']) if defn.get('orderLength') is not None else '5' + code_length = str(defn['codeLength']) if defn.get('codeLength') is not None else '9' + description_length = str(defn['descriptionLength']) if defn.get('descriptionLength') is not None else '25' X(f'{i}{code_length}') X(f'{i}{description_length}') - X(f'{i}{code_series}') - X(f'{i}false') - X(f'{i}AsDescription') - X(f'{i}{auto_order}') - X(f'{i}{order_length}') - X(f'{i}InDialog') + X(f'{i}{get_enum_prop("CodeSeries", "codeSeries", "WholeChartOfAccounts")}') + X(f'{i}{"false" if defn.get("checkUnique") is False else "true"}') + X(f'{i}{get_enum_prop("DefaultPresentation", "defaultPresentation", "AsCode")}') emit_standard_attributes(i, 'ChartOfAccounts') + emit_characteristics(i, defn.get('characteristics')) + # StandardTabularSections — ExtDimensionTypes (обёртка платформенно-константна: Synonym с пустым lang «Виды субконто», + # Comment/ToolTip/FillChecking; 4 вложенных стандартных реквизита, ExtDimensionType → FillChecking=ShowError). X(f'{i}') X(f'{i}\t') + X(f'{i}\t\t') + X(f'{i}\t\t\t') + X(f'{i}\t\t\t\t') + X(f'{i}\t\t\t\tВиды субконто') + X(f'{i}\t\t\t') + X(f'{i}\t\t') + X(f'{i}\t\t') + X(f'{i}\t\t') + X(f'{i}\t\tDontCheck') X(f'{i}\t\t') for st_attr in ['TurnoversOnly', 'Predefined', 'ExtDimensionType', 'LineNumber']: - emit_standard_attribute(f'{i}\t\t\t', st_attr) + st_ov = {'FillChecking': 'ShowError'} if st_attr == 'ExtDimensionType' else None + emit_standard_attribute(f'{i}\t\t\t', st_attr, st_ov) X(f'{i}\t\t') X(f'{i}\t') X(f'{i}') - X(f'{i}') - X(f'{i}Auto') - quick_choice = 'true' if defn.get('quickChoice') is True else 'false' - X(f'{i}{quick_choice}') - X(f'{i}BothWays') - X(f'{i}') - X(f'{i}\tChartOfAccounts.{obj_name}.StandardAttribute.Description') - X(f'{i}\tChartOfAccounts.{obj_name}.StandardAttribute.Code') - X(f'{i}') - X(f'{i}Begin') + X(f'{i}{get_enum_prop("PredefinedDataUpdate", "predefinedDataUpdate", "Auto")}') + X(f'{i}{get_enum_prop("EditType", "editType", "InDialog")}') + X(f'{i}{"true" if defn.get("quickChoice") is True else "false"}') + X(f'{i}{get_enum_prop("ChoiceMode", "choiceMode", "BothWays")}') + # InputByString: override ЛИБО дефолт [Descr при D>0]+[Code при C>0] (prefix ChartOfAccounts). + if 'inputByString' in defn: + ib_fields = [expand_data_path(str(x)) for x in (defn.get('inputByString') or [])] + else: + ib_fields = [] + if int(description_length) > 0: + ib_fields.append(f'ChartOfAccounts.{obj_name}.StandardAttribute.Description') + if int(code_length) > 0: + ib_fields.append(f'ChartOfAccounts.{obj_name}.StandardAttribute.Code') + emit_field_block(i, 'InputByString', ib_fields) + X(f'{i}{get_enum_prop("SearchStringModeOnInputByString", "searchStringModeOnInputByString", "Begin")}') X(f'{i}DontUse') X(f'{i}Directly') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}') - X(f'{i}false') - X(f'{i}') - X(f'{i}') - data_lock_control_mode = get_enum_prop('DataLockControlMode', 'dataLockControlMode', 'Automatic') - X(f'{i}{data_lock_control_mode}') - full_text_search = get_enum_prop('FullTextSearch', 'fullTextSearch', 'Use') - X(f'{i}{full_text_search}') + X(f'{i}{get_enum_prop("CreateOnInput", "createOnInput", "DontUse")}') + X(f'{i}{get_enum_prop("ChoiceHistoryOnInput", "choiceHistoryOnInput", "Auto")}') + emit_form_ref(i, 'DefaultObjectForm', defn.get('defaultObjectForm')) + emit_form_ref(i, 'DefaultListForm', defn.get('defaultListForm')) + emit_form_ref(i, 'DefaultChoiceForm', defn.get('defaultChoiceForm')) + emit_form_ref(i, 'AuxiliaryObjectForm', defn.get('auxiliaryObjectForm')) + emit_form_ref(i, 'AuxiliaryListForm', defn.get('auxiliaryListForm')) + emit_form_ref(i, 'AuxiliaryChoiceForm', defn.get('auxiliaryChoiceForm')) + auto_order = 'false' if defn.get('autoOrderByCode') is False else 'true' + X(f'{i}{auto_order}') + order_length = str(defn['orderLength']) if defn.get('orderLength') is not None else '9' + X(f'{i}{order_length}') + dl_fields = [expand_data_path(str(x)) for x in defn.get('dataLockFields', [])] if 'dataLockFields' in defn else [] + emit_field_block(i, 'DataLockFields', dl_fields) + X(f'{i}{get_enum_prop("DataLockControlMode", "dataLockControlMode", "Automatic")}') + X(f'{i}{get_enum_prop("FullTextSearch", "fullTextSearch", "Use")}') + X(f'{i}{get_enum_prop("DataHistory", "dataHistory", "DontUse")}') + upd_dh = 'true' if get_bool_prop('updateDataHistoryImmediatelyAfterWrite', False) else 'false' + X(f'{i}{upd_dh}') + exec_dh = 'true' if get_bool_prop('executeAfterWriteDataHistoryVersionProcessing', False) else 'false' + X(f'{i}{exec_dh}') emit_mltext(i, 'ObjectPresentation', defn.get('objectPresentation')) emit_mltext(i, 'ExtendedObjectPresentation', defn.get('extendedObjectPresentation')) emit_mltext(i, 'ListPresentation', defn.get('listPresentation')) emit_mltext(i, 'ExtendedListPresentation', defn.get('extendedListPresentation')) emit_mltext(i, 'Explanation', defn.get('explanation')) - X(f'{i}DontUse') - X(f'{i}Auto') - X(f'{i}DontUse') - X(f'{i}false') - X(f'{i}false') def emit_accounting_register_properties(indent): i = indent @@ -3006,68 +3052,6 @@ def emit_column(indent, col_def): X(f'{indent}\t') X(f'{indent}') -def emit_accounting_flag(indent, flag_name): - uid = new_uuid() - flag_synonym = split_camel_case(flag_name) - X(f'{indent}') - X(f'{indent}\t') - X(f'{indent}\t\t{esc_xml(flag_name)}') - emit_mltext(f'{indent}\t\t', 'Synonym', flag_synonym) - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\t\txs:boolean') - X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tDontCheck') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tAuto') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tAuto') - X(f'{indent}\t') - X(f'{indent}') - -def emit_ext_dimension_accounting_flag(indent, flag_name): - uid = new_uuid() - flag_synonym = split_camel_case(flag_name) - X(f'{indent}') - X(f'{indent}\t') - X(f'{indent}\t\t{esc_xml(flag_name)}') - emit_mltext(f'{indent}\t\t', 'Synonym', flag_synonym) - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\t\txs:boolean') - X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\t') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\tfalse') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tDontCheck') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tAuto') - X(f'{indent}\t\t') - X(f'{indent}\t\t') - X(f'{indent}\t\tAuto') - X(f'{indent}\t') - X(f'{indent}') - def emit_url_template(indent, tmpl_name, tmpl_def): uid = new_uuid() tmpl_synonym = split_camel_case(tmpl_name) @@ -3321,14 +3305,15 @@ if obj_type in types_with_attr_ts: for k, v in ts_data.items(): ts_sections[k] = new_ts_entry(v) ts_order.append(k) - # ChartOfAccounts: AccountingFlags + ExtDimensionAccountingFlags + # ChartOfAccounts: AccountingFlags + ExtDimensionAccountingFlags (признаки учёта — структурно как реквизит, + # но без Indexing/FullTextSearch/Use; тип по умолчанию Boolean). Парсим как реквизиты. acct_flags = [] ext_dim_flags = [] if obj_type == 'ChartOfAccounts': if defn.get('accountingFlags'): - acct_flags = _as_list(defn['accountingFlags']) + acct_flags = [parse_attribute_shorthand(af) for af in _as_list(defn['accountingFlags'])] if defn.get('extDimensionAccountingFlags'): - ext_dim_flags = _as_list(defn['extDimensionAccountingFlags']) + ext_dim_flags = [parse_attribute_shorthand(edf) for edf in _as_list(defn['extDimensionAccountingFlags'])] # Task: AddressingAttributes addr_attrs = [] if obj_type == 'Task' and defn.get('addressingAttributes'): @@ -3355,7 +3340,9 @@ if obj_type in types_with_attr_ts: context = 'processor' elif obj_type == 'ChartOfCharacteristicTypes': context = 'catalog' # реквизиты ПВХ структурно как у справочника (Use/FillFromFillingValue/DataHistory) - elif obj_type in ('ChartOfAccounts', 'ChartOfCalculationTypes'): + elif obj_type == 'ChartOfAccounts': + context = 'account' # как catalog, но БЕЗ (реквизиты ПС не иерархичны как справочник) + elif obj_type == 'ChartOfCalculationTypes': context = 'chart' else: context = 'object' @@ -3365,11 +3352,9 @@ if obj_type in types_with_attr_ts: e = ts_sections[ts_name] emit_tabular_section('\t\t\t', ts_name, e['columns'], obj_type, obj_name, e['synonym'], e['tooltip'], e['comment'], e.get('lineNumber')) for af in acct_flags: - af_name = af['name'] if isinstance(af, dict) else str(af) - emit_accounting_flag('\t\t\t', af_name) + emit_attribute('\t\t\t', af, 'account-flag', 'AccountingFlag') for edf in ext_dim_flags: - edf_name = edf['name'] if isinstance(edf, dict) else str(edf) - emit_ext_dimension_accounting_flag('\t\t\t', edf_name) + emit_attribute('\t\t\t', edf, 'account-flag', 'ExtDimensionAccountingFlag') for aa in addr_attrs: emit_addressing_attribute('\t\t\t', aa) for cmd in commands: @@ -3663,6 +3648,83 @@ def build_predefined_xml(items, xsi_type, code_type): out.append('') return '\n'.join(out) + '\n' +# --- Предопределённые СЧЕТА Плана счетов (отдельная грамматика: AccountType/OffBalance/Order/AccountingFlags/ +# ExtDimensionTypes/ChildItems). Флаги перечисляем по def-порядку признаков плана; в DSL — только TRUE. --- +def _predef_acc_get(o, keys): + for k in keys: + if isinstance(o, dict): + if k in o: + return o[k] + return None + +def emit_predef_account_flags(out, indent, tag, ref_kind, obj_nm, flag_names, true_set): + if not flag_names: + out.append(f'{indent}<{tag}/>') + return + tset = set(str(t) for t in (true_set or [])) + out.append(f'{indent}<{tag}>') + for fn in flag_names: + v = 'true' if fn in tset else 'false' + out.append(f'{indent}\t{v}') + out.append(f'{indent}') + +def emit_predef_account(out, val, indent, obj_nm, acct_flag_names, ext_dim_flag_names): + name = str(_predef_acc_get(val, ('name', 'имя')) or '') + code_v = _predef_acc_get(val, ('code', 'код')) + code = str(code_v) if code_v is not None else '' + has_desc = isinstance(val, dict) and ('description' in val or 'наименование' in val) + desc_v = _predef_acc_get(val, ('description', 'наименование')) + desc = str(desc_v) if has_desc else split_camel_case(name) + acct_type = str(_predef_acc_get(val, ('accountType', 'видСчета', 'вид')) or '') or 'ActivePassive' + off = 'true' if _predef_acc_get(val, ('offBalance', 'забалансовый')) is True else 'false' + order = str(_predef_acc_get(val, ('order', 'порядок')) or '') + flags = _predef_acc_get(val, ('flags', 'признаки')) + subconto = _predef_acc_get(val, ('subconto', 'extDimensionTypes', 'видыСубконто')) + children = _predef_acc_get(val, ('childItems', 'подчиненные')) + + out.append(f'{indent}') + out.append(f'{indent}\t{esc_xml_text(name)}') + out.append(f'{indent}\t' if not code else f'{indent}\t{esc_xml_text(code)}') + out.append(f'{indent}\t' if desc == '' else f'{indent}\t{esc_xml_text(desc)}') + out.append(f'{indent}\t{acct_type}') + out.append(f'{indent}\t{off}') + out.append(f'{indent}\t{esc_xml_text(order)}') + emit_predef_account_flags(out, f'{indent}\t', 'AccountingFlags', 'AccountingFlag', obj_nm, acct_flag_names, flags) + sub_arr = list(subconto) if subconto else [] + if not sub_arr: + out.append(f'{indent}\t') + else: + out.append(f'{indent}\t') + for sc in sub_arr: + sc_type = str(_predef_acc_get(sc, ('type', 'тип')) or '') + if '.' in sc_type: + sc_pfx, sc_sfx = sc_type.split('.', 1) + if sc_pfx in object_type_synonyms: + sc_pfx = object_type_synonyms[sc_pfx] + sc_type = f'{sc_pfx}.{sc_sfx}' + sc_turn = 'true' if _predef_acc_get(sc, ('turnover', 'оборотный')) is True else 'false' + sc_flags = _predef_acc_get(sc, ('flags', 'признаки')) + out.append(f'{indent}\t\t') + out.append(f'{indent}\t\t\t{sc_turn}') + emit_predef_account_flags(out, f'{indent}\t\t\t', 'AccountingFlags', 'ExtDimensionAccountingFlag', obj_nm, ext_dim_flag_names, sc_flags) + out.append(f'{indent}\t\t') + out.append(f'{indent}\t') + child_arr = list(children) if children else [] + if child_arr: + out.append(f'{indent}\t') + for c in child_arr: + emit_predef_account(out, c, f'{indent}\t\t', obj_nm, acct_flag_names, ext_dim_flag_names) + out.append(f'{indent}\t') + out.append(f'{indent}') + +def build_predefined_account_xml(items, obj_nm, acct_flag_names, ext_dim_flag_names): + out = [''] + out.append(f'') + for it in items: + emit_predef_account(out, it, '\t', obj_nm, acct_flag_names, ext_dim_flag_names) + out.append('') + return '\n'.join(out) + '\n' + # Special files if obj_type == 'ExchangePlan': content_path = os.path.join(ext_dir, 'Content.xml') @@ -3682,7 +3744,16 @@ if obj_type == 'BusinessProcess': # Предопределённые элементы (Ext/Predefined.xml). Root-элемент по типу. predef_root_by_type = {'Catalog': 'CatalogPredefinedItems', 'ChartOfCharacteristicTypes': 'PlanOfCharacteristicKindPredefinedItems'} -if obj_type in predef_root_by_type and defn.get('predefined'): +if obj_type == 'ChartOfAccounts' and defn.get('predefined'): + # Предопределённые СЧЕТА — отдельная грамматика (флаги разворачиваются по def-порядку признаков плана). + ensure_ext_dir() + af_names = [parse_attribute_shorthand(af)['name'] for af in _as_list(defn['accountingFlags'])] if defn.get('accountingFlags') else [] + edf_names = [parse_attribute_shorthand(edf)['name'] for edf in _as_list(defn['extDimensionAccountingFlags'])] if defn.get('extDimensionAccountingFlags') else [] + predef_xml = build_predefined_account_xml(defn['predefined'], obj_name, af_names, edf_names) + predef_path = os.path.join(ext_dir, 'Predefined.xml') + write_utf8_bom(predef_path, predef_xml) + modules_created.append(predef_path) +elif obj_type in predef_root_by_type and defn.get('predefined'): ensure_ext_dir() cat_code_type = str(defn['codeType']) if defn.get('codeType') else 'String' predef_xml = build_predefined_xml(defn['predefined'], predef_root_by_type[obj_type], cat_code_type) diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index a7b245e4..a91e205b 100644 --- a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 +++ b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 @@ -1,7 +1,7 @@ -# meta-decompile v0.25 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.26 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # -# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes. Инверс meta-compile (omit-on-default: ключ эмитим только +# Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts. Инверс meta-compile (omit-on-default: ключ эмитим только # когда значение в XML отличается от умолчания компилятора). Неподдерживаемый тип / не-MetaDataObject # root → exit 3 (ring3, как form-decompile). param( @@ -91,8 +91,8 @@ foreach ($c in $rootEl.ChildNodes) { if ($c.NodeType -eq 'Element') { $objNode = if (-not $objNode) { [Console]::Error.WriteLine("meta-decompile: пустой MetaDataObject"); exit 3 } $objType = $objNode.LocalName -if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes')) { - [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan, ChartOfCharacteristicTypes)"); exit 3 +if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts')) { + [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts)"); exit 3 } $props = $objNode.SelectSingleNode('md:Properties', $nsm) @@ -394,9 +394,10 @@ Add-EnumProp 'subordinationUse' 'SubordinationUse' 'ToItems' # Тип-зависимые дефолты (компилятор задаёт их по типу — декомпилятор обязан зеркалить, иначе omit ≠ значению). $descrLenDef = switch ($objType) { 'ExchangePlan' { 150 } 'ChartOfCharacteristicTypes' { 100 } default { 25 } } $createInpDef = if ($objType -eq 'Catalog') { 'Use' } else { 'DontUse' } -$dataLockDef = if ($objType -eq 'Catalog') { 'Automatic' } else { 'Managed' } -$codeSeriesDef = if ($objType -eq 'ChartOfCharacteristicTypes') { 'WholeCharacteristicKind' } else { 'WholeCatalog' } -$checkUniqueDef = ($objType -eq 'ChartOfCharacteristicTypes') # ПВХ дефолт true, Catalog false +$dataLockDef = if ($objType -in @('Catalog', 'ChartOfAccounts')) { 'Automatic' } else { 'Managed' } +$codeSeriesDef = switch ($objType) { 'ChartOfCharacteristicTypes' { 'WholeCharacteristicKind' } 'ChartOfAccounts' { 'WholeChartOfAccounts' } default { 'WholeCatalog' } } +$checkUniqueDef = ($objType -in @('ChartOfCharacteristicTypes', 'ChartOfAccounts')) # ПВХ/ПС дефолт true, Catalog false +$defPresDef = if ($objType -eq 'ChartOfAccounts') { 'AsCode' } else { 'AsDescription' } # ПС по умолчанию AsCode Add-IntProp 'codeLength' 'CodeLength' 9 Add-IntProp 'descriptionLength' 'DescriptionLength' $descrLenDef Add-EnumProp 'codeType' 'CodeType' 'String' @@ -404,7 +405,7 @@ Add-EnumProp 'codeAllowedLength' 'CodeAllowedLength' 'Variable' Add-BoolProp 'autonumbering' 'Autonumbering' $true Add-BoolProp 'checkUnique' 'CheckUnique' $checkUniqueDef Add-EnumProp 'codeSeries' 'CodeSeries' $codeSeriesDef -Add-EnumProp 'defaultPresentation' 'DefaultPresentation' 'AsDescription' +Add-EnumProp 'defaultPresentation' 'DefaultPresentation' $defPresDef Add-BoolProp 'quickChoice' 'QuickChoice' $false Add-EnumProp 'choiceMode' 'ChoiceMode' 'BothWays' Add-EnumProp 'dataLockControlMode' 'DataLockControlMode' $dataLockDef @@ -437,6 +438,17 @@ if ($objType -eq 'ChartOfCharacteristicTypes') { if ($vtStr -and $vtStr -ne 'Boolean + String(100) + Number(15,2) + DateTime') { $dsl['valueType'] = $vtStr } } } +# ChartOfAccounts-специфичные свойства (у Catalog этих тегов нет → блок его не трогает). +if ($objType -eq 'ChartOfAccounts') { + $edt = P 'ExtDimensionTypes'; if ($edt) { $dsl['extDimensionTypes'] = $edt } + Add-IntProp 'maxExtDimensionCount' 'MaxExtDimensionCount' 3 + $cm = P 'CodeMask'; if ($cm) { $dsl['codeMask'] = $cm } + Add-BoolProp 'autoOrderByCode' 'AutoOrderByCode' $true + Add-IntProp 'orderLength' 'OrderLength' 9 + Add-EnumProp 'dataHistory' 'DataHistory' 'DontUse' + Add-BoolProp 'updateDataHistoryImmediatelyAfterWrite' 'UpdateDataHistoryImmediatelyAfterWrite' $false + Add-BoolProp 'executeAfterWriteDataHistoryVersionProcessing' 'ExecuteAfterWriteDataHistoryVersionProcessing' $false +} # Короткая форма поля: ..StandardAttribute.X / .Attribute.X → StandardAttribute.X / Attribute.X # (Expand-DataPath компилятора разворачивает частичную форму обратно — dogfood резолвера). @@ -557,6 +569,11 @@ $stdProfileByType = @{ 'Description' = @{ fillChecking = 'ShowError' } 'Parent' = @{ fillFromFillingValue = $true } } + 'ChartOfAccounts' = @{ + 'Description' = @{ fillChecking = 'ShowError' } + 'Code' = @{ fillChecking = 'ShowError' } + 'Parent' = @{ fillFromFillingValue = $true } + } } $catStdProfile = if ($stdProfileByType.ContainsKey($objType)) { $stdProfileByType[$objType] } else { @{} } # Фикс-список стандартных реквизитов типа (зеркало standardAttributesByType компилятора) — чтобы отличать @@ -565,11 +582,12 @@ $stdFixedByType = @{ 'Catalog' = @('PredefinedDataName','Predefined','Ref','DeletionMark','IsFolder','Owner','Parent','Description','Code') 'ExchangePlan' = @('Ref','DeletionMark','Code','Description','ThisNode','SentNo','ReceivedNo') 'ChartOfCharacteristicTypes' = @('PredefinedDataName','Predefined','Ref','DeletionMark','Description','Code','Parent','ValueType') + 'ChartOfAccounts' = @('PredefinedDataName','Order','OffBalance','Type','Description','Code','Parent','Predefined','DeletionMark','Ref') } $stdFixed = if ($stdFixedByType.ContainsKey($objType)) { $stdFixedByType[$objType] } else { @() } # Условные типы: блок эмитим-как-триггер даже пустым (материализуется при отклонении ≥1 реквизита от schema-default; # у ExchangePlan это почти всегда — Description/Code=ShowError; редкий all-default EP блок опускает). -$stdConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes') +$stdConditionalTypes = @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts') $saNode = $props.SelectSingleNode('md:StandardAttributes', $nsm) if ($saNode) { $saMap = [ordered]@{} @@ -617,6 +635,20 @@ if ($childObjs) { foreach ($a in $attrs) { [void]$arr.Add((Attr-ToDsl $a)) } $dsl['attributes'] = $arr } + # ChartOfAccounts: признаки учёта (AccountingFlag) и признаки учёта субконто (ExtDimensionAccountingFlag) — + # структурно как реквизит, захватываем тем же Attr-ToDsl (тип Boolean уходит в короткую запись). + $acctFlagNodes = @($childObjs.SelectNodes('md:AccountingFlag', $nsm)) + if ($acctFlagNodes.Count -gt 0) { + $arr = [System.Collections.ArrayList]@() + foreach ($a in $acctFlagNodes) { [void]$arr.Add((Attr-ToDsl $a)) } + $dsl['accountingFlags'] = $arr + } + $extDimFlagNodes = @($childObjs.SelectNodes('md:ExtDimensionAccountingFlag', $nsm)) + if ($extDimFlagNodes.Count -gt 0) { + $arr = [System.Collections.ArrayList]@() + foreach ($a in $extDimFlagNodes) { [void]$arr.Add((Attr-ToDsl $a)) } + $dsl['extDimensionAccountingFlags'] = $arr + } $tsNodes = @($childObjs.SelectNodes('md:TabularSection', $nsm)) if ($tsNodes.Count -gt 0) { $tsMap = [ordered]@{} @@ -755,8 +787,65 @@ if (Test-Path -LiteralPath $predefPath) { } return $o } + # Предопределённые СЧЕТА Плана счетов — отдельная грамматика (AccountType/OffBalance/Order/AccountingFlags/ + # ExtDimensionTypes). Флаги: захватываем только TRUE (компилятор развернёт по def-порядку признаков плана). + function PredefAccount-ToDsl { + param($itemEl) + $name = ($itemEl.SelectSingleNode("*[local-name()='Name']")).InnerText + $codeEl = $itemEl.SelectSingleNode("*[local-name()='Code']") + $code = if ($codeEl -and $codeEl.InnerText) { $codeEl.InnerText } else { '' } + $descEl = $itemEl.SelectSingleNode("*[local-name()='Description']") + $desc = if ($descEl) { $descEl.InnerText } else { '' } + $atEl = $itemEl.SelectSingleNode("*[local-name()='AccountType']") + $acctType = if ($atEl) { $atEl.InnerText } else { 'ActivePassive' } + $offEl = $itemEl.SelectSingleNode("*[local-name()='OffBalance']") + $off = ($offEl -and $offEl.InnerText -eq 'true') + $ordEl = $itemEl.SelectSingleNode("*[local-name()='Order']") + $order = if ($ordEl) { $ordEl.InnerText } else { '' } + $auto = Split-CamelWords $name + # TRUE-флаги (leaf после последней точки в ref). + $trueFlags = @() + foreach ($fl in @($itemEl.SelectNodes("*[local-name()='AccountingFlags']/*[local-name()='Flag']"))) { + if ($fl.InnerText -eq 'true') { $r = $fl.GetAttribute('ref'); $trueFlags += ($r -split '\.')[-1] } + } + # ExtDimensionTypes → subconto [{type, turnover?, flags?}]. + $subconto = [System.Collections.ArrayList]@() + foreach ($edt in @($itemEl.SelectNodes("*[local-name()='ExtDimensionTypes']/*[local-name()='ExtDimensionType']"))) { + $so = [ordered]@{ type = $edt.GetAttribute('name') } + $tEl = $edt.SelectSingleNode("*[local-name()='Turnover']") + if ($tEl -and $tEl.InnerText -eq 'true') { $so['turnover'] = $true } + $stf = @() + foreach ($fl in @($edt.SelectNodes("*[local-name()='AccountingFlags']/*[local-name()='Flag']"))) { + if ($fl.InnerText -eq 'true') { $r = $fl.GetAttribute('ref'); $stf += ($r -split '\.')[-1] } + } + if ($stf.Count -gt 0) { $so['flags'] = [System.Collections.ArrayList]@($stf) } + [void]$subconto.Add($so) + } + $childContainer = $itemEl.SelectSingleNode("*[local-name()='ChildItems']") + $kids = @(if ($childContainer) { $childContainer.SelectNodes("*[local-name()='Item']") } else { @() }) + + $o = [ordered]@{ name = $name } + if ($code) { $o['code'] = $code } + if ($desc -ne $auto) { $o['description'] = $desc } + $o['accountType'] = $acctType + if ($off) { $o['offBalance'] = $true } + $o['order'] = $order + if ($trueFlags.Count -gt 0) { $o['flags'] = [System.Collections.ArrayList]@($trueFlags) } + if ($subconto.Count -gt 0) { $o['subconto'] = $subconto } + if ($kids.Count -gt 0) { + $sub = [System.Collections.ArrayList]@() + foreach ($k in $kids) { [void]$sub.Add((PredefAccount-ToDsl $k)) } + $o['childItems'] = $sub + } + return $o + } + $rootItems = [System.Collections.ArrayList]@() - foreach ($it in @($pdoc.DocumentElement.SelectNodes("*[local-name()='Item']"))) { [void]$rootItems.Add((PredefItem-ToDsl $it)) } + if ($objType -eq 'ChartOfAccounts') { + foreach ($it in @($pdoc.DocumentElement.SelectNodes("*[local-name()='Item']"))) { [void]$rootItems.Add((PredefAccount-ToDsl $it)) } + } else { + foreach ($it in @($pdoc.DocumentElement.SelectNodes("*[local-name()='Item']"))) { [void]$rootItems.Add((PredefItem-ToDsl $it)) } + } if ($rootItems.Count -gt 0) { $dsl['predefined'] = $rootItems } } diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index a5aab975..bbf74879 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -653,6 +653,62 @@ omit-on-empty. Поля пишутся частичной формой (`Standar ] ``` +### 7.2c ChartOfAccounts (План счетов) + +Иерархический ссылочный тип бухгалтерских счетов (без папок/уровней/владельцев). Общий с Catalog слой: `synonym`, +`comment`, `useStandardCommands`, `includeHelpInContents`, коды (`codeLength`/`descriptionLength`/`checkUnique`/ +`codeMask`), `defaultPresentation`, `standardAttributes` (§7.1.1), `characteristics` (§7.1.4), `inputByString` (§7.1.5), +формы (без `*Folder*`), `basedOn`, `dataLockFields`, презентации. + +| Поле JSON | Умолчание | XML элемент | +|-----------|----------|-------------| +| `extDimensionTypes` | пусто | ExtDimensionTypes (ссылка на ПВХ видов субконто; `ПланВидовХарактеристик.X` → `ChartOfCharacteristicTypes.X`) | +| `maxExtDimensionCount` | `3` | MaxExtDimensionCount (число субконто; `0` → нет субконто) | +| `codeMask` | пусто | CodeMask (маска кода счёта) | +| `codeSeries` | `WholeChartOfAccounts` | CodeSeries | +| `checkUnique` | `true` | CheckUnique *(≠ Catalog `false`)* | +| `defaultPresentation` | `AsCode` | DefaultPresentation *(≠ Catalog `AsDescription`)* | +| `autoOrderByCode` | `true` | AutoOrderByCode | +| `orderLength` | `9` | OrderLength | +| `dataLockControlMode` | `Automatic` | DataLockControlMode | +| `dataHistory` + `updateDataHistoryImmediatelyAfterWrite` + `executeAfterWriteDataHistoryVersionProcessing` | `DontUse`/`false`/`false` | DataHistory-триплет | +| `accountingFlags` | `[]` | AccountingFlag в ChildObjects (признаки учёта — как реквизит, тип по умолчанию Boolean; §4.2) | +| `extDimensionAccountingFlags` | `[]` | ExtDimensionAccountingFlag в ChildObjects (признаки учёта субконто; как реквизит) | +| `predefined` | `[]` | Ext/Predefined.xml — предопределённые счета (грамматика ниже) | + +Стандартные реквизиты ПС: PredefinedDataName, Order, OffBalance, Type, Description, Code, Parent, Predefined, +DeletionMark, Ref (профиль: Наименование/Код → FillChecking=ShowError, Родитель → FillFromFillingValue=true). Блок +**условный** (`standardAttributes`). Реквизит `Type` (Тип счёта) несёт FillValue-перечисление **`ent:AccountType`** — +значения `Active`/`Passive`/`ActivePassive` (распознаются автоматически в `fillValue`/параметрах выбора). Всегда +эмитится вложенный блок субконто `StandardTabularSections/ExtDimensionTypes` (платформенно-константен: обёртка +«Виды субконто», вложенный ExtDimensionType → FillChecking=ShowError). + +**Предопределённые счета** — отдельная грамматика (объектная форма). Признаки (`flags`) перечисляют только +**включённые** (`true`) имена; компилятор разворачивает полный список по def-порядку `accountingFlags`/ +`extDimensionAccountingFlags` плана. `order` — вербатим (не выводится). `description` опускается при равенстве +Split-CamelCase имени. + +| Поле счёта | Умолчание | XML | +|-----------|----------|-----| +| `name` / `code` / `description` | — / пусто / *(авто из имени)* | Name / Code / Description | +| `accountType` | `ActivePassive` | AccountType (`Active`/`Passive`/`ActivePassive`) | +| `offBalance` | `false` | OffBalance | +| `order` | — | Order (строка сортировки, вербатим) | +| `flags` | `[]` | AccountingFlags → `` по каждому признаку плана | +| `subconto` | `[]` | ExtDimensionTypes → `` `{type, turnover?, flags?}` | +| `childItems` | `[]` | ChildItems (иерархия счетов) | + +```json +"predefined": [ + { "name": "ОсновныеСредства", "code": "01", "accountType": "Active", "order": " 01", + "flags": ["Количественный"], + "subconto": [{ "type": "ChartOfCharacteristicTypes.ВидыСубконто.ОсновныеСредства", "flags": ["Суммовой"] }], + "childItems": [ + { "name": "ОС в организации", "code": "01.01", "accountType": "Active", "order": " 01.01" } + ] } +] +``` + ### 7.3 Enum | Поле JSON | Умолчание | XML элемент | @@ -886,35 +942,7 @@ DSL для `columns` (§12). ### 7.16 ChartOfAccounts -| Поле JSON | Умолчание | XML элемент | -|-----------|----------|-------------| -| `extDimensionTypes` | `""` | ExtDimensionTypes (ссылка на ПВХ) | -| `maxExtDimensionCount` | `3` | MaxExtDimensionCount | -| `codeMask` | `""` | CodeMask | -| `codeLength` | `8` | CodeLength | -| `descriptionLength` | `120` | DescriptionLength | -| `codeSeries` | `WholeChartOfAccounts` | CodeSeries | -| `autoOrderByCode` | `true` | AutoOrderByCode | -| `orderLength` | `5` | OrderLength | -| `hierarchical` | `false` | Hierarchical | -| `dataLockControlMode` | `Automatic` | DataLockControlMode | -| `fullTextSearch` | `Use` | FullTextSearch | -| `accountingFlags` | `[]` | → AccountingFlag в ChildObjects (§13) | -| `extDimensionAccountingFlags` | `[]` | → ExtDimensionAccountingFlag в ChildObjects (§14) | -| `attributes` | `[]` | → Attribute в ChildObjects | -| `tabularSections` | `{}` | → TabularSection в ChildObjects | - -Модули: `Ext/ObjectModule.bsl` (пустой). - -```json -{ - "type": "ChartOfAccounts", "name": "Хозрасчетный", - "extDimensionTypes": "ChartOfCharacteristicTypes.ВидыСубконто", "maxExtDimensionCount": 3, - "codeMask": "@@@.@@.@", "codeLength": 8, - "accountingFlags": ["Валютный", "Количественный"], - "extDimensionAccountingFlags": ["Суммовой", "Валютный"] -} -``` +Полное описание типа (все поля, стандартные реквизиты, грамматика предопределённых счетов) — см. **§7.2c**. ### 7.17 AccountingRegister diff --git a/tests/skills/cases/meta-compile/chart-of-accounts.json b/tests/skills/cases/meta-compile/chart-of-accounts.json index 6d7d8dff..1fe8ab83 100644 --- a/tests/skills/cases/meta-compile/chart-of-accounts.json +++ b/tests/skills/cases/meta-compile/chart-of-accounts.json @@ -1,15 +1,42 @@ { - "name": "План счетов с признаками учёта", + "name": "План счетов: признаки учёта и предопределённые счета", "input": { "type": "ChartOfAccounts", "name": "Хозрасчетный", - "codeLength": 4, + "synonym": { "ru": "План счетов бухгалтерского учета", "en": "Chart of accounts" }, + "codeLength": 8, "descriptionLength": 120, + "codeMask": "@@@.@@.@", "maxExtDimensionCount": 0, - "accountingFlags": ["Валютный", "Количественный"] + "checkUnique": true, + "accountingFlags": [ + { "name": "Валютный", "synonym": "Валютный учет", "tooltip": "Ведется валютный учет" }, + "Количественный" + ], + "predefined": [ + { + "name": "ОсновныеСредства", + "code": "01", + "description": "Основные средства", + "accountType": "Active", + "order": " 01", + "flags": ["Количественный"], + "childItems": [ + { + "name": "ОсновныеСредстваВОрганизации", + "code": "01.01", + "description": "Основные средства в организации", + "accountType": "Active", + "order": " 01.01", + "flags": ["Количественный"] + } + ] + }, + { "name": "Служебный", "code": "000", "accountType": "ActivePassive", "order": " 00" } + ] }, "validatePath": "ChartsOfAccounts/Хозрасчетный", "expect": { - "files": ["ChartsOfAccounts/Хозрасчетный.xml", "ChartsOfAccounts/Хозрасчетный/Ext/ObjectModule.bsl"] + "files": ["ChartsOfAccounts/Хозрасчетный.xml", "ChartsOfAccounts/Хозрасчетный/Ext/Predefined.xml"] } } diff --git a/tests/skills/cases/meta-compile/snapshots/chart-of-accounts/ChartsOfAccounts/Хозрасчетный.xml b/tests/skills/cases/meta-compile/snapshots/chart-of-accounts/ChartsOfAccounts/Хозрасчетный.xml index 264225e9..aa71ef28 100644 --- a/tests/skills/cases/meta-compile/snapshots/chart-of-accounts/ChartsOfAccounts/Хозрасчетный.xml +++ b/tests/skills/cases/meta-compile/snapshots/chart-of-accounts/ChartsOfAccounts/Хозрасчетный.xml @@ -36,286 +36,37 @@ ru - Хозрасчетный + План счетов бухгалтерского учета + + + en + Chart of accounts true + false + 0 - - 4 + @@@.@@.@ + 8 120 WholeChartOfAccounts - false - AsDescription - true - 5 - InDialog - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - - - DontCheck - false - false - Auto - - - false - - - Auto - Auto - - false - Use - false - - - - Use - - - - - - + true + AsCode + + + + + Виды субконто + + + + + DontCheck @@ -371,7 +122,7 @@ - DontCheck + ShowError false false Auto @@ -424,8 +175,8 @@ - Auto + InDialog false BothWays @@ -435,27 +186,27 @@ Begin DontUse Directly + DontUse + Auto - false - + true + 9 Automatic Use + DontUse + false + false - DontUse - Auto - DontUse - false - false @@ -464,7 +215,7 @@ ru - Валютный + Валютный учет @@ -474,20 +225,30 @@ false - + + + ru + Ведется валютный учет + + false false false + false + DontCheck + Items Auto + Auto Auto + Use @@ -513,13 +274,18 @@ false + false + DontCheck + Items Auto + Auto Auto + Use diff --git a/tests/skills/cases/meta-compile/snapshots/chart-of-accounts/ChartsOfAccounts/Хозрасчетный/Ext/Predefined.xml b/tests/skills/cases/meta-compile/snapshots/chart-of-accounts/ChartsOfAccounts/Хозрасчетный/Ext/Predefined.xml new file mode 100644 index 00000000..b4291c7c --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/chart-of-accounts/ChartsOfAccounts/Хозрасчетный/Ext/Predefined.xml @@ -0,0 +1,44 @@ + + + + ОсновныеСредства + 01 + Основные средства + Active + false + 01 + + false + true + + + + + ОсновныеСредстваВОрганизации + 01.01 + Основные средства в организации + Active + false + 01.01 + + false + true + + + + + + + Служебный + 000 + Служебный + ActivePassive + false + 00 + + false + false + + + +