Рассмотрим достаточно распространенную задачу, с которой часто сталкиваются начинающие разработчики 1С во время стажировок или при доработке конфигураций. Суть задачи: в документе «Заказ клиента» необходимо по нажатию специальной кнопки автоматически добавлять в табличную часть набор бесплатных товаров для клиента (например, 1 коробку, 6 салфеток и соус). Разберем по шагам, как правильно реализовать данный функционал, какие ошибки часто допускаются и какие альтернативные подходы существуют.
Прежде чем приступать к написанию кода, проанализируем ситуацию с точки зрения архитектуры современных решений 1С. В типовых конфигурациях (таких как «Управление торговлей 11», «Комплексная автоматизация 2», «ERP») задачу добавления бесплатных товаров правильнее решать вообще без программирования.
Для этого используется стандартная подсистема автоматических скидок и наценок. Достаточно создать правило с типом скидки «Подарок». Это позволит пользователям или маркетологам самостоятельно настраивать условия выдачи подарков (например, при достижении суммы заказа или покупке определенного товара) без изменения конфигурации. Однако, если конфигурация самописная или стоит жесткое требование реализовать именно программную кнопку, рассмотрим технические варианты решения.
Если состав бесплатного набора фиксирован и редко меняется, отличным решением будет использование предопределенных элементов справочника Номенклатура. Добавив нужные элементы в конфигураторе (например, элементы с именами Коробка, Салфетка, Соус), мы можем заполнять табличную часть прямо на клиенте, избегая лишних серверных вызовов.
Посмотрим на пример реализации данного подхода:
&НаКлиенте
Процедура ДобавитьНабор(Команда)
// Добавляем коробку
НовСтр = Объект.СписокТоваров.Добавить();
НовСтр.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Коробка");
НовСтр.Количество = 1;
// Добавляем салфетки
НовСтр = Объект.СписокТоваров.Добавить();
НовСтр.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Салфетка");
НовСтр.Количество = 6;
// Добавляем соус
НовСтр = Объект.СписокТоваров.Добавить();
НовСтр.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.Соус");
НовСтр.Количество = 1;
КонецПроцедуры
Этот метод работает быстро, так как обращение к предопределенным данным на управляемых формах кэшируется.
Если предопределенных значений нет, нам потребуется выполнить код на сервере. При этом многие разработчики совершают ошибку, используя методы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы для работы с табличной частью. Проанализируем, почему это избыточно.
В управляемом приложении табличная часть документа на форме имеет тип ДанныеФормыКоллекция. Мы можем добавлять в нее строки напрямую методом Добавить() без конвертации всего тяжелого объекта документа туда-и-обратно. Интерфейс формы обновится автоматически.
&НаСервере
Процедура ДобавитьНаборНаСервере()
// Получаем ссылки на товары по коду
ТоварКоробка = Справочники.Номенклатура.НайтиПоКоду("00001");
ТоварСалфетка = Справочники.Номенклатура.НайтиПоКоду("00002");
ТоварСоус = Справочники.Номенклатура.НайтиПоКоду("00003");
Если Не ЗначениеЗаполнено(ТоварКоробка) Тогда
Возврат; // Обработка ситуации, если товар не найден
КонецЕсли;
// Работаем напрямую с коллекцией данных формы
НовСтр = Объект.СписокТоваров.Добавить();
НовСтр.Номенклатура = ТоварКоробка;
НовСтр.Количество = 1;
НовСтр = Объект.СписокТоваров.Добавить();
НовСтр.Номенклатура = ТоварСалфетка;
НовСтр.Количество = 6;
НовСтр = Объект.СписокТоваров.Добавить();
НовСтр.Номенклатура = ТоварСоус;
НовСтр.Количество = 1;
КонецПроцедуры
Если список бесплатных товаров может динамически меняться, жестко прописывать их коды в конфигурации — плохая практика. Выясним причину: каждый раз, когда состав подарка изменится, придется переписывать код.
Искать элементы через оператор запроса ПОДОБНО "%Соус%" — крайне ненадежно. В базу могут добавить товар «Соусник» или «Соус для салата (платный)», и этот алгоритм отработает неверно. Вместо этого следует создать отдельный Регистр сведений (например, «Состав бесплатных наборов») или добавить реквизит типа Булево в саму номенклатуру (например, ЭтоБесплатныйТоварДоставки).
Рассмотрим пример правильного запроса, если мы используем реквизит в справочнике:
&НаСервере
Процедура ЗаполнитьБесплатнымиТоварамиНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Номенклатура,
| 1 КАК Количество
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоБесплатныйТоварДоставки = ИСТИНА
| И Номенклатура.ПометкаУдаления = ЛОЖЬ";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НовСтр = Объект.СписокТоваров.Добавить();
ЗаполнитьЗначенияСвойств(НовСтр, Выборка);
КонецЦикла;
КонецПроцедуры
Важный нюанс: Обратите внимание на использование метода ЗаполнитьЗначенияСвойств. Чтобы он отработал корректно и товары не добавились «пустыми», псевдонимы полей в тексте запроса (в нашем случае КАК Номенклатура и КАК Количество) должны строго, вплоть до символа, совпадать с именами колонок табличной части документа.
Объект.СписокТоваров.НайтиСтроки().Применяя описанные подходы, вы сможете создать надежный, быстро работающий и легко поддерживаемый механизм добавления строк в табличные части документов.