Как запретить редактирование документа после проведения в клиент-серверном режиме 1С?

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

В процессе эксплуатации систем на базе 1С:Предприятие 8.3 часто возникает задача ограничить возможность редактирования документов, которые уже прошли процедуру проведения. Особенно это актуально для торговых конфигураций, таких как УТ 11.2, где менеджеры могут случайно изменить данные в закрытых периодах или уже отгруженных заказах. Однако при реализации этой задачи в клиент-серверном режиме разработчики часто сталкиваются с тем, что код, работавший в файловой версии, перестает функционировать или вызывает ошибки выполнения.

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

Разбор типичных ошибок при работе в клиент-серверном режиме

Рассмотрим ситуацию: разработчик вставляет проверку в модуль объекта документа в процедуру ПередЗаписью. В файловом варианте всё работает корректно, но в клиент-серверном — условие игнорируется или выдает ошибку. Выясним причину этого поведения.

  1. Разделение контекста: В клиент-серверном режиме код модуля объекта всегда выполняется на сервере. Если внутри условия используются конструкции препроцессора типа #Если Клиент Тогда или функции, доступные только на клиенте, серверная часть их просто проигнорирует.
  2. Функция РольДоступна(): Эта функция на сервере проверяет роли текущего сеанса. Если вы неправильно определили контекст (например, пытаетесь вызвать клиентскую проверку), код не сработает.
  3. Особенности вывода сообщений: Использование стандартной команды Сообщить() на сервере имеет свои нюансы. В некоторых случаях при откате транзакции (когда Отказ = Истина), сообщения могут не дойти до пользователя, если не используются механизмы БСП (Библиотеки стандартных подсистем).

Логическая ловушка проверки статуса «Проведен»

Проанализируем код, который часто пытаются использовать новички:


Если ЭтотОбъект.Проведен Тогда
    Отказ = Истина;
КонецЕсли;

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

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


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

Реализация через подписку на событие

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

Рассмотрим по шагам, как правильно создать подписку, чтобы избежать ошибок, упомянутых в обсуждении на форуме:

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

Теперь проанализируем код обработчика. Важно помнить: в общем модуле нет переменной ЭтотОбъект. Вместо нее используется первый параметр процедуры — Источник.


Процедура ПроверитьЗапретИзмененияПроведенногоПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

    // Игнорируем проверку, если это отмена проведения
    Если РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения Тогда
        Возврат;
    КонецЕсли;

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

КонецПроцедуры

Закрытие лазейки с отменой проведения

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

Выясним причину: при отмене проведения Отказ = Истина не срабатывает, так как мы добавили исключение. Чтобы полностью защитить документ, необходимо вводить проверку и на событие отмены проведения, либо проверять «дату запрета редактирования» программно для конкретного объекта.

Улучшение UX: Визуальная блокировка формы

Хотя серверная проверка надежно защищает данные, пользователю будет неудобно заполнять документ 10 минут, чтобы только при сохранении узнать о запрете. Рассмотрим, как заблокировать форму интерактивно.

В модуле формы документа (в процедуре ПриЧтенииНаСервере) добавим логику:


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    
    // Если документ проведен и прав нет - блокируем форму целиком
    Если ТекущийОбъект.Проведен И НЕ РольДоступна("ПолныеПрава") Тогда
        ЭтаФорма.ТолькоПросмотр = Истина;
    КонецЕсли;
    
КонецПроцедуры

Важный момент: Свойство ТолькоПросмотр = Истина делает форму недоступной для редактирования, но оставляет возможность просмотра данных. Это наиболее правильный подход с точки зрения интерфейса (User Experience).

Итоги и рекомендации

Подведем итог нашему анализу. Для надежной блокировки в клиент-серверном режиме 1С необходимо:

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

← На главную