Как программно заполнить табличную часть 1С по значениям текущей ячейки с учетом вида тарифа

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

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

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

Анализ исходной задачи

Представим ситуацию: у нас есть документ, содержащий табличную часть ТорговыеТочки и реквизит шапки Тариф (тип ПеречислениеСсылка.ВидыТарифа). Нам нужно реализовать команду, которая берет данные из выделенной пользователем строки и копирует их во все строки таблицы. При этом, если выбран тариф «Фиксированный», копируется сумма. Если тариф «По SKU» — копируются количество и цена.

Рассмотрим, с какими сложностями столкнулся автор темы, и как их правильно решить.

Работа с текущей строкой таблицы

Для того чтобы получить данные строки, на которой в данный момент установлен курсор, мы используем свойство элемента формы ТекущиеДанные. Важно понимать разницу между элементом формы (визуальным объектом) и данными (объектом ДанныеФормыСтруктура).

Проанализируем базовый алгоритм получения текущей строки:


&НаКлиенте
Процедура ЗаполнитьПоТекущейСтроке(Команда)
    
    // Получаем текущие данные из элемента формы "ТорговыеТочки"
    ТекДанные = Элементы.ТорговыеТочки.ТекущиеДанные;
    
    // Обязательная проверка: если таблица пуста, ТекущиеДанные будут Неопределено
    Если ТекДанные = Неопределено Тогда
        Сообщить("Пожалуйста, выберите строку для копирования!");
        Возврат;
    КонецЕсли;
    
    // Далее следует логика заполнения
КонецПроцедуры

Обращение к перечислениям на клиенте

Одной из главных ошибок начинающих разработчиков является попытка прямого обращения к менеджеру перечислений на клиенте, например: Перечисления.ВидыТарифа.Фиксированный. В управляемом приложении на стороне клиента менеджеры объектов недоступны. Это приведет к ошибке компиляции.

Разберем три способа решения этой проблемы:

  1. Использование функции ПредопределенноеЗначение(). Это самый эффективный и современный способ для клиента. Он позволяет получить ссылку на объект по его строковому имени (имени в метаданных).
  2. Вызов функции на сервере. Можно написать функцию &НаСервере, которая вернет нужное значение, но это создает лишний контекстный вызов, что замедляет работу интерфейса.
  3. Булевы реквизиты формы. Можно при создании формы передать нужные ссылки в реквизиты, но это загромождает структуру данных.

Наилучшим вариантом будет использование ПредопределенноеЗначение(). Посмотрим на примере:


// Правильное сравнение перечисления на клиенте
Если Объект.Тариф = ПредопределенноеЗначение("Перечисление.ВидыТарифа.Фиксированный") Тогда
    // Ваша логика
КонецЕсли;

Реализация цикла заполнения табличной части

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


&НаКлиенте
Процедура ЗаполнитьТарифыПоВыделеннойСтроке(Команда)
    
    ТекСтрока = Элементы.ТорговыеТочки.ТекущиеДанные;
    
    // Проверка на наличие данных
    Если ТекСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Кэшируем значения перечислений для удобства
    ТарифФикс = ПредопределенноеЗначение("Перечисление.ВидыТарифа.Фиксированный");
    ТарифSKU  = ПредопределенноеЗначение("Перечисление.ВидыТарифа.ПоSKU");
    
    Если Объект.Тариф = ТарифФикс Тогда
        
        ТекСумма = ТекСтрока.Сумма;
        
        Для Каждого СтрокаТЧ Из Объект.ТорговыеТочки Цикл 
            СтрокаТЧ.Сумма = ТекСумма;
        КонецЦикла;
        
    ИначеЕсли Объект.Тариф = ТарифSKU Тогда
        
        ТекКоличество = ТекСтрока.Количество;
        ТекЦена = ТекСтрока.Цена;
        
        Для Каждого СтрокаТЧ Из Объект.ТорговыеТочки Цикл
            СтрокаТЧ.Цена = ТекЦена;
            СтрокаТЧ.Количество = ТекКоличество;
        КонецЦикла;
        
    КонецЕсли;

КонецПроцедуры

Оптимизация кода: использование метода ЗаполнитьЗначенияСвойств

Если в табличной части много колонок, которые нужно копировать, ручное присваивание становится громоздким. Мы можем оптимизировать процесс, используя встроенную функцию ЗаполнитьЗначенияСвойств. Однако помните, что на клиенте она работает только с объектами ДанныеФормыСтруктура.

Рассмотрим пример сокращения кода:


// Вместо:
// СтрокаТЧ.Цена = ТекСтрока.Цена;
// СтрокаТЧ.Количество = ТекСтрока.Количество;

// Можно использовать (если имена колонок совпадают):
ЗаполнитьЗначенияСвойств(СтрокаТЧ, ТекСтрока, "Цена, Количество");

Динамическое управление видимостью колонок

Как упоминал автор темы, при смене тарифа часто требуется менять интерфейс: скрывать ненужные колонки или менять их заголовки. Эту логику крайне важно вынести в отдельную процедуру, чтобы вызывать её в нескольких местах: при открытии формы и при изменении поля Тариф.


&НаКлиенте
Процедура ТарифПриИзменении(Элемент)
    УстановитьВидимостьКолонок();
КонецПроцедуры

&НаСервере
Процедура УстановитьВидимостьКолонок()
    
    ВидТарифа = Объект.Тариф;
    Фиксированный = Перечисления.ВидыТарифа.Фиксированный;
    
    // Управление элементами формы
    Элементы.ТорговыеТочкиСумма.Видимость = (ВидТарифа = Фиксированный);
    Элементы.ТорговыеТочкиЦена.Видимость = (ВидТарифа <> Фиксированный);
    Элементы.ТорговыеТочкиКоличество.Видимость = (ВидТарифа <> Фиксированный);
    
    // Смена заголовка программно
    Если ВидТарифа = Фиксированный Тогда
        Элементы.ТорговыеТочкиСумма.Заголовок = "Фиксированная сумма в месяц";
    КонецЕсли;

КонецПроцедуры

Типичные ошибки и способы их решения

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

  1. Не привязано событие. Как выяснилось в обсуждении, одной из причин была простая опечатка в имени процедуры. Всегда проверяйте в свойствах кнопки на форме, что в поле "Имя команды" или "Действие" указана именно ваша процедура.
  2. Контекст выполнения. Если вы пытаетесь изменить данные табличной части в функции &НаСервереБезКонтекста, у вас ничего не получится, так как эта функция не видит данные формы Объект. Используйте либо &НаКлиенте, либо &НаСервере.
  3. Типы данных. При сравнении Если Тариф = "Фиксированный" 1С сравнивает Ссылку со Строкой. Результат всегда будет Ложь. Используйте ПредопределенноеЗначение().

Рекомендации по улучшению пользовательского опыта

Когда вы реализуете групповое изменение строк, пользователю может быть неочевидно, что произошло. Хорошим тоном считается добавление оповещения после завершения цикла:

ПоказатьОповещениеПользователя("Успешно", , "Данные в таблице обновлены по тарифу: " + Объект.Тариф);

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

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

← На главную