Как изменить данные во всех строках табличной части при смене даты документа?

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

При разработке документов в 1С часто возникает задача автоматического пересчета данных в табличной части при изменении ключевых реквизитов шапки, таких как Дата, Валюта или ТипЦен. Однако начинающие разработчики сталкиваются с ситуацией, когда пересчет срабатывает только для той строки, которая в данный момент выделена курсором (активна), а остальные строки остаются без изменений. Давайте подробно разберем, почему так происходит и как правильно организовать алгоритм для обновления всей коллекции строк.

Суть проблемы: обновление только одной строки

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

Разберем причины поведения системы

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

Если в процедуре изменения даты вы вызываете функцию пересчета, которая обращается к Элементы.Товары.ТекущиеДанные, то система берет данные только одной конкретной строки — той, что находится в фокусе. Остальной массив данных (коллекция строк табличной части) остается нетронутым, так как код к нему не обращается.

Решение: Использование цикла по табличной части

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

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

  1. На клиенте в событии ПриИзменении поля "Дата" вызываем серверную процедуру.
  2. На сервере обращаемся не к элементам формы, а к объекту (коллекции данных).
  3. Запускаем цикл по строкам табличной части.

Посмотрим на пример правильной реализации серверной процедуры:


&НаСервере
Процедура ПересчитатьДанныеПриИзмененииДатыНаСервере()
    
    // Получаем коллекцию строк табличной части через Объект
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        
        // Здесь выполняем логику пересчета для каждой строки
        // Например, если нужно обновить ставку или цену в зависимости от новой даты
        
        // Пример вызова функции пересчета
        ОбработатьСтроку(СтрокаТЧ, Объект.Дата);
        
    КонецЦикла;
    
КонецПроцедуры

В этом коде СтрокаТЧ будет последовательно принимать значение каждой строки документа, что гарантирует обновление всех данных.

Важный момент: Оптимизация запросов в цикле

Мы должны быть внимательны к производительности. Если внутри цикла (в функции ОбработатьСтроку) происходит запрос к базе данных (например, получение цены срезом последних), это приведет к проблеме "запрос в цикле". Если в документе 1000 строк, система сделает 1000 запросов к БД, что существенно замедлит работу.

Правильный подход:

  1. До цикла одним запросом получить необходимые данные для всех номенклатур из табличной части на новую дату.
  2. Выгрузить результат в таблицу значений или структуру.
  3. В цикле обходить строки документа и подставлять уже полученные данные из памяти.

Получение данных из регистра сведений без измерений

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

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

Синтаксис метода: РегистрыСведений.ИмяРегистра.ПолучитьПоследнее(Дата, Отбор).

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

Рассмотрим пример кода:


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

КонецФункции

Итоги

Для корректной работы автоматического пересчета при изменении даты необходимо:

  1. Разделять контекст выполнения. Событие срабатывает на клиенте, но расчеты лучше делать на сервере.
  2. Использовать цикл Для Каждого по коллекции Объект.ИмяТЧ, чтобы затронуть все строки, а не только текущую.
  3. Для получения периодических данных (курсов, ставок) использовать метод ПолучитьПоследнее с передачей новой даты документа.
← На главную