Как программно изменить статус документа при его открытии в 1С

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

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

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

Вариант 1. Изменение реквизита непосредственно в объекте

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

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

Проанализируем пример кода:


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

Важный нюанс: Использование метода Записать() внутри формы открытия имеет свои минусы. Если пользователь просто открыл документ «посмотреть» и не планировал ничего менять, документ все равно будет перезаписан. Это может привести к конфликтам блокировок, если одновременно с этим другой процесс (например, фоновое задание) пытается обработать этот же документ.

Вариант 2. Использование независимого регистра сведений (Рекомендуемый)

Разберем более профессиональный и «чистый» подход. Если статус «Прочитано» или «Принято» не влияет на проведение документа и логику учета, а служит лишь индикатором для пользователей, лучше хранить такие состояния в отдельном Независимом регистре сведений.

Это решение обладает рядом преимуществ:

  1. Отсутствие блокировок: Мы не перезаписываем сам документ, а значит, не меняем его версию и не вызываем лишних срабатываний подписок на события.
  2. История изменений: В регистре можно хранить информацию о том, КТО и КОГДА открыл документ.
  3. Права доступа: Пользователю могут быть запрещены права на изменение документа, но разрешены права на запись в регистр сведений.

Выясним, как это реализовать. Предположим, у нас есть регистр СостоянияДокументов с измерением Документ и ресурсом Состояние.


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

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

Вариант 3. Защита от случайных открытий (Обработчик ожидания)

Часто пользователи случайно открывают документы, просто пролистывая список. Чтобы статус не менялся мгновенно, можно использовать ПодключаемыйОбработчикОжидания. В этом случае статус изменится только тогда, когда пользователь продержит форму открытой более 2-3 секунд.

Разберем реализацию этого метода по шагам:

  1. В процедуре ПриОткрытии на клиенте подключаем обработчик.
  2. В самом обработчике вызываем серверную процедуру смены статуса.

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем процедуру, которая сработает через 3 секунды
    ПодключитьОбработчикОжидания("УстановитьСтатусПрочтенияПоТаймеру", 3, Истина);
КонецПроцедуры

&НаКлиенте
Процедура УстановитьСтатусПрочтенияПоТаймеру()
    // Вызываем серверный метод для записи данных
    ИзменитьСтатусНаСервере();
КонецПроцедуры

Обновление статуса в форме списка

Проанализируем ситуацию: вы изменили статус документа (в объекте или регистре), но пользователь, у которого открыта форма списка, все еще видит старое значение. Чтобы этого избежать, мы использовали метод ОповеститьОбИзменении(Ссылка).

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

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

Резюме

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

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

← На главную