Как исправить ошибку «Поле объекта недоступно для записи» при программном подписании документа в 1С:Документооборот?

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

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

Анализ причины возникновения ошибки

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


ЭтотДокумент = Процесс.Предметы[0].Предмет; 
ЭтотДокумент.РезультатПодписания = Перечисления.РезультатыПодписания.Подписан;

В данном случае переменная ЭтотДокумент содержит Ссылку (тип ДокументСсылка). В архитектуре платформы 1С «ссылка» предназначена только для чтения данных и навигации по базе. Она не содержит в себе данных для записи. Чтобы внести изменения в базу данных, нам необходимо получить Объект (тип ДокументОбъект).

Проанализируем сообщение об ошибке: Ошибка при выполнении обработчика - 'ВыполнитьПроцессБезДействийОбработка' по причине: {(5)}: Поле объекта недоступно для записи (РезультатПодписания). Это прямое указание на то, что система пытается записать данные в структуру, которая для этого не предназначена. Решением является переход от работы со ссылкой к работе с объектом.

Шаг 1: Правильное получение объекта документа

Для того чтобы система позволила нам редактировать поля, мы должны использовать метод ПолучитьОбъект(). Однако, прежде чем это сделать, важно убедиться, что предмет процесса действительно является документом нужного нам типа, чтобы код не «сломался», если в предметах окажется файл или контрагент.

Рассмотрим безопасный способ получения объекта:


ПредметСписка = Процесс.Предметы[0].Предмет;

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

Шаг 2: Изменение реквизитов и метод Записать()

Одной из самых распространенных ошибок после получения объекта является отсутствие вызова метода Записать(). Без этого метода все изменения останутся только в оперативной памяти сервера и не попадут в базу данных.

Выясним, какие именно реквизиты необходимо заполнить для корректной регистрации факта подписания в «1С:Документооборот». Помимо результата подписания, важно зафиксировать, кто и когда подписал документ, а также кто технически установил эту отметку.


АвторДокумента = ЭтотДокументОбъект.Подписал; // Берем подписанта из документа
ТекущаяДатаСеанса = ТекущаяДата();

ЭтотДокументОбъект.РезультатПодписания = Перечисления.РезультатыПодписания.Подписан;
ЭтотДокументОбъект.ДатаПодписания = ТекущаяДатаСеанса;
ЭтотДокументОбъект.КомментарийПодписи = "Документ подписан автоматически (автор является подписантом)";
ЭтотДокументОбъект.УстановилПодпись = АвторДокумента;
ЭтотДокументОбъект.ДатаУстановкиПодписи = ТекущаяДатаСеанса;

// Фиксируем изменения в базе данных
ЭтотДокументОбъект.Записать();

Шаг 3: Работа с состоянием документа через типовые модули

В конфигурации 1С:Документооборот статус документа (например, «Подписан») часто хранится не только в самом объекте, но и в специальных регистрах сведений (например, СостоянияДокументов). Если мы просто запишем объект документа, статус в списках может не обновиться автоматически.

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


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

Обратите внимание: в метод ЗаписатьСостояниеДокумента мы передаем именно Ссылку (через ЭтотДокументОбъект.Ссылка), так как регистрам сведений для связи нужен уникальный идентификатор записи, а не весь объект целиком.

Контекст выполнения и отладка

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

  1. Отсутствие диалогов: Мы не можем использовать методы Сообщить() или Вопрос(), так как некому на них ответить (процесс может стартовать регламентным заданием). Для проверки типа объекта или значений переменных используйте ЗаписьЖурналаРегистрации().
  2. Режим выполнения: Если у пользователя, стартующего процесс, недостаточно прав на прямое редактирование документа, код может выдать ошибку доступа. В таких случаях можно использовать УстановитьПривилегированныйРежим(Истина) перед записью объекта.
  3. Тип клиента: В файловых версиях базы ошибка может не проявляться так явно, как в клиент-серверных, из-за особенностей работы «толстого клиента». Всегда ориентируйтесь на клиент-серверную модель разработки.

Итоговый правильный алгоритм

Подведем итог и соберем работающий программный код для автоматической обработки в комплексном процессе:


// 1. Получаем ссылку на основной предмет
СсылкаНаДокумент = Процесс.Предметы[0].Предмет;

// 2. Проверяем тип (нужно убедиться, что это документ)
Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(СсылкаНаДокумент)) Тогда
    
    // 3. Получаем объект для записи
    ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
    
    Если ДокументОбъект <> Неопределено Тогда
        
        АвторПодписи = ДокументОбъект.Подписал;
        ДатаСобытия = ТекущаяДата();
        
        // 4. Заполняем реквизиты объекта
        ДокументОбъект.РезультатПодписания = Перечисления.РезультатыПодписания.Подписан;
        ДокументОбъект.ДатаПодписания = ДатаСобытия;
        ДокументОбъект.КомментарийПодписи = "Автоматическое подписание.";
        ДокументОбъект.УстановилПодпись = АвторПодписи;
        ДокументОбъект.ДатаУстановкиПодписи = ДатаСобытия;
        
        // 5. Записываем объект в БД
        Попытка
            ДокументОбъект.Записать();
            
            // 6. Обновляем статус в системных регистрах
            Делопроизводство.ЗаписатьСостояниеДокумента(
                ДокументОбъект.Ссылка, 
                ДатаСобытия, 
                Перечисления.СостоянияДокументов.Подписан, 
                АвторПодписи
            );
        Исключение
            // Записываем ошибку в журнал, если что-то пошло не так
            ТекстОшибки = ОписаниеОшибки();
            ЗаписьЖурналаРегистрации("Автоподписание", УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
        КонецПопытки;
        
    КонецЕсли;
КонецЕсли;

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

← На главную