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