Как программно добавить колонки в динамический список и вывести остатки по организациям без дублей

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

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

В этой статье мы подробно разберем, как модифицировать текст запроса динамического списка, как избежать «размножения» строк при соединении с таблицами остатков и как программно вывести новые данные на форму.

Анализ проблемы: почему появляются дубли

Рассмотрим стандартную ситуацию. У нас есть основной запрос динамического списка, который выбирает данные из справочника Номенклатура. Нам нужно добавить данные об остатках по каждой организации. Если мы просто добавим ЛЕВОЕ СОЕДИНЕНИЕ с регистром накопления по полю Номенклатура, то в результате выполнения запроса для одной позиции номенклатуры будет получено столько строк, сколько организаций имеют остатки по этому товару.

Динамический список крайне чувствителен к дублированию ключевых полей (обычно это ссылка на объект). Как только платформа обнаруживает две строки с одинаковой ссылкой, она выдает ошибку: «Обнаружено дублирование ключевых значений». Чтобы решить эту проблему, нам нужно выполнить операцию транспонирования: превратить строки с организациями в отдельные колонки для каждой номенклатуры.

Шаг 1. Программное изменение текста запроса

Первым делом проанализируем, как должен выглядеть итоговый запрос. Чтобы данные по организациям выстроились в одну строку, мы будем использовать группировку и конструкцию ВЫБОР КОГДА... внутри агрегатной функции СУММА. Рассмотрим этот подход на примере.

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


// Пример формирования текста запроса для трех организаций
ТекстЗапроса = 
"ВЫБРАТЬ
|	Номенклатура.Ссылка КАК Ссылка,
|	Номенклатура.Код КАК Код,
|	Номенклатура.Наименование КАК Наименование,
|	СУММА(ВЫБОР КОГДА Остатки.Организация = &Организация1 ТОГДА Остатки.В наличии ИНАЧЕ 0 КОНЕЦ) КАК Остаток_Организация1,
|	СУММА(ВЫБОР КОГДА Остатки.Организация = &Организация2 ТОГДА Остатки.В наличии ИНАЧЕ 0 КОНЕЦ) КАК Остаток_Организация2
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыОрганизаций.Остатки КАК Остатки
|		ПО Номенклатура.Ссылка = Остатки.Номенклатура
|ГРУППИРОВАТЬ ПО
|	Номенклатура.Ссылка,
|	Номенклатура.Код,
|	Номенклатура.Наименование";

Обратите внимание на важный момент: использование псевдонимов полей (Остаток_Организация1). Они должны быть уникальными и предсказуемыми, чтобы мы могли позже обратиться к ним при создании элементов формы.

Шаг 2. Реализация динамического цикла

Поскольку количество организаций заранее неизвестно, мы должны сформировать текст запроса в цикле. Проанализируем, как это реализовать в коде:


// Получаем массив или таблицу нужных организаций
СписокОрганизаций = ПолучитьАктуальныеОрганизации(); 

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

// Вставляем сформированные поля в основной запрос ДС
Список.ТекстЗапроса = СтрЗаменить(Список.ТекстЗапроса, "Номенклатура.Наименование", "Номенклатура.Наименование" + ТекстПолейОрганизаций);

// Не забываем установить параметры для каждой организации
Для Каждого ТекущаяОрганизация Из СписокОрганизаций Цикл
    ИмяПоля = "Остаток_" + СтрЗаменить(ТекущаяОрганизация.УникальныйИдентификатор(), "-", "_");
    Список.Параметры.УстановитьЗначениеПараметра("Орг_" + ИмяПоля, ТекущаяОрганизация);
КонецЦикла;

Шаг 3. Программное добавление колонок на форму

После того как мы изменили ТекстЗапроса, поля появились в схеме компоновки данных динамического списка, но они еще не видны пользователю. Выясним, как вывести их на форму в виде колонок таблицы. Нам потребуется метод Элементы.Добавить().

Рассмотрим алгоритм добавления визуальных элементов:

  1. Определяем родительский элемент (таблицу, в которой отображается динамический список).
  2. В цикле по организациям создаем новые элементы формы типа ПолеФормы.
  3. Устанавливаем свойство ПутьКДанным, связывая элемент с полем из запроса ДС (например, "Список.Остаток_Организация1").
  4. Задаем заголовок (наименование организации) и вид поля.

Для Каждого ТекущаяОрганизация Из СписокОрганизаций Цикл
    ИмяПоля = "Остаток_" + СтрЗаменить(ТекущаяОрганизация.УникальныйИдентификатор(), "-", "_");
    
    // Добавляем элемент на форму
    НоваяКолонка = Элементы.Добавить(ИмяПоля, Тип("ПолеФормы"), Элементы.Список);
    НоваяКолонка.Заголовок = Строка(ТекущаяОрганизация);
    НоваяКолонка.Вид = ВидПоляФормы.ПолеНадписи; // Или ПолеВвода, если нужно редактирование
    НоваяКолонка.ПутьКДанным = "Список." + ИмяПоля; // "Список" - это имя реквизита ДС на форме
КонецЦикла;

Важные нюансы при работе в УТ 11 (Подбор товаров)

Если вы работаете в конфигурации Управление торговлей 11, важно помнить, что механизм подбора товаров довольно сложен. Модификация текста запроса напрямую может конфликтовать с типовыми механизмами фильтрации. Рассмотрим рекомендации по внедрению в такие системы:

Подведем итоги

Реализация динамических колонок — это двухэтапный процесс. Сначала мы подготавливаем данные в запросе, используя агрегатные функции для «схлопывания» дублей в одну строку. Затем мы программно создаем интерфейсные элементы, которые отображают эти данные пользователю.

Использование конструкции СУММА(ВЫБОР КОГДА...) — это классический и наиболее надежный способ транспонирования данных в 1С. Он позволяет сохранить функциональность динамического списка (поиск, отборы, сортировка) и при этом предоставить пользователю актуальную информацию в удобном табличном виде.

← На главную