В практике разработки на платформе 1С:Предприятие 8.3 часто встречается задача: при выборе номенклатуры в табличной части документа необходимо автоматически подставить связанные данные — артикул, единицу измерения, актуальную цену и пересчитать сумму с налогом. На первый взгляд задача кажется простой, но неоптимальный подход может привести к серьезным «тормозам» интерфейса, особенно при работе через интернет или при большом количестве строк.
Разберем типичные ошибки и лучшие практики на основе реального примера кода, который вызвал активное обсуждение в сообществе разработчиков.
Рассмотрим фрагмент кода, с которого началось обсуждение. В нем программист пытается получить данные для каждой колонки отдельными серверными вызовами:
&НаКлиенте
Процедура СписокТоваровНаименованиеПриИзменении(Элемент)
ТекСтрока = Элементы.СписокТоваров.Текущиеданные;
ТекСтрока.Артикул = ПолучитьРекПоНаим(ТекСтрока.Наименование, "Артикуль");
ТекСтрока.ЕдиницаИзмерения = ПолучитьРекПоНаим(ТекСтрока.Наименование, "ЕдиницаИзмерения");
ТекСтрока.Количество = ПолучитьРекПоНаим(ТекСтрока.Наименование, "Количество");
ТекСтрока.Цена = ПолучитьРекПоНаим(ТекСтрока.Наименование, "Цена");
// ... расчет суммы и НДС
КонецПроцедуры
&НаСервере
Функция ПолучитьРекПоНаим(СсылкаПоНаименованию, Реквизит)
Возврат СсылкаПоНаименованию[Реквизит];
КонецФункции
Проанализируем ситуацию и выделим основные критические моменты:
&НаСервере сопровождается передачей всего контекста формы (данных всех реквизитов и таблиц) туда и обратно. Это создает огромную нагрузку на сеть.Объект.НДС = Объект.Итого / 20 * 100. Это логическая ошибка. Если ставка НДС составляет 20%, то налог вычисляется либо как 20% «сверху» (умножение на 0.2), либо как 20% «внутри» (умножение на 20 и деление на 120)."Артикуль" вместо "Артикул" приведет к ошибке выполнения, так как платформа не найдет реквизит с таким именем.Если ваша конфигурация не использует Библиотеку стандартных подсистем (БСП), самый правильный путь — собрать все необходимые данные на сервере за один раз и вернуть их на клиент в виде структуры. Это сократит количество вызовов сервера в разы.
Рассмотрим подробнее реализацию этого метода:
&НаКлиенте
Процедура СписокТоваровНаименованиеПриИзменении(Элемент)
ТекущаяСтрока = Элементы.СписокТоваров.ТекущиеДанные;
Если ТекущаяСтрока.Наименование.Пустая() Тогда
Возврат;
КонецЕсли;
// Получаем все данные одним вызовом
ДанныеТовара = ПолучитьДанныеНоменклатуры(ТекущаяСтрока.Наименование);
// Используем ЗаполнитьЗначенияСвойств для быстрого копирования
ЗаполнитьЗначенияСвойств(ТекущаяСтрока, ДанныеТовара);
// Выполняем расчеты на клиенте
ПересчитатьСуммуСтроки(ТекущаяСтрока);
ПересчитатьИтогиДокумента();
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьДанныеНоменклатуры(СсылкаНаТовар)
Результат = Новый Структура;
Результат.Вставить("Артикул", СсылкаНаТовар.Артикул);
Результат.Вставить("ЕдиницаИзмерения", СсылкаНаТовар.ЕдиницаИзмерения);
Результат.Вставить("Цена", СсылкаНаТовар.Цена);
Возврат Результат;
КонецФункции
Важный момент: Обратите внимание на использование директивы &НаСервереБезКонтекста. В этом случае форма не передается на сервер, что делает вызов максимально «легким» и быстрым. Мы передаем только ссылку на номенклатуру, а сервер возвращает маленькую структуру с тремя значениями.
Если вы работаете в современной конфигурации (УТ 11, ERP, БП 3.0), использование функций БСП является обязательным стандартом качества. Для получения реквизитов объекта существует универсальный механизм в общем модуле ОбщегоНазначения.
Однако здесь есть нюанс, вызвавший спор на форуме. Модуль ОбщегоНазначения имеет флаг «Сервер», но не имеет флага «Вызов сервера». Это означает, что напрямую с клиента вызвать функцию ЗначениеРеквизитаОбъекта нельзя.
Рассмотрим, как правильно организовать этот процесс:
ОбщегоНазначенияВызовСервера.Пример вызова через БСП для получения нескольких полей сразу:
// На сервере внутри формы
МассивРеквизитов = "Артикул, ЕдиницаИзмерения, Цена";
Данные = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ТекущаяСтрока.Наименование, МассивРеквизитов);
// Теперь в переменной "Данные" лежит структура с нужными полями
Помните, что функции БСП оптимизированы: они используют кэширование и максимально быстрые запросы к базе данных, что гораздо эффективнее, чем обращение к реквизитам через точку (например, Ссылка.Артикул), которое может привести к неявному считыванию всего объекта из базы.
Выясним причину, по которой расчет налогов часто вызывает затруднения. Необходимо четко разделять логику расчета в строке и по всему документу. Посмотрим на пример корректного пересчета:
&НаКлиенте
Процедура ПересчитатьСуммуСтроки(СтрокаТаблицы)
СтрокаТаблицы.Сумма = СтрокаТаблицы.Количество * СтрокаТаблицы.Цена;
// Пример расчета НДС 20% (включен в сумму)
СтавкаНДС = 20;
СтрокаТаблицы.СуммаНДС = Окр(СтрокаТаблицы.Сумма * СтавкаНДС / (100 + СтавкаНДС), 2);
КонецПроцедуры
&НаКлиенте
Процедура ПересчитатьИтогиДокумента()
Объект.ИтогоСумма = Объект.СписокТоваров.Итог("Сумма");
Объект.ИтогоНДС = Объект.СписокТоваров.Итог("СуммаНДС");
КонецПроцедуры
Использование метода Итог() на клиенте — это эффективный способ быстро получить сумму по колонке без обхода таблицы в цикле. Это работает быстро, так как данные уже находятся в памяти клиента.
Проанализируем ситуацию, когда расчеты все же необходимо выполнить на сервере (например, если логика получения цены очень сложная и требует запросов к регистрам сведений). Распространенная ошибка — попытка обратиться к Элементы.СписокТоваров.ТекущиеДанные на сервере. Это свойство там недоступно.
В таких случаях мы должны передать на сервер идентификатор строки:
&НаКлиенте
Процедура СписокТоваровНаименованиеПриИзменении(Элемент)
ИдентификаторСтроки = Элементы.СписокТоваров.ТекущаяСтрока;
ОбработатьВыборТовараНаСервере(ИдентификаторСтроки);
КонецПроцедуры
&НаСервере
Процедура ОбработатьВыборТовараНаСервере(ИдСтроки)
ТекСтрока = Объект.СписокТоваров.НайтиПоИдентификатору(ИдСтроки);
// Теперь здесь можно менять данные строки напрямую в контексте формы
ТекСтрока.Цена = ... // Логика получения цены
КонецПроцедуры
Для создания качественного и быстрого интерфейса в 1С 8.3 придерживайтесь следующих правил:
&НаСервереБезКонтекста везде, где вам не нужно менять саму форму, а нужно лишь получить справочные данные.ОбщегоНазначения написаны профессионалами и учитывают множество нюансов производительности.Окр()), чтобы избежать проблем с копейками в бухгалтерском учете.Соблюдение этих принципов позволит вашим формам работать мгновенно даже при большом количестве данных, а код будет понятным и легким для доработки другими программистами.