При разработке логики в формах документов часто возникает задача: ограничить возможность предоставления скидки для определенных категорий товаров. Распространенная ошибка заключается в том, что проверку одной строки подменяют проверкой всей табличной части. В этой статье мы проанализируем, почему код может работать некорректно, и разберем правильный алгоритм обработки данных в строках табличной части.
Рассмотрим ситуацию: разработчик хочет запретить скидку на товары из группы «ЗАКАЗНОЕ». В исходном коде была сделана попытка перебрать все строки документа при изменении любой из них:
Для каждого ТС Из ЭтаФорма.Товары Цикл
Если (ТС.номенклатура.ПринадлежитЭлементу(ЗАКАЗНОЕ) и ЭтотОбъект.Товары.Итог("ПроцентСкидки") > 0) Тогда
Сообщить("На группу товаров ЗАКАЗНОЕ скидка не действует!");
// Очистка скидки...
КонецЕсли;
КонецЦикла;
Проанализируем этот подход. Использование конструкции Для каждого внутри обработчика события строки (например, ПриИзменении) приводит к тому, что при редактировании любой позиции система заново проверяет каждую строку документа. Если в документе уже есть хотя бы один товар из группы «ЗАКАЗНОЕ», предупреждение будет всплывать при изменении любых других товаров, даже не входящих в эту группу. Кроме того, использование метода Итог("ПроцентСкидки") в условии является некорректным, так как он возвращает сумму процентов по всему документу, а не значение в конкретной строке.
Для того чтобы логика срабатывала только для той строки, которую редактирует пользователь, необходимо отказаться от цикла и использовать контекст текущей строки. Выясним, как это реализовать наиболее эффективно.
В обычных формах (1С 8.3) доступ к данным редактируемой строки можно получить через свойство элемента формы ТекущаяСтрока. Рассмотрим исправленный алгоритм:
Ниже приведен пример кода для обработчика события ПроцентСкидкиПриИзменении:
// Получаем ссылку на группу (лучше вынести в параметры или константы)
ГруппаЗаказное = Справочники.Номенклатура.НайтиПоКоду("00000005");
// Получаем текущую строку табличной части
СтрокаТаблицы = ЭлементыФормы.Товары.ТекущиеДанные;
Если СтрокаТаблицы <> Неопределено Тогда
// Проверяем принадлежность товара к иерархии группы
Если СтрокаТаблицы.Номенклатура.ПринадлежитЭлементу(ГруппаЗаказное) Тогда
Если СтрокаТаблицы.ПроцентСкидки > 0 Тогда
Сообщить("На группу товаров ЗАКАЗНОЕ скидка не действует, только наценка!", СтатусСообщения.Важное);
// Обнуляем показатели скидки
СтрокаТаблицы.ПроцентСкидки = 0;
СтрокаТаблицы.СуммаСкидки = 0;
// Выполняем пересчет суммы и НДС
СтрокаТаблицы.СуммаВсего = СтрокаТаблицы.Сумма;
// Рассчитываем НДС (важно использовать правильное округление)
СтавкаНДС = СтрокаТаблицы.СтавкаНДС.Ставка; // Число, например, 20
СтрокаТаблицы.СуммаНДС = Окр(СтрокаТаблицы.СуммаВсего - (СтрокаТаблицы.СуммаВсего / (СтавкаНДС / 100 + 1)), 2);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Разберем несколько важных моментов, которые помогут сделать ваш код более профессиональным и надежным:
1. Избегайте поиска по коду в теле обработчика. Метод НайтиПоКоду выполняет запрос к базе данных. Если пользователь быстро редактирует строки, это создает лишнюю нагрузку. Рекомендуется один раз получить ссылку на группу при открытии формы (в процедуре ПриОткрытии) и сохранить ее в переменную модуля формы.
2. Типизация данных. В исходном коде автору советовали присваивать пустую строку "" числовому полю ПроцентСкидки. Это методически неверно. Для числовых реквизитов всегда используйте 0, чтобы избежать ошибок при записи или расчетах в других модулях.
3. Иерархическая проверка. Метод ПринадлежитЭлементу отлично работает для проверки вхождения в группу. Однако помните, что если иерархия справочника «Номенклатура» очень сложная, а проверка должна выполняться на сервере при проведении документа, лучше использовать запрос с оператором В ИЕРАРХИИ.
4. Расчет НДС. Самостоятельный расчет НДС по формуле может привести к расхождениям в копейках. Проанализируйте конфигурацию: если в ней есть общие модули для работы с ценами и налогами (например, ОбщегоНазначения.РассчитатьСуммуНДС), лучше использовать их. Это гарантирует соответствие вашего расчета типовым правилам округления 1С.
5. Проверка отрицательных значений (наценки). Если ваша бизнес-логика разрешает наценку (отрицательную скидку), убедитесь, что условие ПроцентСкидки > 0 правильно обрабатывает такие случаи. Как видно из примера, мы блокируем только положительную скидку, позволяя наценке оставаться в строке.
Используя обращение к ТекущиеДанные или ТекущаяСтрока, мы обеспечиваем точечную работу алгоритма, исключаем лишние предупреждения для пользователя и повышаем общую производительность системы.