Почему пропадает добавленная колонка в динамическом списке 1С и как это исправить

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

Всем доброго дня! Разберем весьма интересную задачу, которую многие разработчики 1С называют «загадкой динамического списка». Проанализируем ситуацию на примере конфигурации 1С:Управление торговлей 11.4, однако подобное поведение встречается и в других современных решениях: ERP, Комплексная автоматизация, ЗУП 3.1.

Допустим, стоит задача добавить дополнительную колонку в форму списка документов. Вы действуете по стандартной и проверенной технологии через расширения:

  1. Добавляете в расширение нужную форму списка (например, обработку ЖурналДокументовЗакупки и ее форму СписокДокументов).
  2. Переносите в расширение нужные документы.
  3. Модифицируете визуальный запрос динамического списка, вытягивая левым соединением необходимые данные.
  4. Размещаете добавленное поле в элементах формы и настраиваете пользовательскую видимость.

Для документов продажи все работает отлично: колонка появляется, фильтры применяются. Но при аналогичных действиях с документами закупки происходит непредвиденное. В отладчике в обработчике ПриСозданииНаСервере(После) элемент формы присутствует, и запрос выглядит корректно. Однако к моменту срабатывания ПриОткрытии колонка пропадает из видимости, как по волшебству, а в пользовательских настройках ее просто нет. Выясним причину такого поведения и найдем грамотное решение.

В чем кроется корень проблемы?

Если данные берутся корректно, права на новые реквизиты есть, а колонка все равно пропадает, первое, что мы должны проверить — не изменяется ли текст запроса программно. Посмотрим на типовой механизм 1С. В сложных журналах документов, объединяющих данные разных типов, платформа часто перестраивает запрос динамического списка на лету.

По стандартам Библиотеки стандартных подсистем (БСП), в визуальном редакторе динамического списка разработчики 1С задают лишь базовый, «заглушечный» запрос. Это нужно, чтобы в конфигураторе была видна структура полей. А вот реальный, рабочий текст собирается программно в процедуре ПриСозданииНаСервере с учетом включенных функциональных опций (ЭДО, регламентированный учет, статусы проверок).

Рассмотрим типовой код, который и удаляет наши модификации, сделанные в визуальном редакторе расширения:


Процедура НастроитьФормуПоВыбраннымОперациямИДокументам(ТЗХозОперацииИТипыДокументов)
    // ... получение данных рабочего места ...
    
    СвойстваСписка = ОбщегоНазначения.СтруктураСвойствДинамическогоСписка();
    ЗаполнитьЗначенияСвойств(СвойстваСписка, СписокДокументыЗакупки);
    
    // Вот здесь происходит полная замена текста запроса!
    СвойстваСписка.ТекстЗапроса = ТекстЗапросаСписокДокументыЗакупки();
    
    // Применение типовых автозамен для статусов
    СвойстваСписка.ТекстЗапроса = СтрЗаменить(СвойстваСписка.ТекстЗапроса, "&СтатусПроверки КАК СтатусПроверки", "НЕОПРЕДЕЛЕНО КАК УдаленСтатусПроверки");
    СвойстваСписка.ТекстЗапроса = СтрЗаменить(СвойстваСписка.ТекстЗапроса, "&ИндикаторПроверки КАК ИндикаторПроверки", "НЕОПРЕДЕЛЕНО КАК УдаленИндикаторПроверки");
    
    ОбщегоНазначения.УстановитьСвойстваДинамическогоСписка(Элементы.СписокДокументыЗакупки, СвойстваСписка);
КонецПроцедуры

Как мы видим, система полностью переопределяет ТекстЗапроса, вызывая функцию ТекстЗапросаСписокДокументыЗакупки(). Соответственно, все наши визуальные настройки затираются.

Опасное решение (как делать не нужно)

На первый взгляд, самое очевидное решение — перехватить функцию, возвращающую системный запрос, с помощью аннотации &Вместо, и вернуть наш модифицированный запрос из расширения:


&Вместо("ТекстЗапросаСписокДокументыЗакупки")
Функция ТекстЗапросаСписокДокументыЗакупки_()
    // Опасный код: возвращает визуальный запрос расширения, отсекая типовую логику
    Возврат СписокДокументыЗакупки.ТекстЗапроса;
КонецФункции

Проанализируем риски такого подхода: Это крайне небезопасный вариант. Затирая функцию целиком, вы отключаете типовую логику вычисления важных статусов (например, проверки контрагентов или ЭДО). Более того, при первом же обновлении конфигурации, если фирма 1С добавит в журнал новые обязательные параметры или колонки, у пользователей база выдаст критическую ошибку об отсутствии нужных полей.

Как правильно модифицировать динамические списки программно

Вместо жесткой подмены системного запроса, сообщество разработчиков рекомендует применять программную модификацию итогового текста. Разберем два надежных способа.

Вариант А: Безопасная модификация строки запроса через &После

Суть метода заключается в том, чтобы дождаться, пока типовой код сформирует свой запрос, а затем аккуратно встроить в него наши данные. Создаем расширение для обработчика ПриСозданииНаСервере с аннотацией &После:


&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    ТекстЗапроса = СписокДокументыЗакупки.ТекстЗапроса;
    
    // Аккуратно вставляем нужное поле в секцию ВЫБРАТЬ
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, 
        "ДокументыЗакупки.Ссылка КАК Ссылка,", 
        "ДокументыЗакупки.Ссылка КАК Ссылка,
        |   МойРегистр.МоеДопПоле КАК МоеДопПоле,");
        
    // Добавляем ЛЕВОЕ СОЕДИНЕНИЕ перед секцией ГДЕ или перед концом запроса
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, 
        "ГДЕ", 
        "ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.МойРегистр КАК МойРегистр
        |   ПО ДокументыЗакупки.Ссылка = МойРегистр.Документ
        |ГДЕ");
        
    // Применяем изменения
    СвойстваСписка = ОбщегоНазначения.СтруктураСвойствДинамическогоСписка();
    СвойстваСписка.ТекстЗапроса = ТекстЗапроса;
    ОбщегоНазначения.УстановитьСвойстваДинамическогоСписка(Элементы.СписокДокументыЗакупки, СвойстваСписка);
    
КонецПроцедуры

Таким образом, мы сохраняем весь типовой фундамент запроса, добавляя только свои куски кода.

Вариант Б: Использование аннотации &ИзменениеИКонтроль

Если функция формирования запроса слишком сложная и замена строк небезопасна, мы можем использовать &ИзменениеИКонтроль. Это позволяет вставить добавление колонок прямо в исходный код платформы. Платформа сама будет контролировать при обновлениях, не изменился ли критично исходный код 1С.


&ИзменениеИКонтроль("ТекстЗапросаСписокДокументыЗакупки")
Функция Расш_ТекстЗапросаСписокДокументыЗакупки()
    
    ТекстЗапроса = "... типовой текст запроса ...";
    
    #Вставка
    ТекстЗапроса = ТекстЗапроса + " ... наше левое соединение и поле ...";
    #КонецВставки
    
    Возврат ТекстЗапроса;
    
КонецФункции

Программное добавление элементов формы (Колонок)

Часто бывает так, что даже при успешной модификации запроса колонка, добавленная визуально через редактор формы в расширении, все равно остается пустой. Это происходит потому, что в момент полной перезаписи запроса типовым кодом свойство ПутьКДанным у визуально созданного элемента может потерять связь с динамическим списком.

Чтобы избежать этого, создадим саму колонку программно в том же обработчике ПриСозданииНаСервере:


НовыйЭлемент = Элементы.Добавить("СписокДокументыЗакупкиМоеДопПоле", Тип("ПолеФормы"), Элементы.СписокДокументыЗакупки);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеНадписи;
НовыйЭлемент.ПутьКДанным = "СписокДокументыЗакупки.МоеДопПоле";
НовыйЭлемент.Заголовок = "Доп. Инфо";

Используя комплексный подход (модификацию строки текста запроса и программное создание элемента формы), вы гарантированно решите загадку пропадающих колонок, сохранив при этом типовой функционал 1С и обезопасив базу при будущих обновлениях.

← На главную