В процессе разработки в среде 1С часто возникает задача ограничить редактирование определенных данных в зависимости от бизнес-логики. Типичный пример: в документе Заказ клиента необходимо запретить изменять цену в тех строках, по которым уже созданы и проведены документы Реализация товаров и услуг. При этом, если по заказу отгружена только часть позиций, остальные строки должны оставаться доступными для редактирования.
Проанализируем ситуацию: платформа 1С на управляемых формах не позволяет напрямую обратиться к конкретной ячейке строки и установить ей свойство Доступность. Это свойство управляется на уровне всей колонки для всех строк сразу. Для решения нашей задачи мы воспользуемся механизмом Условного оформления и вспомогательными реквизитами формы.
Это самый оптимальный и рекомендуемый метод. Суть его заключается в том, чтобы создать «флаг» в каждой строке, который будет сигнализировать системе, нужно ли блокировать цену.
Шаг 1. Создание реквизита формы
Рассмотрим порядок действий. Нам не нужно менять структуру метаданных в конфигураторе (добавлять реквизит в объект Документ). Достаточно добавить реквизит в саму форму:
Заказ клиента.Товары и добавим в неё новый реквизит (не колонку элемента формы, а именно реквизит данных).ЦенаЗаблокирована, тип данных — Булево.Шаг 2. Заполнение признака блокировки
Теперь нам необходимо реализовать логику, которая при открытии документа или при его обновлении будет проверять наличие реализаций. Проанализируем пример кода, который выполняет эту проверку эффективно. Вместо того чтобы делать запросы в цикле, мы соберем данные одним пакетом.
&НаСервере
Процедура ЗаполнитьБлокировкуЦен()
// Получаем массив номенклатуры и характеристик из текущего заказа для анализа
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказТовары.Номенклатура КАК Номенклатура,
| ЗаказТовары.Характеристика КАК Характеристика,
| СУММА(РеализацияТовары.Количество) КАК КоличествоВРеализациях
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Ссылка.ЗаказКлиента = &Ссылка
| И РеализацияТовары.Ссылка.Проведен = ИСТИНА
|СГРУППИРОВАТЬ ПО
| РеализацияТовары.Номенклатура,
| РеализацияТовары.Характеристика";
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Обходим строки заказа и проставляем флаг
Для Каждого СтрокаТовара Из Объект.Товары Цикл
ПараметрыПоиска = Новый Структура("Номенклатура, Характеристика", СтрокаТовара.Номенклатура, СтрокаТовара.Характеристика);
НайденныеСтроки = РезультатЗапроса.НайтиСтроки(ПараметрыПоиска);
// Если нашли отгрузку по этой позиции, ставим флаг блокировки
Если НайденныеСтроки.Количество() > 0 Тогда
СтрокаТовара.ЦенаЗаблокирована = Истина;
Иначе
СтрокаТовара.ЦенаЗаблокирована = Ложь;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Шаг 3. Настройка Условного оформления
Теперь, когда у нас есть данные в колонке ЦенаЗаблокирована, настроим визуальное поведение. Это можно сделать как в конфигураторе, так и программно в процедуре ПриСозданииНаСервере. Разберем программный способ, так как он более гибкий:
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// 1. Что оформляем?
ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("ТоварыЦена");
// 2. Какое условие?
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.ЦенаЗаблокирована");
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.ПравоеЗначение = Истина;
// 3. Какое оформление применяем?
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ТолькоПросмотр", Истина);
// Дополнительно можно подсветить серым цветом, чтобы пользователь видел блокировку
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", ЦветаСтиля.ФормаЦветТекстаСпецСправки);
Обратите внимание, что мы используем параметр ТолькоПросмотр, а не Доступность. Это важный момент: при установке Доступность = Ложь ячейка становится полностью «мертвой», ее нельзя даже выделить, чтобы скопировать значение. Режим ТолькоПросмотр позволяет пользователю взаимодействовать с текстом, но запрещает его изменение.
Выясним причину, почему поиск по Номенклатуре и Характеристике может быть опасен. В сложных заказах одна и та же номенклатура может встречаться в разных строках (например, с разными датами отгрузки или складами). В этом случае простой поиск по товару выдаст ошибку или заблокирует лишние строки.
Проанализируем более надежный подход: в современных конфигурациях (ERP, УТ 11, КА) существует скрытый реквизит табличных частей КлючСвязи. Это уникальный идентификатор (число), который связывает строку заказа со строкой реализации. Если ваша конфигурация поддерживает этот механизм, в запросе выше следует делать соединение именно по полю КлючСвязи. Это обеспечит стопроцентную точность блокировки конкретной строки.
Если вам нужно менять доступность элементов динамически без использования УО, можно использовать событие таблицы ПриАктивизацииСтроки. Однако помним, что этот метод создает нагрузку на клиент-серверное взаимодействие при каждом перемещении курсора.
&НаКлиенте
Процедура ТоварыПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Управляем доступностью колонки на уровне элемента формы
// Внимание: это изменит доступность для ВСЕЙ колонки,
// но визуально это будет срабатывать только для текущей строки
Элементы.ТоварыЦена.ТолькоПросмотр = ТекущиеДанные.ЦенаЗаблокирована;
КонецПроцедуры
Важное ограничение: Метод с ПриАктивизацииСтроки не подсвечивает заблокированные ячейки заранее. Пользователь узнает, что цена недоступна, только когда кликнет на строку. Поэтому Метод 1 (Условное оформление) остается приоритетным.
Если в вашей базе внедрена Библиотека стандартных подсистем (БСП), стоит рассмотреть возможность использования подсистемы «Запрет редактирования реквизитов объектов». Она позволяет настраивать правила доступности полей в зависимости от статуса документа или наличия связанных объектов. Это более «архитектурный» подход, который минимизирует количество «самописного» кода в формах и позволяет централизованно управлять логикой запретов.
В завершение отметим, что блокировка на уровне интерфейса — это лишь часть решения. Для полной уверенности рекомендуется также добавить проверку в процедуру ПередЗаписью на сервере в модуле объекта, чтобы опытные пользователи не смогли обойти ограничение через групповое изменение реквизитов или внешние обработки.