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

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

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

Исходная ситуация: у нас есть документ с несколькими реквизитами (например, стСТП, стКфП, стШкКлРук) и регистр сведений «ПоказателиРасчета» с соответствующими ресурсами (СТП, КфП, ШкКлРук). Наша цель — при создании нового документа заполнить его реквизиты последними актуальными значениями из этого регистра на дату документа.

Шаг 1. Определяем место для кода: процедура «ПриСозданииНаСервере»

Любая логика, связанная с обращением к базе данных, должна выполняться на сервере. Это основной принцип клиент-серверной архитектуры 1С, обеспечивающий производительность и безопасность. Идеальным местом для нашего кода является обработчик события формы документа ПриСозданииНаСервере.

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

Важный момент: нам нужно, чтобы заполнение происходило только для нового документа, а не при открытии уже существующего. Для этого внутри процедуры добавим проверку с помощью метода Объект.ЭтоНовый().

Структура процедуры будет выглядеть так:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Выполняем код только при создании нового документа
    Если НЕ Объект.ЭтоНовый() Тогда
        Возврат; // Если документ не новый, просто выходим из процедуры
    КонецЕсли;

    //
    // Здесь будет наш код для получения данных и заполнения реквизитов
    //
    
КонецПроцедуры

Шаг 2. Выбираем способ получения данных

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

Способ 1: Получение данных с помощью Запроса (гибкий и мощный)

Использование запросов — это наиболее универсальный способ работы с данными в 1С. Он позволяет не только получать данные, но и связывать их с другими таблицами, применять сложные условия отбора и упорядочивать результат. Для нашей задачи мы будем использовать виртуальную таблицу регистра сведений СрезПоследних.

Виртуальная таблица СрезПоследних на лету формирует срез актуальных данных на указанную дату. Это именно то, что нам нужно.

Давайте напишем запрос и разберем его по частям.


// Создаем новый объект Запрос
Запрос = Новый Запрос;

// Определяем текст запроса
Запрос.Текст =
    "ВЫБРАТЬ
    |    ПоказателиРасчетаСрезПоследних.СТП,
    |    ПоказателиРасчетаСрезПоследних.КфП,
    |    ПоказателиРасчетаСрезПоследних.ШкКлРук,
    |    ПоказателиРасчетаСрезПоследних.ГорКлРук,
    |    ПоказателиРасчетаСрезПоследних.ФедКлРук
    |ИЗ
    |    РегистрСведений.ПоказателиРасчета.СрезПоследних(&ДатаДокумента) КАК ПоказателиРасчетаСрезПоследних";

// Устанавливаем значение параметра. В качестве даты среза передаем дату нашего нового документа
Запрос.УстановитьПараметр("ДатаДокумента", Объект.Дата);

// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();

// Проверяем, не пустой ли результат (вдруг в регистре еще нет записей)
Если НЕ РезультатЗапроса.Пустой() Тогда
    // Получаем выборку из результата. Так как измерений нет, запись будет одна
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий(); // Позиционируемся на первой (и единственной) строке

    // Последовательно заполняем реквизиты документа из данных выборки
    Объект.стСТП = Выборка.СТП;
    Объект.стКфП = Выборка.КфП;
    Объект.стШкКлРук = Выборка.ШкКлРук;
    Объект.стГорКлРук = Выборка.ГорКлРук;
    Объект.стФедКлРук = Выборка.ФедКлРук;
КонецЕсли;

Пояснение к коду:

  1. Мы создаем объект Запрос.
  2. В тексте запроса обращаемся к виртуальной таблице РегистрСведений.ПоказателиРасчета.СрезПоследних(). В скобках указываем параметр &ДатаДокумента — это дата, на которую нужно получить срез.
  3. Методом УстановитьПараметр() мы передаем в запрос значение даты из нашего создаваемого документа (Объект.Дата).
  4. После выполнения запроса мы получаем результат. Чтобы извлечь из него данные, мы создаем Выборку.
  5. Команда Выборка.Следующий() перемещает указатель на первую строку результата.
  6. Далее мы обращаемся к полям выборки по именам (Выборка.СТП, Выборка.КфП и т.д.) и присваиваем их значения соответствующим реквизитам документа (Объект.стСТП).

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

Способ 2: Использование Менеджера регистра сведений (простой и быстрый)

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

Метод СрезПоследних() менеджера регистра возвращает готовую Структуру, где ключами являются имена ресурсов, а значениями — их данные на указанную дату.


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

ДанныеПоказателей = РегистрыСведений.ПоказателиРасчета.СрезПоследних(Объект.Дата);

// Заполняем реквизиты документа из полученной структуры
// Обращаемся к элементам структуры по ключу (имени ресурса)
Объект.стСТП      = ДанныеПоказателей.СТП;
Объект.стКфП      = ДанныеПоказателей.КфП;
Объект.стШкКлРук  = ДанныеПоказателей.ШкКлРук;
Объект.стГорКлРук = ДанныеПоказателей.ГорКлРук;
Объект.стФедКлРук = ДанныеПоказателей.ФедКлРук;

Как видите, этот код значительно короче и проще для понимания, но менее гибок, чем полноценный запрос.

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

Если имена реквизитов в документе и ресурсов в регистре сведений совпадают, можно еще больше сократить код. В этом поможет глобальный метод ЗаполнитьЗначенияСвойств(). Он копирует значения из одного объекта (например, выборки из запроса или структуры) в другой (в наш объект документа) по совпадению имен свойств.

Важно: для этого имена должны совпадать полностью. В нашем исходном примере имена не совпадают (стСТП и СТП). Чтобы использовать этот метод, вам пришлось бы переименовать реквизиты документа, убрав префикс "ст". Предположим, вы это сделали, и теперь реквизиты называются СТП, КфП и т.д.

Тогда код с использованием запроса можно упростить так:


// ... код запроса до выполнения ...
РезультатЗапроса = Запрос.Выполнить();

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

А код с использованием менеджера регистра будет еще короче:


ДанныеПоказателей = РегистрыСведений.ПоказателиРасчета.СрезПоследних(Объект.Дата);

// Заполняем все совпадающие по имени реквизиты из структуры
ЗаполнитьЗначенияСвойств(Объект, ДанныеПоказателей);

Этот прием значительно повышает читаемость кода и сокращает его объем, особенно когда реквизитов много.

Замечание про "старые" и "новые" значения

В обсуждении прозвучал вопрос о том, как показать в документе и старые, и новые значения. Такая задача подразумевает, что регистр сведений является периодическим (с установленной периодичностью, например, "По дню"). "Новые" значения — это те, что мы получили на дату документа. "Старые" — это те, что действовали до последнего изменения перед датой документа. Их получение — более сложная задача, которая решается отдельным, более сложным запросом (часто пакетным) для определения даты предыдущей записи и получения среза на тот момент времени.

← На главную