Рассмотрим часто встречающуюся ситуацию при разработке в 1С: необходимо, чтобы при создании нового документа определенное поле (например, автор или ответственный) автоматически заполнялось именем текущего пользователя. Однако при попытке программно присвоить значение система выдает ошибку «Поле объекта недоступно для записи». Проанализируем причины этой ошибки и разберем по шагам, как правильно реализовать автоматическое заполнение.
Разберем типичный ошибочный подход, когда разработчик пытается получить доступ к документу через метод Выбрать() и записать туда данные:
&НаСервере
Функция ТекПолн()
тру = Документы.КлиентскаяБазаДанных.Выбрать();
тру.Ведет = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
КонецФункции;
Выясним причину ошибки в этом коде. Метод Выбрать() возвращает выборку документов. Выборки и ссылки в 1С предоставляются платформой исключительно для чтения. Платформа выдает ошибку, потому что мы пытаемся изменить свойство объекта, к которому у нас нет полного (объектного) доступа. Чтобы изменять данные существующего документа, необходимо получать сам объект с помощью метода ПолучитьОбъект(). Но в случае, когда мы уже находимся в форме создаваемого документа, нам вообще не нужно делать запросы к базе данных или обращаться к менеджеру документа.
Посмотрим на правильный вариант заполнения. Если мы хотим заполнить реквизит именно в момент открытия формы нового документа, нам необходимо использовать стандартный обработчик ПриСозданииНаСервере в модуле формы. Внутри формы доступ к реквизитам самого документа осуществляется через основной реквизит формы, который по умолчанию называется Объект.
Рассмотрим рабочий пример кода:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, что документ новый (ссылка еще не существует в базе)
Если Объект.Ссылка.Пустая() Тогда
Объект.Ведет = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
КонецЕсли;
КонецПроцедуры
В этом примере мы проверяем, является ли документ новым с помощью Объект.Ссылка.Пустая(). Если условие выполняется, мы обращаемся к реквизиту Ведет напрямую через Объект и присваиваем ему имя текущего пользователя.
Хотя предложенный выше код работает, проанализируем ситуацию глубже и рассмотрим более правильные архитектурные подходы.
ПользователиИнформационнойБазы.ТекущийПользователь().Имя возвращает простую строку. Если в вашей конфигурации реквизит документа имеет ссылочный тип (например, СправочникСсылка.Пользователи), то попытка записать в него строку не увенчается успехом. В таком случае лучше использовать параметры сеанса: ПараметрыСеанса.ТекущийПользователь. Они сразу возвращают ссылку на элемент справочника пользователей и работают быстрее за счет кэширования.ОбработкаЗаполнения в модуле самого объекта (документа), а не в модуле формы.Посмотрим на пример реализации через модуль объекта:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
// Реквизиты доступны напрямую по их именам
Если Не ЗначениеЗаполнено(Ведет) Тогда
Ведет = ПараметрыСеанса.ТекущийПользователь;
КонецЕсли;
КонецПроцедуры
Преимущество этого метода в том, что реквизит заполнится автоматически вне зависимости от того, как создается документ — интерактивно пользователем через интерфейс или программно с помощью внешнего кода (когда форма вообще не открывается).
Важное примечание: Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), то механизмы автоматического заполнения автора или ответственного там уже встроены. Достаточно включить документ в соответствующую подсистему, и писать собственный код для заполнения пользователя не потребуется.