В процессе разработки на платформе 1С:Предприятие часто возникает задача массового изменения данных в табличной части (ТЧ) документа или обработки. Это может быть как простое увеличение цены на определенный коэффициент, так и сложное распределение накладных расходов по всем позициям номенклатуры. В данной статье мы подробно разберем, как правильно реализовать такие механизмы, избежав типичных ошибок новичков.
Рассмотрим ситуацию, с которой столкнулся автор темы. При попытке изменить значения во всех строках, код работал некорректно: менялась только первая (выделенная) строка. Проанализируем ошибочный фрагмент кода:
Для каждого Строка Из Объект.ТабличнаяЧасть Цикл
Строка = Элементы.ТабличнаяЧасть.ТекущиеДанные;
Строка.Сумма = Строка.Сумма + НаценкаЗаОдинТовар;
КонецЦикла;
Выясним причину такого поведения. В среде 1С управляемые формы разделяют данные (объект) и их визуальное представление (элементы формы). Элементы.ТабличнаяЧасть.ТекущиеДанные — это ссылка на ту строку, на которой в данный момент физически стоит курсор пользователя. Сколько бы раз ни выполнялся цикл, это выражение всегда будет возвращать одну и ту же активную строку.
Чтобы исправить эту ошибку, нам достаточно использовать переменную цикла, которая на каждой итерации автоматически указывает на следующую строку коллекции Объект.ТабличнаяЧасть. Лишнее присваивание внутри цикла нужно просто удалить.
Рассмотрим правильный подход. Допустим, нам нужно прибавить число 10 к колонке Сумма в каждой строке. Проанализируем код, который будет работать быстро и безошибочно:
&НаСервере
Процедура ПрибавитьДесятьНаСервере()
// Обязательно проверяем, есть ли строки в таблице
Если Объект.Товары.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Для каждого ТекущаяСтрока Из Объект.Товары Цикл
// Обращаемся напрямую к свойствам строки через переменную цикла
ТекущаяСтрока.Сумма = ТекущаяСтрока.Сумма + 10;
КонецЦикла;
КонецПроцедуры
В этом примере мы используем переменную ТекущаяСтрока. На каждом шаге цикла 1С сама подставляет в неё следующую строку из Объект.Товары. Это самый прозрачный и эффективный способ для математических преобразований данных. Если вам требуется не программная логика, а удобный интерфейс для правки данных, можно использовать универсальный редактор справочников, позволяющий видеть табличные части и реквизиты на одном экране.
Теперь разберем более сложную и экономически обоснованную задачу, упомянутую в обсуждении: распределение фиксированной суммы (например, стоимости доставки) по всем строкам документа. Часто это требуется, когда выполняется массовое редактирование реквизитов номенклатуры в документах поступления или перемещения. Простое деление общей суммы на количество строк, как правило, не подходит для бухгалтерского учета, так как не учитывает весомость каждой позиции.
Рассмотрим подробнее три основных метода распределения:
Объект.ТабличнаяЧасть.Количество().Проанализируем пример кода для распределения пропорционально сумме строк, так как это наиболее востребованный алгоритм:
&НаСервере
Процедура РаспределитьСуммуПропорционально(ОбщаяСуммаНаценки)
ИтоговаяСуммаДокумента = Объект.Товары.Итог("Сумма");
Если ИтоговаяСуммаДокумента = 0 Тогда
Возврат; // Избегаем деления на ноль
КонецЕсли;
ОстатокНаценки = ОбщаяСуммаНаценки;
КоличествоСтрок = Объект.Товары.Количество();
Для Индекс = 0 По КоличествоСтрок - 1 Цикл
ТекущаяСтрока = Объект.Товары[Индекс];
// Если это последняя строка, отдаем ей весь оставшийся «хвост»
Если Индекс = КоличествоСтрок - 1 Тогда
ТекущаяНаценка = ОстатокНаценки;
Иначе
// Вычисляем долю текущей строки
ТекущаяНаценка = Окр((ОбщаяСуммаНаценки * ТекущаяСтрока.Сумма) / ИтоговаяСуммаДокумента, 2);
ОстатокНаценки = ОстатокНаценки - ТекущаяНаценка;
КонецЕсли;
ТекущаяСтрока.Сумма = ТекущаяСтрока.Сумма + ТекущаяНаценка;
КонецЦикла;
КонецПроцедуры
При математическом распределении часто возникает ситуация, когда из-за округления сумма частей не совпадает с исходным целым числом. Например, если распределить 100 рублей на 3 строки поровну, мы получим 33.33 + 33.33 + 33.33 = 99.99 рублей. В учете потерянная копейка недопустима.
Посмотрим на решение: лучший способ — это расчет наценки для каждой строки по отдельности с вычитанием полученного результата из общего «котла». Последней строке всегда присваивается оставшееся значение. Именно этот механизм реализован в коде выше через проверку Если Индекс = КоличествоСтрок - 1 Тогда. Это гарантирует, что итоговое сальдо всегда сойдется до копейки.
Если ваша конфигурация построена на базе современных решений (УТ 11, ERP, БП 3.0), мы рекомендуем не изобретать велосипед, а использовать встроенные функции БСП. Разобраться в них поможет справочник по методам БСП с примерами использования, где можно быстро найти нужный программный код. В общем модуле ОбщегоНазначенияУТ или аналогичных модулях часто встречается функция РаспределитьСуммуПропорционально.
Она принимает массив коэффициентов и общую сумму, возвращая массив распределенных значений, где проблема округления уже решена на уровне платформенных алгоритмов. Это делает код чище и снижает вероятность ошибок в расчетах.
Выясним, как сделать работу алгоритма максимально комфортной для пользователя. Программное изменение данных в ТЧ требует внимания к интерфейсу:
&НаСервере. Это значительно быстрее, так как данные не перекачиваются постоянно между клиентом и сервером.Объект.Товары.ЗаполнитьЗначения(Значение, "ИмяКолонки"). Это работает молниеносно на больших объемах данных.Подводя итог, можно сказать, что работа с табличными частями требует понимания разницы между объектом данных и элементами формы, а также внимательного отношения к типам распределения и округлениям. Использование правильных циклов и проверок на пустые значения сделает ваш код надежным и профессиональным.