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