При настройке автоматического расчета цен в программах «1С:Предприятие 8» (таких как «Управление торговлей», «ERP» или «Комплексная автоматизация») пользователи и разработчики часто сталкиваются с необходимостью создания сложных многоуровневых условий. Типичный инструмент для этого — тернарный оператор или встроенная функция ?(). Однако при большом количестве вложений легко допустить ошибку, которую система прокомментирует лаконичным сообщением: «В формуле обнаружены ошибки».
В данной статье мы разберем конкретный пример сложной формулы, выясним причины возникновения ошибок и научимся оптимизировать логические выражения для повышения их надежности и читаемости.
Рассмотрим ситуацию, когда необходимо рассчитать цену в зависимости от процента наценки (отношения розничной цены к закупочной). Автор предложил следующую формулу:
?([Розничные]*100/[Закупочные]-100 < 25,[Розничные]*97/100,
?([Розничные]*100/[Закупочные]-100 >= 25 и [Розничные]*100/[Закупочные]-100 < 30,[Розничные]*96/100,
?([Розничные]*100/[Закупочные]-100 >= 30 и [Розничные]*100/[Закупочные]-100 < 35,[Розничные]*95/100,
?([Розничные]*100/[Закупочные]-100 >= 35 и [Розничные]*100/[Закупочные]-100 < 45,[Розничные]*94/100,
?([Розничные]*100/[Закупочные]-100 >= 45 и [Розничные]*100/[Закупочные]-100 < 60,[Розничные]*93/100,
?([Розничные]*100/[Закупочные]-100 >= 60 и [Розничные]*100/[Закупочные]-100 < 65,[Розничные]*90/100,
?([Розничные]*100/[Закупочные]-100 >= 65 ,[Розничные]*88/100)))))))
Проанализируем, почему эта формула не работает. Основная причина кроется в синтаксисе функции ?(). В языке 1С эта функция является аналогом конструкции Если...Тогда...Иначе и всегда требует три параметра:
Посмотрим на самую внутреннюю часть формулы автора: ?([Розничные]*100/[Закупочные]-100 >= 65 ,[Розничные]*88/100). Здесь указано условие и значение «Тогда», но отсутствует обязательное значение «Иначе». Программа не понимает, что делать, если наценка окажется меньше 65 (в контексте последнего вложения), и выдает ошибку синтаксиса.
Чтобы формула заработала, нам необходимо «закрыть» каждое вложение значением, которое будет возвращено, если ни одно из предыдущих условий не выполнилось. Рассмотрим исправленный вариант, где в последнем условии добавлено значение по умолчанию (например, сама розничная цена или ноль):
?([Розничные]*100/[Закупочные]-100 < 25,[Розничные]*97/100,
?([Розничные]*100/[Закупочные]-100 >= 25 и [Розничные]*100/[Закупочные]-100 < 30,[Розничные]*96/100,
?([Розничные]*100/[Закупочные]-100 >= 30 и [Розничные]*100/[Закупочные]-100 < 35,[Розничные]*95/100,
?([Розничные]*100/[Закупочные]-100 >= 35 и [Розничные]*100/[Закупочные]-100 < 45,[Розничные]*94/100,
?([Розничные]*100/[Закупочные]-100 >= 45 и [Розничные]*100/[Закупочные]-100 < 60,[Розничные]*93/100,
?([Розничные]*100/[Закупочные]-100 >= 60 и [Розничные]*100/[Закупочные]-100 < 65,[Розничные]*90/100,
?([Розничные]*100/[Закупочные]-100 >= 65 ,[Розничные]*88/100, [Розничные])))))))
Здесь в самом конце добавлена переменная [Розничные]. Теперь функция имеет все три аргумента и будет корректно интерпретирована системой.
Проанализируем структуру условий. Заметим, что мы проверяем диапазоны последовательно. Если первое условие наценка < 25 не выполнилось, это автоматически означает, что наценка >= 25. Следовательно, во второй строке повторная проверка [Розничные]*100/[Закупочные]-100 >= 25 является избыточной.
Выясним, как сделать формулу короче и понятнее. Мы можем убрать все левые части сравнений с И, оставив только верхнюю границу для каждого шага. Это значительно сократит текст и уменьшит вероятность опечатки:
?([Розничные]*100/[Закупочные]-100 < 25, [Розничные]*0.97,
?([Розничные]*100/[Закупочные]-100 < 30, [Розничные]*0.96,
?([Розничные]*100/[Закупочные]-100 < 35, [Розничные]*0.95,
?([Розничные]*100/[Закупочные]-100 < 45, [Розничные]*0.94,
?([Розничные]*100/[Закупочные]-100 < 60, [Розничные]*0.93,
?([Розничные]*100/[Закупочные]-100 < 65, [Розничные]*0.90, [Розничные]*0.88))))))
Преимущества такого подхода:
[Розничные]*0.88 теперь корректно срабатывает для всех случаев, когда наценка >= 65.Проанализируем еще несколько критических моментов, которые часто упускаются при написании формул в типах цен.
1. Защита от деления на ноль
В формуле используется делитель [Закупочные]. Если для какого-то товара закупочная цена не будет установлена (равна 0), расчет всей колонки цен прервется с ошибкой. Рекомендуем всегда добавлять проверку делителя с помощью функции ?() или Макс(). Например:
[Розничные]*100 / ?([Закупочные] = 0, 1, [Закупочные])
2. Округление результата
При умножении на коэффициенты вроде 0.97 или 97/100 часто получаются дробные числа с большим количеством знаков после запятой (например, 150.33333). Для корректной работы кассового ПО и эстетичного вида ценников следует использовать функцию округления:
Окр(ВашаФормула, 2) — для округления до копеек.
3. Читаемость кода
Хотя редактор 1С позволяет писать формулу в одну строку, мы советуем использовать переносы строк и отступы («лесенку»), как показано в примерах выше. Это никак не влияет на производительность системы, но позволяет визуально сопоставить открывающие и закрывающие скобки, количество которых должно строго совпадать.
Если ваша логика становится еще сложнее (например, условий больше десяти), использование вложенных ?() становится неэффективным. В таких случаях рассмотрим альтернативы:
ВЫБОР КОГДА... ТОГДА... ИНАЧЕ КОНЕЦ выглядит и читается гораздо лучше.Подводя итог, помните: любая функция ?() должна иметь три составляющих, а последовательная проверка диапазонов позволяет значительно упростить логику, убрав лишние сравнения И.