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

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

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

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

В чем сложность стандартной блокировки?

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

Для решения этой задачи мы применим комплексный подход, состоящий из трех основных шагов:

  1. Создание служебного реквизита (флага) в табличной части документа для идентификации программно добавленных строк.
  2. Программная настройка механизма Условного оформления формы на сервере для визуальной блокировки ячеек.
  3. Блокировка интерактивных действий (удаление, копирование, изменение) на клиенте через события таблицы формы для обеспечения полной безопасности данных.

---

Шаг 1. Создание служебного реквизита в табличной части

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

Рассмотрим порядок действий по шагам:

  1. Откроем конфигуратор и найдем нужный документ (например, РасходнаяНакладная).
  2. Перейдем на вкладку «Данные» и найдем нашу табличную часть (например, СписокНоменклатуры).
  3. Добавим в эту табличную часть новый реквизит с именем Автодобавление (или СлужебнаяСтрока) и типом данных Булево.
  4. Вынесем эту колонку на форму документа, но сделаем ее невидимой для пользователя, сняв флажок у свойства Видимость элемента формы. Этот реквизит будет использоваться исключительно в кодовой логике.

---

Шаг 2. Заполнение служебного реквизита при программном добавлении строк

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


&НаСервере
Процедура ДобавитьКомплектующиеНаСервере(НаименованиеКомплекта)
    
    // Запрос для получения состава комплекта из регистра сведений
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Комплектация.Материал КАК Материал,
        |   Комплектация.Количество КАК Количество
        |ИЗ
        |   РегистрСведений.Комплектация КАК Комплектация
        |ГДЕ
        |   Комплектация.Товар = &Товар";
        
    Запрос.УстановитьПараметр("Товар", НаименованиеКомплекта);
    Выборка = Запрос.Выполнить().Выбрать();
    
    // В цикле обходим комплектующие и добавляем их в табличную часть документа
    Пока Выборка.Следующий() Цикл
        
        НоваяСтрока = Объект.СписокНоменклатуры.Добавить();
        НоваяСтрока.Номенклатура = Выборка.Material;
        НоваяСтрока.Количество   = Выборка.Количество;
        
        // Получаем цену (например, среднюю по складу)
        НоваяСтрока.Цена         = Серверный.СредняяПоСкладу(Выборка.Материал, Объект.Склад);
        НоваяСтрока.Сумма        = НоваяСтрока.Количество * НоваяСтрока.Цена;
        
        // Устанавливаем признак программно добавленной строки
        НоваяСтрока.Автодобавление = Истина;
        
    КонецЦикла;
    
    // Пересчитываем итог документа
    Объект.СуммаПоДокументу = Объект.СписокНоменклатуры.Итог("Сумма");
    
КонецПроцедуры

---

Шаг 3. Блокировка ячеек через Условное оформление

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

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    НастроитьБлокировкуСтрокТаблицы();
    
КонецПроцедуры

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

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

---

Шаг 4. Полная защита от удаления и копирования на клиенте

Хотя условное оформление отлично справляется с визуальной блокировкой ячеек для ввода данных, оно имеет существенную брешь в безопасности: пользователь все еще может выделить заблокированную строку в интерфейсе и нажать клавишу Del на клавиатуре (или выбрать пункт контекстного меню «Удалить»). Строка удалится, что нарушит комплектность накладной.

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

Рассмотрим код клиентских обработчиков:


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

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

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

---

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

В реальных бизнес-сценариях просто заблокировать строки комплектующих бывает недостаточно. Возникает закономерный вопрос: а что делать, если пользователь решит изменить количество основного товара (например, заказать не 1 стеллаж, а 3) или вовсе удалить сам стеллаж из документа?

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

  1. В табличную часть добавляется числовой реквизит КлючСвязи.
  2. При добавлении строки основного товара генерируется уникальный номер (например, 1). Он записывается в поле КлючСвязи основного товара.
  3. У всех подчиненных строк (комплектующих) в поле КлючСвязи записывается этот же номер 1.
  4. При изменении количества основного товара система перехватывает событие ПриИзменении, находит в табличной части все строки с аналогичным КлючомСвязи и пропорционально пересчитывает их количество.
  5. При удалении основного товара (событие ПередУдалением) система автоматически находит все строки с его ключом связи и программно удаляет их вместе с ним.

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

← На главную