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