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