Как правильно проверить принадлежность товара к группе и ограничить скидку в табличной части 1С?

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

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

Анализ типичной ошибки: почему цикл по всей таблице не подходит

Рассмотрим ситуацию: разработчик хочет запретить скидку на товары из группы «ЗАКАЗНОЕ». В исходном коде была сделана попытка перебрать все строки документа при изменении любой из них:


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

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

Правильное решение: работа с текущей строкой

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

В обычных формах (1С 8.3) доступ к данным редактируемой строки можно получить через свойство элемента формы ТекущаяСтрока. Рассмотрим исправленный алгоритм:

  1. Определим ссылку на группу «ЗАКАЗНОЕ».
  2. Получим данные текущей строки табличной части.
  3. Проверим условие принадлежности именно этого товара к запрещенной группе.
  4. Обнулим скидку и пересчитаем суммы, если условие выполнено.

Ниже приведен пример кода для обработчика события ПроцентСкидкиПриИзменении:


// Получаем ссылку на группу (лучше вынести в параметры или константы)
ГруппаЗаказное = Справочники.Номенклатура.НайтиПоКоду("00000005");

// Получаем текущую строку табличной части
СтрокаТаблицы = ЭлементыФормы.Товары.ТекущиеДанные;

Если СтрокаТаблицы <> Неопределено Тогда
    // Проверяем принадлежность товара к иерархии группы
    Если СтрокаТаблицы.Номенклатура.ПринадлежитЭлементу(ГруппаЗаказное) Тогда
        Если СтрокаТаблицы.ПроцентСкидки > 0 Тогда
            Сообщить("На группу товаров ЗАКАЗНОЕ скидка не действует, только наценка!", СтатусСообщения.Важное);
            
            // Обнуляем показатели скидки
            СтрокаТаблицы.ПроцентСкидки = 0;
            СтрокаТаблицы.СуммаСкидки = 0;
            
            // Выполняем пересчет суммы и НДС
            СтрокаТаблицы.СуммаВсего = СтрокаТаблицы.Сумма;
            
            // Рассчитываем НДС (важно использовать правильное округление)
            СтавкаНДС = СтрокаТаблицы.СтавкаНДС.Ставка; // Число, например, 20
            СтрокаТаблицы.СуммаНДС = Окр(СтрокаТаблицы.СуммаВсего - (СтрокаТаблицы.СуммаВсего / (СтавкаНДС / 100 + 1)), 2);
        КонецЕсли;
    КонецЕсли;
КонецЕсли;

Оптимизация и важные нюансы

Разберем несколько важных моментов, которые помогут сделать ваш код более профессиональным и надежным:

1. Избегайте поиска по коду в теле обработчика. Метод НайтиПоКоду выполняет запрос к базе данных. Если пользователь быстро редактирует строки, это создает лишнюю нагрузку. Рекомендуется один раз получить ссылку на группу при открытии формы (в процедуре ПриОткрытии) и сохранить ее в переменную модуля формы.

2. Типизация данных. В исходном коде автору советовали присваивать пустую строку "" числовому полю ПроцентСкидки. Это методически неверно. Для числовых реквизитов всегда используйте 0, чтобы избежать ошибок при записи или расчетах в других модулях.

3. Иерархическая проверка. Метод ПринадлежитЭлементу отлично работает для проверки вхождения в группу. Однако помните, что если иерархия справочника «Номенклатура» очень сложная, а проверка должна выполняться на сервере при проведении документа, лучше использовать запрос с оператором В ИЕРАРХИИ.

4. Расчет НДС. Самостоятельный расчет НДС по формуле может привести к расхождениям в копейках. Проанализируйте конфигурацию: если в ней есть общие модули для работы с ценами и налогами (например, ОбщегоНазначения.РассчитатьСуммуНДС), лучше использовать их. Это гарантирует соответствие вашего расчета типовым правилам округления 1С.

5. Проверка отрицательных значений (наценки). Если ваша бизнес-логика разрешает наценку (отрицательную скидку), убедитесь, что условие ПроцентСкидки > 0 правильно обрабатывает такие случаи. Как видно из примера, мы блокируем только положительную скидку, позволяя наценке оставаться в строке.

Используя обращение к ТекущиеДанные или ТекущаяСтрока, мы обеспечиваем точечную работу алгоритма, исключаем лишние предупреждения для пользователя и повышаем общую производительность системы.

← На главную