В разработке на платформе 1С:Предприятие 8.2 или 8.3 при использовании обычных форм часто возникает задача ограничить действия пользователя в рамках одной табличной части. Классический пример — запрет на изменение цены для определенных категорий товаров (например, акционных позиций или товаров с фиксированным прайсом), в то время как для остальной номенклатуры цена должна оставаться доступной для редактирования.
Сложность обычных форм заключается в том, что свойство ТолькоПросмотр у колонки табличного поля применяется ко всей колонке целиком, а не к конкретной ячейке. В этой статье мы подробно разберем несколько профессиональных подходов, которые позволяют имитировать построчную блокировку и обеспечить надежный контроль данных.
Прежде чем приступать к написанию кода в форме документа, нам необходимо определить критерий, по которому система поймет, что цену редактировать нельзя. Рассмотрим наиболее правильный вариант — добавление нового реквизита в справочник Номенклатура.
Проанализируем ситуацию: создадим реквизит ЗапретитьРедактированиеЦены с типом Булево. Если этот флаг установлен, программа должна блокировать ввод в поле цены в документах (например, в «Заказе покупателя» или «Реализации товаров и услуг»).
Этот метод является наиболее корректным с точки зрения интерфейса. Событие ПередНачаломИзменения возникает в тот момент, когда пользователь пытается войти в режим редактирования ячейки (нажимает Enter или делает двойной щелчок мыши). Мы можем перехватить это действие и отменить его.
Разберем реализацию этого метода по шагам:
Процедура ТоварыПередНачаломИзменения(Элемент, Отказ)
// Получаем данные текущей строки, которую пытается редактировать пользователь
ТекущаяСтрока = Элемент.ТекущиеДанные;
// Если строка пустая, ничего не делаем
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
// Проверяем, что пользователь пытается изменить именно колонку "Цена"
// и проверяем наше условие блокировки из справочника Номенклатура
Если Элемент.ТекущаяКолонка.Имя = "Цена" И ТекущаяСтрока.Номенклатура.ЗапретитьРедактированиеЦены Тогда
// Выводим предупреждение пользователю
Сообщить("Для позиции '" + ТекущаяСтрока.Номенклатура + "' цена зафиксирована и не подлежит изменению!", СтатусСообщения.Внимание);
// Устанавливаем Отказ в Истина, чтобы предотвратить вход в режим редактирования
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Преимущества: Пользователь не может даже начать ввод данных. Это выглядит профессионально и не ломает логику работы других ячеек строки.
Рассмотрим альтернативный вариант. Мы можем переключать доступность всей колонки в зависимости от того, на какой строке находится курсор. Это реализуется в событии ПриАктивизацииСтроки или ПриАктивизацииЯчейки табличного поля.
Посмотрим на пример кода:
Процедура ТоварыПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элемент.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Определяем, должна ли колонка "Цена" быть доступной для данной строки
НужноБлокировать = ТекущиеДанные.Номенклатура.ЗапретитьРедактированиеЦены;
// Устанавливаем свойство ТолькоПросмотр для колонки динамически
ЭлементыФормы.Товары.Колонки.Цена.ТолькоПросмотр = НужноБлокировать;
КонецЕсли;
КонецПроцедуры
Нюанс: Данный метод имеет одну особенность — если пользователь будет быстро переключаться между строками, интерфейс может незначительно «подмигивать». Однако этот способ дает визуальную подсказку: если ячейка заблокирована, при попытке ввода курсор может просто не активироваться в данном поле.
Просто заблокировать ввод недостаточно для хорошего UX (User Experience). Пользователь должен заранее видеть, какие цены он может менять, а какие — нет. Для этого проанализируем событие ПриВыводеСтроки.
Это событие вызывается при отрисовке каждой строки на экране. Здесь мы можем изменить цвет фона ячейки Цена.
Процедура ТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Проверяем условие блокировки
Если ДанныеСтроки.Номенклатура.ЗапретитьРедактированиеЦены Тогда
// Устанавливаем серый цвет фона для ячейки цены, чтобы показать ее недоступность
ОформлениеСтроки.Ячейки.Цена.ЦветФона = ЦветаСтиля.ЦветФонаФормы;
// Можно также установить текст, объясняющий причину (опционально)
ОформлениеСтроки.Ячейки.Цена.Подсказка = "Цена установлена прайс-листом и не редактируется";
КонецЕсли;
КонецПроцедуры
Важно: Если строк в таблице очень много (сотни или тысячи), использование ПриВыводеСтроки может замедлить прокрутку. В таких случаях рекомендуется использовать событие ПриПолученииДанных, которое работает с массивом строк и выполняется значительно быстрее.
Выясним причину, почему иногда стоит использовать именно этот метод. Если данные вставляются в таблицу копированием или программно, события активации ячеек могут не сработать. В таком случае мы можем проверять факт изменения цены и возвращать её к исходному состоянию.
Процедура ТоварыЦенаПриИзменении(Элемент)
ТекущаяСтрока = ЭлементыФормы.Товары.ТекущиеДанные;
Если ТекущаяСтрока.Номенклатура.ЗапретитьРедактированиеЦены Тогда
// Получаем актуальную цену из регистра цен или другого источника
АктуальнаяЦена = Ценообразование.ПолучитьЦенуНоменклатуры(ТекущаяСтрока.Номенклатура, Дата);
Если ТекущаяСтрока.Цена <> АктуальнаяЦена Тогда
Сообщить("Цена для этой номенклатуры была возвращена к исходному значению!");
ТекущаяСтрока.Цена = АктуальнаяЦена;
// Не забудьте пересчитать сумму строки
ОбработкаТабличныхЧастей.РассчитатьСуммуТабЧасти(ТекущаяСтрока, ЭтотОбъект);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Ни один из методов на уровне формы не дает 100% гарантии защиты (например, при программном изменении объекта). Поэтому всегда следует добавлять финальную проверку в модуле объекта документа в процедуре ПередЗаписью.
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Для Каждого СтрокаТовара Из Товары Цикл
Если СтрокаТовара.Номенклатура.ЗапретитьРедактированиеЦены Тогда
ЦенаВСистеме = Ценообразование.ПолучитьЦенуНоменклатуры(СтрокаТовара.Номенклатура, Дата);
Если СтрокаТовара.Цена <> ЦенаВСистеме Тогда
Сообщить("Документ не может быть записан! В строке " + СтрокаТовара.НомерСтроки +
" изменена фиксированная цена позиции " + СтрокаТовара.Номенклатура);
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Мы рассмотрели комплексный подход к блокировке редактирования цен в обычных формах 1С. Подведем итоги:
Сочетание этих методов обеспечит надежную работу системы и прозрачный интерфейс для пользователя, предотвращая случайные или намеренные ошибки при вводе цен.