Как исправить ошибку «Процедура или функция с указанным именем не определена (Итог)» в 1С

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

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

Выясняем причину ошибки

Давайте проанализируем, почему возникает данная ошибка. Во встроенном языке 1С глобальный контекст не содержит функции с именем Итог. Метод Итог() является встроенным методом конкретного типа данных — ТаблицаЗначений. Его нельзя вызвать "сам по себе", как это пытался сделать автор темы в строке:

об.Параметры.СуммаПР = Итог(стрТЗПроводки.Сумма);

Компилятор платформы на этапе проверки модуля (особенно при проверке на сервере) справедливо сообщает, что такая функция в глобальном контексте не определена.

Вторая частая ошибка возникает при попытке применить этот метод к строке таблицы значений. Например:


стрТЗПроводки = ТЗПроводки.Найти(СТР.Номенклатура, "Номенклатура");
// ...
об.Параметры.СуммаПР = стрТЗПроводки.Итог("Сумма");

В данном случае переменная стрТЗПроводки имеет тип СтрокаТаблицыЗначений. У этого объекта отсутствуют собственные методы для работы с коллекциями, включая метод Итог(). Попытка его вызова закономерно возвращает ошибку «Метод объекта не обнаружен».

Для успешного вызова метода его необходимо применять исключительно к объекту типа ТаблицаЗначений, передавая имя суммируемой колонки в качестве строкового параметра:

ИтоговаяСумма = ТЗПроводки.Итог("Сумма"); ---

Разбор практического кейса: вывод данных в печатную форму

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

Исходя из обсуждения, перед разработчиком стояли две задачи:

  1. Вывести построчно номенклатуру, количество, цену и сумму в табличный документ.
  2. В подвале печатной формы вывести общую сумму прописью (или числом) по всем выведенным строкам.

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

---

Решение 1: Прямое использование метода Итог() таблицы значений

Если нам гарантировано, что структура таблицы значений ТЗПроводки полностью соответствует выводимым в печатную форму данным (нет лишних строк, нет скрытых фильтров), мы можем обратиться напрямую к методу таблицы значений. В этом случае правильный фрагмент кода будет выглядеть следующим образом:


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

// Получаем область подвала макета
обПодвал = Макет.ПолучитьОбласть("СуммаПР");

// Правильный вызов метода Итог у таблицы значений ТЗПроводки
обПодвал.Параметры.СуммаПР = ТЗПроводки.Итог("Сумма");
ТабДок.Вывести(obПодвал);

---

Решение 2: Накопление суммы в цикле (Безопасный и надежный способ)

Как справедливо заметили участники обсуждения в сообщениях 24 и 33, использование ТЗПроводки.Итог("Сумма") таит в себе скрытую логическую опасность. Давайте разберем подробнее, почему этот метод может вернуть неверный результат:

Чтобы избежать подобных расхождений, самым надежным решением является ручное суммирование выводимых значений непосредственно в момент обхода коллекции строк. Объявим переменную-аккумулятор перед началом цикла и будем прибавлять к ней фактически выводимые суммы:


СуммаСтрок = 0; // Переменная для накопления итога
А = 0;

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

// Выводим область подвала
обПодвал = Макет.ПолучитьОбласть("СуммаПР");

// Присваиваем накопленную в цикле сумму параметров подвала
обПодвал.Параметры.СуммаПР = СуммаСтрок;
ТабДок.Вывести(obПодвал);

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

---

Решение 3: Оптимизация производительности (Индексация ТЗ)

Проанализируем производительность исходного алгоритма. Вызов метода Найти() внутри цикла по табличной части документа выполняет последовательный перебор строк таблицы значений ТЗПроводки. Если в документе содержится большое количество строк (например, несколько сотен или тысяч), производительность формирования печатной формы резко снизится, так как алгоритм имеет квадратичную сложность.

Для ускорения поиска во встроенном языке 1С предусмотрен механизм индексации колонок таблицы значений. Перед запуском цикла обхода нам необходимо явно проиндексировать колонку, по которой будет осуществляться поиск:


// Добавляем индекс по ключевому полю для ускорения поиска в цикле
ТЗПроводки.Индексы.Добавить("Номенклатура");

СуммаСтрок = 0;
Для Каждого СТР Из Ссылка.Товары Цикл
    // Теперь этот метод работает мгновенно благодаря индексу
    стрТЗПроводки = ТЗПроводки.Найти(СТР.Номенклатура, "Номенклатура");
    
    // Дальнейшая логика заполнения параметров...
КонецЦикла;

Использование метода Индексы.Добавить() существенно сокращает время работы алгоритма на больших объемах данных, сводя время поиска строки к минимуму.

---

Рекомендация: Использование запросов для расчета итогов

В соответствии со стандартами разработки фирмы «1С», любые расчеты для печатных форм (включая получение сумм, цен, остатков и оборотов) рекомендуется выполнять на уровне СУБД с помощью объекта Запрос. Попытки производить ручные выборки, сопоставления таблиц в оперативной памяти сервера приложений и последующие вычисления цен делением в цикле считаются устаревшим подходом.

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

← На главную