Как реализовать автоматическое заполнение реквизитов формы данными из регистра сведений?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача автоматизации ввода данных. Типичный сценарий: пользователь выбирает объект (например, «Оборудование»), и система должна мгновенно подтянуть связанные с ним данные (например, «Заменяемый картридж») из истории, хранящейся в регистре сведений. Несмотря на кажущуюся простоту, здесь есть несколько «подводных камней», связанных с типами данных, контекстом исполнения кода и особенностями работы с временными отметками.

Разберем подробно, как правильно организовать этот процесс, проанализируем типичные ошибки начинающих разработчиков и рассмотрим наиболее эффективные методы получения данных.

Метод 1. Использование функции ПолучитьПоследнее

Самый простой и быстрый в написании способ получить данные из периодического регистра сведений — использование метода менеджера регистра ПолучитьПоследнее(). Рассмотрим пример реализации, который часто применяется в общих модулях.

Предположим, у нас есть периодический регистр РасходныеМатериалыВОборудовании с измерением Оборудование и ресурсом ЗаменяемыйКартридж. Наша задача — получить значение ресурса на определенную дату.

Проанализируем программный код в общем модуле:


// Функция в общем модуле (должны быть установлены флаги "Сервер" и "Вызов сервера")
Функция ПолучитьАктуальныйКартридж(АктуальнаяДата, ВыбранноеОборудование) Экспорт
    
    // Создаем структуру отбора. 
    // ВАЖНО: Отбор всегда идет по ИЗМЕРЕНИЯМ регистра.
    Отбор = Новый Структура();
    Отбор.Вставить("Оборудование", ВыбранноеОборудование);
    
    // Получаем структуру последних значений ресурсов
    ЗначенияРесурсов = РегистрыСведений.РасходныеМатериалыВОборудовании.ПолучитьПоследнее(АктуальнаяДата, Отбор);
    
    // Возвращаем конкретный ресурс. 
    // Если запись не найдена, структура будет содержать пустые значения соответствующих типов.
    Возврат ЗначенияРесурсов.ЗаменяемыйКартридж;
    
КонецФункции

Важные замечания по этому методу:

  1. Отбор по измерениям: Одной из самых частых ошибок является попытка наложить отбор на ресурсы или реквизиты регистра внутри структуры отбора. Метод ПолучитьПоследнее принимает в отбор только измерения.
  2. Типизация: Убедитесь, что значение ВыбранноеОборудование имеет тот же тип, что и измерение в регистре (например, СправочникСсылка.Номенклатура). Если вы передадите строку вместо ссылки, поиск не даст результатов.
  3. Проверка на пустую дату: Если в параметр АктуальнаяДата передать пустую дату, система вернет самую последнюю запись в регистре за всю историю.

Проблема границы времени (Почему «не работает» подстановка)

Рассмотрим ситуацию, которую часто обсуждают на форумах: код написан верно, данные в регистре есть, но поле на форме остается пустым. Выясним причину, проанализировав работу платформы с временем.

Метод ПолучитьПоследнее(Дата, Отбор) ищет запись, период которой меньше или равен переданной дате. Если в документе реквизит Объект.Дата равен 15.10.2023 00:00:00 (начало дня), а запись в регистре была сделана тем же числом, но позже (например, в 12:00:00), то метод её «не увидит».

Для решения этой проблемы при вызове функции из формы рекомендуется использовать либо текущую дату сеанса, либо конец дня документа:


&НаКлиенте
Процедура ОборудованиеПриИзменении(Элемент)
    
    // Используем КонецДня, чтобы захватить все записи, сделанные в течение дня документа
    ДатаДляПоиска = КонецДня(Объект.Дата);
    
    // Вызываем серверную функцию для получения данных
    Объект.СтарыйКартридж = ОбщийМодульСервер.ПолучитьАктуальныйКартридж(ДатаДляПоиска, Объект.Оборудование);
    
КонецПроцедуры

Метод 2. Использование запроса (СрезПоследних)

Более профессиональным и гибким подходом считается использование запроса к виртуальной таблице СрезПоследних. Это позволяет избежать проблем с производительностью на больших объемах данных и дает возможность накладывать сложные условия.

Рассмотрим пример запроса:


&НаСервереБезКонтекста
Функция ПолучитьКартриджЗапросом(АктуальнаяДата, ОборудованиеСсылка)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   РМ.ЗаменяемыйКартридж КАК Картридж
        |ИЗ
        |   РегистрСведений.РасходныеМатериалыВОборудовании.СрезПоследних(&Период, Оборудование = &Оборудование) КАК РМ";
    
    Запрос.УстановитьПараметр("Период", АктуальнаяДата);
    Запрос.УстановитьПараметр("Оборудование", ОборудованиеСсылка);
    
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Картридж;
    КонецЕсли;
    
    Возврат Справочники.Номенклатура.ПустаяСсылка();
    
КонецФункции

Преимущества использования запроса:

Организация кода в управляемой форме

Чтобы подстановка работала корректно в управляемом интерфейсе, необходимо соблюдать правила контекстных вызовов. Выполним настройку по шагам:

  1. Создадим на форме событие ПриИзменении для поля, которое является «триггером» (в нашем случае — «Оборудование»).
  2. В процедуре события обязательно проверим, не очистил ли пользователь поле. Если поле пустое, нужно очистить и зависимый реквизит.
  3. Вызовем серверную функцию. Лучше всего использовать &НаСервереБезКонтекста, так как это работает быстрее (не передается вся форма на сервер).

Посмотрим на итоговую структуру модуля формы:


&НаКлиенте
Процедура ОборудованиеПриИзменении(Элемент)
    
    Если ЗначениеЗаполнено(Объект.Оборудование) Тогда
        // Передаем дату документа и ссылку на оборудование
        Объект.ЗаменяемыйКартридж = ПолучитьДанныеИзРегистра(Объект.Дата, Объект.Оборудование);
    Иначе
        // Очищаем зависимое поле, если основное пустое
        Объект.ЗаменяемыйКартридж = ПредопределенноеЗначение("Справочник.Номенклатура.ПустаяСсылка");
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьДанныеИзРегистра(ДатаДокумента, СсылкаОборудование)
    // Здесь может быть либо логика с ПолучитьПоследнее(), либо Запрос
    // Для надежности используем границу времени или текущий момент
    СтруктураДанных = РегистрыСведений.РасходныеМатериалыВОборудовании.ПолучитьПоследнее(КонецДня(ДатаДокумента), Новый Структура("Оборудование", СсылкаОборудование));
    Возврат СтруктураДанных.ЗаменяемыйКартридж;
КонецФункции

Резюме и рекомендации

Проанализировав ситуацию, можно выделить основные правила безопасной подстановки данных:

Во-первых, всегда проверяйте структуру регистра сведений. Отборы в методах ПолучитьПоследнее или параметрах СрезПоследних работают только по измерениям. Если вам нужно найти данные по значению ресурса, используйте обычный запрос к физической таблице регистра с условием в секции ГДЕ.

Во-вторых, помните о времени. В 1С 00:00:00 — это самое начало дня. Если записи вносятся оперативно в течение дня, поиск на начало дня их не найдет. Используйте КонецДня() или Неопределено (для получения самого последнего значения вне зависимости от даты).

В-третьих, следите за контекстом. В управляемых формах обращение к объекту РегистрыСведений напрямую на клиенте невозможно. Всегда выносите логику получения данных на сервер.

Соблюдение этих простых правил позволит вам создавать отзывчивые и надежные интерфейсы, которые экономят время пользователей и минимизируют ошибки ручного ввода.

← На главную