Как добавить сумму НДС из табличных частей в форму списка документа 1С

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

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

Анализ типичных ошибок при модификации запроса динамического списка

Проанализируем распространенные подходы, которые приводят к некорректным результатам:

  1. Использование внутреннего соединения (ВНУТРЕННЕЕ СОЕДИНЕНИЕ): если связать шапку документа с табличной частью Товары и табличной частью Услуги через внутреннее соединение, из списка пропадут все документы, в которых заполнена только одна из табличных частей или которые вовсе не содержат строк.
  2. Декартово произведение строк: если соединить несколько табличных частей документа напрямую через ЛЕВОЕ СОЕДИНЕНИЕ по ссылке, произойдет перемножение строк. Например, если в документе 3 строки с товарами и 2 строки с услугами, в результате соединения получится 6 строк, и простая группировка с суммированием выдаст кратно завышенную сумму НДС.
  3. Использование пакетных запросов и временных таблиц: динамический список с включенным свойством Основная таблица не поддерживает пакетные запросы с ключевым словом ПОМЕСТИТЬ. Запрос списка должен состоять из одной инструкции ВЫБРАТЬ.
  4. Использование конструкции ОБЪЕДИНИТЬ ВСЕ: объединение наборов данных в основном запросе динамического списка либо вызывает синтаксическую ошибку платформы, либо отключает динамическое считывание данных, из-за чего весь список документов начинает медленно загружаться в память.

Способ 1. Коррелированные скалярные подзапросы в секции ВЫБРАТЬ

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

Посмотрим на пример формирования поля суммы НДС в запросе динамического списка:


ВЫБРАТЬ
	ДокументПоступление.Ссылка КАК Ссылка,
	ДокументПоступление.Номер КАК Номер,
	ДокументПоступление.Дата КАК Дата,
	ДокументПоступление.ВидОперации КАК ВидОперации,
	ДокументПоступление.Организация КАК Организация,
	ДокументПоступление.Контрагент КАК Контрагент,
	ДокументПоступление.СуммаДокумента КАК СуммаДокумента,
	ЕСТЬNULL((ВЫБРАТЬ СУММА(ТЧ_Товары.СуммаНДС)
	          ИЗ Документ.ПоступлениеТоваровУслуг.Товары КАК ТЧ_Товары
	          ГДЕ ТЧ_Товары.Ссылка = ДокументПоступление.Ссылка), 0)
	+
	ЕСТЬNULL((ВЫБРАТЬ СУММА(ТЧ_Услуги.СуммаНДС)
	          ИЗ Документ.ПоступлениеТоваровУслуг.Услуги КАК ТЧ_Услуги
	          ГДЕ ТЧ_Услуги.Ссылка = ДокументПоступление.Ссылка), 0) КАК СуммаНДС
ИЗ
	Документ.ПоступлениеТоваровУслуг КАК ДокументПоступление

Преимущества метода: запрос остается единым, сохраняется указание основной таблицы Документ.ПоступлениеТоваровУслуг, корректно работают стандартные отборы и сортировки платформы.

Ограничения: при интенсивной прокрутке больших списков документов подзапросы в секции ВЫБРАТЬ создают дополнительную нагрузку на СУБД.

Способ 2. Расчет сумм в событии ПриПолученииДанныхНаСервере

Наиболее производительный вариант для динамических списков без изменения структуры метаданных — вычисление суммы НДС только для тех строк, которые физически отображаются на экране пользователя (обычно 20–50 записей за порцию).

Разберем реализацию по шагам:

  1. В форму списка добавляем новую колонку таблицы, не привязанную к данным запроса динамического списка (или добавляем в запрос фиктивное поле 0 КАК СуммаНДС).
  2. В модуле формы определяем обработчик события ПриПолученииДанныхНаСервере.
  3. Формируем пакетную выборку сумм только по ссылкам документов, переданным в параметре Строки.

Посмотрим на пример серверного кода обработки отображаемых строк:


&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, УстановленныеНастройки, Строки)
	
	МассивСсылок = Новый Массив;
	Для Каждого КлючСтроки Из Строки.ПолучитьКлючи() Цикл
		МассивСсылок.Добавить(КлючСтроки);
	КонецЦикла;
	
	Если МассивСсылок.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ТаблицаСумм.Ссылка КАК Ссылка,
		|	СУММА(ТаблицаСумм.СуммаНДС) КАК СуммаНДС
		|ИЗ
		|	(ВЫБРАТЬ
		|		Товары.Ссылка КАК Ссылка,
		|		Товары.СуммаНДС КАК СуммаНДС
		|	ИЗ
		|		Документ.ПоступлениеТоваровУслуг.Товары КАК Товары
		|	ГДЕ
		|		Товары.Ссылка В(&МассивСсылок)
		|
		|	ОБЪЕДИНИТЬ ВСЕ
		|
		|	ВЫБРАТЬ
		|		Услуги.Ссылка КАК Ссылка,
		|		Услуги.СуммаНДС КАК СуммаНДС
		|	ИЗ
		|		Документ.ПоступлениеТоваровУслуг.Услуги КАК Услуги
		|	ГДЕ
		|		Услуги.Ссылка В(&МассивСсылок)) КАК ТаблицаСумм
		|СГРУППИРОВАТЬ ПО
		|	ТаблицаСумм.Ссылка";
		
	Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		ДанныеСтроки = Строки[Выборка.Ссылка];
		Если ДанныеСтроки <> Неопределено Тогда
			ДанныеСтроки.Данные["СуммаНДС"] = Выборка.СуммаНДС;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Этот способ гарантирует максимальную скорость отклика интерфейса, так как основной запрос динамического списка остается полностью типовым.

Способ 3. Добавление реквизита в шапку документа через расширение

Если пользователям требуется сортировать список документов по сумме НДС или накладывать быстрые фильтры, оптимальным решением с точки зрения архитектуры является добавление отдельного реквизита шапки.

Порядок реализации:

  1. В расширении конфигурации добавляем в документ реквизит шапки СуммаНДС (тип Число(15, 2)).
  2. В обработчике ПередЗаписью документа рассчитываем сумму по всем табличным частям и заполняем значение реквизита.
  3. Выполняем разовую обработку по заполнению реквизита для исторических документов в информационной базе.
  4. Включаем созданный реквизит в динамический список формы как стандартное поле шапки.

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

← На главную