mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-07 20:20:20 +03:00
fix(cfe-borrow): глубокие пути через ТЧ + DefinedType-тоталы при заимствовании формы
На формах со сложными табличными частями (напр. Document.РеализацияТоваровУслуг) строгий импорт ibcmd падал «Неверный путь к данным» по двум причинам (Designer /LoadConfigFromFiles это пропускал). Оба корня выверены эталоном Конфигуратора. 1. Глубокие пути через ТЧ: Объект.<ТЧ>.<Колонка>.<Подреквизит> (Объект.Товары.Номенклатура.ТипНоменклатуры). Сборщик терял 3-й сегмент, а обработка вообще исключала ТЧ-корни → каталог колонки заимствовался пустой оболочкой без под-реквизитов. Теперь сборщик хранит SubSubAttr, а общий helper Borrow-DeepTargetAttrs/borrow_deep_target_attrs заимствует каталог колонки с под-реквизитами (как Designer: Catalog.Номенклатура с ТипНоменклатуры/ЕдиницаИзмерения). 2. Тоталы колонок: Объект.<ТЧ>.Total<Колонка> → «тип колонки не определён». Колонка типизирована через DefinedType, а DefinedType заимствовался оболочкой без <Type>. Теперь Read-SourceObject добывает <Type> DefinedType, Build-BorrowedObjectXml его эмитит (Designer кладёт полный <Type>, напр. xs:decimal Nonnegative). Регресс cfe-borrow 6/6 + form-bindings на обоих рантаймах; acc-форма без изменений. Паритет PS↔PY. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
330f52c6e6
commit
8e9f9465b6
@@ -1,4 +1,4 @@
|
|||||||
# cfe-borrow v1.7 — Borrow objects from configuration into extension (CFE)
|
# cfe-borrow v1.8 — Borrow objects from configuration into extension (CFE)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)][string]$ExtensionPath,
|
[Parameter(Mandatory)][string]$ExtensionPath,
|
||||||
@@ -444,6 +444,14 @@ function Read-SourceObject {
|
|||||||
$srcProps[$propName] = $propNode.InnerText.Trim()
|
$srcProps[$propName] = $propNode.InnerText.Trim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# DefinedType: carry the <Type> definition. A type alias is meaningless as a bare shell —
|
||||||
|
# the platform needs its underlying type (e.g. to know a column is a summable Number for totals).
|
||||||
|
if ($typeName -eq "DefinedType") {
|
||||||
|
$typeNode = $propsNode.SelectSingleNode("md:Type", $srcNs)
|
||||||
|
if ($typeNode) {
|
||||||
|
$srcProps["__TypeXml"] = [regex]::Replace($typeNode.OuterXml, '\s+xmlns(?::\w+)?="[^"]*"', '')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return @{
|
return @{
|
||||||
@@ -1057,7 +1065,8 @@ function Collect-FormDataPaths {
|
|||||||
if ($segments.Count -ge 2) {
|
if ($segments.Count -ge 2) {
|
||||||
$seg1 = $segments[1]
|
$seg1 = $segments[1]
|
||||||
if ($script:standardFields -contains $seg1) { continue }
|
if ($script:standardFields -contains $seg1) { continue }
|
||||||
$deepPaths += @{ ObjectAttr = $seg0; SubAttr = $seg1 }
|
$seg2 = if ($segments.Count -ge 3) { $segments[2] } else { $null }
|
||||||
|
$deepPaths += @{ ObjectAttr = $seg0; SubAttr = $seg1; SubSubAttr = $seg2 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1082,7 +1091,7 @@ function Collect-FormDataPaths {
|
|||||||
$seen = @{}
|
$seen = @{}
|
||||||
$uniqueDeep = @()
|
$uniqueDeep = @()
|
||||||
foreach ($dp in $deepPaths) {
|
foreach ($dp in $deepPaths) {
|
||||||
$key = "$($dp.ObjectAttr).$($dp.SubAttr)"
|
$key = "$($dp.ObjectAttr).$($dp.SubAttr).$($dp.SubSubAttr)"
|
||||||
if (-not $seen.ContainsKey($key)) {
|
if (-not $seen.ContainsKey($key)) {
|
||||||
$seen[$key] = $true
|
$seen[$key] = $true
|
||||||
$uniqueDeep += $dp
|
$uniqueDeep += $dp
|
||||||
@@ -1516,79 +1525,46 @@ function Borrow-MainAttribute {
|
|||||||
|
|
||||||
# Step 5: Handle deep paths (Form mode only)
|
# Step 5: Handle deep paths (Form mode only)
|
||||||
if ($mode -eq "Form" -and $deepPaths.Count -gt 0) {
|
if ($mode -eq "Form" -and $deepPaths.Count -gt 0) {
|
||||||
# Filter out deep paths where ObjectAttr is a TabularSection (those are TS column refs, not deep attribute refs)
|
# Top-level ref deep paths: Объект.<Ref>.<Sub> — borrow the ref attribute's catalog with the sub-attribute
|
||||||
$realDeep = @()
|
$deepByAttr = @{}
|
||||||
foreach ($dp in $deepPaths) {
|
foreach ($dp in $deepPaths) {
|
||||||
if (-not $tsNames.ContainsKey($dp.ObjectAttr)) { $realDeep += $dp }
|
if ($tsNames.ContainsKey($dp.ObjectAttr)) { continue }
|
||||||
|
if (-not $deepByAttr.ContainsKey($dp.ObjectAttr)) { $deepByAttr[$dp.ObjectAttr] = @() }
|
||||||
|
if ($deepByAttr[$dp.ObjectAttr] -notcontains $dp.SubAttr) { $deepByAttr[$dp.ObjectAttr] += $dp.SubAttr }
|
||||||
}
|
}
|
||||||
|
if ($deepByAttr.Count -gt 0) {
|
||||||
if ($realDeep.Count -gt 0) {
|
Info " Processing $($deepByAttr.Count) deep path attribute(s)..."
|
||||||
Info " Processing $($realDeep.Count) deep path(s)..."
|
|
||||||
|
|
||||||
# Group by ObjectAttr → target catalog
|
|
||||||
$deepByAttr = @{}
|
|
||||||
foreach ($dp in $realDeep) {
|
|
||||||
if (-not $deepByAttr.ContainsKey($dp.ObjectAttr)) { $deepByAttr[$dp.ObjectAttr] = @() }
|
|
||||||
$deepByAttr[$dp.ObjectAttr] += $dp.SubAttr
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($attrName in $deepByAttr.Keys) {
|
foreach ($attrName in $deepByAttr.Keys) {
|
||||||
# Find the attribute's type to determine target catalog
|
|
||||||
$attrInfo = $srcAttrs | Where-Object { $_.Name -eq $attrName } | Select-Object -First 1
|
$attrInfo = $srcAttrs | Where-Object { $_.Name -eq $attrName } | Select-Object -First 1
|
||||||
if (-not $attrInfo) { continue }
|
if (-not $attrInfo) { continue }
|
||||||
|
|
||||||
# Extract catalog name from type: cfg:CatalogRef.XXX
|
|
||||||
$catMatch = [regex]::Match($attrInfo.TypeXml, 'cfg:(\w+)Ref\.(\w+)')
|
$catMatch = [regex]::Match($attrInfo.TypeXml, 'cfg:(\w+)Ref\.(\w+)')
|
||||||
if (-not $catMatch.Success) { continue }
|
if (-not $catMatch.Success) { continue }
|
||||||
|
Borrow-DeepTargetAttrs $catMatch.Groups[1].Value $catMatch.Groups[2].Value $deepByAttr[$attrName]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$targetTypeName = $catMatch.Groups[1].Value
|
# Tabular-section deep paths: Объект.<ТЧ>.<Колонка>.<Sub> — borrow the column's catalog with the sub-attribute
|
||||||
$targetObjName = $catMatch.Groups[2].Value
|
$tsDeepByCol = @{}
|
||||||
|
foreach ($dp in $deepPaths) {
|
||||||
# Ensure target is borrowed
|
if (-not $tsNames.ContainsKey($dp.ObjectAttr)) { continue }
|
||||||
if (-not (Test-ObjectBorrowed $targetTypeName $targetObjName)) {
|
if (-not $dp.SubSubAttr) { continue }
|
||||||
$tSrc = Read-SourceObject $targetTypeName $targetObjName
|
if ($script:standardFields -contains $dp.SubSubAttr) { continue }
|
||||||
$tBorrowedXml = Build-BorrowedObjectXml $targetTypeName $targetObjName $tSrc.Uuid $tSrc.Properties
|
$k = "$($dp.ObjectAttr)|$($dp.SubAttr)"
|
||||||
$tTargetDir = Join-Path $extDir $childTypeDirMap[$targetTypeName]
|
if (-not $tsDeepByCol.ContainsKey($k)) { $tsDeepByCol[$k] = @() }
|
||||||
if (-not (Test-Path $tTargetDir)) {
|
if ($tsDeepByCol[$k] -notcontains $dp.SubSubAttr) { $tsDeepByCol[$k] += $dp.SubSubAttr }
|
||||||
New-Item -ItemType Directory -Path $tTargetDir -Force | Out-Null
|
}
|
||||||
}
|
if ($tsDeepByCol.Count -gt 0) {
|
||||||
$tTargetFile = Join-Path $tTargetDir "${targetObjName}.xml"
|
Info " Processing $($tsDeepByCol.Count) tabular-section deep path(s)..."
|
||||||
[System.IO.File]::WriteAllText($tTargetFile, $tBorrowedXml, $encBom)
|
foreach ($k in $tsDeepByCol.Keys) {
|
||||||
Add-ToChildObjects $targetTypeName $targetObjName
|
$parts = $k.Split("|")
|
||||||
$script:borrowedFiles += $tTargetFile
|
$tsName = $parts[0]; $colName = $parts[1]
|
||||||
Info " Auto-borrowed for deep path: ${targetTypeName}.${targetObjName}"
|
$tsInfo = $srcTS | Where-Object { $_.Name -eq $tsName } | Select-Object -First 1
|
||||||
}
|
if (-not $tsInfo) { continue }
|
||||||
|
$colInfo = $tsInfo.Attributes | Where-Object { $_.Name -eq $colName } | Select-Object -First 1
|
||||||
# Resolve sub-attributes in target catalog
|
if (-not $colInfo) { continue }
|
||||||
$subNames = @{}
|
$catMatch = [regex]::Match($colInfo.TypeXml, 'cfg:(\w+)Ref\.(\w+)')
|
||||||
foreach ($sn in $deepByAttr[$attrName]) { $subNames[$sn] = $true }
|
if (-not $catMatch.Success) { continue }
|
||||||
$subResolved = Resolve-SourceAttributes $targetTypeName $targetObjName $subNames
|
Borrow-DeepTargetAttrs $catMatch.Groups[1].Value $catMatch.Groups[2].Value $tsDeepByCol[$k]
|
||||||
|
|
||||||
if ($subResolved.Attributes.Count -gt 0) {
|
|
||||||
Merge-AttributesIntoObject $targetTypeName $targetObjName $subResolved.Attributes
|
|
||||||
|
|
||||||
# Collect and borrow ref types from deep attributes
|
|
||||||
$subTypeXmls = @()
|
|
||||||
foreach ($sa in $subResolved.Attributes) { $subTypeXmls += $sa.TypeXml }
|
|
||||||
$subRefTypes = Collect-ReferenceTypes $subTypeXmls
|
|
||||||
foreach ($srt in $subRefTypes) {
|
|
||||||
if (-not $childTypeDirMap.ContainsKey($srt.TypeName)) { continue }
|
|
||||||
if (Test-ObjectBorrowed $srt.TypeName $srt.ObjName) { continue }
|
|
||||||
$sSrcFile = Join-Path (Join-Path $cfgDir $childTypeDirMap[$srt.TypeName]) "$($srt.ObjName).xml"
|
|
||||||
if (-not (Test-Path $sSrcFile)) { continue }
|
|
||||||
$sSrc = Read-SourceObject $srt.TypeName $srt.ObjName
|
|
||||||
$sBorrowedXml = Build-BorrowedObjectXml $srt.TypeName $srt.ObjName $sSrc.Uuid $sSrc.Properties
|
|
||||||
$sTargetDir = Join-Path $extDir $childTypeDirMap[$srt.TypeName]
|
|
||||||
if (-not (Test-Path $sTargetDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $sTargetDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
$sTargetFile = Join-Path $sTargetDir "$($srt.ObjName).xml"
|
|
||||||
[System.IO.File]::WriteAllText($sTargetFile, $sBorrowedXml, $encBom)
|
|
||||||
Add-ToChildObjects $srt.TypeName $srt.ObjName
|
|
||||||
$script:borrowedFiles += $sTargetFile
|
|
||||||
Info " Auto-borrowed (deep): $($srt.TypeName).$($srt.ObjName)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1596,6 +1572,57 @@ function Borrow-MainAttribute {
|
|||||||
Info " Main attribute borrowing complete"
|
Info " Main attribute borrowing complete"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --- 11i. Helper: borrow a deep-path target catalog together with the referenced sub-attributes ---
|
||||||
|
# Used for both Объект.<Ref>.<Sub> (top-level ref attr) and Объект.<ТЧ>.<Колонка>.<Sub> (tabular-section
|
||||||
|
# column ref). Mirrors Designer: the referenced catalog is adopted WITH the sub-attributes the form shows,
|
||||||
|
# otherwise the platform rejects the deep DataPath ("Неверный путь к данным").
|
||||||
|
function Borrow-DeepTargetAttrs {
|
||||||
|
param([string]$targetTypeName, [string]$targetObjName, $subAttrNames)
|
||||||
|
|
||||||
|
$encBomLocal = New-Object System.Text.UTF8Encoding($true)
|
||||||
|
|
||||||
|
# Ensure target is borrowed (shell)
|
||||||
|
if (-not (Test-ObjectBorrowed $targetTypeName $targetObjName)) {
|
||||||
|
$tSrc = Read-SourceObject $targetTypeName $targetObjName
|
||||||
|
$tBorrowedXml = Build-BorrowedObjectXml $targetTypeName $targetObjName $tSrc.Uuid $tSrc.Properties
|
||||||
|
$tTargetDir = Join-Path $extDir $childTypeDirMap[$targetTypeName]
|
||||||
|
if (-not (Test-Path $tTargetDir)) { New-Item -ItemType Directory -Path $tTargetDir -Force | Out-Null }
|
||||||
|
$tTargetFile = Join-Path $tTargetDir "${targetObjName}.xml"
|
||||||
|
[System.IO.File]::WriteAllText($tTargetFile, $tBorrowedXml, $encBomLocal)
|
||||||
|
Add-ToChildObjects $targetTypeName $targetObjName
|
||||||
|
$script:borrowedFiles += $tTargetFile
|
||||||
|
Info " Auto-borrowed for deep path: ${targetTypeName}.${targetObjName}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Resolve sub-attributes in target catalog and merge them in
|
||||||
|
$subNames = @{}
|
||||||
|
foreach ($sn in $subAttrNames) { $subNames[$sn] = $true }
|
||||||
|
$subResolved = Resolve-SourceAttributes $targetTypeName $targetObjName $subNames
|
||||||
|
if ($subResolved.Attributes.Count -gt 0) {
|
||||||
|
Merge-AttributesIntoObject $targetTypeName $targetObjName $subResolved.Attributes
|
||||||
|
|
||||||
|
# Borrow ref types referenced by the sub-attributes
|
||||||
|
$subTypeXmls = @()
|
||||||
|
foreach ($sa in $subResolved.Attributes) { $subTypeXmls += $sa.TypeXml }
|
||||||
|
$subRefTypes = Collect-ReferenceTypes $subTypeXmls
|
||||||
|
foreach ($srt in $subRefTypes) {
|
||||||
|
if (-not $childTypeDirMap.ContainsKey($srt.TypeName)) { continue }
|
||||||
|
if (Test-ObjectBorrowed $srt.TypeName $srt.ObjName) { continue }
|
||||||
|
$sSrcFile = Join-Path (Join-Path $cfgDir $childTypeDirMap[$srt.TypeName]) "$($srt.ObjName).xml"
|
||||||
|
if (-not (Test-Path $sSrcFile)) { continue }
|
||||||
|
$sSrc = Read-SourceObject $srt.TypeName $srt.ObjName
|
||||||
|
$sBorrowedXml = Build-BorrowedObjectXml $srt.TypeName $srt.ObjName $sSrc.Uuid $sSrc.Properties
|
||||||
|
$sTargetDir = Join-Path $extDir $childTypeDirMap[$srt.TypeName]
|
||||||
|
if (-not (Test-Path $sTargetDir)) { New-Item -ItemType Directory -Path $sTargetDir -Force | Out-Null }
|
||||||
|
$sTargetFile = Join-Path $sTargetDir "$($srt.ObjName).xml"
|
||||||
|
[System.IO.File]::WriteAllText($sTargetFile, $sBorrowedXml, $encBomLocal)
|
||||||
|
Add-ToChildObjects $srt.TypeName $srt.ObjName
|
||||||
|
$script:borrowedFiles += $sTargetFile
|
||||||
|
Info " Auto-borrowed (deep): $($srt.TypeName).$($srt.ObjName)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# --- 12. Helper: build borrowed object XML ---
|
# --- 12. Helper: build borrowed object XML ---
|
||||||
function Build-BorrowedObjectXml {
|
function Build-BorrowedObjectXml {
|
||||||
param(
|
param(
|
||||||
@@ -1634,6 +1661,11 @@ function Build-BorrowedObjectXml {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# DefinedType: emit the carried <Type> definition (needed for the alias to resolve, e.g. totals)
|
||||||
|
if ($typeName -eq "DefinedType" -and $sourceProps.ContainsKey("__TypeXml")) {
|
||||||
|
$sb.AppendLine("`t`t`t$($sourceProps['__TypeXml'])") | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
$sb.AppendLine("`t`t</Properties>") | Out-Null
|
$sb.AppendLine("`t`t</Properties>") | Out-Null
|
||||||
|
|
||||||
# ChildObjects (for types that need it)
|
# ChildObjects (for types that need it)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# cfe-borrow v1.7 — Borrow objects from configuration into extension (CFE)
|
# cfe-borrow v1.8 — Borrow objects from configuration into extension (CFE)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -492,6 +492,13 @@ def main():
|
|||||||
prop_node = props_node.find(f"{{{MD_NS}}}{prop_name}")
|
prop_node = props_node.find(f"{{{MD_NS}}}{prop_name}")
|
||||||
if prop_node is not None:
|
if prop_node is not None:
|
||||||
src_props[prop_name] = (prop_node.text or "").strip()
|
src_props[prop_name] = (prop_node.text or "").strip()
|
||||||
|
# DefinedType: carry the <Type> definition. A type alias is meaningless as a bare shell —
|
||||||
|
# the platform needs its underlying type (e.g. to know a column is a summable Number for totals).
|
||||||
|
if type_name == "DefinedType":
|
||||||
|
type_node = props_node.find(f"{{{MD_NS}}}Type")
|
||||||
|
if type_node is not None:
|
||||||
|
type_xml = etree.tostring(type_node, encoding="unicode")
|
||||||
|
src_props["__TypeXml"] = re.sub(r'\s+xmlns(?::\w+)?="[^"]*"', '', type_xml)
|
||||||
|
|
||||||
return {"Uuid": src_uuid, "Properties": src_props, "Element": src_el}
|
return {"Uuid": src_uuid, "Properties": src_props, "Element": src_el}
|
||||||
|
|
||||||
@@ -563,6 +570,10 @@ def main():
|
|||||||
prop_val = source_props.get(prop_name, "false")
|
prop_val = source_props.get(prop_name, "false")
|
||||||
lines.append(f"\t\t\t<{prop_name}>{prop_val}</{prop_name}>")
|
lines.append(f"\t\t\t<{prop_name}>{prop_val}</{prop_name}>")
|
||||||
|
|
||||||
|
# DefinedType: emit the carried <Type> definition (needed for the alias to resolve, e.g. totals)
|
||||||
|
if type_name == "DefinedType" and "__TypeXml" in source_props:
|
||||||
|
lines.append(f"\t\t\t{source_props['__TypeXml']}")
|
||||||
|
|
||||||
lines.append("\t\t</Properties>")
|
lines.append("\t\t</Properties>")
|
||||||
|
|
||||||
if type_name in TYPES_WITH_CHILD_OBJECTS:
|
if type_name in TYPES_WITH_CHILD_OBJECTS:
|
||||||
@@ -688,7 +699,8 @@ def main():
|
|||||||
seg1 = segments[1]
|
seg1 = segments[1]
|
||||||
if seg1 in STANDARD_FIELDS:
|
if seg1 in STANDARD_FIELDS:
|
||||||
continue
|
continue
|
||||||
deep_paths.append({"ObjectAttr": seg0, "SubAttr": seg1})
|
seg2 = segments[2] if len(segments) >= 3 else None
|
||||||
|
deep_paths.append({"ObjectAttr": seg0, "SubAttr": seg1, "SubSubAttr": seg2})
|
||||||
|
|
||||||
# Also scan <Field>Объект.X</Field> — object attributes referenced by filter/conditional-appearance
|
# Also scan <Field>Объект.X</Field> — object attributes referenced by filter/conditional-appearance
|
||||||
# fields (and dynamic lists), not via a *DataPath binding (e.g. УдалитьЮрФизЛицо). Designer borrows these too.
|
# fields (and dynamic lists), not via a *DataPath binding (e.g. УдалитьЮрФизЛицо). Designer borrows these too.
|
||||||
@@ -703,13 +715,14 @@ def main():
|
|||||||
seg1 = segments[1]
|
seg1 = segments[1]
|
||||||
if seg1 in STANDARD_FIELDS:
|
if seg1 in STANDARD_FIELDS:
|
||||||
continue
|
continue
|
||||||
deep_paths.append({"ObjectAttr": seg0, "SubAttr": seg1})
|
seg2 = segments[2] if len(segments) >= 3 else None
|
||||||
|
deep_paths.append({"ObjectAttr": seg0, "SubAttr": seg1, "SubSubAttr": seg2})
|
||||||
|
|
||||||
# Deduplicate deep paths
|
# Deduplicate deep paths
|
||||||
seen = set()
|
seen = set()
|
||||||
unique_deep = []
|
unique_deep = []
|
||||||
for dp in deep_paths:
|
for dp in deep_paths:
|
||||||
key = f"{dp['ObjectAttr']}.{dp['SubAttr']}"
|
key = f"{dp['ObjectAttr']}.{dp['SubAttr']}.{dp.get('SubSubAttr')}"
|
||||||
if key not in seen:
|
if key not in seen:
|
||||||
seen.add(key)
|
seen.add(key)
|
||||||
unique_deep.append(dp)
|
unique_deep.append(dp)
|
||||||
@@ -1065,79 +1078,93 @@ def main():
|
|||||||
|
|
||||||
# Step 5: Handle deep paths (Form mode only)
|
# Step 5: Handle deep paths (Form mode only)
|
||||||
if mode == "Form" and deep_paths:
|
if mode == "Form" and deep_paths:
|
||||||
# Filter out deep paths where ObjectAttr is a TabularSection
|
# Top-level ref deep paths: Объект.<Ref>.<Sub> — borrow the ref attribute's catalog with the sub-attribute
|
||||||
real_deep = [dp for dp in deep_paths if dp["ObjectAttr"] not in ts_names]
|
deep_by_attr = {}
|
||||||
|
for dp in deep_paths:
|
||||||
if real_deep:
|
if dp["ObjectAttr"] in ts_names:
|
||||||
info(f" Processing {len(real_deep)} deep path(s)...")
|
continue
|
||||||
|
deep_by_attr.setdefault(dp["ObjectAttr"], [])
|
||||||
# Group by ObjectAttr -> target catalog
|
if dp["SubAttr"] not in deep_by_attr[dp["ObjectAttr"]]:
|
||||||
deep_by_attr = {}
|
|
||||||
for dp in real_deep:
|
|
||||||
if dp["ObjectAttr"] not in deep_by_attr:
|
|
||||||
deep_by_attr[dp["ObjectAttr"]] = []
|
|
||||||
deep_by_attr[dp["ObjectAttr"]].append(dp["SubAttr"])
|
deep_by_attr[dp["ObjectAttr"]].append(dp["SubAttr"])
|
||||||
|
if deep_by_attr:
|
||||||
|
info(f" Processing {len(deep_by_attr)} deep path attribute(s)...")
|
||||||
for attr_name, sub_attr_names in deep_by_attr.items():
|
for attr_name, sub_attr_names in deep_by_attr.items():
|
||||||
# Find the attribute's type to determine target catalog
|
attr_info = next((a for a in src_attrs if a["Name"] == attr_name), None)
|
||||||
attr_info = None
|
|
||||||
for a in src_attrs:
|
|
||||||
if a["Name"] == attr_name:
|
|
||||||
attr_info = a
|
|
||||||
break
|
|
||||||
if not attr_info:
|
if not attr_info:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Extract catalog name from type: cfg:CatalogRef.XXX
|
|
||||||
cat_match = re.search(r'cfg:(\w+)Ref\.(\w+)', attr_info["TypeXml"])
|
cat_match = re.search(r'cfg:(\w+)Ref\.(\w+)', attr_info["TypeXml"])
|
||||||
if not cat_match:
|
if not cat_match:
|
||||||
continue
|
continue
|
||||||
|
borrow_deep_target_attrs(cat_match.group(1), cat_match.group(2), sub_attr_names)
|
||||||
|
|
||||||
target_type_name = cat_match.group(1)
|
# Tabular-section deep paths: Объект.<ТЧ>.<Колонка>.<Sub> — borrow the column's catalog with the sub-attribute
|
||||||
target_obj_name = cat_match.group(2)
|
ts_deep_by_col = {}
|
||||||
|
for dp in deep_paths:
|
||||||
# Ensure target is borrowed
|
if dp["ObjectAttr"] not in ts_names:
|
||||||
if not test_object_borrowed(target_type_name, target_obj_name):
|
continue
|
||||||
t_src = read_source_object(target_type_name, target_obj_name)
|
if not dp.get("SubSubAttr"):
|
||||||
t_borrowed_xml = build_borrowed_object_xml(target_type_name, target_obj_name, t_src["Uuid"], t_src["Properties"])
|
continue
|
||||||
t_target_dir = os.path.join(ext_dir, CHILD_TYPE_DIR_MAP[target_type_name])
|
if dp["SubSubAttr"] in STANDARD_FIELDS:
|
||||||
os.makedirs(t_target_dir, exist_ok=True)
|
continue
|
||||||
t_target_file = os.path.join(t_target_dir, f"{target_obj_name}.xml")
|
k = (dp["ObjectAttr"], dp["SubAttr"])
|
||||||
save_text_bom(t_target_file, t_borrowed_xml)
|
ts_deep_by_col.setdefault(k, [])
|
||||||
add_to_child_objects(target_type_name, target_obj_name)
|
if dp["SubSubAttr"] not in ts_deep_by_col[k]:
|
||||||
borrowed_files.append(t_target_file)
|
ts_deep_by_col[k].append(dp["SubSubAttr"])
|
||||||
info(f" Auto-borrowed for deep path: {target_type_name}.{target_obj_name}")
|
if ts_deep_by_col:
|
||||||
|
info(f" Processing {len(ts_deep_by_col)} tabular-section deep path(s)...")
|
||||||
# Resolve sub-attributes in target catalog
|
for (ts_name, col_name), sub_attr_names in ts_deep_by_col.items():
|
||||||
sub_names = {sn: True for sn in sub_attr_names}
|
ts_info = next((t for t in src_ts if t["Name"] == ts_name), None)
|
||||||
sub_resolved = resolve_source_attributes(target_type_name, target_obj_name, sub_names)
|
if not ts_info:
|
||||||
|
continue
|
||||||
if sub_resolved["Attributes"]:
|
col_info = next((c for c in ts_info["Attributes"] if c["Name"] == col_name), None)
|
||||||
merge_attributes_into_object(target_type_name, target_obj_name, sub_resolved["Attributes"])
|
if not col_info:
|
||||||
|
continue
|
||||||
# Collect and borrow ref types from deep attributes
|
cat_match = re.search(r'cfg:(\w+)Ref\.(\w+)', col_info["TypeXml"])
|
||||||
sub_type_xmls = [sa["TypeXml"] for sa in sub_resolved["Attributes"]]
|
if not cat_match:
|
||||||
sub_ref_types = collect_reference_types(sub_type_xmls)
|
continue
|
||||||
for srt in sub_ref_types:
|
borrow_deep_target_attrs(cat_match.group(1), cat_match.group(2), sub_attr_names)
|
||||||
if srt["TypeName"] not in CHILD_TYPE_DIR_MAP:
|
|
||||||
continue
|
|
||||||
if test_object_borrowed(srt["TypeName"], srt["ObjName"]):
|
|
||||||
continue
|
|
||||||
s_src_file = os.path.join(cfg_dir, CHILD_TYPE_DIR_MAP[srt["TypeName"]], f"{srt['ObjName']}.xml")
|
|
||||||
if not os.path.isfile(s_src_file):
|
|
||||||
continue
|
|
||||||
s_src = read_source_object(srt["TypeName"], srt["ObjName"])
|
|
||||||
s_borrowed_xml = build_borrowed_object_xml(srt["TypeName"], srt["ObjName"], s_src["Uuid"], s_src["Properties"])
|
|
||||||
s_target_dir = os.path.join(ext_dir, CHILD_TYPE_DIR_MAP[srt["TypeName"]])
|
|
||||||
os.makedirs(s_target_dir, exist_ok=True)
|
|
||||||
s_target_file = os.path.join(s_target_dir, f"{srt['ObjName']}.xml")
|
|
||||||
save_text_bom(s_target_file, s_borrowed_xml)
|
|
||||||
add_to_child_objects(srt["TypeName"], srt["ObjName"])
|
|
||||||
borrowed_files.append(s_target_file)
|
|
||||||
info(f" Auto-borrowed (deep): {srt['TypeName']}.{srt['ObjName']}")
|
|
||||||
|
|
||||||
info(" Main attribute borrowing complete")
|
info(" Main attribute borrowing complete")
|
||||||
|
|
||||||
|
def borrow_deep_target_attrs(target_type_name, target_obj_name, sub_attr_names):
|
||||||
|
# Borrow a deep-path target catalog together with the referenced sub-attributes, for both
|
||||||
|
# Объект.<Ref>.<Sub> and Объект.<ТЧ>.<Колонка>.<Sub>. Mirrors Designer: the referenced catalog
|
||||||
|
# is adopted WITH the sub-attributes the form shows, else the platform rejects the deep DataPath.
|
||||||
|
if not test_object_borrowed(target_type_name, target_obj_name):
|
||||||
|
t_src = read_source_object(target_type_name, target_obj_name)
|
||||||
|
t_borrowed_xml = build_borrowed_object_xml(target_type_name, target_obj_name, t_src["Uuid"], t_src["Properties"])
|
||||||
|
t_target_dir = os.path.join(ext_dir, CHILD_TYPE_DIR_MAP[target_type_name])
|
||||||
|
os.makedirs(t_target_dir, exist_ok=True)
|
||||||
|
t_target_file = os.path.join(t_target_dir, f"{target_obj_name}.xml")
|
||||||
|
save_text_bom(t_target_file, t_borrowed_xml)
|
||||||
|
add_to_child_objects(target_type_name, target_obj_name)
|
||||||
|
borrowed_files.append(t_target_file)
|
||||||
|
info(f" Auto-borrowed for deep path: {target_type_name}.{target_obj_name}")
|
||||||
|
|
||||||
|
sub_names = {sn: True for sn in sub_attr_names}
|
||||||
|
sub_resolved = resolve_source_attributes(target_type_name, target_obj_name, sub_names)
|
||||||
|
if sub_resolved["Attributes"]:
|
||||||
|
merge_attributes_into_object(target_type_name, target_obj_name, sub_resolved["Attributes"])
|
||||||
|
sub_type_xmls = [sa["TypeXml"] for sa in sub_resolved["Attributes"]]
|
||||||
|
sub_ref_types = collect_reference_types(sub_type_xmls)
|
||||||
|
for srt in sub_ref_types:
|
||||||
|
if srt["TypeName"] not in CHILD_TYPE_DIR_MAP:
|
||||||
|
continue
|
||||||
|
if test_object_borrowed(srt["TypeName"], srt["ObjName"]):
|
||||||
|
continue
|
||||||
|
s_src_file = os.path.join(cfg_dir, CHILD_TYPE_DIR_MAP[srt["TypeName"]], f"{srt['ObjName']}.xml")
|
||||||
|
if not os.path.isfile(s_src_file):
|
||||||
|
continue
|
||||||
|
s_src = read_source_object(srt["TypeName"], srt["ObjName"])
|
||||||
|
s_borrowed_xml = build_borrowed_object_xml(srt["TypeName"], srt["ObjName"], s_src["Uuid"], s_src["Properties"])
|
||||||
|
s_target_dir = os.path.join(ext_dir, CHILD_TYPE_DIR_MAP[srt["TypeName"]])
|
||||||
|
os.makedirs(s_target_dir, exist_ok=True)
|
||||||
|
s_target_file = os.path.join(s_target_dir, f"{srt['ObjName']}.xml")
|
||||||
|
save_text_bom(s_target_file, s_borrowed_xml)
|
||||||
|
add_to_child_objects(srt["TypeName"], srt["ObjName"])
|
||||||
|
borrowed_files.append(s_target_file)
|
||||||
|
info(f" Auto-borrowed (deep): {srt['TypeName']}.{srt['ObjName']}")
|
||||||
|
|
||||||
def borrow_form(type_name, obj_name, form_name, borrow_main_attr=False):
|
def borrow_form(type_name, obj_name, form_name, borrow_main_attr=False):
|
||||||
dir_name = CHILD_TYPE_DIR_MAP[type_name]
|
dir_name = CHILD_TYPE_DIR_MAP[type_name]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user