Как вывести параметры из регистра накопления в печатную форму 1С

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

При разработке печатных форм в среде «1С:Предприятие» программисты часто сталкиваются с задачей, когда стандартных данных из табличной части документа оказывается недостаточно. Например, требуется вывести информацию, которая формируется непосредственно в моменте проведения документа и записывается в регистры накопления или сведений. Типичный пример — получение ставки НДС или конкретного события по НДС из регистра накопления НДСПродажи вместо стандартного значения из документа.

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

Почему не работает простое добавление колонок?

Типичная ошибка начинающих разработчиков — попытка добавить колонку в локальную таблицу значений документа на лету через метод Таблица.Колонки.Добавить() с указанием нужного типа, например, ПеречислениеСсылка.СобытияПоНДСПродажи. Рассмотрим, почему этот подход ошибочен.

Метод Колонки.Добавить() всего лишь конструирует пустую колонку в оперативной памяти компьютера. Он никак не связан с базой данных СУБД и не заставит платформу автоматически обратиться к регистру НДСПродажи за данными. Чтобы получить реальные записи физических таблиц базы данных, мы в обязательном порядке должны использовать механизм запросов.

Существует два основных способа решения этой задачи. Проанализируем каждый из них подробнее.

Способ 1. Получение данных из регистра отдельным запросом в цикле вывода

Этот способ отлично подойдет в ситуации, когда печатная форма уже написана, ее код работает через обход строк табличной части документа в цикле Для Каждого..., и вам нужно минимально вмешаться в существующий алгоритм, добавив лишь одно поле из регистра.

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

Выполним это по шагам:

  1. Создадим запрос к регистру накопления НДСПродажи с отбором по текущему документу (параметр Регистратор).
  2. Выберем из регистра поле Событие (которое должно пойти в колонку «Ставка НДС») и обязательно поле НомерСтроки (для точного сопоставления с табличной частью документа).
  3. Выгрузим результат запроса в таблицу значений и проиндексируем поле НомерСтроки, чтобы поиск в цикле выполнялся мгновенно.
  4. В цикле вывода печатной формы найдем строку по номеру строки и подставим значение в параметры макета.

Посмотрим на практический пример реализации этого алгоритма:


// 1. Формируем запрос к регистру накопления
ЗапросРегистра = Новый Запрос;
ЗапросРегистра.Текст = 
    "ВЫБРАТЬ
    |	НДСПродажи.Событие КАК СобытиеНДС,
    |	НДСПродажи.НомерСтроки КАК НомерСтроки
    |ИЗ
    |	РегистрНакопления.НДСПродажи КАК НДСПродажи
    |ГДЕ
    |	НДСПродажи.Регистратор = &Регистратор";

// В качестве регистратора передаем ссылку на печатаемый документ
ЗапросРегистра.УстановитьПараметр("Регистратор", Ссылка); 

// Выгружаем данные в таблицу значений
ТаблицаРегистра = ЗапросРегистра.Выполнить().Выгрузить();

// Индексируем колонку связи для быстрого поиска по методу НайтиСтроки()
ТаблицаРегистра.Индексы.Добавить("НомерСтроки"); 

// 2. Основной цикл вывода строк в печатную форму
Для Каждого СтрокаДокумента Из Ссылка.Товары Цикл
    
    ПараметрыСтроки = Новый Структура;
    
    // Ищем запись регистра, соответствующую текущей строке документа
    Отбор = Новый Структура("НомерСтроки", СтрокаДокумента.НомерСтроки);
    НайденныеСтроки = ТаблицаРегистра.НайтиСтроки(Отбор);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        // Заполняем параметр "СтавкаНДС" событием из регистра
        ПараметрыСтроки.Вставить("СтавкаНДС", НайденныеСтроки[0].СобытиеНДС);
    Иначе
        // Если запись в регистре не найдена (например, документ не проведен), 
        // берем стандартное значение из табличной части
        ПараметрыСтроки.Вставить("СтавкаНДС", СтрокаДокумента.СтавкаНДС);
    КонецЕсли;
    
    // Заполняем остальные стандартные параметры
    ПараметрыСтроки.Вставить("СуммаНДС",  СтрокаДокумента.СуммаНДС);
    ПараметрыСтроки.Вставить("СуммаСНДС", СтрокаДокумента.СуммаСНДС);
    
    // Код заполнения области макета и вывода в ТабличныйДокумент...
КонецЦикла;

Способ 2. Оптимальное решение — Левое Соединение в основном запросе печатной формы

Использование отдельного запроса в цикле или перед ним — рабочий вариант, но он не является оптимальным с точки зрения производительности (особенно если печатная форма вызывается сразу для списка документов). Профессиональным стандартом разработки в 1С является получение всех необходимых данных одним запросом с помощью левого соединения.

Давайте проанализируем ситуацию: у нас есть исходная таблица — табличная часть документа (например, Документ.РеализацияТоваровУслуг.Товары), и есть подчиненная таблица — движения регистра накопления РегистрНакопления.НДСПродажи. Мы можем соединить их по двум полям: по ссылке на документ (Ссылка = Регистратор) и по номеру строки (НомерСтроки = НомерСтроки).

Рассмотрим пример построения такого запроса в коде модуля менеджера документа:


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

Запрос.УстановитьПараметр("СсылкаДокумента", Ссылка);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетали = РезультатЗапроса.Выбрать();

Пока ВыборкаДетали.Следующий() Цикл
    // Здесь мы просто передаем уже готовые, соединенные данные напрямую в параметры макета
    ОбластьСтрока.Параметры.Заполнить(ВыборкаДетали);
    ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;

Использование функции ЕСТЬNULL в запросе гарантирует, что если документ еще не был проведен (и записей в регистре физически не существует), печатная форма не останется с пустыми полями — вместо этого подставится дефолтная ставка НДС из табличной части документа.

Как заполнить параметр области макета, но не выводить саму область?

В процессе обсуждения часто возникает сопутствующий вопрос: как сделать так, чтобы значение параметра (например, СтавкаНДС) было заполнено в коде, но сама ячейка или целая область макета временно не выводилась на печать?

Разберем логику работы табличного документа. За вывод данных отвечает исключительно метод Вывести(). Заполнение параметров структуры макета и непосредственный вывод области в итоговый табличный документ — это две абсолютно независимые операции.

Если вам требуется заполнить параметры, но не выводить строку (или вывести ее только при соблюдении определенного условия), управляйте вызовом метода Вывести(). Посмотрим на примере:


// Получаем рабочую область из макета
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");

// Заполняем параметры области (данные в нее запишутся в памяти)
ОбластьСтрока.Параметры.Номенклатура = СтрокаДанных.Номенклатура;
ОбластьСтрока.Параметры.СтавкаНДС   = СтрокаДанных.СтавкаНДС;

// Проверяем условие вывода
Если ВыводитьСтрокуНДС Тогда
    // Только при ИСТИНА строка физически добавится в итоговый документ
    ТабличныйДокумент.Вывести(ОбластьСтрока);
КонецЕсли;

Если область выводить нужно всегда, но само значение СтавкаНДС по какому-то условию должно быть скрыто от глаз пользователя, можно прибегнуть к программной очистке параметра перед выводом или сделать текст невидимым:


Если СкрыватьСтавкуНДС Тогда
    // Способ 1. Просто очищаем значение параметра
    ОбластьСтрока.Параметры.СтавкаНДС = ""; 
    
    // Способ 2. Делаем текст невидимым (окрашиваем в цвет фона ячейки)
    ОбластьСтрока.Область("СтавкаНДС").ЦветТекста = WebЦвета.Белый;
КонецЕсли;

ТабличныйДокумент.Вывести(ОбластьСтрока);

Таким образом, мы детально изучили механизмы извлечения данных из регистров накопления для их последующей интеграции в печатные формы 1С. Использование оптимальных запросов с левым соединением позволит вашим печатным формам работать быстро и безотказно при любых объемах данных.

← На главную