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

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

В разработке на платформе 1С:Предприятие 8.2 или 8.3 при использовании обычных форм часто возникает задача ограничить действия пользователя в рамках одной табличной части. Классический пример — запрет на изменение цены для определенных категорий товаров (например, акционных позиций или товаров с фиксированным прайсом), в то время как для остальной номенклатуры цена должна оставаться доступной для редактирования.

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

Подготовительный этап: Признак блокировки

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

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

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

Этот метод является наиболее корректным с точки зрения интерфейса. Событие ПередНачаломИзменения возникает в тот момент, когда пользователь пытается войти в режим редактирования ячейки (нажимает Enter или делает двойной щелчок мыши). Мы можем перехватить это действие и отменить его.

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


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

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

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

Преимущества: Пользователь не может даже начать ввод данных. Это выглядит профессионально и не ломает логику работы других ячеек строки.

Способ 2. Динамическое управление свойством «ТолькоПросмотр»

Рассмотрим альтернативный вариант. Мы можем переключать доступность всей колонки в зависимости от того, на какой строке находится курсор. Это реализуется в событии ПриАктивизацииСтроки или ПриАктивизацииЯчейки табличного поля.

Посмотрим на пример кода:


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

Нюанс: Данный метод имеет одну особенность — если пользователь будет быстро переключаться между строками, интерфейс может незначительно «подмигивать». Однако этот способ дает визуальную подсказку: если ячейка заблокирована, при попытке ввода курсор может просто не активироваться в данном поле.

Способ 3. Визуальное выделение заблокированных строк

Просто заблокировать ввод недостаточно для хорошего UX (User Experience). Пользователь должен заранее видеть, какие цены он может менять, а какие — нет. Для этого проанализируем событие ПриВыводеСтроки.

Это событие вызывается при отрисовке каждой строки на экране. Здесь мы можем изменить цвет фона ячейки Цена.


Процедура ТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    // Проверяем условие блокировки
    Если ДанныеСтроки.Номенклатура.ЗапретитьРедактированиеЦены Тогда
        
        // Устанавливаем серый цвет фона для ячейки цены, чтобы показать ее недоступность
        ОформлениеСтроки.Ячейки.Цена.ЦветФона = ЦветаСтиля.ЦветФонаФормы;
        
        // Можно также установить текст, объясняющий причину (опционально)
        ОформлениеСтроки.Ячейки.Цена.Подсказка = "Цена установлена прайс-листом и не редактируется";
        
    КонецЕсли;
    
КонецПроцедуры

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

Способ 4. Контроль в событии «ПриИзменении» (Откат значения)

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


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

Способ 5. Тотальный контроль в «ПередЗаписью»

Ни один из методов на уровне формы не дает 100% гарантии защиты (например, при программном изменении объекта). Поэтому всегда следует добавлять финальную проверку в модуле объекта документа в процедуре ПередЗаписью.


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

Резюме и рекомендации

Мы рассмотрели комплексный подход к блокировке редактирования цен в обычных формах 1С. Подведем итоги:

  1. Используйте реквизит в справочнике для хранения признака запрета.
  2. Реализуйте событие ПередНачаломИзменения для мягкой блокировки входа в ячейку.
  3. Добавьте визуальное оформление через ПриВыводеСтроки, чтобы пользователь не гадал, почему поле не редактируется.
  4. Для обеспечения целостности данных обязательно делайте проверку в модуле объекта ПередЗаписью.

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

← На главную