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

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

При разработке документов в системе «1С:Предприятие 8.3» программисты часто сталкиваются с задачей: необходимо динамически рассчитывать и выводить в подвал таблицы или форму документа различные итоги. Например, общее количество товаров в базовых единицах измерения, суммарный вес, объем или количество мест хранения. При этом документ еще не записан в базу данных, а пользователь активно редактирует строки табличной части.

В этой статье мы подробно разберем, как реализовать такой расчет грамотно, избегая зависаний интерфейса и избыточных вызовов сервера. Мы проанализируем различные подходы — от классических запросов до современных клиентских механизмов кэширования, применяемых в типовых конфигурациях ERP, КА и УТ.

Особенности клиент-серверной архитектуры управляемых форм

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

Для выполнения серверных расчетов нам необходимо передать эти временные данные на сервер. Однако частые серверные вызовы (например, при каждом изменении количества в строке) приводят к задержкам в интерфейсе (так называемым «фризам»), особенно если пользователи работают через веб-клиент или мобильное соединение. Поэтому наша главная задача — минимизировать передачу данных между клиентом и сервером.

Вариант 1. Запрос к незаписанной табличной части на сервере

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

Некоторые разработчики используют метод РеквизитФормыВЗначение("Объект"), который полностью воссоздает весь объект ДокументОбъект со всеми его реквизитами на сервере. Однако этот метод достаточно «тяжелый». Если нам нужна только конкретная табличная часть, гораздо эффективнее выгрузить ее в таблицу значений на сервере напрямую через свойства реквизита формы.

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


&НаСервере
Функция РассчитатьИтогиЗапросомНаСервере()
    
    // Получаем таблицу значений из данных формы без создания тяжелого объекта
    ТаблицаТоваров = Объект.Товары.Выгрузить();
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ВТ_ДанныеФормы.Номенклатура КАК Номенклатура,
        |	ВТ_ДанныеФормы.Количество КАК Количество,
        |	ЕСТnull(ЕдиницыИзмерения.Коэффициент, 1) КАК Коэффициент
        |ПОМЕСТИТЬ ВТ_Товары
        |ИЗ
        |	&ТаблицаДанных КАК ВТ_ДанныеФормы
        |		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения
        |		ПО ВТ_ДанныеФормы.Номенклатура.БазоваяЕдиница = ЕдиницыИзмерения.Ссылка
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |	СУММА(ВТ_Товары.Количество * ВТ_Товары.Коэффициент) КАК ВсегоВБазовыхЕдиницах
        |ИЗ
        |	ВТ_Товары КАК ВТ_Товары";
        
    Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаТоваров);
    
    РезультатЗапроса = Запрос.Выполнить();
    Если Не РезультатЗапроса.Пустой() Тогда
        Выборка = РезультатЗапроса.Выбрать();
        Выборка.Следующий();
        Возврат Выборка.ВсегоВБазовыхЕдиницах;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

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

Недостатки метода: Низкая производительность при частом вызове. При каждом изменении количества система будет гонять таблицу по сети на сервер и выполнять SQL-запрос.

Вариант 2. Быстрый обход коллекции в цикле на клиенте

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

Рассмотрим, как это выглядит на практике:


&НаКлиенте
Функция РассчитатьИтогНаКлиенте()
    
    ИтоговоеКоличество = 0;
    
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        // Производим локальный расчет без обращения к серверу
        ИтоговоеКоличество = ИтоговоеКоличество + (СтрокаТЧ.Количество * СтрокаТЧ.Коэффициент);
    КонецЦикла;
    
    Возврат ИтоговоеКоличество;
    
КонецФункции

Преимущества метода: Молниеносная скорость работы. Интерфейс программы не блокируется, сетевой трафик равен нулю.

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

Вариант 3. Оптимальный гибридный подход (кэширование коэффициентов)

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

  1. Редкие события (Выбор номенклатуры или единицы измерения): Происходят нечасто. В этот момент мы делаем серверный вызов, получаем из базы данных актуальный коэффициент пересчета и записываем его в скрытый служебный реквизит строки ТЧ — например, в колонку Коэффициент.
  2. Частые события (Изменение количества в строке): Происходят постоянно при ручном вводе или сканировании. Здесь мы работаем строго на клиенте. Мы берем измененное количество, умножаем на уже сохраненный в строке Коэффициент и записываем результат в колонку КоличествоБазовое.

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


&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    
    ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
    Если ТекущаяСтрока <> Неопределено Тогда
        // Редкое событие: получаем коэффициент с сервера
        ТекущаяСтрока.Коэффициент = ПолучитьКоэффициентНаСервере(ТекущаяСтрока.Номенклатура);
        // Сразу пересчитываем базовое значение
        РассчитатьБазовоеКоличествоСтроки(ТекущаяСтрока);
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
    
    ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
    Если ТекущаяСтрока <> Неопределено Тогда
        // Частое событие: мгновенный расчет на клиенте без сервера!
        РассчитатьБазовоеКоличествоСтроки(ТекущаяСтрока);
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура РассчитатьБазовоеКоличествоСтроки(ТекущаяСтрока)
    
    КоэффициентПересчета = ?(ТекущаяСтрока.Коэффициент = 0, 1, ТекущаяСтрока.Коэффициент);
    ТекущаяСтрока.КоличествоБазовое = ТекущаяСтрока.Количество * КоэффициентПересчета;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьКоэффициентНаСервере(Знач ВыбраннаяНоменклатура)
    // Извлекаем коэффициент из справочника Номенклатуры или Единиц Измерения
    Возврат ВыбраннаяНоменклатура.ЕдиницаХранения.Коэффициент;
КонецФункции

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

Использование штатных механизмов платформы для вывода итогов

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

Платформа «1С:Предприятие 8.3» умеет делать это автоматически силами самого клиентского приложения. Для этого выполним следующие действия:

  1. Откроем управляемую форму документа в конфигураторе.
  2. Выберем элемент формы «Таблица» (нашу ТЧ Товары) и в свойствах установим флаг «Подвал» в значение Истина.
  3. Найдем элемент-колонку, по которой мы хотим видеть итог (например, КоличествоБазовое).
  4. В панели свойств этой колонки найдем поле «ПутьКДаннымПодвала» и укажем путь к автоматическому итогу: Объект.Товары.ИтогКоличествоБазовое.

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

Стандарты оформления интерфейса итогов (1С:ИТС)

Согласно юзабилити-стандартам фирмы «1С», выводить итоги непосредственно в подвале таблицы удобно только в том случае, если табличная часть лаконична и не имеет горизонтальной полосы прокрутки. Если же колонок много, пользователю придется скроллить таблицу вправо, чтобы увидеть итоговое значение, что крайне неудобно.

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

  1. Создайте группу элементов формы (тип — «Группа без отображения») и разместите ее сразу под таблицей.
  2. Добавьте в эту группу декоративные поля (тип — «Поле надписи» или «Поле ввода» в режиме «Только просмотр»).
  3. Свяжите эти поля с реквизитами формы, в которые программно транслируйте итоги с помощью быстрого клиентского метода Объект.Товары.Итог("ИмяКолонки") в обработчиках изменения табличной части.

Использование этих простых, но эффективных практик позволит вам создавать быстрые, надежные и интуитивно понятные интерфейсы для любых прикладных решений на платформе «1С:Предприятие 8.3».

← На главную