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