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