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