mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-27 12:35:54 +03:00
fix(meta-edit): свойства-списки у заимствованного объекта и не своего типа (#99)
У заимствованного объекта расширения в Properties только изменённые свойства. add-registerRecord и прочие add-*/set-* над списками не находили элемент, печатали WARN, файл не меняли и выходили с кодом 0. - Движения заимствованного документа: отсутствующий RegisterRecords создаётся. - Прочие списки у заимствованного объекта — отказ. Проверено на 8.3.27: Owners и RegisteredDocuments платформа контролирует на равенство основной конфигурации (расширение не применяется), BasedOn/InputByString/DataLockFields и движения последовательности молча выбрасывает при загрузке. - Свойство, которого у типа объекта нет (движения у справочника), — отказ; раньше modify.properties дописывал его, и meta-validate это пропускал. - У обычного объекта отсутствие элемента — отказ вместо WARN. - reference/properties.md: типы объектов в таблице — по выгрузкам ERP, БП, УТ, УНФ. - verify-snapshots: двухэтапная загрузка и по params.extensionPath кейса. Co-Authored-By: Roman Syuzyov <rsyuzyov@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Roman Syuzyov
Claude Opus 5.5
parent
5d1b5cdf74
commit
51bcc503b0
@@ -29,13 +29,15 @@
|
||||
|
||||
| Свойство | Объекты | Inline-значение |
|
||||
|----------|---------|-----------------|
|
||||
| Owners | Catalog, ChartOfCharacteristicTypes | `Catalog.XXX` |
|
||||
| RegisterRecords | Document | `AccumulationRegister.XXX` |
|
||||
| BasedOn | Document, Catalog, BP, Task | `Document.XXX` |
|
||||
| InputByString | Catalog, ChartOf*, Task | `StandardAttribute.Description` |
|
||||
| DataLockFields | Catalog, Document, регистры и др. | `Организация` (короткое имя реквизита → полный путь) |
|
||||
| Owners | Catalog | `Catalog.XXX` |
|
||||
| RegisterRecords | Document, Sequence | `AccumulationRegister.XXX` |
|
||||
| BasedOn | ссылочные* | `Document.XXX` |
|
||||
| InputByString | ссылочные* | `StandardAttribute.Description` |
|
||||
| DataLockFields | ссылочные* | `Организация` (короткое имя реквизита → полный путь) |
|
||||
| RegisteredDocuments | DocumentJournal | `Document.XXX` |
|
||||
|
||||
\* Catalog, Document, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, ExchangePlan, BusinessProcess, Task.
|
||||
|
||||
### add-owner / add-registerRecord / add-basedOn / add-registeredDocument
|
||||
|
||||
Полное имя метаданных `MetaType.Name`:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# meta-edit v1.54 — Edit existing 1C metadata object XML
|
||||
# meta-edit v1.55 — Edit existing 1C metadata object XML
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
[CmdletBinding(PositionalBinding=$false)]
|
||||
param(
|
||||
@@ -374,6 +374,13 @@ function Info($msg) {
|
||||
Write-Host "[INFO] $msg" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Операцию выполнить нельзя: в stderr и exit 1 до сохранения — файл не меняется.
|
||||
# Console.Error, а не Write-Error: под ErrorActionPreference=Stop тот бросает исключение.
|
||||
function Die($msg) {
|
||||
[Console]::Error.WriteLine($msg)
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Section 2: Detect object type
|
||||
# ============================================================
|
||||
@@ -3126,13 +3133,18 @@ function Normalize-MDObjectRef {
|
||||
|
||||
# mdref — значения списка суть MDObjectRef-пути → прогоняем через Normalize-MDObjectRef.
|
||||
# root — корень для голого имени без точки.
|
||||
# types — у каких объектов свойство есть (Properties выгрузок ERP, БП, УТ, УНФ).
|
||||
# adopted — у каких заимствованных объектов расширение может менять свойство (8.3.27): прочие
|
||||
# списки платформа либо контролирует на равенство основной конфигурации (Owners, RegisteredDocuments —
|
||||
# расширение не применяется), либо молча выбрасывает при загрузке.
|
||||
$script:refObjectTypes = @('Catalog','Document','ChartOfAccounts','ChartOfCalculationTypes','ChartOfCharacteristicTypes','ExchangePlan','BusinessProcess','Task')
|
||||
$script:complexPropertyMap = @{
|
||||
"Owners" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true; root = 'Catalog' }
|
||||
"RegisterRecords" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true }
|
||||
"BasedOn" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true }
|
||||
"InputByString" = @{ tag = "xr:Field"; attr = $null }
|
||||
"DataLockFields" = @{ tag = "xr:Field"; attr = $null; expand = $true }
|
||||
"RegisteredDocuments" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true }
|
||||
"Owners" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true; root = 'Catalog'; types = @('Catalog') }
|
||||
"RegisterRecords" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true; types = @('Document','Sequence'); adopted = @('Document') }
|
||||
"BasedOn" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true; types = $script:refObjectTypes }
|
||||
"InputByString" = @{ tag = "xr:Field"; attr = $null; types = $script:refObjectTypes }
|
||||
"DataLockFields" = @{ tag = "xr:Field"; attr = $null; expand = $true; types = $script:refObjectTypes }
|
||||
"RegisteredDocuments" = @{ tag = "xr:Item"; attr = 'xsi:type="xr:MDObjectRef"'; mdref = $true; types = @('DocumentJournal') }
|
||||
}
|
||||
|
||||
# Известные свойства объекта (union по корпусу acc+erp 8.3.24) — allowlist для modify-property.
|
||||
@@ -3573,6 +3585,30 @@ function Find-PropertyElement([string]$propName) {
|
||||
return $null
|
||||
}
|
||||
|
||||
# Элемент свойства-списка. Свойство, которого у типа объекта нет, — ошибка (раньше на справочнике
|
||||
# add-registerRecord тихо не делал ничего). У заимствованного объекта расширения в Properties только
|
||||
# изменённые свойства, поэтому отсутствующий элемент при $create создаём (в конец, как Modify-Properties);
|
||||
# у обычного объекта выгрузка содержит все свойства, и отсутствие элемента — ошибка.
|
||||
function Get-ListPropertyElement([string]$propName, [bool]$create) {
|
||||
$mapEntry = $script:complexPropertyMap[$propName]
|
||||
if ($mapEntry -and $mapEntry.types -cnotcontains $script:objType) {
|
||||
Die "Свойство '$propName' не применимо к $($script:objType)"
|
||||
}
|
||||
$belonging = Find-PropertyElement 'ObjectBelonging'
|
||||
$isAdopted = $belonging -and $belonging.InnerText -ceq 'Adopted'
|
||||
if ($isAdopted -and $mapEntry.adopted -cnotcontains $script:objType) {
|
||||
Die "Свойство '$propName' заимствованного объекта $($script:objType).$($script:objName) расширение не меняет — значение берётся из основной конфигурации"
|
||||
}
|
||||
$propEl = Find-PropertyElement $propName
|
||||
if ($propEl -or -not $create) { return $propEl }
|
||||
if (-not $isAdopted) {
|
||||
Die "В Properties объекта $($script:objType).$($script:objName) нет элемента '$propName' — файл не из выгрузки платформы?"
|
||||
}
|
||||
$newNodes = Import-Fragment "<$propName/>"
|
||||
Insert-PropertyInOrder $script:propertiesEl $newNodes[0] $null $propName
|
||||
return $newNodes[0]
|
||||
}
|
||||
|
||||
function Get-ComplexPropertyValues([System.Xml.XmlElement]$propEl) {
|
||||
$values = @()
|
||||
foreach ($child in $propEl.ChildNodes) {
|
||||
@@ -3589,11 +3625,7 @@ function Add-ComplexPropertyItem([string]$propertyName, [string[]]$values) {
|
||||
if ($mapEntry.expand) { $values = @($values | ForEach-Object { Expand-DataPath "$_" }) }
|
||||
if ($mapEntry.mdref) { $values = @($values | ForEach-Object { Normalize-MDObjectRef "$_" $mapEntry.root }) }
|
||||
|
||||
$propEl = Find-PropertyElement $propertyName
|
||||
if (-not $propEl) {
|
||||
Warn "Property element '$propertyName' not found in Properties"
|
||||
return
|
||||
}
|
||||
$propEl = Get-ListPropertyElement $propertyName $true
|
||||
|
||||
# Get existing values to check duplicates
|
||||
$existing = Get-ComplexPropertyValues $propEl
|
||||
@@ -3638,7 +3670,7 @@ function Remove-ComplexPropertyItem([string]$propertyName, [string[]]$values) {
|
||||
$mapEntry = $script:complexPropertyMap[$propertyName]
|
||||
if ($mapEntry -and $mapEntry.expand) { $values = @($values | ForEach-Object { Expand-DataPath "$_" }) }
|
||||
if ($mapEntry -and $mapEntry.mdref) { $values = @($values | ForEach-Object { Normalize-MDObjectRef "$_" $mapEntry.root }) }
|
||||
$propEl = Find-PropertyElement $propertyName
|
||||
$propEl = Get-ListPropertyElement $propertyName $false
|
||||
if (-not $propEl) {
|
||||
Warn "Property element '$propertyName' not found in Properties"
|
||||
return
|
||||
@@ -3678,11 +3710,9 @@ function Set-ComplexProperty([string]$propertyName, [string[]]$values) {
|
||||
if ($mapEntry.expand) { $values = @($values | ForEach-Object { Expand-DataPath "$_" }) }
|
||||
if ($mapEntry.mdref) { $values = @($values | ForEach-Object { Normalize-MDObjectRef "$_" $mapEntry.root }) }
|
||||
|
||||
$propEl = Find-PropertyElement $propertyName
|
||||
if (-not $propEl) {
|
||||
Warn "Property element '$propertyName' not found in Properties"
|
||||
return
|
||||
}
|
||||
# Пустой список на отсутствующем элементе: очищать нечего, пустой элемент не создаём
|
||||
$propEl = Get-ListPropertyElement $propertyName ($values.Count -gt 0)
|
||||
if (-not $propEl) { return }
|
||||
|
||||
$indent = Get-ChildIndent $script:propertiesEl
|
||||
$childIndent = "$indent`t"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# meta-edit v1.54 — Edit existing 1C metadata object XML
|
||||
# meta-edit v1.55 — Edit existing 1C metadata object XML
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -2988,13 +2988,18 @@ def normalize_md_object_ref(ref, default_root=None):
|
||||
|
||||
# mdref — значения списка суть MDObjectRef-пути → прогоняем через normalize_md_object_ref.
|
||||
# root — корень для голого имени без точки.
|
||||
# types — у каких объектов свойство есть (Properties выгрузок ERP, БП, УТ, УНФ).
|
||||
# adopted — у каких заимствованных объектов расширение может менять свойство (8.3.27): прочие
|
||||
# списки платформа либо контролирует на равенство основной конфигурации (Owners, RegisteredDocuments —
|
||||
# расширение не применяется), либо молча выбрасывает при загрузке.
|
||||
ref_object_types = ["Catalog", "Document", "ChartOfAccounts", "ChartOfCalculationTypes", "ChartOfCharacteristicTypes", "ExchangePlan", "BusinessProcess", "Task"]
|
||||
complex_property_map = {
|
||||
"Owners": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True, "root": "Catalog"},
|
||||
"RegisterRecords": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True},
|
||||
"BasedOn": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True},
|
||||
"InputByString": {"tag": "xr:Field", "attr": None},
|
||||
"DataLockFields": {"tag": "xr:Field", "attr": None, "expand": True},
|
||||
"RegisteredDocuments": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True},
|
||||
"Owners": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True, "root": "Catalog", "types": ["Catalog"]},
|
||||
"RegisterRecords": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True, "types": ["Document", "Sequence"], "adopted": ["Document"]},
|
||||
"BasedOn": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True, "types": ref_object_types},
|
||||
"InputByString": {"tag": "xr:Field", "attr": None, "types": ref_object_types},
|
||||
"DataLockFields": {"tag": "xr:Field", "attr": None, "expand": True, "types": ref_object_types},
|
||||
"RegisteredDocuments": {"tag": "xr:Item", "attr": 'xsi:type="xr:MDObjectRef"', "mdref": True, "types": ["DocumentJournal"]},
|
||||
}
|
||||
|
||||
# Известные свойства объекта (union по корпусу acc+erp 8.3.24) — allowlist для modify-property.
|
||||
@@ -3514,6 +3519,28 @@ def find_property_element(prop_name):
|
||||
return None
|
||||
|
||||
|
||||
# Элемент свойства-списка. Свойство, которого у типа объекта нет, — ошибка (раньше на справочнике
|
||||
# add-registerRecord тихо не делал ничего). У заимствованного объекта расширения в Properties только
|
||||
# изменённые свойства, поэтому отсутствующий элемент при create создаём (в конец, как modify_properties);
|
||||
# у обычного объекта выгрузка содержит все свойства, и отсутствие элемента — ошибка.
|
||||
def get_list_property_element(prop_name, create):
|
||||
map_entry = complex_property_map.get(prop_name)
|
||||
if map_entry and obj_type not in map_entry["types"]:
|
||||
die(f"Свойство '{prop_name}' не применимо к {obj_type}")
|
||||
belonging = find_property_element("ObjectBelonging")
|
||||
is_adopted = belonging is not None and (belonging.text or "") == "Adopted"
|
||||
if is_adopted and obj_type not in (map_entry or {}).get("adopted", []):
|
||||
die(f"Свойство '{prop_name}' заимствованного объекта {obj_type}.{obj_name} расширение не меняет — значение берётся из основной конфигурации")
|
||||
prop_el = find_property_element(prop_name)
|
||||
if prop_el is not None or not create:
|
||||
return prop_el
|
||||
if not is_adopted:
|
||||
die(f"В Properties объекта {obj_type}.{obj_name} нет элемента '{prop_name}' — файл не из выгрузки платформы?")
|
||||
new_nodes = import_fragment(f"<{prop_name}/>")
|
||||
insert_property_in_order(properties_el, new_nodes[0], None, prop_name)
|
||||
return new_nodes[0]
|
||||
|
||||
|
||||
def get_complex_property_values(prop_el):
|
||||
values = []
|
||||
for child in prop_el:
|
||||
@@ -3533,10 +3560,7 @@ def add_complex_property_item(property_name, values):
|
||||
if map_entry.get("mdref"):
|
||||
values = [normalize_md_object_ref(str(v), map_entry.get("root")) for v in values]
|
||||
|
||||
prop_el = find_property_element(property_name)
|
||||
if prop_el is None:
|
||||
warn(f"Property element '{property_name}' not found in Properties")
|
||||
return
|
||||
prop_el = get_list_property_element(property_name, True)
|
||||
|
||||
# Get existing values to check duplicates
|
||||
existing = get_complex_property_values(prop_el)
|
||||
@@ -3576,7 +3600,7 @@ def remove_complex_property_item(property_name, values):
|
||||
values = [expand_data_path(str(v)) for v in values]
|
||||
if map_entry and map_entry.get("mdref"):
|
||||
values = [normalize_md_object_ref(str(v), map_entry.get("root")) for v in values]
|
||||
prop_el = find_property_element(property_name)
|
||||
prop_el = get_list_property_element(property_name, False)
|
||||
if prop_el is None:
|
||||
warn(f"Property element '{property_name}' not found in Properties")
|
||||
return
|
||||
@@ -3611,9 +3635,9 @@ def set_complex_property(property_name, values):
|
||||
if map_entry.get("mdref"):
|
||||
values = [normalize_md_object_ref(str(v), map_entry.get("root")) for v in values]
|
||||
|
||||
prop_el = find_property_element(property_name)
|
||||
# Пустой список на отсутствующем элементе: очищать нечего, пустой элемент не создаём
|
||||
prop_el = get_list_property_element(property_name, len(values) > 0)
|
||||
if prop_el is None:
|
||||
warn(f"Property element '{property_name}' not found in Properties")
|
||||
return
|
||||
|
||||
indent = get_child_indent(properties_el)
|
||||
|
||||
Reference in New Issue
Block a user