Как изменить реквизит документа в закрытом периоде 1С без нарушения границы запрета редактирования?

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

В процессе работы с базами данных «1С:Предприятие» регулярно возникает классическая задача: пользователю или администратору необходимо изменить значение какого-либо реквизита в документе, период редактирования которого уже закрыт (установлена дата запрета изменения данных). Это может быть признак возврата оригинала документа (флаг «Оригинал получен»), внутренний текстовый комментарий менеджера, признак согласования или ссылка на связанную сделку в управленческом учете. Такие реквизиты, как правило, не влияют на проведение документа, не меняют его движения по регистрам накопления или бухгалтерии и не искажают финансовую отчетность. Однако стандартный механизм даты запрета жестко блокирует любую попытку записи объекта.

В данной статье мы подробно разберем, как решить эту задачу. Мы проанализируем различные подходы — от быстрых программных «обходов» до архитектурно правильных решений, которые не требуют снятия даты запрета и не создают рисков для ведения учета.

---

Метод 1. Программный обход через свойство ОбменДанными.Загрузка

Рассмотрим самый быстрый способ внесения изменений из внешней обработки или программного кода. Этот метод основан на использовании стандартного свойства объекта ОбменДанными.Загрузка.

Принцип работы этого механизма заключается в том, что при установке флага загрузки в значение Истина платформа 1С сигнализирует всем подпискам на события и встроенным проверкам о том, что объект записывается в процессе переноса данных (например, при обмене распределенными базами). В типовых конфигурациях (УТ 10.3, КА 1.1, УПП 1.3) код проверки даты запрета изменения в подписках на события начинается со следующей строки:


Если Источник.ОбменДанными.Загрузка Тогда
    Возврат;
КонецЕсли;

Благодаря этому проверка закрытого периода полностью игнорируется, позволяя записать изменения в документ. Посмотрим на практический пример программного кода:


// Получаем объект документа по ссылке
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

// Устанавливаем флаг обхода проверок
ДокументОбъект.ОбменДанными.Загрузка = Истина;

// Изменяем требуемый реквизит
ДокументОбъект.ОригиналПолучен = Истина;

Попытка
    // Записываем документ БЕЗ проведения (только запись)
    ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
    Сообщить("Документ успешно изменен в закрытом периоде!");
Исключение
    Сообщить("Не удалось записать документ: " + ОписаниеОшибки());
КонецПопытки;

Важные ограничения и риски данного метода:

  1. Режим записи: Настоятельно рекомендуется использовать только режим РежимЗаписиДокумента.Запись. Пытаться проводить документ с установленным свойством Загрузка = Истина категорически нельзя. В режиме загрузки отключаются не только проверки даты запрета, но и контроль остатков, сверка взаиморасчетов и другие важнейшие прикладные бизнес-правила. Это может привести к повреждению данных учета.
  2. Обмен данными: Запись объекта с флагом загрузки может не зарегистрировать изменения на узлах планов обмена. Если измененный документ должен мигрировать в другую базу (например, признак оригинала должен уйти из УТ в БП), вам придется регистрировать изменения для обмена вручную.

---

Метод 2. Временное программное смещение даты запрета в параметрах сеанса

Выясним причину, почему метод с флагом ОбменДанными.Загрузка может не подойти, если нам все-таки требуется провести документ. В старых конфигурациях (таких как УПП или Комплексная автоматизация) проверка даты запрета при проведении опирается на параметры сеанса, хранящие границы запрета для текущего пользователя. Мы можем временно «обмануть» систему, изменив эти границы в памяти текущего сеанса непосредственно перед записью документа, а затем вернув их в исходное состояние.

Проанализируем пример кода, реализующий данный подход:


// Получаем объект документа
ЗаказОбъект = СсылкаНаЗаказПокупателя.ПолучитьОбъект();

// Извлекаем текущие границы запрета изменения данных из параметров сеанса
СоответствиеГраниц = ПараметрыСеанса.ГраницыЗапретаИзмененияДанных.Получить();
ОбщаяДатаЗапрета = СоответствиеГраниц["ОбщаяДатаЗапретаРедактирования"];
ДатаДокумента = ЗаказОбъект.Дата;

// Если документ попадает под ограничение, временно сдвигаем дату запрета назад
Если ОбщаяДатаЗапрета >= ДатаДокумента Тогда
    // Сдвигаем временную границу на один день раньше даты нашего документа
    ВременнаяДатаЗапрета = ДатаДокумента - 24 * 60 * 60; 
    СоответствиеГраниц["ОбщаяДатаЗапретаРедактирования"] = ВременнаяДатаЗапрета;
    
    // Записываем измененное соответствие обратно в параметры сеанса
    ПараметрыСеанса.ГраницыЗапретаИзмененияДанных = Новый ХранилищеЗначения(СоответствиеГраниц);
КонецЕсли;

// Производим необходимые изменения и проводим документ
ЗаказОбъект.Сделка = НоваяСделкаСсылка;

Попытка
    ЗаказОбъект.Записать(РежимЗаписиДокумента.Проведение);
    Сообщить("Документ успешно перепроведен в закрытом периоде!");
Исключение
    Сообщить("Ошибка проведения: " + ОписаниеОшибки());
КонецПопытки;

// ОБЯЗАТЕЛЬНО возвращаем исходную дату запрета на место
Если ОбщаяДатаЗапрета >= ДатаДокумента Тогда
    СоответствиеГраниц["ОбщаяДатаЗапретаРедактирования"] = ОбщаяДатаЗапрета;
    ПараметрыСеанса.ГраницыЗапретаИзмененияДанных = Новый ХранилищеЗначения(СоответствиеГраниц);
КонецЕсли;

Этот метод более безопасен с точки зрения бизнес-логики проведения, так как документ проводится со всеми включенными проверками, однако он требует монопольного выполнения кода в рамках текущего сеанса пользователя и аккуратного восстановления параметров сеанса в блоке обработки исключений (чтобы при возникновении ошибки транзакции пользователь не остался с открытым периодом для редактирования).

---

Метод 3. Использование механизма «Свойств и категорий» (No-code альтернатива)

Если перед нами стоит задача дать возможность обычным пользователям (например, бухгалтерам или логистам) отмечать получение оригиналов документов или менять другие аналитические признаки без изменения конфигурации и программирования, идеальным решением станет штатный механизм Свойств и Категорий объектов.

Разберем по шагам, почему это работает и как это настроить:

  1. Физически свойства и категории документов в УТ 10.3 / УПП 1.3 хранятся не в самом документе, а в независимых регистрах сведений: ЗначенияСвойствОбъектов и КатегорииОбъектов.
  2. Для установки категории или свойства пользователю не нужно открывать форму документа на редактирование и нажимать кнопку «Записать». Изменение аналитики происходит через отдельную форму, вызываемую по кнопке на панели инструментов («Категории» или «Свойства»).
  3. Так как сам документ при этом физически не перезаписывается и его табличные части не затрагиваются, встроенная проверка даты запрета редактирования документов не срабатывает. Пользователи могут беспрепятственно менять данные признаки в документах любой давности.

Как настроить свойство для документа (на примере УТ 10.3):

  1. Перейдем в меню «Операции» -> «Планы видов характеристик» -> «Свойства объектов».
  2. Создадим новый элемент, укажем назначение свойства (например, «Документ реализация товаров и услуг»), наименование «Оригинал возвращен» и тип значения «Булево».
  3. После этого в форме списка или внутри самой формы документа реализации пользователи увидят кнопку «Свойства объектов» (значок в виде синего блокнота или карточки), где смогут устанавливать галочку «Да/Нет» даже для документов пятилетней давности. Из этих данных можно легко строить любые отчеты.

---

Метод 4. Архитектурный стандарт: Независимый регистр сведений

Если существующий реквизит документа был добавлен программистом вручную через Конфигуратор и с ним уже завязано множество алгоритмов, то использование этого реквизита в закрытом периоде неизбежно вызывает конфликты. Проанализируем наиболее правильное с точки зрения архитектуры 1С решение — вынесение реквизита в независимый регистр сведений.

Если реквизит не влияет на проведение документа, хранить его внутри самого документа — методологическая ошибка. Правильнее сделать следующее:

  1. Создадим в конфигураторе новый регистр сведений (например, СтатусыОригиналовДокументов) со следующей структурой:
    • Измерение: Документ (тип: ДокументСсылка на нужные виды документов).
    • Ресурс: ОригиналПолучен (тип: Булево).
    • Ресурс: ДатаПолучения (тип: Дата).
    • Ресурс: Ответственный (тип: СправочникСсылка.Пользователи).
  2. Настроим режим записи регистра как Независимый. Это ключевой момент: запись в такой регистр происходит независимо от проведения или записи самого документа-регистратора. Соответственно, проверка даты запрета изменения данных для этого регистра не будет вызываться платформой.
  3. На форме документа заменим стандартное поле ввода реквизита на декоративное поле (флажок), данные для которого при открытии формы будут считываться из нашего регистра сведений с помощью простого запроса:

// ПриОткрытии формы документа считываем статус
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   СтатусыОригиналовДокументов.ОригиналПолучен КАК ОригиналПолучен
    |ИЗ
    |   РегистрСведений.СтатусыОригиналовДокументов КАК СтатусыОригиналовДокументов
    |ГДЕ
    |   СтатусыОригиналовДокументов.Документ = &Документ";

Запрос.УстановитьПараметр("Документ", ЭтотОбъект.Ссылка);
Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    ЭлементыФормы.ФлажокОригинал.Значение = Выборка.ОригиналПолучен;
Иначе
    ЭлементыФормы.ФлажокОригинал.Значение = Ложь;
КонецЕсли;

При изменении этого флажка пользователем на форме мы будем программно записывать данные напрямую в регистр сведений, минуя запись самого документа:


Процедура ФлажокОригиналПриИзменении(Элемент)
    
    МенеджерЗаписи = РегистрыСведений.СтатусыОригиналовДокументов.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Документ = ЭтотОбъект.Ссылка;
    МенеджерЗаписи.ОригиналПолучен = ЭлементыФормы.ФлажокОригинал.Значение;
    МенеджерЗаписи.ДатаПолучения = ТекущаяДата();
    МенеджерЗаписи.Ответственный = ПараметрыСеанса.ТекущийПользователь;
    
    Попытка
        МенеджерЗаписи.Записать(Истина); // Замещаем существующую запись
        Сообщить("Статус оригинала успешно обновлен!");
    Исключение
        Сообщить("Ошибка сохранения статуса: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Этот подход полностью безопасен, не нарушает целостность закрытого периода, не вызывает блокировок базы данных и позволяет гибко разграничивать права доступа: вы можете дать менеджерам права на изменение записей этого регистра сведений, при этом оставив сами документы закрытого периода доступными только для чтения.

---

Метод 5. Использование расширений конфигурации (для платформы 8.3)

Если вы работаете на платформе «1С:Предприятие 8.3» с управляемыми формами, то изменять типовой код общего модуля НастройкаПравДоступа или подписки на события крайне нежелательно, так как это усложнит последующие обновления базы данных. Вместо этого мы можем применить механизм расширений конфигурации.

Мы можем перехватить процедуру проверки даты запрета изменений (например, ПередЗаписьюДокументаПроверкаДоступностиПериода) с помощью аннотации &Вместо или &Перед в модуле расширения. Рассмотрим пример реализации такого перехвата:


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

Вспомогательная функция ТолькоРеквизитОригиналаИзменен(Источник) должна сравнивать текущие значения реквизитов объекта в памяти со значениями, сохраненными в базе данных (через запрос к ссылке документа), чтобы гарантировать, что пользователь не изменил сумму, контрагента или дату документа вместе с признаком оригинала.

---

Резюме и рекомендации

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

← На главную