Как получить значения нескольких ресурсов регистра сведений по двум измерениям при автозаполнении в 1С?

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

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

Рассмотрим, с какими сложностями можно столкнуться при раздельном вызове функций, как правильно построить составной отбор по нескольким измерениям и как корректно передать структуру ресурсов на форму.

В чем заключается ошибка раздельного поиска

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

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

Шаг 1. Создание серверной функции для получения ресурсов

Создадим функцию в общем модуле (или в модуле формы с директивой &НаСервереБезКонтекста), которая принимает актуальную дату среза и ссылки на оба ключевых измерения. Передадим отбор в виде структуры с двумя ключами.


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

Метод ПолучитьПоследнее возвращает объект типа Структура, в котором ключами являются имена ресурсов регистра сведений, а значениями — их актуальные данные на указанный момент времени.

Шаг 2. Реализация логики на клиенте управляемой формы

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

Вынесем процедуру заполнения строки в отдельный метод и вызовем его из клиентских событий ПриИзменении:


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

&НаКлиенте
Процедура ВРемонтНоменклатураПриИзменении(Элемент)
    СтрокаТабличнойЧасти = Элементы.ВРемонт.ТекущиеДанные;
    ЗаполнитьЦенуИСрокВСтроке(СтрокаТабличнойЧасти);
КонецПроцедуры

&НаКлиенте
Процедура ВРемонтКонтрагентПриИзменении(Элемент)
    СтрокаТабличнойЧасти = Элементы.ВРемонт.ТекущиеДанные;
    ЗаполнитьЦенуИСрокВСтроке(СтрокаТабличнойЧасти);
КонецПроцедуры

&НаКлиенте
Процедура ПересчитатьСуммуСтроки(СтрокаТабличнойЧасти)
    СтрокаТабличнойЧасти.Сумма = СтрокаТабличнойЧасти.Количество * СтрокаТабличнойЧасти.Цена;
КонецПроцедуры

Оптимизация заполнения с помощью ЗаполнитьЗначенияСвойств

Если имена ресурсов регистра сведений полностью совпадают с именами колонок табличной части документа (например, Цена и СрокПоставки), вместо ручного присвоения каждого поля удобно использовать встроенную процедуру ЗаполнитьЗначенияСвойств:


// Заполнение всех совпадающих по имени полей одной командой
ЗаполнитьЗначенияСвойств(СтрокаТабличнойЧасти, ПараметрыПоставки);

Такой подход защищает код от опечаток при обращении к ключам структуры и упрощает добавление новых ресурсов в регистр в будущем.

Важные особенности метода ПолучитьПоследнее

Проанализируем тонкости поведения платформы 1С при работе с периодическими регистрами сведений:

  1. Возврат значений по умолчанию: если в регистре нет записей по указанной комбинации номенклатуры и контрагента, метод ПолучитьПоследнее все равно возвращает структуру, в которой числовые поля равны 0, а ссылочные — пустым ссылкам. Метод никогда не возвращает Неопределено.
  2. Точность имен свойств: ключи возвращаемой структуры строго соответствуют именам ресурсов в метаданных. Если в регистре ресурс назван СрокПоставки, а в коде идет обращение к свойству ПараметрыПоставки.Срок, платформа вызовет исключение «Поле объекта не обнаружено».
  3. Контроль пустой даты: если в новом документе поле Объект.Дата еще не заполнено (содержит пустую дату '00010101'), срез вернет данные на начало времен. Всегда подставляйте ТекущаяДатаСеанса() при пустой дате объекта.
  4. Привязка событий в конфигураторе: если процедура написана в коде, но автозаполнение не происходит, обязательно убедитесь через палитру свойств элемента формы, что обработчик события ПриИзменении действительно назначен соответствующей процедуре.

Групповая обработка строк через запрос

Если требуется заполнить цены и сроки не для одной строки при интерактивном вводе, а для всей табличной части разом (например, при загрузке документа или нажатии кнопки «Перезаполнить цены»), вызывать ПолучитьПоследнее в цикле категорически не рекомендуется из-за высокой нагрузки на СУБД.

В таких случаях используют один пакетный запрос к виртуальной таблице СрезПоследних с передачей пар «Номенклатура — Контрагент» через временную таблицу.

← На главную