При разработке документов в 1С часто встречается задача: пользователь выбирает номенклатуру в табличной части, и программа должна автоматически подставить цену, хранящуюся в карточке товара или регистре. Нередко возникает ситуация, когда код написан, синтаксических ошибок нет, но при выборе товара в режиме предприятия ничего не происходит — цена остается пустой или равной нулю. Рассмотрим причины такого поведения и способы решения проблемы, от простых ошибок внимательности до архитектурных нюансов.
Самая распространенная причина, по которой код «не работает», заключается в том, что платформа просто не знает, что этот код нужно выполнить. Написание процедуры в модуле формы с правильным названием (например, ТабличнаяЧасть1ТоварПриИзменении) недостаточно.
Разберем порядок действий для проверки:
ТабличнаяЧасть1Товар).ПриИзменении.Важный момент: если поле напротив события пустое, процедура не привязана. Необходимо нажать на кнопку с лупой (или выбрать из выпадающего списка), чтобы указать платформе, какую именно процедуру выполнять при изменении этого поля. После этого связь будет установлена.
В исходном коде используется директива &НаСервере. Для получения простых данных (таких как цена) это неэффективно, так как при вызове обычной серверной процедуры на сервер передается весь контекст формы (все данные документа), что создает лишний трафик.
Мы рекомендуем использовать директиву &НаСервереБезКонтекста. Она позволяет передать только необходимые параметры (ссылку на товар) и получить ответ, не нагружая систему передачей всей формы.
Перепишем код функции более правильно:
&НаСервереБезКонтекста
Функция ПолучитьЦенуТовараНаСервере(СсылкаНаТовар)
// Проверка на пустую ссылку, чтобы не делать лишний запрос
Если СсылкаНаТовар.Пустая() Тогда
Возврат 0;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(Товары.Цена, 0) КАК Цена
|ИЗ
| Справочник.Товары КАК Товары
|ГДЕ
| Товары.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаТовар);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
Возврат Выборка.Цена;
Иначе
Возврат 0;
КонецЕсли;
КонецФункции
Обратите внимание, мы добавили конструкцию ЕСТЬNULL в запросе. Это гарантирует, что если цена в карточке товара не задана (равна NULL), запрос вернет 0, и мы избежим ошибок при математических операциях в дальнейшем.
Теперь рассмотрим клиентскую часть кода. Здесь важно убедиться, что мы работаем с актуальными данными текущей строки. Используем свойство ТекущиеДанные.
&НаКлиенте
Процедура ТабличнаяЧасть1ТоварПриИзменении(Элемент)
// Получаем текущую строку табличной части
СтрокаТЧ = Элементы.ТабличнаяЧасть1.ТекущиеДанные;
Если СтрокаТЧ = Неопределено Тогда
Возврат; // Защита от случая, если строка не активна
КонецЕсли;
// Вызываем серверную функцию без контекста
СтрокаТЧ.Цена = ПолучитьЦенуТовараНаСервере(СтрокаТЧ.Товар);
// Если нужно пересчитать сумму строки:
// СтрокаТЧ.Сумма = СтрокаТЧ.Цена * СтрокаТЧ.Количество;
КонецПроцедуры
Если после исправления привязки события и кода цена все равно не появляется, необходимо воспользоваться отладчиком. Это позволит понять, на каком этапе теряется значение.
ТабличнаяЧасть1ТоварПриИзменении.Если программа остановилась на точке останова, значит, событие работает. Нажимая F10 (Шаг через), проследите выполнение кода. Проверьте значение переменной СтрокаТЧ.Товар (нажав Shift+F9). Если ссылка корректна, зайдите внутрь серверной функции (F11) и посмотрите, что возвращает запрос. Возможно, для выбранного товара цена в базе действительно равна 0.
Важно отметить, что хранение цены непосредственно в реквизитах справочника Товары характерно только для учебных задач или очень простых конфигураций. В реальных типовых решениях (УТ, ERP, Бухгалтерия) цены хранятся в Регистрах сведений (например, ЦеныНоменклатуры), так как они меняются во времени и зависят от вида цен.
Если вы работаете с типовой конфигурацией, ваш запрос к справочнику не вернет цену, так как реквизита Цена там просто нет. В таком случае запрос должен обращаться к виртуальной таблице среза последних регистра сведений:
// Пример текста запроса для реальных задач (упрощенно)
"ВЫБРАТЬ
| ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
| &Период,
| Номенклатура = &Номенклатура И ВидЦены = &ВидЦены) КАК ЦеныНоменклатурыСрезПоследних"