При разработке и доработке интерфейсов в «1С:Предприятии 8.3» часто возникает задача: отобразить в форме списка документов данные, которые пользователь видит в форме самого документа (например, строку с номером и датой подчиненного счета-фактуры). При попытке просто вытащить соответствующий элемент формы в список разработчики сталкиваются с трудностями. Разберем природу этой проблемы и рассмотрим правильные варианты реализации задачи.
Проанализируем архитектуру управляемых форм. Реквизит формы (в отличие от реквизита объекта метаданных) существует исключительно в контексте открытой формы в оперативной памяти клиента и сервера. Значение такого реквизита не хранится в таблицах базы данных, а вычисляется программным кодом при открытии формы или изменении других данных.
Динамический список работает принципиально иначе: он считывает данные напрямую из базы с помощью SQL-запроса порциями по мере прокрутки таблицы на клиенте. Список документов физически не имеет доступа к объектам контекста формы конкретного документа. Создание дополнительного реквизита объекта в метаданных для хранения расчетной строки также не всегда оправдано: реквизит в базе данных требует постоянного контроля актуализации при любых изменениях связанных документов. Поэтому правильный путь — получать данные непосредственно из базы при формировании списка.
Рассмотрим основной и наиболее универсальный метод — включение необходимых данных в текст запроса самого динамического списка. В конфигурации «Бухгалтерия предприятия 3.0» информация о счетах-фактурах хранится в подчиненных документах, ссылающихся на документ-основание через табличную часть ДокументыОснования.
Разберем по шагам порядок настройки:
Список (тип ДинамическийСписок) установим флаг ПроизвольныйЗапрос.Посмотрим на пример текста запроса для динамического списка документов «Корректировка поступления»:
ВЫБРАТЬ
ДокументКорректировка.Ссылка КАК Ссылка,
ДокументКорректировка.ПометкаУдаления КАК ПометкаУдаления,
ДокументКорректировка.Номер КАК Номер,
ДокументКорректировка.Дата КАК Дата,
ДокументКорректировка.Проведен КАК Проведен,
ДокументКорректировка.Контрагент КАК Контрагент,
ДокументКорректировка.СуммаДокумента КАК СуммаДокумента,
ВложенныйЗапрос.ПредставлениеСФ КАК ПредставлениеСФ
ИЗ
Документ.КорректировкаПоступления КАК ДокументКорректировка
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
СФОснования.ДокументОснование КАК ДокументОснование,
МАКСИМУМ(СФ.Номер + " от " + ФОРМАТ(СФ.Дата, "ДФ=dd.MM.yyyy")) КАК ПредставлениеСФ
ИЗ
Документ.СчетФактураПолученный.ДокументыОснования КАК СФОснования
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СчетФактураПолученный КАК СФ
ПО СФОснования.Ссылка = СФ.Ссылка
И НЕ СФ.ПометкаУдаления
СГРУППИРОВАТЬ ПО
СФОснования.ДокументОснование
) КАК ВложенныйЗапрос
ПО ВложенныйЗапрос.ДокументОснование = ДокументКорректировка.Ссылка
Преимущества подхода с запросом:
Если логика формирования надписи слишком сложна для языка запросов (например, вызывает типовые функции подсистемы НДС с множеством проверок статусов), рассмотрим программное заполнение строк на сервере.
В динамическом списке управляемой формы предусмотрено серверное событие ПриПолученииДанныхНаСервере. Оно срабатывает только для тех строк, которые фактически отображаются на экране пользователя в текущий момент.
Разберем по шагам реализацию этого метода:
Строка), не привязывая ее к реквизитам динамического списка.СписокПриПолученииДанныхНаСервере.ОформленияСтрок извлечем массив ссылок отображаемых документов методом ПолучитьКлючи().ОформленияСтрок.Посмотрим на пример программного кода обработчика события:
&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(Элемент, ОформленияСтрок)
МассивСсылок = ОформленияСтрок.ПолучитьКлючи();
Если МассивСсылок.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СФОснования.ДокументОснование КАК ДокументОснование,
| СФ.Ссылка КАК СчетФактура,
| СФ.Номер КАК Номер,
| СФ.Дата КАК Дата,
| СФ.Проведен КАК Проведен
|ИЗ
| Документ.СчетФактураПолученный.ДокументыОснования КАК СФОснования
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СчетФактураПолученный КАК СФ
| ПО СФОснования.Ссылка = СФ.Ссылка
|ГДЕ
| СФОснования.ДокументОснование В(&МассивСсылок)
| И НЕ СФ.ПометкаУдаления";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Выборка = Запрос.Выполнить().Выбрать();
СоответствиеДанных = Новый Соответствие;
Пока Выборка.Следующий() Цикл
ТекстНадписи = "№ " + СокрЛП(Выборка.Номер) + " от " + Формат(Выборка.Дата, "ДФ=dd.MM.yyyy");
СоответствиеДанных.Вставить(Выборка.ДокументОснование, ТекстНадписи);
КонецЦикла;
Для Каждого Оформление Из ОформленияСтрок Цикл
ЗначениеНадписи = СоответствиеДанных[Оформление.Ключ];
Если ЗначениеНадписи <> Неопределено Тогда
Ячейка = Оформление.Значение.Ячейки.НадписьСчетФактура;
Ячейка.УстановитьТекст(ЗначениеНадписи);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем оба решения для выбора оптимального:
Оба способа позволяют полностью отказаться от хранения избыточных данных в реквизитах документов и гарантируют актуальность отображаемой информации на управляемой форме.