При разработке конфигураций на платформе 1С:Предприятие 8 часто возникает задача: не просто прервать запись документа при обнаружении некорректных данных в табличной части, но и максимально облегчить пользователю поиск этой ошибки. Идеальный вариант — когда система сама подсвечивает нужную ячейку и активизирует строку, в которой допущена оплошность. Рассмотрим, как добиться такого поведения, если проверка выполняется на стороне сервера, например, в подписке на события или в модуле объекта.
Часто программисты используют объект СообщениеПользователю для вывода уведомлений. Однако для того, чтобы платформа смогла сопоставить текстовое сообщение с конкретным элементом на форме (ячейкой в таблице), необходимо строго соблюдать формат пути к данным. Разберем ситуацию: если проверка происходит в подписке на событие ПередЗаписью, объект еще не зафиксирован в базе, а связь между серверным объектом и формой может быть неочевидной.
Основная сложность заключается в том, что в подписке на события параметром Источник выступает сам объект данных. Для корректной привязки сообщения к полю на форме путь к данным должен начинаться с префикса Объект, если мы работаем в контексте формы. Проанализируем типовую ошибку в расчете индекса: НомерСтроки в 1С начинается с 1, в то время как коллекция строк в пути к данным (массив) индексируется с 0. Таким образом, путь к первой строке должен выглядеть как Объект.Товары[0].Цена.
Как показывает практика и обсуждение экспертов, наиболее методологически верным решением является вынос проверок из события ПередЗаписью в специализированное событие ОбработкаПроверкиЗаполнения. Это событие специально спроектировано платформой для взаимодействия с интерфейсом. Рассмотрим, почему это лучше:
ПроверяемыеРеквизиты.Посмотрим на пример реализации такой проверки в модуле объекта (или аналогично через подписку):
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Для Каждого ТекСтрока Из Товары Цикл
Если ТекСтрока.Цена = 0 Тогда
ТекстСообщения = НСтр("ru='Цена в строке %Номер% должна быть заполнена!'");
ТекстСообщения = СтрЗаменить(ТекстСообщения, "%Номер%", ТекСтрока.НомерСтроки);
Индекс = Товары.Индекс(ТекСтрока);
Поле = "Объект.Товары[" + Формат(Индекс, "ЧГ=0") + "].Цена";
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ТекстСообщения;
Сообщение.Поле = Поле;
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если в вашей конфигурации используется Библиотека Стандартных Подсистем (БСП), задачу можно упростить, используя методы общего модуля ОбщегоНазначенияКлиентСервер. Разберем, как правильно вызвать этот метод в подписке на событие, чтобы обеспечить переход на нужную строку.
Проанализируем ситуацию: в подписке на событие нам доступен Источник. Мы можем использовать функцию ПутьКТабличнойЧасти, чтобы не формировать строку пути вручную. Выясним причину, по которой это может не сработать: важно передать правильный индекс.
// В обработчике подписки на событие ПередЗаписью
Процедура ПроверитьДанныеПередЗаписью(Источник, Отказ, Замещение) Экспорт
Для Каждого СтрокаТЧ Из Источник.Товары Цикл
Если СтрокаТЧ.Количество <= 0 Тогда
ИмяПути = ОбщегоНазначенияКлиентСервер.ПутьКТабличнойЧасти(
"Объект.Товары",
СтрокаТЧ.НомерСтроки,
"Количество"
);
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru='Количество должно быть больше нуля'"),
Источник,
ИмяПути,
,
Отказ
);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный нюанс: В методе ПутьКТабличнойЧасти БСП самостоятельно вычитает единицу из НомерСтроки, преобразуя его в индекс 0-based. Это избавляет разработчика от лишних арифметических операций и снижает риск ошибки.
Бывают сложные случаи, когда проверка должна произойти на сервере в подписке, а фокус на строку нужно установить программно на клиенте после неудачной попытки записи. Рассмотрим алгоритм действий:
Отказ = Истина, но и записываем индекс ошибочной строки в структуру Источник.ДополнительныеСвойства.ПослеЗаписиНаСервере (которое вызывается, даже если запись не состоялась из-за отказа на сервере в определенных сценариях или при использовании клиентских оберток) мы считываем этот индекс.ТекущаяСтрока для элемента управления таблицей.Пример записи свойства на сервере:
Источник.ДополнительныеСвойства.Вставить("ОшибкаВСтрокеИндекс", ИндексСтроки);
Пример установки фокуса на форме (в процедуре, вызываемой после серверной проверки):
Если ПараметрыЗаписи.Свойство("ОшибкаВСтрокеИндекс") Тогда
Элементы.Товары.ТекущаяСтрока = Объект.Товары[ПараметрыЗаписи.ОшибкаВСтрокеИндекс].ПолучитьИдентификатор();
КонецЕсли;
Проанализируем еще один важный аспект, упомянутый в обсуждении — производительность. Выполнение запросов внутри подписки ПередЗаписью (внутри транзакции) — это ресурсозатратная операция. Если ваша проверка требует данных из базы (например, проверка остатков), постарайтесь:
Источник.Товары), не перечитывая их из базы без необходимости.Соблюдение этих правил позволит не только реализовать удобный переход к ошибкам для пользователя, но и сохранить высокую скорость работы системы при записи документов.