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