При разработке расширений для «1С:Предприятие 8.3» программисты часто сталкиваются с необходимостью внедрить дополнительную проверку или изменить логику при выполнении стандартных команд. Одной из таких задач является модификация поведения кнопки Провести в форме списка. Сложность заключается в том, что эта команда является платформенной: она не привязана напрямую к коду в модуле формы списка, а сразу инициирует процесс записи объекта на сервере.
В этой статье мы подробно разберем, почему попытки изменить логику через форму списка часто оказываются неэффективными, и рассмотрим правильные архитектурные подходы к решению этой задачи с использованием расширений модулей объектов.
Рассмотрим ситуацию: нам нужно запретить проведение документа «Заказ поставщику», если товара «в пути» недостаточно для резервирования. Первая мысль — найти обработчик команды в форме списка. Однако стандартная команда Провести реализована на уровне платформы. Она просто берет выделенные ссылки и вызывает для каждой метод Записать(РежимЗаписиДокумента.Проведение).
Если мы попытаемся создать свою команду в расширении формы списка, нам придется скрывать стандартную кнопку и программно описывать цикл по всем выделенным строкам. Это решит задачу только для конкретной формы. Но если пользователь проведет документ из формы самого документа, из другой формы списка или через групповую обработку — наша проверка не сработает. Поэтому наиболее надежным способом является перенос логики в модуль объекта.
Для того чтобы наша проверка работала всегда, независимо от того, откуда вызвано проведение, мы будем использовать расширение модуля объекта документа. Рассмотрим подробнее, почему именно ПередЗаписью подходит лучше всего.
Многие начинающие разработчики пытаются использовать &Перед("ОбработкаПроведения"). Однако на этом этапе документ уже фактически записан в базу данных, и его состояние (флаг Проведен) в оперативной памяти уже установлено в Истина. Если нам нужно проверить, был ли документ проведен до текущего нажатия кнопки, этот обработчик нам не поможет.
Разберем пример кода для расширения модуля объекта:
&Перед("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем, что инициировано именно проведение документа
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
// Выполняем нашу прикладную проверку
Если Не ПроверитьНаличиеТовараВПути() Тогда
Отказ = Истина;
// Важно оповестить пользователя о причине отказа
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Недостаточно товара в пути для подтверждения резерва!";
Сообщение.Сообщить();
Возврат;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
В этом коде мы используем параметр РежимЗаписи. Если он равен РежимЗаписиДокумента.Проведение, это означает, что пользователь или система нажали кнопку «Провести». Установка Отказ = Истина прерывает транзакцию, и документ не будет ни записан, ни проведен.
Часто возникает вопрос: как понять, был ли документ уже проведен ранее? В обработчиках записи объект в памяти (ЭтотОбъект) уже содержит новые значения. Чтобы узнать «старое» состояние, нужно обратиться к ссылке, которая все еще хранит данные из базы данных (до завершения транзакции).
Проанализируем пример кода для проверки изменения статуса проведения:
&Перед("ПередЗаписью")
Процедура Расш1_ПроверитьСтатусПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
// Ссылка.Проведен — это состояние в БД до записи
// ЭтотОбъект.Проведен — это состояние, которое мы пытаемся установить
Если Не Ссылка.Проведен Тогда
// Этот код выполнится только при первичном проведении
// или если документ был ранее распроведен
ЗаписатьВЛог("Документ проводится впервые");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важный нюанс: при первом создании документа Ссылка может быть пустой, поэтому в реальном коде стоит добавить проверку Если Не Ссылка.Пустая().
Если ваша логика сводится исключительно к проверке корректности данных, платформа предоставляет специализированный механизм — ОбработкаПроверкиЗаполнения. Этот метод вызывается перед записью, если установлен соответствующий флаг проверки. Рассмотрим, как расширить этот механизм:
&После или &Перед для ОбработкаПроверкиЗаполнения.Преимущество этого метода в том, что он стандартно обрабатывается всеми формами и механизмами платформы, включая автоматическую подсветку незаполненных полей на форме.
Иногда логика проверки зависит от действий пользователя в конкретной форме списка (например, пользователь нажал специальную кнопку «Провести без проверок»). Так как модуль объекта не имеет прямого доступа к контексту формы, мы можем использовать структуру ДополнительныеСвойства.
Выясним, как это реализовать. В расширении формы документа (или формы списка при программной записи) мы пишем:
// В расширении формы
&НаСервере
Процедура Расш1_ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
ТекущийОбъект.ДополнительныеСвойства.Вставить("ПроверкаОтключенаПользователем", Истина);
КонецПроцедуры
Затем в расширении модуля объекта мы считываем это значение:
&Перед("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ЭтотОбъект.ДополнительныеСвойства.Свойство("ПроверкаОтключенаПользователем") Тогда
Возврат; // Пропускаем проверку, так как есть спецфлаг из формы
КонецЕсли;
// ... стандартная логика проверки ...
КонецПроцедуры
Когда пользователь выделяет 50 документов в форме списка и нажимает «Провести», ваш код в расширении модуля объекта будет выполнен 50 раз. Если внутри проверки ПроверитьНаличиеТовараВПути() выполняется тяжелый запрос к регистрам, это может привести к длительному ожиданию.
Проанализируем рекомендации по оптимизации:
СообщениеПользователю, чтобы при массовом проведении пользователь видел, какие именно документы не провелись и почему.Мы рассмотрели, что изменение поведения стандартных команд формы списка в 1С эффективнее всего делать через расширение модуля объекта. Это гарантирует, что ваша бизнес-логика и проверки будут соблюдены в любой ситуации, а не только при работе с конкретной формой.
Основные инструменты разработчика здесь:
ПередЗаписью с анализом РежимЗаписи.Ссылка для определения изменения статуса.ДополнительныеСвойства для передачи контекста из интерфейса в логику.СообщениеПользователю для вывода причин отказа в проведении.Используя эти подходы, вы сможете создавать надежные расширения, которые корректно интегрируются в стандартную логику конфигураций на базе 1С:Предприятие.