Как реализовать таблицу с документами и динамическими колонками-складами для выбора склада флажками?

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

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

Анализ постановки задачи

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

Шаг 1: Подготовка данных и получение списка складов

Для начала проанализируем, какие данные нам понадобятся. Нам нужны все актуальные склады и список документов за определенный период. Сначала получим список складов, которые станут нашими колонками. Важно помнить, что имена колонок в 1С должны соответствовать правилам идентификаторов (не содержать пробелов и спецсимволов).

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Склады.Ссылка КАК Ссылка,
    |	Склады.Наименование КАК Наименование
    |ИЗ
    |	Справочник.Склады КАК Склады
    |ГДЕ
    |	НЕ Склады.ПометкаУдаления";

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

Шаг 2: Программное создание реквизитов формы

Теперь выясним причину, почему нельзя просто добавить колонки в таблицу значений. На управляемых формах структура данных (реквизиты) отделена от визуального представления (элементы). Поэтому сначала мы должны изменить структуру реквизитов формы с помощью метода ИзменитьРеквизиты. Мы добавим новые реквизиты в нашу таблицу значений на форме, которая, предположим, называется ТаблицаДокументов.

Рассмотрим подробнее этот процесс. Нам нужно создать массив объектов РеквизитФормы. Каждый реквизит будет иметь тип Булево, так как нам нужны флажки.


ДобавляемыеРеквизиты = Новый Массив;
Для Каждого Склад Из МассивСкладов Цикл
    НовыйРеквизит = Новый РеквизитФормы(Склад.Имя, Новый ОписаниеТипов("Булево"), "ТаблицаДокументов", Склад.Заголовок);
    ДобавляемыеРеквизиты.Добавить(НовыйРеквизит);
КонецЦикла;

// Добавляем реквизиты на форму
ЭтаФорма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);

Шаг 3: Динамическое создание элементов формы

После того как данные (реквизиты) созданы, их нужно отобразить. Проанализируем ситуацию: нам нужно создать элементы типа ПолеФормы и разместить их внутри таблицы. Выясним, как это сделать программно:


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

Использование метода УстановитьДействие позволяет нам назначить одну процедуру-обработчик для всех динамических колонок, что значительно упрощает код.

Шаг 4: Заполнение таблицы данными

Теперь нам нужно заполнить нашу таблицу значениями. Проанализируем, как связать документы и склады. Мы выполняем запрос к документам ПриобретениеТоваровУслуг, получаем их текущие склады и заполняем таблицу. Если склад в документе совпадает с одной из наших динамических колонок, мы ставим Истина.

Посмотрим на пример логики заполнения:


// Получаем данные документов запросом
// ... (Запрос к ПриобретениеТоваровУслуг) ...

ВыборкаДок = ЗапросДокументы.Выполнить().Выбрать();
Пока ВыборкаДок.Следующий() Цикл
    НоваяСтрока = ТаблицаДокументов.Добавить();
    НоваяСтрока.Документ = ВыборкаДок.Ссылка;
    
    // Ищем колонку, соответствующую складу документа
    Для Каждого Склад Из МассивСкладов Цикл
        Если ВыборкаДок.Склад = Склад.Ссылка Тогда
            НоваяСтрока[Склад.Имя] = Истина;
            Прервать;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Шаг 5: Реализация интерактивности (выбор только одного склада)

Важный момент: если документ может быть оприходован только на один склад, нам нужно реализовать поведение "радиокнопки". При установке флажка в одной колонке, в остальных колонках этой же строки флажки должны сниматься. Разберем, как это сделать в обработчике ПриИзменении.


&НаКлиенте
Процедура Подключаемый_ПриИзмененииФлажкаСклада(Элемент)
    ТекущаяСтрока = Элементы.ТаблицаДокументов.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ИмяТекущейКолонки = Элемент.Имя;
    // Отрезаем префикс таблицы из имени элемента, чтобы получить имя реквизита
    ИмяРеквизита = СтрЗаменить(ИмяТекущейКолонки, "ТаблицаДокументов", "");
    
    // Если флажок сняли - ничего не делаем, или возвращаем склад по умолчанию
    Если Не ТекущаяСтрока[ИмяРеквизита] Тогда
        Возврат;
    КонецЕсли;
    
    // Если флажок поставили - обходим все колонки складов и снимаем остальные
    // Для этого заранее сохраните список имен колонок в переменную формы или через свойства элементов
    Для Каждого СтрСклад Из МассивИменКолонок Склад Цикл
        Если СтрСклад <> ИмяРеквизита Тогда
            ТекущаяСтрока[СтрСклад] = Ложь;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Шаг 6: Запись данных и проведение документов

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

Рассмотрим логику сохранения на сервере:


&НаСервере
Процедура ЗаписатьИзмененияНаСервере()
    Для Каждого СтрокаТЗ Из ТаблицаДокументов Цикл
        ВыбранныйСклад = Неопределено;
        
        // Определяем, какой склад выбран по флажку
        Для Каждого Склад Из МассивСкладов Цикл
            Если СтрокаТЗ[Склад.Имя] Тогда
                ВыбранныйСклад = Склад.Ссылка;
                Прервать;
            КонецЕсли;
        КонецЦикла;
        
        Если ЗначениеЗаполнено(ВыбранныйСклад) Тогда
            ОбъектДок = СтрокаТЗ.Документ.ПолучитьОбъект();
            Если ОбъектДок.Склад <> ВыбранныйСклад Тогда
                ОбъектДок.Склад = ВыбранныйСклад;
                // Записываем и проводим, если нужно
                Попытка
                    ОбъектДок.Записать(РежимЗаписиДокумента.Проведение);
                Исключение
                    Сообщить("Ошибка при проведении документа " + ОбъектДок);
                КонецПопытки;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Важные рекомендации и нюансы

Проанализируем возможные проблемы производительности. Если в вашей базе данных сотни складов, создание такого количества колонок приведет к тому, что форма будет открываться очень медленно. В этом случае обязательно внедряйте фильтры (например, по группе складов или по территории), чтобы в матрице одновременно отображалось не более 15-20 колонок.

Также стоит обратить внимание на структуру самих документов. В конфигурациях вроде 1С:Управление торговлей 11 или ERP склад может указываться не только в шапке, но и в табличной части (если включена соответствующая настройка). В такой ситуации ваша обработка должна корректно перезаписывать склад во всех строках товаров документа.

В качестве альтернативы использованию ТаблицыЗначений можно рассмотреть ПолеТабличногоДокумента. Оно работает быстрее при большом количестве ячеек и позволяет рисовать более сложные сетки, однако программная обработка кликов в нем сложнее, так как требует вычисления координат ячейки или использования расшифровок.

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

← На главную