При разработке в среде 1С:Предприятие 8 начинающие программисты часто сталкиваются с ситуацией, когда необходимо изменить логику проведения документа или расчета суммы в зависимости от определенных свойств объекта. Типичный пример — разделение алгоритмов для "Товаров" и "Услуг". Рассмотрим, как правильно реализовать такую проверку, почему сравнение со строкой является ошибкой и как оптимизировать код для повышения производительности системы.
В исходном примере кода автор пытался использовать конструкцию Если стр.Номенклатура.ТипНоменклатуры = Строка("Товар"). Разберем, почему так делать не стоит. В 1С реквизит ТипНоменклатуры, как правило, имеет тип СправочникСсылка. Ссылка — это уникальный идентификатор объекта в базе данных (GUID), в то время как "Товар" — это просто текстовая строка. Система не может напрямую приравнять объект к тексту, поэтому такое условие всегда будет возвращать Ложь, либо потребует принудительного приведения типов, что крайне неэффективно.
Основные недостатки сравнения со строкой:
Строка()) — это ресурсоемкая операция, которая замедляет работу цикла.Если тип номенклатуры реализован как справочник, самым правильным и надежным способом будет создание предопределенных элементов в конфигураторе. Предопределенные элементы имеют уникальное имя (идентификатор), к которому можно обращаться напрямую из кода.
Предположим, в справочнике ТипНоменклатуры созданы элементы с именами Товар и Услуга. Тогда наше условие в процедуре обработки проведения будет выглядеть следующим образом:
Процедура ОбработкаПроведения(Отказ, Режим)
Движения.Проводки.Записывать = Истина;
Для Каждого стр Из Товары Цикл
Движение = Движения.Проводки.Добавить();
Движение.Период = Дата;
// Правильное обращение к предопределенному элементу справочника
Если стр.Номенклатура.ТипНоменклатуры = Справочники.ТипНоменклатуры.Товар Тогда
Движение.Сумма = стр.Цена * 100;
ИначеЕсли стр.Номенклатура.ТипНоменклатуры = Справочники.ТипНоменклатуры.Услуга Тогда
Движение.Сумма = стр.Цена / 100;
Иначе
Движение.Сумма = стр.Цена;
КонецЕсли;
Движение.Номенклатура = стр.Номенклатура;
КонецЦикла;
КонецПроцедуры
Этот метод работает быстро, так как сравнение идет по внутренним ссылкам, и код не зависит от того, какое "Наименование" (синоним) видит пользователь в интерфейсе.
Проанализируем структуру данных: если набор типов номенклатуры жестко ограничен (например, только Товар, Услуга, Работа) и не предполагает добавления новых элементов пользователем в режиме "1С:Предприятие", то архитектурно правильнее использовать объект метаданных Перечисление.
Если бы ТипНоменклатуры был перечислением, код стал бы еще прозрачнее:
Если стр.Номенклатура.ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Товар Тогда
// Ваша логика
КонецЕсли;
Перечисления работают быстрее справочников и идеально подходят для логических переключателей в коде.
В коде автора присутствует серьезная проблема производительности, известная как "обращение через точку" в цикле. Когда мы пишем стр.Номенклатура.ТипНоменклатуры, система для каждой строки документа делает отдельный неявный запрос к базе данных, чтобы получить значение типа. Если в документе 200 строк, система сделает 200 лишних запросов.
Рассмотрим, как выполнить ту же задачу профессионально — с помощью запроса. Мы выберем данные из табличной части и сразу получим типы номенклатуры за один сеанс связи с БД.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажаТовары.Номенклатура КАК Номенклатура,
| ПродажаТовары.Цена КАК Цена,
| ПродажаТовары.Номенклатура.ТипНоменклатуры КАК Тип
|ИЗ
| Документ.ПродажаТовара.Товары КАК ПродажаТовары
|ГДЕ
| ПродажаТовары.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.Проводки.Добавить();
Движение.Период = Дата;
// Используем уже полученное в запросе значение Тип
Если Выборка.Тип = Справочники.ТипНоменклатуры.Товар Тогда
Движение.Сумма = Выборка.Цена * 100;
Иначе
Движение.Сумма = Выборка.Цена / 100;
КонецЕсли;
КонецЦикла;
Проанализируем этот подход: мы один раз обратились к серверу БД, получили готовую таблицу со всеми нужными данными и просто обошли ее в цикле. Это стандарт "чистого кода" в 1С, обеспечивающий высокую скорость работы программы даже при больших объемах данных.
Разберем еще один критический момент. Если в справочнике Номенклатура у какой-то позиции не заполнен реквизит ТипНоменклатуры, сравнение стр.Номенклатура.ТипНоменклатуры = Справочники.ТипНоменклатуры.Товар вернет Ложь, и выполнение уйдет в ветку Иначе. Это может привести к неверному расчету суммы (например, для товара без типа применится логика услуги).
Чтобы избежать ошибок, всегда рекомендуется использовать функцию ЗначениеЗаполнено() или проверять на пустую ссылку:
Если НЕ ЗначениеЗаполнено(стр.Номенклатура.ТипНоменклатуры) Тогда
Сообщить("У номенклатуры " + стр.Номенклатура + " не задан тип!");
Отказ = Истина;
Возврат;
КонецЕсли;
Подведем итог: для написания качественного условия в 1С забудьте о сравнении со строками. Используйте предопределенные элементы для справочников или перечисления. Старайтесь выносить получение данных из циклов в запросы, чтобы ваш код работал эффективно и быстро.