fix(meta-compile,meta-validate): fix 7 e2e bugs, add hints and reserved name checks

Group 1: ExchangePlan — remove invalid CodeType/CheckUnique/Autonumbering;
Flowchart.xml — add version="2.17"; Content.xml — fix namespace + version.

Group 2: Add missing GeneratedType categories — DefinedType, ChartOfAccounts
ExtDimensionTypes/Row, CalculationRegister RecalculationsManager/Recalcs.

Group 3: BusinessProcess — emit <Task> property from DSL.

Group 4: Cross-reference [HINT] output after compilation for AccountingRegister,
CalculationRegister, BusinessProcess, ChartOfAccounts (oriented to /meta-edit DSL).

Group 5: Reserved attribute name warnings in meta-compile and meta-validate
(Check 7b); cross-reference validation in Check 10 with [HINT] output.

All changes synced to both PS1 and PY versions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-03-07 21:33:56 +03:00
parent 24751a59de
commit 6051972391
5 changed files with 274 additions and 22 deletions
@@ -436,13 +436,16 @@ $script:generatedTypes = @{
@{ prefix = "CalculationRegisterList"; category = "List" }
@{ prefix = "CalculationRegisterRecordSet"; category = "RecordSet" }
@{ prefix = "CalculationRegisterRecordKey"; category = "RecordKey" }
@{ prefix = "RecalculationsManager"; category = "Recalcs" }
)
"ChartOfAccounts" = @(
@{ prefix = "ChartOfAccountsObject"; category = "Object" }
@{ prefix = "ChartOfAccountsRef"; category = "Ref" }
@{ prefix = "ChartOfAccountsSelection"; category = "Selection" }
@{ prefix = "ChartOfAccountsList"; category = "List" }
@{ prefix = "ChartOfAccountsManager"; category = "Manager" }
@{ prefix = "ChartOfAccountsObject"; category = "Object" }
@{ prefix = "ChartOfAccountsRef"; category = "Ref" }
@{ prefix = "ChartOfAccountsSelection"; category = "Selection" }
@{ prefix = "ChartOfAccountsList"; category = "List" }
@{ prefix = "ChartOfAccountsManager"; category = "Manager" }
@{ prefix = "ChartOfAccountsExtDimensionTypes"; category = "ExtDimensionTypes" }
@{ prefix = "ChartOfAccountsExtDimensionTypesRow"; category = "ExtDimensionTypesRow" }
)
"ChartOfCharacteristicTypes" = @(
@{ prefix = "ChartOfCharacteristicTypesObject"; category = "Object" }
@@ -487,6 +490,9 @@ $script:generatedTypes = @{
@{ prefix = "ExchangePlanList"; category = "List" }
@{ prefix = "ExchangePlanManager"; category = "Manager" }
)
"DefinedType" = @(
@{ prefix = "DefinedType"; category = "DefinedType" }
)
"DocumentJournal" = @(
@{ prefix = "DocumentJournalSelection"; category = "Selection" }
@{ prefix = "DocumentJournalList"; category = "List" }
@@ -592,9 +598,26 @@ function Emit-TabularStandardAttributes {
# --- 8. Attribute emitter ---
$script:reservedAttrNames = @{
"Ref"="Ссылка"; "DeletionMark"="ПометкаУдаления"; "Code"="Код"; "Description"="Наименование"
"Date"="Дата"; "Number"="Номер"; "Posted"="Проведен"; "Parent"="Родитель"; "Owner"="Владелец"
"IsFolder"="ЭтоГруппа"; "Predefined"="Предопределенный"; "PredefinedDataName"="ИмяПредопределенныхДанных"
"Recorder"="Регистратор"; "Period"="Период"; "LineNumber"="НомерСтроки"; "Active"="Активность"
"Order"="Порядок"; "Type"="Тип"; "OffBalance"="Забалансовый"
"Started"="Стартован"; "Completed"="Завершен"; "HeadTask"="ВедущаяЗадача"
"Executed"="Выполнена"; "RoutePoint"="ТочкаМаршрута"; "BusinessProcess"="БизнесПроцесс"
"ThisNode"="ЭтотУзел"; "SentNo"="НомерОтправленного"; "ReceivedNo"="НомерПринятого"
"CalculationType"="ВидРасчета"; "RegistrationPeriod"="ПериодРегистрации"; "ReversingEntry"="СторноЗапись"
"Account"="Счет"; "ValueType"="ТипЗначения"; "ActionPeriodIsBasic"="ПериодДействияБазовый"
}
function Emit-Attribute {
param([string]$indent, $parsed, [string]$context)
# $context: "catalog", "document", "object", "processor", "tabular", "processor-tabular", "register"
$attrName = $parsed.name
if ($script:reservedAttrNames.ContainsKey($attrName) -or $script:reservedAttrNames.ContainsValue($attrName)) {
Write-Warning "Attribute '$attrName' conflicts with a standard attribute name. This may cause errors when loading into 1C."
}
$uuid = New-Guid-String
X "$indent<Attribute uuid=`"$uuid`">"
X "$indent`t<Properties>"
@@ -1440,19 +1463,13 @@ function Emit-ExchangePlanProperties {
$codeLength = if ($null -ne $def.codeLength) { "$($def.codeLength)" } else { "9" }
$descriptionLength = if ($null -ne $def.descriptionLength) { "$($def.descriptionLength)" } else { "100" }
$codeType = if ($def.codeType) { "$($def.codeType)" } else { "String" }
$codeAllowedLength = if ($def.codeAllowedLength) { "$($def.codeAllowedLength)" } else { "Variable" }
$autonumbering = if ($def.autonumbering -eq $false) { "false" } else { "true" }
$checkUnique = if ($def.checkUnique -eq $true) { "true" } else { "false" }
X "$i<CodeLength>$codeLength</CodeLength>"
X "$i<CodeType>$codeType</CodeType>"
X "$i<CodeAllowedLength>$codeAllowedLength</CodeAllowedLength>"
X "$i<DescriptionLength>$descriptionLength</DescriptionLength>"
X "$i<DefaultPresentation>AsDescription</DefaultPresentation>"
X "$i<EditType>InDialog</EditType>"
X "$i<CheckUnique>$checkUnique</CheckUnique>"
X "$i<Autonumbering>$autonumbering</Autonumbering>"
Emit-StandardAttributes $i "ExchangePlan"
@@ -1941,6 +1958,13 @@ function Emit-BusinessProcessProperties {
Emit-StandardAttributes $i "BusinessProcess"
X "$i<Characteristics/>"
$task = if ($def.task) { "$($def.task)" } else { "" }
if ($task) {
X "$i<Task>$task</Task>"
} else {
X "$i<Task/>"
}
X "$i<BasedOn/>"
X "$i<InputByString>"
X "$i`t<xr:Field>BusinessProcess.$objName.StandardAttribute.Number</xr:Field>"
@@ -2708,7 +2732,7 @@ if ($objType -in $typesWithModule) {
if ($objType -eq "ExchangePlan") {
$contentPath = Join-Path $extDir "Content.xml"
if (-not (Test-Path $contentPath)) {
$contentXml = "<?xml version=`"1.0`" encoding=`"UTF-8`"?>`r`n<ExchangePlanContent xmlns=`"http://v8.1c.ru/8.3/MDClasses`" xmlns:xs=`"http://www.w3.org/2001/XMLSchema`" xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`"/>`r`n"
$contentXml = "<?xml version=`"1.0`" encoding=`"UTF-8`"?>`r`n<ExchangePlanContent xmlns=`"http://v8.1c.ru/8.3/xcf/extrnprops`" xmlns:xr=`"http://v8.1c.ru/8.3/xcf/readable`" version=`"2.17`"/>`r`n"
[System.IO.File]::WriteAllText($contentPath, $contentXml, $enc)
$modulesCreated += $contentPath
}
@@ -2716,7 +2740,7 @@ if ($objType -eq "ExchangePlan") {
if ($objType -eq "BusinessProcess") {
$flowchartPath = Join-Path $extDir "Flowchart.xml"
if (-not (Test-Path $flowchartPath)) {
$flowchartXml = "<?xml version=`"1.0`" encoding=`"UTF-8`"?>`r`n<Flowchart xmlns=`"http://v8.1c.ru/8.3/MDClasses`"/>`r`n"
$flowchartXml = "<?xml version=`"1.0`" encoding=`"UTF-8`"?>`r`n<Flowchart xmlns=`"http://v8.1c.ru/8.3/MDClasses`" version=`"2.17`"/>`r`n"
[System.IO.File]::WriteAllText($flowchartPath, $flowchartXml, $enc)
$modulesCreated += $flowchartPath
}
@@ -2842,3 +2866,24 @@ switch ($regResult) {
"no-childobj" { Write-Warning "Configuration.xml found but <ChildObjects> not found" }
"no-config" { Write-Host " Configuration.xml: not found at $configXmlPath (register manually)" }
}
# Cross-reference hints
if ($objType -eq "AccountingRegister" -and -not $def.chartOfAccounts) {
Write-Host "[HINT] AccountingRegister requires ChartOfAccounts reference:"
Write-Host " /meta-edit -Operation modify-property -Value `"ChartOfAccounts=ChartOfAccounts.XXX`""
}
if ($objType -eq "CalculationRegister" -and -not $def.chartOfCalculationTypes) {
Write-Host "[HINT] CalculationRegister requires ChartOfCalculationTypes reference:"
Write-Host " /meta-edit -Operation modify-property -Value `"ChartOfCalculationTypes=ChartOfCalculationTypes.XXX`""
}
if ($objType -eq "BusinessProcess" -and -not $def.task) {
Write-Host "[HINT] BusinessProcess requires Task reference:"
Write-Host " /meta-edit -Operation modify-property -Value `"Task=Task.XXX`""
}
if ($objType -eq "ChartOfAccounts") {
$maxExtDim = if ($null -ne $def.maxExtDimensionCount) { [int]$def.maxExtDimensionCount } else { 0 }
if ($maxExtDim -gt 0 -and -not $def.extDimensionTypes) {
Write-Host "[HINT] ChartOfAccounts with MaxExtDimensionCount>0 requires ExtDimensionTypes:"
Write-Host " /meta-edit -Operation modify-property -Value `"ExtDimensionTypes=ChartOfCharacteristicTypes.XXX`""
}
}
@@ -406,6 +406,7 @@ generated_types = {
{'prefix': 'CalculationRegisterList', 'category': 'List'},
{'prefix': 'CalculationRegisterRecordSet', 'category': 'RecordSet'},
{'prefix': 'CalculationRegisterRecordKey', 'category': 'RecordKey'},
{'prefix': 'RecalculationsManager', 'category': 'Recalcs'},
],
'ChartOfAccounts': [
{'prefix': 'ChartOfAccountsObject', 'category': 'Object'},
@@ -413,6 +414,8 @@ generated_types = {
{'prefix': 'ChartOfAccountsSelection', 'category': 'Selection'},
{'prefix': 'ChartOfAccountsList', 'category': 'List'},
{'prefix': 'ChartOfAccountsManager', 'category': 'Manager'},
{'prefix': 'ChartOfAccountsExtDimensionTypes', 'category': 'ExtDimensionTypes'},
{'prefix': 'ChartOfAccountsExtDimensionTypesRow', 'category': 'ExtDimensionTypesRow'},
],
'ChartOfCharacteristicTypes': [
{'prefix': 'ChartOfCharacteristicTypesObject', 'category': 'Object'},
@@ -457,6 +460,9 @@ generated_types = {
{'prefix': 'ExchangePlanList', 'category': 'List'},
{'prefix': 'ExchangePlanManager', 'category': 'Manager'},
],
'DefinedType': [
{'prefix': 'DefinedType', 'category': 'DefinedType'},
],
'DocumentJournal': [
{'prefix': 'DocumentJournalSelection', 'category': 'Selection'},
{'prefix': 'DocumentJournalList', 'category': 'List'},
@@ -554,7 +560,40 @@ def emit_tabular_standard_attributes(indent):
# 8. Attribute emitter
# ---------------------------------------------------------------------------
RESERVED_ATTR_NAMES = {
'Ref', 'DeletionMark', 'Code', 'Description', 'Date', 'Number', 'Posted',
'Parent', 'Owner', 'IsFolder', 'Predefined', 'PredefinedDataName',
'Recorder', 'Period', 'LineNumber', 'Active', 'Order', 'Type', 'OffBalance',
'Started', 'Completed', 'HeadTask', 'Executed', 'RoutePoint', 'BusinessProcess',
'ThisNode', 'SentNo', 'ReceivedNo', 'CalculationType', 'RegistrationPeriod',
'ReversingEntry', 'Account', 'ValueType', 'ActionPeriodIsBasic',
}
RESERVED_ATTR_NAMES_RU = {
'\u0421\u0441\u044b\u043b\u043a\u0430', '\u041f\u043e\u043c\u0435\u0442\u043a\u0430\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u044f',
'\u041a\u043e\u0434', '\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435',
'\u0414\u0430\u0442\u0430', '\u041d\u043e\u043c\u0435\u0440', '\u041f\u0440\u043e\u0432\u0435\u0434\u0435\u043d',
'\u0420\u043e\u0434\u0438\u0442\u0435\u043b\u044c', '\u0412\u043b\u0430\u0434\u0435\u043b\u0435\u0446',
'\u042d\u0442\u043e\u0413\u0440\u0443\u043f\u043f\u0430', '\u041f\u0440\u0435\u0434\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439',
'\u0418\u043c\u044f\u041f\u0440\u0435\u0434\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445\u0414\u0430\u043d\u043d\u044b\u0445',
'\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440', '\u041f\u0435\u0440\u0438\u043e\u0434',
'\u041d\u043e\u043c\u0435\u0440\u0421\u0442\u0440\u043e\u043a\u0438', '\u0410\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c',
'\u041f\u043e\u0440\u044f\u0434\u043e\u043a', '\u0422\u0438\u043f', '\u0417\u0430\u0431\u0430\u043b\u0430\u043d\u0441\u043e\u0432\u044b\u0439',
'\u0421\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u043d', '\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043d',
'\u0412\u0435\u0434\u0443\u0449\u0430\u044f\u0417\u0430\u0434\u0430\u0447\u0430',
'\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430', '\u0422\u043e\u0447\u043a\u0430\u041c\u0430\u0440\u0448\u0440\u0443\u0442\u0430',
'\u0411\u0438\u0437\u043d\u0435\u0441\u041f\u0440\u043e\u0446\u0435\u0441\u0441',
'\u042d\u0442\u043e\u0442\u0423\u0437\u0435\u043b', '\u041d\u043e\u043c\u0435\u0440\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e',
'\u041d\u043e\u043c\u0435\u0440\u041f\u0440\u0438\u043d\u044f\u0442\u043e\u0433\u043e',
'\u0412\u0438\u0434\u0420\u0430\u0441\u0447\u0435\u0442\u0430', '\u041f\u0435\u0440\u0438\u043e\u0434\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438',
'\u0421\u0442\u043e\u0440\u043d\u043e\u0417\u0430\u043f\u0438\u0441\u044c',
'\u0421\u0447\u0435\u0442', '\u0422\u0438\u043f\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u044f',
'\u041f\u0435\u0440\u0438\u043e\u0434\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0411\u0430\u0437\u043e\u0432\u044b\u0439',
}
def emit_attribute(indent, parsed, context):
attr_name = parsed['name']
if 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}<Attribute uuid="{uid}">')
X(f'{indent}\t<Properties>')
@@ -1250,18 +1289,12 @@ def emit_exchange_plan_properties(indent):
X(f'{i}<UseStandardCommands>true</UseStandardCommands>')
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 '100'
code_type = str(defn['codeType']) if defn.get('codeType') else 'String'
code_allowed_length = str(defn['codeAllowedLength']) if defn.get('codeAllowedLength') else 'Variable'
autonumbering = 'false' if defn.get('autonumbering') is False else 'true'
check_unique = 'true' if defn.get('checkUnique') is True else 'false'
X(f'{i}<CodeLength>{code_length}</CodeLength>')
X(f'{i}<CodeType>{code_type}</CodeType>')
X(f'{i}<CodeAllowedLength>{code_allowed_length}</CodeAllowedLength>')
X(f'{i}<DescriptionLength>{description_length}</DescriptionLength>')
X(f'{i}<DefaultPresentation>AsDescription</DefaultPresentation>')
X(f'{i}<EditType>InDialog</EditType>')
X(f'{i}<CheckUnique>{check_unique}</CheckUnique>')
X(f'{i}<Autonumbering>{autonumbering}</Autonumbering>')
emit_standard_attributes(i, 'ExchangePlan')
distributed = 'true' if defn.get('distributedInfoBase') is True else 'false'
include_ext = 'true' if defn.get('includeConfigurationExtensions') is True else 'false'
@@ -1664,6 +1697,11 @@ def emit_business_process_properties(indent):
X(f'{i}<Autonumbering>{autonumbering}</Autonumbering>')
emit_standard_attributes(i, 'BusinessProcess')
X(f'{i}<Characteristics/>')
task_ref = str(defn['task']) if defn.get('task') else ''
if task_ref:
X(f'{i}<Task>{task_ref}</Task>')
else:
X(f'{i}<Task/>')
X(f'{i}<BasedOn/>')
X(f'{i}<InputByString>')
X(f'{i}\t<xr:Field>BusinessProcess.{obj_name}.StandardAttribute.Number</xr:Field>')
@@ -2335,14 +2373,14 @@ if obj_type in types_with_module:
if obj_type == 'ExchangePlan':
content_path = os.path.join(ext_dir, 'Content.xml')
if not os.path.isfile(content_path):
content_xml = '<?xml version="1.0" encoding="UTF-8"?>\r\n<ExchangePlanContent xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>\r\n'
content_xml = '<?xml version="1.0" encoding="UTF-8"?>\r\n<ExchangePlanContent xmlns="http://v8.1c.ru/8.3/xcf/extrnprops" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17"/>\r\n'
write_utf8_bom(content_path, content_xml)
modules_created.append(content_path)
if obj_type == 'BusinessProcess':
flowchart_path = os.path.join(ext_dir, 'Flowchart.xml')
if not os.path.isfile(flowchart_path):
flowchart_xml = '<?xml version="1.0" encoding="UTF-8"?>\r\n<Flowchart xmlns="http://v8.1c.ru/8.3/MDClasses"/>\r\n'
flowchart_xml = '<?xml version="1.0" encoding="UTF-8"?>\r\n<Flowchart xmlns="http://v8.1c.ru/8.3/MDClasses" version="2.17"/>\r\n'
write_utf8_bom(flowchart_path, flowchart_xml)
modules_created.append(flowchart_path)
@@ -2464,3 +2502,19 @@ elif reg_result == 'no-childobj':
print('WARNING: Configuration.xml found but <ChildObjects> not found', file=sys.stderr)
elif reg_result == 'no-config':
print(f' Configuration.xml: not found at {config_xml_path} (register manually)')
# Cross-reference hints
if obj_type == 'AccountingRegister' and not defn.get('chartOfAccounts'):
print('[HINT] AccountingRegister requires ChartOfAccounts reference:')
print(' /meta-edit -Operation modify-property -Value "ChartOfAccounts=ChartOfAccounts.XXX"')
if obj_type == 'CalculationRegister' and not defn.get('chartOfCalculationTypes'):
print('[HINT] CalculationRegister requires ChartOfCalculationTypes reference:')
print(' /meta-edit -Operation modify-property -Value "ChartOfCalculationTypes=ChartOfCalculationTypes.XXX"')
if obj_type == 'BusinessProcess' and not defn.get('task'):
print('[HINT] BusinessProcess requires Task reference:')
print(' /meta-edit -Operation modify-property -Value "Task=Task.XXX"')
if obj_type == 'ChartOfAccounts':
max_ext_dim = int(defn['maxExtDimensionCount']) if defn.get('maxExtDimensionCount') is not None else 0
if max_ext_dim > 0 and not defn.get('extDimensionTypes'):
print('[HINT] ChartOfAccounts with MaxExtDimensionCount>0 requires ExtDimensionTypes:')
print(' /meta-edit -Operation modify-property -Value "ExtDimensionTypes=ChartOfCharacteristicTypes.XXX"')
@@ -649,6 +649,41 @@ if ($childObjNode) {
if ($script:stopped) { & $finalize; exit 1 }
# --- Check 7b: Reserved attribute names ---
$reservedAttrNames = @(
"Ref","DeletionMark","Code","Description","Date","Number","Posted","Parent","Owner",
"IsFolder","Predefined","PredefinedDataName","Recorder","Period","LineNumber","Active",
"Order","Type","OffBalance","Started","Completed","HeadTask","Executed","RoutePoint",
"BusinessProcess","ThisNode","SentNo","ReceivedNo","CalculationType","RegistrationPeriod",
"ReversingEntry","Account","ValueType","ActionPeriodIsBasic"
)
if ($childObjNode) {
$check7bOk = $true
$attrNodes = $childObjNode.SelectNodes("md:Attribute", $ns)
foreach ($attrNode in $attrNodes) {
$attrProps = $attrNode.SelectSingleNode("md:Properties", $ns)
if ($attrProps) {
$attrNameNode = $attrProps.SelectSingleNode("md:Name", $ns)
if ($attrNameNode -and $attrNameNode.InnerText) {
$an = $attrNameNode.InnerText
if ($reservedAttrNames -contains $an) {
Report-Warn "7b. Attribute '$an' conflicts with a standard attribute name"
$check7bOk = $false
}
}
}
}
if ($check7bOk) {
Report-OK "7b. Reserved attribute names: no conflicts"
}
} else {
Report-OK "7b. Reserved attribute names: N/A"
}
if ($script:stopped) { & $finalize; exit 1 }
# --- Check 8: Name uniqueness ---
function Check-Uniqueness {
@@ -887,6 +922,51 @@ if ($propsNode) {
$check10Issues++
}
}
# AccountingRegister: ChartOfAccounts must not be empty
if ($mdType -eq "AccountingRegister") {
$coa = $propsNode.SelectSingleNode("md:ChartOfAccounts", $ns)
if (-not $coa -or -not $coa.InnerText.Trim()) {
Report-Error "10. AccountingRegister: empty ChartOfAccounts"
$check10Ok = $false
$check10Issues++
Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"ChartOfAccounts=ChartOfAccounts.XXX`""
}
}
# CalculationRegister: ChartOfCalculationTypes must not be empty
if ($mdType -eq "CalculationRegister") {
$coct = $propsNode.SelectSingleNode("md:ChartOfCalculationTypes", $ns)
if (-not $coct -or -not $coct.InnerText.Trim()) {
Report-Error "10. CalculationRegister: empty ChartOfCalculationTypes"
$check10Ok = $false
$check10Issues++
Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"ChartOfCalculationTypes=ChartOfCalculationTypes.XXX`""
}
}
# BusinessProcess: Task should not be empty
if ($mdType -eq "BusinessProcess") {
$taskProp = $propsNode.SelectSingleNode("md:Task", $ns)
if (-not $taskProp -or -not $taskProp.InnerText.Trim()) {
Report-Warn "10. BusinessProcess: empty Task reference"
$check10Issues++
Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"Task=Task.XXX`""
}
}
# ChartOfAccounts: ExtDimensionTypes should be set if MaxExtDimensionCount > 0
if ($mdType -eq "ChartOfAccounts") {
$maxExtDim = $propsNode.SelectSingleNode("md:MaxExtDimensionCount", $ns)
if ($maxExtDim -and [int]$maxExtDim.InnerText -gt 0) {
$edt = $propsNode.SelectSingleNode("md:ExtDimensionTypes", $ns)
if (-not $edt -or -not $edt.InnerText.Trim()) {
Report-Warn "10. ChartOfAccounts: MaxExtDimensionCount>0 but ExtDimensionTypes is empty"
$check10Issues++
Write-Host "[HINT] /meta-edit -Operation modify-property -Value `"ExtDimensionTypes=ChartOfCharacteristicTypes.XXX`""
}
}
}
}
if ($check10Ok -and $check10Issues -eq 0) {
@@ -626,6 +626,37 @@ if stopped:
finalize()
sys.exit(1)
# ── Check 7b: Reserved attribute names ───────────────────────
RESERVED_ATTR_NAMES = {
'Ref', 'DeletionMark', 'Code', 'Description', 'Date', 'Number', 'Posted',
'Parent', 'Owner', 'IsFolder', 'Predefined', 'PredefinedDataName',
'Recorder', 'Period', 'LineNumber', 'Active', 'Order', 'Type', 'OffBalance',
'Started', 'Completed', 'HeadTask', 'Executed', 'RoutePoint', 'BusinessProcess',
'ThisNode', 'SentNo', 'ReceivedNo', 'CalculationType', 'RegistrationPeriod',
'ReversingEntry', 'Account', 'ValueType', 'ActionPeriodIsBasic',
}
if child_obj_node is not None:
check7b_ok = True
for attr_node in find_all(child_obj_node, 'md:Attribute'):
attr_props = find(attr_node, 'md:Properties')
if attr_props is not None:
attr_name_node = find(attr_props, 'md:Name')
if attr_name_node is not None and inner_text(attr_name_node):
an = inner_text(attr_name_node)
if an in RESERVED_ATTR_NAMES:
report_warn(f"7b. Attribute '{an}' conflicts with a standard attribute name")
check7b_ok = False
if check7b_ok:
report_ok("7b. Reserved attribute names: no conflicts")
else:
report_ok("7b. Reserved attribute names: N/A")
if stopped:
finalize()
sys.exit(1)
# ── Check 8: Name uniqueness ─────────────────────────────────
@@ -841,6 +872,47 @@ if props_node is not None:
check10_ok = False
check10_issues += 1
# AccountingRegister: ChartOfAccounts must not be empty
if md_type == 'AccountingRegister':
coa = find(props_node, 'md:ChartOfAccounts')
if coa is None or not text_of(coa):
report_error('10. AccountingRegister: empty ChartOfAccounts')
check10_ok = False
check10_issues += 1
print('[HINT] /meta-edit -Operation modify-property -Value "ChartOfAccounts=ChartOfAccounts.XXX"')
# CalculationRegister: ChartOfCalculationTypes must not be empty
if md_type == 'CalculationRegister':
coct = find(props_node, 'md:ChartOfCalculationTypes')
if coct is None or not text_of(coct):
report_error('10. CalculationRegister: empty ChartOfCalculationTypes')
check10_ok = False
check10_issues += 1
print('[HINT] /meta-edit -Operation modify-property -Value "ChartOfCalculationTypes=ChartOfCalculationTypes.XXX"')
# BusinessProcess: Task should not be empty
if md_type == 'BusinessProcess':
task_prop = find(props_node, 'md:Task')
if task_prop is None or not text_of(task_prop):
report_warn('10. BusinessProcess: empty Task reference')
check10_issues += 1
print('[HINT] /meta-edit -Operation modify-property -Value "Task=Task.XXX"')
# ChartOfAccounts: ExtDimensionTypes should be set if MaxExtDimensionCount > 0
if md_type == 'ChartOfAccounts':
max_ext_dim = find(props_node, 'md:MaxExtDimensionCount')
if max_ext_dim is not None:
try:
med_val = int(inner_text(max_ext_dim) or '0')
except ValueError:
med_val = 0
if med_val > 0:
edt = find(props_node, 'md:ExtDimensionTypes')
if edt is None or not text_of(edt):
report_warn('10. ChartOfAccounts: MaxExtDimensionCount>0 but ExtDimensionTypes is empty')
check10_issues += 1
print('[HINT] /meta-edit -Operation modify-property -Value "ExtDimensionTypes=ChartOfCharacteristicTypes.XXX"')
if check10_ok and check10_issues == 0:
report_ok("10. Cross-property consistency")
+2 -1
View File
@@ -580,6 +580,7 @@ DSL для `columns` (§12).
| `autonumbering` | `true` | Autonumbering |
| `dataLockControlMode` | `Automatic` | DataLockControlMode |
| `fullTextSearch` | `Use` | FullTextSearch |
| `task` | `""` | Task (ссылка на Task.XXX) |
| `attributes` | `[]` | → Attribute в ChildObjects |
| `tabularSections` | `{}` | → TabularSection в ChildObjects |
@@ -587,7 +588,7 @@ DSL для `columns` (§12).
Дополнительно: `Ext/Flowchart.xml` (заглушка карты маршрута).
```json
{ "type": "BusinessProcess", "name": "Задание", "attributes": ["Описание: String(200)"] }
{ "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] }
```
### 7.21 Task