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

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

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

Выясним причину: почему Доступность блокирует всю колонку

Типичная ошибка начинающего разработчика — попытка обойти строки таблицы в цикле и установить свойство элемента формы:


Для Каждого ТекущаяСтрока Из Таб Цикл 
    Если ТекущаяСтрока.Автор <> ТекущийПользователь Тогда
        ЭтаФорма.Элементы.Клиент.Доступность = Ложь;
    КонецЕсли;
КонецЦикла;

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

Подводные камни и архитектурные ограничения платформы

Прежде чем настраивать запреты в коде, проанализируем важные системные ограничения платформы 1С:

  1. Блокировки при параллельной работе: Табличная часть — это единое целое с документом. Если двое или более сотрудников одновременно откроют документ и начнут добавлять строки, первый записавший сохранит изменения, а второй получит ошибку оптимистической блокировки («Данные были изменены или удалены другим пользователем»). Либо сработает пессимистическая блокировка при начале редактирования. Платформа 1С не умеет автоматически объединять строки из разных сеансов.
  2. Ограничение механизма RLS: Права доступа на уровне записей (RLS) в 1С действуют только на целые объекты (документы, справочники, записи регистров). Разграничить доступ к отдельным строкам табличной части через RLS невозможно.
  3. Ненадежность только клиентских проверок: Любой запрет, реализованный только в коде формы, можно случайно или намеренно обойти (например, при пакетной обработке или загрузке данных). Поэтому ограничения всегда требуют серверного контроля.

Способ 1. Использование событий таблицы ПередНачаломИзменения и ПередНачаломУдаления

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

Вместо изменения доступности элементов следует использовать события самой таблицы формы. Перехватим попытку войти в режим редактирования строки с помощью события ПередНачаломИзменения:


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

Однако запрета на изменение недостаточно: пользователь по-прежнему может выделить чужую строку и нажать клавишу Delete. Чтобы исключить такую возможность, обязательно добавим обработчик события ПередНачаломУдаления:


&НаКлиенте
Процедура ТабличнаяЧастьПередНачаломУдаления(Элемент, Отказ)
    
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Если ТекущиеДанные.Автор <> ПараметрыСеанса.ТекущийПользователь Тогда
        Отказ = Истина;
        ПоказатьПредупреждение(, "Запрещено удалять строки, созданные другими пользователями!");
    КонецЕсли;
    
КонецПроцедуры

Способ 2. Визуальное выделение и блокировка через УсловноеОформление

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    ЭлементОформления = УсловноеОформление.Элементы.Добавить();
    
    // 1. Указываем оформляемые поля (все колонки строки)
    ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
    ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("ТабличнаяЧасть");
    
    // 2. Задаем условие: Автор не равен текущему пользователю
    ОтборОформления = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ОтборОформления.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ТабличнаяЧасть.Автор");
    ОтборОформления.ВидСравнения = ВидСравненияКомпоновкиДанных.НеРавно;
    ОтборОформления.ПравоеЗначение = ПараметрыСеанса.ТекущийПользователь;
    
    // 3. Устанавливаем свойства: только просмотр и серый цвет текста
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ТолькоПросмотр", Истина);
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветТекста", ЦветаСтиля.ТекстЗапрещеннойЯчейки);
    
КонецПроцедуры

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

Автоматическое заполнение автора и защита поля от подмены

Чтобы описанный механизм работал, поле Автор в строке должно автоматически заполняться при добавлении новой записи, а пользователь не должен иметь возможности вручную выбрать другого автора. Реализуем обработчик ПриНачалеРедактирования:


&НаКлиенте
Процедура ТабличнаяЧастьПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    
    Если НоваяСтрока Тогда
        Элемент.ТекущиеДанные.Автор = ПараметрыСеанса.ТекущийПользователь;
    КонецЕсли;
    
КонецПроцедуры

Для самого элемента формы, связанного с колонкой Автор, на уровне свойств формы установим ТолькоПросмотр = Истина.

Гарантированная проверка в модуле объекта ПередЗаписью

Для предотвращения обхода интерфейсных запретов добавим серверный контроль в модуль документа в процедуру ПередЗаписью. Проверим, не были ли изменены или удалены чужие строки по сравнению с версией из базы данных:


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

Альтернативные архитектурные решения

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

  1. Использование регистра сведений:

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

  2. Подчиненные документы:

    Создается документ-основание (например, заказ-наряд или карточка автомобиля) и подчиненные документы исполнителей (например, отдельные акты выполненных работ по мастерам). На форме основного документа выводится сводный список подчиненных документов. Это исключает коллизии параллельной записи и позволяет гибко разграничивать права доступа через типовые механизмы ролей и RLS.

← На главную