fix(cfe-borrow): стандартные поля и Items-пути в связях параметров выбора

Эталоны Issue66Example7 и 7_1 (три формы, оба режима) показали, что прошлая
правка была неполной в двух местах.

1. Путь на СТАНДАРТНОЕ поле объекта («Объект.Owner», «Объект.Date», «Объект.Ref»)
текстом не разрешается даже при заимствованном основном реквизите: платформа
отвергает загрузку «Неверный путь к данным». Мы такой путь оставляли текстом.
Конфигуратор оставляет ссылку на сам реквизит — «1». Теперь так же: реквизит
объекта (есть в ChildObjects) остаётся читаемым текстом, стандартное поле
сводится к id основного реквизита. Проверено загрузкой: было падение, стало
успешно; выход совпал с эталоном 7_1 дословно.

2. Пути «Items.<Элемент>.CurrentData.<Поле>» при заимствованном основном
реквизите разрешаются текстом — элементы формы на месте, а их данные доступны
через основной реквизит. Конфигуратор их и не трогает. Прошлая правка вырезала
их в обоих режимах, то есть теряла рабочие связи. Теперь вырезаются только без
заимствования основного реквизита, где они действительно не разрешаются.

Уточнение по кодировке для будущей работы: без заимствования Конфигуратор
кодирует стандартное поле как «1/-N» (Owner у справочника и Ref у документа
дали -5, Date у документа -3), а Items-путь — как
«<id элемента>:02023637-7868-4a5f-8576-835a76e0c9ba/0:<uuid поля>». Таблицу
отрицательных индексов по трём точкам не построить, поэтому в скелетном режиме
обе разновидности по-прежнему вырезаются с предупреждением.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-14 18:42:20 +03:00
co-authored by Claude Opus 5
parent ace9e29e91
commit 112166dc0c
23 changed files with 1067 additions and 8 deletions
@@ -87,8 +87,14 @@ function Rewrite-ChoiceParameterLinks {
# Путь на основной реквизит формы
if ($mainPat -and $path -match "^${mainPat}\.(.+)$") {
if ($mainAttrBorrowed) { return $link }
$attrName = $Matches[1]
if ($mainAttrBorrowed) {
# Реквизит объекта разрешается текстом и остаётся читаемым. Стандартное поле
# («Объект.Owner», «Объект.Date») — нет: платформа отвергает «Неверный путь к данным».
# Конфигуратор в этом случае оставляет ссылку на сам реквизит (эталон Issue66Example7_1).
if ($attrUuids.ContainsKey($attrName)) { return $link }
return [regex]::Replace($link, '(<xr:DataPath[^>]*>)[^<]+(</xr:DataPath>)', "`${1}${mainId}`${2}")
}
if ($attrUuids.ContainsKey($attrName)) {
return [regex]::Replace($link, '(<xr:DataPath[^>]*>)[^<]+(</xr:DataPath>)', "`${1}${mainId}/0:$($attrUuids[$attrName])`${2}")
}
@@ -103,6 +109,11 @@ function Rewrite-ChoiceParameterLinks {
# Уже непрозрачный путь (форма-источник сама из расширения) — не трогаем
if ($path -match '^\d') { return $link }
# С заимствованным основным реквизитом текстовый путь разрешается: элементы формы на месте,
# а их данные доступны через основной реквизит. Конфигуратор такие пути и оставляет текстом
# (эталон Issue66Example7_1: «Items.Товары.CurrentData.Характеристика» перенесён как есть).
if ($mainAttrBorrowed) { return $link }
# Прочее текстом не разрешается: платформа отвергает загрузку «Неверный путь к полю».
# Сюда попадают «Items.<Элемент>.CurrentData.<Поле>» — их кодировка непрозрачна и по
# имеющимся эталонам не воспроизводима. Связь параметров выбора — удобство подбора, а не
@@ -826,8 +837,10 @@ function Borrow-Form {
# uuid реквизитов объекта нужны ровно там, где основной реквизит НЕ попал в форму:
# только тогда путь «<основной>.X» переводится в непрозрачный вид
$srcAttrUuids = @{}
if (-not $mainAttrInfo) { $srcAttrUuids = Get-SourceAttributeUuids $typeName $objName }
# Имена реквизитов объекта нужны в обоих режимах: без заимствования — чтобы построить
# непрозрачный путь, с заимствованием — чтобы отличить реквизит (разрешается текстом) от
# стандартного поля (не разрешается)
$srcAttrUuids = Get-SourceAttributeUuids $typeName $objName
# AutoCommandBar: keep ChildItems (buttons with CommandName→0), Autofill→false
$autoCmdXml = ""
@@ -107,9 +107,15 @@ def rewrite_choice_parameter_links(xml, attr_uuids, form_attr_ids, main_attr_nam
if main_pat:
mm = re.match('^' + main_pat + r'\.(.+)$', path)
if mm:
if main_attr_borrowed:
return link
attr_name = mm.group(1)
if main_attr_borrowed:
# Реквизит объекта разрешается текстом и остаётся читаемым. Стандартное поле
# («Объект.Owner», «Объект.Date») — нет: платформа отвергает «Неверный путь к данным».
# Конфигуратор в этом случае оставляет ссылку на сам реквизит (эталон Issue66Example7_1).
if attr_name in attr_uuids:
return link
return re.sub(r'(<xr:DataPath[^>]*>)[^<]+(</xr:DataPath>)',
lambda x: f"{x.group(1)}{main_id}{x.group(2)}", link)
if attr_name in attr_uuids:
return re.sub(r'(<xr:DataPath[^>]*>)[^<]+(</xr:DataPath>)',
lambda x: f"{x.group(1)}{main_id}/0:{attr_uuids[attr_name]}{x.group(2)}", link)
@@ -124,6 +130,12 @@ def rewrite_choice_parameter_links(xml, attr_uuids, form_attr_ids, main_attr_nam
if re.match(r'^\d', path):
return link
# С заимствованным основным реквизитом текстовый путь разрешается: элементы формы на месте,
# а их данные доступны через основной реквизит. Конфигуратор такие пути и оставляет текстом
# (эталон Issue66Example7_1: «Items.Товары.CurrentData.Характеристика» перенесён как есть).
if main_attr_borrowed:
return link
# Прочее текстом не разрешается: платформа отвергает загрузку «Неверный путь к полю».
# Сюда попадают «Items.<Элемент>.CurrentData.<Поле>» — их кодировка непрозрачна и по
# имеющимся эталонам не воспроизводима. Связь параметров выбора — удобство подбора, а не
@@ -1659,9 +1671,10 @@ def main():
# Основной реквизит исходной формы: его имя — корень путей к данным, которые нужно сохранить
# («Объект.» у формы объекта, «Список.» у формы списка, «Запись.» у формы записи регистра)
main_attr_info = src_main_info if borrow_main_attr else None
# uuid реквизитов объекта нужны ровно там, где основной реквизит НЕ попал в форму:
# только тогда путь «<основной>.X» переводится в непрозрачный вид
src_attr_uuids = {} if main_attr_info else get_source_attribute_uuids(type_name, obj_name)
# Имена реквизитов объекта нужны в обоих режимах: без заимствования — чтобы построить
# непрозрачный путь, с заимствованием — чтобы отличить реквизит (разрешается текстом) от
# стандартного поля (не разрешается)
src_attr_uuids = get_source_attribute_uuids(type_name, obj_name)
main_attr_name = main_attr_info["Name"] if main_attr_info else ""
if borrow_main_attr and main_attr_info is None:
warn(" У формы нет основного реквизита — -BorrowMainAttribute проигнорирован")