Как автоматически заполнить "Основание" в реквизитах печати Заказа клиента и избежать ошибки блокировки данных

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В типовых конфигурациях 1С (таких как Управление торговлей 11, Комплексная автоматизация 2, ERP 2) в документе Заказ клиента предусмотрена гиперссылка "Реквизиты печати". Перейдя по ней, пользователь может заполнить различные дополнительные сведения для печатных форм, включая поле Основание. Обычно оно принимает вид "По счету № [Номер] от [Дата]". Чтобы упростить работу, в форме есть кнопка "Заполнить", но она работает только после того, как документ записан и у него появился номер.

Часто менеджеры забывают нажимать эту кнопку вручную. Логичное желание разработчика — автоматизировать процесс так, чтобы поле заполнялось само при первой записи документа. Однако при попытке сделать это "в лоб" (например, перезаписывая объект в модуле или при записи на форме) разработчики сталкиваются с неприятной ошибкой платформы: "Данные изменены другим пользователем". В этой статье мы подробно разберем, почему возникает эта ошибка и как правильно реализовать автозаполнение без нарушения логики работы управляемых форм.

Выясняем причину: почему возникает ошибка блокировки данных?

Давайте проанализируем физику процесса работы управляемой формы. В 1С:Предприятии 8 управляемая форма хранит в памяти специальный реквизит — Объект (тип ДанныеФормыСтруктура). Этот реквизит имеет скрытое свойство — ВерсияДанных, которое синхронизируется с версией записи в базе данных.

Когда пользователь нажимает кнопку "Записать", последовательность событий выглядит следующим образом:

  1. Форма отправляет данные на сервер.
  2. В транзакции записи создается прикладной объект (ДокументОбъект).
  3. Документ записывается в базу данных. В этот момент ему присваивается новый номер, дата и новая уникальная версия данных.
  4. Если в этот момент мы программно (например, через фоновое задание или прямой вызов нового соединения на сервере) модифицируем этот же документ в базе данных и повторно записываем его, версия данных в БД снова изменяется.
  5. При этом открытая форма пользователя "не знает" о том, что объект в базе данных был повторно изменен. В памяти формы остается старая версия данных.
  6. Когда пользователь пытается изменить что-то еще на форме и повторно нажимает "Записать", платформа сравнивает версию данных в форме и в базе данных. Видя несовпадение, она аварийно завершает операцию с ошибкой "Данные изменены другим пользователем".

Рассмотрим подробнее два наиболее изящных и правильных способа решения этой проблемы, которые позволяют корректно синхронизировать состояние базы данных и управляемой формы.

Решение 1: Заполнение в обработчике "ПослеЗаписи" на клиенте с обновлением данных формы

Этот способ является наиболее надежным, так как мы дожидаемся, пока основная транзакция записи документа завершится, документу гарантированно присвоится номер и дата, а затем мы аккуратно вносим изменения в реквизиты печати и обновляем контекст формы.

Разберем по шагам реализацию этого механизма в модуле формы документа Заказ клиента. Нам потребуется использовать клиентский обработчик ПослеЗаписи и серверную процедуру для модификации данных.

В модуле управляемой формы документа пропишем следующий код:


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    
    // Проверяем, заполнено ли уже основание, чтобы не перезаписывать данные при каждом сохранении
    Если Не ЗначениеЗаполнено(Объект.РеквизитыПечатиОснование) Тогда
        // Вызываем серверный метод для заполнения и обновления реквизита формы
        ЗаполнитьОснованиеНаСервере();
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьОснованиеНаСервере()
    
    // Преобразуем реквизит управляемой формы в прикладной объект базы данных
    ДокОбъект = РеквизитФормыВЗначение("Объект");
    
    // Формируем текст основания по шаблону, используя функции префиксации для красивого вывода номера
    НомерНаПечать = ПрефиксацияОбъектовКлиентСервер.ПолучитьНомерНаПечать(ДокОбъект.Номер, Истина, Ложь);
    ФорматированнаяДата = Формат(ДокОбъект.Дата, "ДФ=dd.MM.yyyy");
    
    ДокОбъект.РеквизитыПечатиОснование = "По счету № " + НомерНаПечать + " от " + ФорматированнаяДата;
    
    // Записываем объект в режиме простой записи (не проведения), чтобы обновить только реквизит
    ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
    
    // Возвращаем измененный объект со свежей ВерсиейДанных обратно в контекст формы
    ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
    
КонецПроцедуры

Важный нюанс: Метод ЗначениеВРеквизитФормы выполняет ключевую роль. Он не только обновляет отображение полей на экране пользователя, но и прописывает новую, актуальную ВерсияДанных в форму, а также сбрасывает признак модифицированности (Модифицированность = Ложь). Теперь пользователь может без проблем продолжать редактировать документ.

Решение 2: Заполнение в обработчике "ПередЗаписьюНаСервере"

Если мы хотим избежать повторной перезаписи документа в базе данных (ведь в Решении 1 документ записывается дважды за один сеанс работы), мы можем попытаться перехватить процесс записи еще до того, как данные окончательно запишутся в БД, но в тот момент, когда номер документу уже назначен.

Посмотрим на пример реализации через обработчик ПередЗаписьюНаСервере в модуле формы:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Проверяем, является ли документ новым
    Если ТекущийОбъект.ЭтоНовый() Тогда
        
        // Устанавливаем автономинацию, чтобы платформа сгенерировала номер прямо сейчас
        Если Не ЗначениеЗаполнено(ТекущийОбъект.Номер) Тогда
            ТекущийОбъект.УстановитьНовыйНомер(ТекущийОбъект.Организация.Префикс);
        КонецЕсли;
        
        НомерНаПечать = ПрефиксацияОбъектовКлиентСервер.ПолучитьНомерНаПечать(ТекущийОбъект.Номер, Истина, Ложь);
        ФорматированнаяДата = Формат(ТекущийОбъект.Дата, "ДФ=dd.MM.yyyy");
        
        ТекущийОбъект.РеквизитыПечатиОснование = "По счету № " + НомерНаПечать + " от " + ФорматированнаяДата;
        
    КонецЕсли;
    
КонецПроцедуры

Этот способ более производителен, так как обращение к базе данных происходит ровно один раз. Мы принудительно вызываем метод УстановитьНовыйНомер, чтобы получить номер документа заранее, заполняем реквизит печати, и платформа штатно завершает запись объекта.

Бизнес-контекст: почему автозаполнение стало критически важным?

Автоматизация заполнения реквизитов печати — это не просто прихоть пользователей для экономии пары секунд. В современных реалиях ведения бизнеса этот процесс напрямую влияет на корректность работы корпоративных систем:

Мы рассмотрели детальные механизмы синхронизации данных управляемых форм и базы данных. Применяя данные подходы, вы навсегда избавите своих пользователей от рутинных кликов по гиперссылкам и предотвратите возникновение досадных блокировок при записи документов.

← На главную