Как рассчитать среднюю цену выделенных строк в динамическом списке 1С?

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

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

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

Решение 1. Рекомендуемый серверный подход (Запрос к базе данных)

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

Разберем этот метод по шагам:

  1. Создадим команду на форме (например, кнопку в командной панели списка или пункт контекстного меню) "Вычислить среднюю цену".
  2. В клиентском обработчике команды получим массив выделенных строк.
  3. Передадим этот массив в серверную функцию, которая выполнит запрос к табличной части документов и вернет результат.
  4. Выведем полученный результат пользователю через оповещение.

Посмотрим на пример реализации кода на форме списка документов:


&НаКлиенте
Процедура ВычислитьСреднююЦенуВыделенных(Команда)

    ВыделенныеСтроки = Элементы.Список.ВыделенныеСтроки;
    
    Если ВыделенныеСтроки.Количество() = 0 Тогда
        ПоказатьПредупреждение(, "Не выделено ни одной строки!");
        Возврат;
    КонецЕсли;
    
    // Передаем массив ссылок на сервер для расчета
    СредняяЦена = ПолучитьСреднююЦенуНаСервере(ВыделенныеСтроки);
    
    // Выводим результат пользователю
    ПоказатьОповещениеПользователя("Расчет окончен", , 
        "Средняя цена выделенных документов: " + Формат(СредняяЦена, "ЧЦ=15; ЧДЦ=2"));

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

&НаСервереБезКонтекста
Функция ПолучитьСреднююЦенуНаСервере(МассивДокументов)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	СРЕДНЕЕ(ДокументТЧ.Цена) КАК СредняяЦена
        |ИЗ
        |	Документ.РеализацияТоваровУслуг.Товары КАК ДокументТЧ
        |ГДЕ
        |	ДокументТЧ.Ссылка В(&МассивДокументов)";
        
    Запрос.УстановитьПараметр("МассивДокументов", МассивДокументов);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() И ЗначениеЗаполнено(Выборка.MediumPrice) Тогда
        Возврат Выборка.СредняяЦена;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

Преимущества серверного подхода: этот метод работает мгновенно даже при выделении сотен и тысяч документов (например, через сочетание клавиш Ctrl + A). Он абсолютно не зависит от того, видима ли колонка цены на клиенте у конкретного пользователя, и не вызывает зависания интерфейса из-за передачи больших объемов данных.

Решение 2. Клиентский расчет «на лету» через ДанныеСтроки()

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

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

Рассмотрим пример реализации клиентского расчета:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    // Подключаем однократный обработчик ожидания с задержкой 0.1 секунды
    ПодключитьОбработчикОжидания("РассчитатьСреднююЦенуКлиент", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура РассчитатьСреднююЦенуКлиент()
    
    ВыделенныеСтроки = Элементы.Список.ВыделенныеСтроки;
    КоличествоВыделено = ВыделенныеСтроки.Количество();
    
    Если КоличествоВыделено = 0 Тогда
        ИтоговаяСредняяЦена = 0;
        Возврат;
    КонецЕсли;
    
    ОбщаяСумма = 0;
    КоличествоУспешноПолученных = 0;
    
    Для Каждого ИдентификаторСтроки Из ВыделенныеСтроки Цикл
        
        ДанныеСтроки = Элементы.Список.ДанныеСтроки(ИдентификаторСтроки);
        
        // Важно проверить на Неопределено (данные могут быть не кэшированы на клиенте)
        Если ДанныеСтроки <> Неопределено Тогда
            ОбщаяСумма = ОбщаяСумма + ДанныеСтроки.Цена;
            КоличествоУспешноПолученных = КоличествоУспешноПолученных + 1;
        КонецЕсли;
        
    КонецЦикла;
    
    Если КоличествоУспешноПолученных > 0 Тогда
        ИтоговаяСредняяЦена = ОбщаяСумма / КоличествоУспешноПолученных;
    Иначе
        ИтоговаяСредняяЦена = 0;
    EndIf;
    
    // Здесь код вывода значения на форму, например, в декорацию или авто-поле
    
КонецПроцедуры

Важные ограничения клиентского метода ДанныеСтроки():

Решение 3. Использование встроенных возможностей платформы (без программирования)

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

  1. Функция «Вывести список»: Пользователь может нажать правой кнопкой мыши в любом месте таблицы, выбрать команду «Вывести список...» и установить флаг «Только выделенные». Платформа сформирует табличный документ. Если теперь выделить в нем колонку с ценами, то в строке состояния (самый низ экрана 1С) платформа автоматически отобразит сумму, среднее значение, количество, минимум и максимум выделенных ячеек.
  2. Буфер обмена и Excel: Достаточно выделить нужные строки в динамическом списке, нажать сочетание клавиш Ctrl + C, открыть Microsoft Excel или Google Таблицы и вставить данные через Ctrl + V. Данные переносятся в виде полноценной таблицы, где можно мгновенно применить любые формулы расчета.
  3. Встроенный калькулятор 1С: В платформе есть встроенный калькулятор, поддерживающий функции накопления (кнопки М+, М-). Если установить курсор в колонку «Цена», выделить нужные строки и нажать кнопку накопительного суммирования в калькуляторе, платформа сама посчитает сумму выделенных ячеек.

Важные предупреждения разработчикам

Проанализируем распространенную ошибку начинающих разработчиков при работе с выделенными строками. В некоторых старых решениях можно встретить попытку получить данные строк через свойство списка ТекущиеДанные, циклически перезаписывая свойство списка ТекущаяСтрока = ИдентификаторСтроки внутри цикла обхода выделенных строк.

Так делать категорически нельзя! Программное изменение активной строки (свойство ТекущаяСтрока) во время цикла мгновенно сбрасывает множественное выделение, которое пользователь делал вручную (с зажатым Ctrl или Shift). В итоге алгоритм собьется, а пользователь потеряет выделенные строки.

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

← На главную