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