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