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

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

Рассмотрим достаточно распространенную задачу, с которой часто сталкиваются начинающие разработчики 1С во время стажировок или при доработке конфигураций. Суть задачи: в документе «Заказ клиента» необходимо по нажатию специальной кнопки автоматически добавлять в табличную часть набор бесплатных товаров для клиента (например, 1 коробку, 6 салфеток и соус). Разберем по шагам, как правильно реализовать данный функционал, какие ошибки часто допускаются и какие альтернативные подходы существуют.

Типовые механизмы вместо программирования

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

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

Вариант 1: Использование предопределенных значений на клиенте

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

Посмотрим на пример реализации данного подхода:


&НаКлиенте
Процедура ДобавитьНабор(Команда)
    
    // Добавляем коробку
    НовСтр = Объект.СписокТоваров.Добавить();
    НовСтр.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Коробка");
    НовСтр.Количество = 1;
    
    // Добавляем салфетки
    НовСтр = Объект.СписокТоваров.Добавить();
    НовСтр.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Салфетка");
    НовСтр.Количество = 6;
    
    // Добавляем соус
    НовСтр = Объект.СписокТоваров.Добавить();
    НовСтр.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Соус");
    НовСтр.Количество = 1;
    
КонецПроцедуры

Этот метод работает быстро, так как обращение к предопределенным данным на управляемых формах кэшируется.

Вариант 2: Поиск по коду на сервере (с учетом оптимизации)

Если предопределенных значений нет, нам потребуется выполнить код на сервере. При этом многие разработчики совершают ошибку, используя методы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы для работы с табличной частью. Проанализируем, почему это избыточно.

В управляемом приложении табличная часть документа на форме имеет тип ДанныеФормыКоллекция. Мы можем добавлять в нее строки напрямую методом Добавить() без конвертации всего тяжелого объекта документа туда-и-обратно. Интерфейс формы обновится автоматически.


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

    // Работаем напрямую с коллекцией данных формы
    НовСтр = Объект.СписокТоваров.Добавить();
    НовСтр.Номенклатура = ТоварКоробка;
    НовСтр.Количество = 1;
    
    НовСтр = Объект.СписокТоваров.Добавить();
    НовСтр.Номенклатура = ТоварСалфетка;
    НовСтр.Количество = 6;
    
    НовСтр = Объект.СписокТоваров.Добавить();
    НовСтр.Номенклатура = ТоварСоус;
    НовСтр.Количество = 1;

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

Вариант 3: Использование запросов и правильная архитектура данных

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

Искать элементы через оператор запроса ПОДОБНО "%Соус%" — крайне ненадежно. В базу могут добавить товар «Соусник» или «Соус для салата (платный)», и этот алгоритм отработает неверно. Вместо этого следует создать отдельный Регистр сведений (например, «Состав бесплатных наборов») или добавить реквизит типа Булево в саму номенклатуру (например, ЭтоБесплатныйТоварДоставки).

Рассмотрим пример правильного запроса, если мы используем реквизит в справочнике:


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

Важный нюанс: Обратите внимание на использование метода ЗаполнитьЗначенияСвойств. Чтобы он отработал корректно и товары не добавились «пустыми», псевдонимы полей в тексте запроса (в нашем случае КАК Номенклатура и КАК Количество) должны строго, вплоть до символа, совпадать с именами колонок табличной части документа.

Лучшие практики и защита от ошибок

  1. Защита от дублирования строк. Код выше добавляет товары каждый раз при нажатии кнопки. Если пользователь нажмет на нее несколько раз случайно, бесплатные товары добавятся многократно. Хорошей практикой является предварительная очистка старых автоматически добавленных строк. Можно искать строки по признаку (например, цена = 0) и удалять их перед добавлением новых, либо проверять существование нужной номенклатуры в табличной части с помощью метода Объект.СписокТоваров.НайтиСтроки().
  2. Использование обработок заполнения. Вместо размещения отдельной кнопки на самой форме документа (что требует снятия формы с поддержки и усложняет будущие обновления), стандартом платформы является использование механизма «Заполнение табличных частей». Создается внешняя обработка вида «Заполнение объекта», которая добавляет свою команду в штатное меню «Заполнить» над табличной частью. Это позволяет сохранить типовую конфигурацию в целостности.

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

← На главную