При разработке документов в 1С начинающие программисты часто сталкиваются с ситуацией, когда ставка налога задана типом ПеречислениеСсылка, а в коде требуется выполнить расчет цены или суммы с учетом налога. Попытка напрямую умножить число на значение реквизита типа перечисления приводит к ошибке несовместимости типов, так как перечисление представляет собой системную ссылку, а не числовую величину.
Разберем подробнее, почему возникает данная сложность, как правильно написать функцию-преобразователь и как корректно выполнить математический расчет в обработчиках событий формы.
Рассмотрим природу проблемы. В конфигурации для хранения возможных вариантов ставок создается объект метаданных Перечисление (например, СтавкиНДС или НДС), содержащий значения Процент20, Процент10, БезНДС. В строке табличной части реквизит с таким типом хранит именно ссылку на элемент перечисления.
Распространенная ошибка заключается в попытке выполнить операцию вида:
СтрокаТабличнойЧасти.ЦенаСНДС = СтрокаТабличнойЧасти.Цена * СтрокаТабличнойЧасти.НДС;
Платформа 1С не умеет автоматически приводить ссылочный тип к числу. Нельзя также просто перезаписать числовое значение в этот же реквизит — если у поля задан тип перечисления, записать число туда не удастся. Для выполнения вычислений необходимо сопоставить каждому элементу перечисления соответствующий числовой процент с помощью отдельного алгоритма.
Разберем по шагам создание функции, которая принимает на вход значение перечисления и возвращает числовое значение процентной ставки.
В управляемых формах такую функцию рекомендуется объявлять с директивой &НаКлиентеНаСервереБезКонтекста либо выносить в общий модуль. Это позволяет вызывать алгоритм на клиенте без передачи контекста формы на сервер и без снижения производительности интерфейса.
&НаКлиентеНаСервереБезКонтекста
Функция ПолучитьСтавкуНДС(СтавкаНДС)
Если СтавкаНДС = ПредопределенноеЗначение("Перечисление.НДС.Процент20") Тогда
Возврат 20;
ИначеЕсли СтавкаНДС = ПредопределенноеЗначение("Перечисление.НДС.Процент10") Тогда
Возврат 10;
ИначеЕсли СтавкаНДС = ПредопределенноеЗначение("Перечисление.НДС.БезНДС") Тогда
Возврат 0;
КонецЕсли;
Возврат 0;
КонецФункции
Если код выполняется в контексте формы, где доступна работа с менеджерами перечислений, можно использовать прямую проверку:
&НаКлиенте
Функция ПолучитьСтавкуНДС(СтавкаНДС)
Если СтавкаНДС = Перечисления.НДС.Процент20 Тогда
Возврат 20;
ИначеЕсли СтавкаНДС = Перечисления.НДС.Процент10 Тогда
Возврат 10;
ИначеЕсли СтавкаНДС = Перечисления.НДС.Процент18 Тогда
Возврат 18;
КонецЕсли;
Возврат 0;
КонецФункции
Теперь выясним причину, по которой формулы пересчета должны размещаться в правильных событиях. Если пользователь изменяет ставку налога или базовую цену, должен срабатывать обработчик изменения соответствующего поля.
Посмотрим на пример обработчика ПриИзменении для колонки выбора ставки НДС:
&НаКлиенте
Процедура ЗаказанныйТоварНДСПриИзменении(Элемент)
СтрокаТабличнойЧасти = Элементы.ЗаказанныйТовар.ТекущиеДанные;
Если СтрокаТабличнойЧасти = Неопределено Тогда
Возврат;
КонецЕсли;
ЧисловаяСтавка = ПолучитьСтавкуНДС(СтрокаТабличнойЧасти.НДС);
// Формула расчета: ЦенаСНДС = Цена + (Цена * Ставка / 100)
СтрокаТабличнойЧасти.ЦенаСНДС = Окр(СтрокаТабличнойЧасти.Цена * (100 + ЧисловаяСтавка) / 100, 2, РежимОкругления.15как20);
КонецПроцедуры
Обратите внимание на обязательное использование функции Окр() с точностью до двух знаков. При делении на 100 могут возникать бесконечные периодические дроби, что приведет к копеечным расхождениям при дальнейшем умножении на количество.
Если пересчет сумм или вывод ставки в числовом виде требуется реализовать не на форме, а внутри запроса (например, при проведении документа или формировании отчета), механизм будет другим. В языке запросов нельзя вызвать пользовательскую функцию, поэтому применяется конструкция ВЫБОР КОГДА.
Проанализируем фрагмент запроса:
ВЫБРАТЬ
Таблица.Номенклатура КАК Номенклатура,
Таблица.Цена КАК Цена,
ВЫБОР
КОГДА Таблица.НДС = ЗНАЧЕНИЕ(Перечисление.НДС.Процент20) ТОГДА 20
КОГДА Таблица.НДС = ЗНАЧЕНИЕ(Перечисление.НДС.Процент10) ТОГДА 10
КОГДА Таблица.НДС = ЗНАЧЕНИЕ(Перечисление.НДС.Процент18) ТОГДА 18
ИНАЧЕ 0
КОНЕЦ КАК СтавкаЧислом
ИЗ
Документ.ЗаказКлиента.Товары КАК Таблица
Рассмотрим более гибкое решение, которое часто применяется в типовых конфигурациях. Использование перечисления имеет существенный недостаток: при изменении налогового законодательства или введении расчетных ставок (например, 20/120) разработчик вынужден вносить изменения в структуру конфигурации через конфигуратор.
Вместо объекта Перечисление архитектурно удобнее использовать Справочник (например, «Ставки НДС»). Добавив в справочник числовой реквизит Ставка, мы получаем ряд преимуществ:
СтрокаТабличнойЧасти.СтавкаНДС.Ставка без написания условий Если ... ИначеЕсли.