Как программно изменить значения во всех строках табличной части в 1С 8.3?

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

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

Разбор типичной ошибки при обходе табличной части

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


Для каждого Строка Из Объект.ТабличнаяЧасть Цикл
    Строка = Элементы.ТабличнаяЧасть.ТекущиеДанные;
    Строка.Сумма = Строка.Сумма + НаценкаЗаОдинТовар;
КонецЦикла;

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

Чтобы исправить эту ошибку, нам достаточно использовать переменную цикла, которая на каждой итерации автоматически указывает на следующую строку коллекции Объект.ТабличнаяЧасть. Лишнее присваивание внутри цикла нужно просто удалить.

Правильная реализация простого изменения значений

Рассмотрим правильный подход. Допустим, нам нужно прибавить число 10 к колонке Сумма в каждой строке. Проанализируем код, который будет работать быстро и безошибочно:


&НаСервере
Процедура ПрибавитьДесятьНаСервере()
    
    // Обязательно проверяем, есть ли строки в таблице
    Если Объект.Товары.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

    Для каждого ТекущаяСтрока Из Объект.Товары Цикл
        // Обращаемся напрямую к свойствам строки через переменную цикла
        ТекущаяСтрока.Сумма = ТекущаяСтрока.Сумма + 10;
    КонецЦикла;

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

В этом примере мы используем переменную ТекущаяСтрока. На каждом шаге цикла 1С сама подставляет в неё следующую строку из Объект.Товары. Это самый прозрачный и эффективный способ для математических преобразований данных. Если вам требуется не программная логика, а удобный интерфейс для правки данных, можно использовать универсальный редактор справочников, позволяющий видеть табличные части и реквизиты на одном экране.

Алгоритмы распределения суммы по строкам

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

Рассмотрим подробнее три основных метода распределения:

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

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


&НаСервере
Процедура РаспределитьСуммуПропорционально(ОбщаяСуммаНаценки)
    
    ИтоговаяСуммаДокумента = Объект.Товары.Итог("Сумма");
    
    Если ИтоговаяСуммаДокумента = 0 Тогда
        Возврат; // Избегаем деления на ноль
    КонецЕсли;

    ОстатокНаценки = ОбщаяСуммаНаценки;
    КоличествоСтрок = Объект.Товары.Количество();
    
    Для Индекс = 0 По КоличествоСтрок - 1 Цикл
        
        ТекущаяСтрока = Объект.Товары[Индекс];
        
        // Если это последняя строка, отдаем ей весь оставшийся «хвост»
        Если Индекс = КоличествоСтрок - 1 Тогда
            ТекущаяНаценка = ОстатокНаценки;
        Иначе
            // Вычисляем долю текущей строки
            ТекущаяНаценка = Окр((ОбщаяСуммаНаценки * ТекущаяСтрока.Сумма) / ИтоговаяСуммаДокумента, 2);
            ОстатокНаценки = ОстатокНаценки - ТекущаяНаценка;
        КонецЕсли;
        
        ТекущаяСтрока.Сумма = ТекущаяСтрока.Сумма + ТекущаяНаценка;
        
    КонецЦикла;

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

Решение проблемы «лишней копейки»

При математическом распределении часто возникает ситуация, когда из-за округления сумма частей не совпадает с исходным целым числом. Например, если распределить 100 рублей на 3 строки поровну, мы получим 33.33 + 33.33 + 33.33 = 99.99 рублей. В учете потерянная копейка недопустима.

Посмотрим на решение: лучший способ — это расчет наценки для каждой строки по отдельности с вычитанием полученного результата из общего «котла». Последней строке всегда присваивается оставшееся значение. Именно этот механизм реализован в коде выше через проверку Если Индекс = КоличествоСтрок - 1 Тогда. Это гарантирует, что итоговое сальдо всегда сойдется до копейки.

Использование Библиотеки Стандартных Подсистем (БСП)

Если ваша конфигурация построена на базе современных решений (УТ 11, ERP, БП 3.0), мы рекомендуем не изобретать велосипед, а использовать встроенные функции БСП. Разобраться в них поможет справочник по методам БСП с примерами использования, где можно быстро найти нужный программный код. В общем модуле ОбщегоНазначенияУТ или аналогичных модулях часто встречается функция РаспределитьСуммуПропорционально.

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

Оптимизация и интерактивность

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

  1. Контекст исполнения: Всегда старайтесь выполнять массовые расчеты в процедурах &НаСервере. Это значительно быстрее, так как данные не перекачиваются постоянно между клиентом и сервером.
  2. Обновление экрана: В управляемых формах изменения данных в объекте обычно отображаются сразу. Однако для повышения удобства можно применить групповое изменение реквизитов с формы через специальное расширение, которое позволяет интерактивно редактировать данные.
  3. Метод ЗаполнитьЗначения: Если вам нужно не прибавить число, а просто установить во всех строках одинаковый статус или дату, используйте метод коллекции Объект.Товары.ЗаполнитьЗначения(Значение, "ИмяКолонки"). Это работает молниеносно на больших объемах данных.

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

← На главную