Как выбрать обороты по счетам в расширении 1С и настроить динамический список без потери производительности?

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

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

В этой статье мы подробно разберем, почему конструктор запросов в расширении выдает ошибки при работе с виртуальной таблицей Хозрасчетный.ОборотыДтКт, как правильно обойти эти ограничения, и как решить бизнес-задачу по расчету оборотов и раскраске строк динамического списка без ущерба для скорости работы системы.

---

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

Типичная ситуация: разработчик пытается отредактировать запрос динамического списка в расширении, обращаясь к виртуальной таблице РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт, но платформа выдает ошибку о том, что таблица или её реквизиты (например, СубконтоДт, КорСчет и др.) не найдены. Выясним причину такого поведения.

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

Если эти объекты не заимствованы в расширение, конструктор запросов расценивает обращение к ним как синтаксическую ошибку.

Способы обхода этой проблемы:

  1. Программный обход конструктора («слепая» вставка): Вы можете составить и отладить запрос во внешней обработке или консоли запросов в основной базе. Затем скопируйте готовый SQL-подобный текст запроса и вставьте его напрямую в поле «Настройка списка -> Запрос» в расширении, минуя вызов конструктора. Сама платформа в режиме предприятия успешно объединяет метаданные, и запрос будет работать корректно, несмотря на предупреждения конфигуратора.
  2. Правильное заимствование метаданных: Добавьте в расширение план счетов Хозрасчетный, установите в свойствах заимствованного регистра контролируемые свойства связи и заимствуйте аналитику (справочники), участвующую в отборах.

---

Опасность использования тяжелых запросов в динамических списках

Связывание (через оператор ЛЕВОЕ СОЕДИНЕНИЕ) основной таблицы справочника «Договоры» с виртуальной таблицей РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт напрямую в тексте запроса динамического списка — это серьезная архитектурная ошибка.

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

---

Современное и производительное решение: событие ПриПолученииДанныхНаСервере

Для реализации бизнес-требования (вывод оборотов между дебетом счетов 41.1, 20, 26, 25 и кредитом счета 60.01 по договорам с последующей раскраской) оптимально использовать событие таблицы формы ПриПолученииДанныхНаСервере. Этот метод появился в платформе начиная с версии 8.3.10 и предназначен как раз для динамического дозаполнения отображаемых на экране строк.

Проанализируем алгоритм работы этого механизма:

  1. В расширении формы списка договоров добавляется колонка (например, СуммаОборота). Важно: она должна быть добавлена просто как элемент формы (поле), не связанный с реквизитами динамического списка (у неё отсутствует путь к данным).
  2. Создается обработчик события ПриПолученииДанныхНаСервере для таблицы списка.
  3. Платформа передает в этот обработчик коллекцию строк, которые в данный момент реально отображаются на экране пользователя (обычно не более 30–40 записей).
  4. Мы собираем массив уникальных ссылок на договоры из этих видимых строк.
  5. Выполняем один быстрый, точечный запрос к регистру бухгалтерии с отбором исключительно по нашему массиву договоров.
  6. Заполняем полученные данные в оформление строк на экране.

Рассмотрим пример реализации данного обработчика в модуле формы расширения:


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

КонецПроцедуры

---

Программная раскраска через Условное Оформление

Если вы всё же решили добавить поле СуммаОборота непосредственно в запрос динамического списка (применив оптимизированные индексы), настраивать цвета визуально в конфигураторе расширения не рекомендуется. При обновлении конфигурации поставщика такие интерактивные настройки условного оформления могут затереться или вызвать конфликты.

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


&НаСервере
Процедура СписокПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
	
	// Настройка условного оформления для 100% достижения лимита (Красный цвет)
	ЭлементОформления = Список.УсловноеОформление.Элементы.Добавить();
	
	// Задаем цвет фона
	ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.Красный);
	
	// Задаем условия сравнения
	КомпоновкаДанныхКлиентСервер.ДобавитьОтбор(ЭлементОформления.Отбор, 
		"СуммаОборота", 
		ПолеКомпоновкиДанных("КритСумма"), 
		ВидСравненияКомпоновкиДанных.БольшеИлиРавно);
		
	// Оформляемые поля (применяется ко всей строке или конкретной колонке)
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("СуммаОборота");
	ОформляемоеПоле.Использование = Истина;

КонецПроцедуры

---

Заключение

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

← На главную