Почему не меняется реквизит «Ответственный» при автоматическом изменении подчиненных документов в 1С?

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

Приветствуем вас! В практике разработки на платформе 1С:Предприятие часто возникает задача жесткого контроля за тем, кто именно внес последние изменения в документ. Для этого программисты нередко используют подписки на события. Однако стандартные механизмы типовых конфигураций (например, в «1С:Бухгалтерия 2.0» или «3.0») могут преподносить сюрпризы: например, при изменении суммы в документе РеализацияТоваровУслуг связанный с ней подчиненный документ СчетФактураВыданный перезаписывается автоматически, но установленный в подписке алгоритм смены ответственного в нем не срабатывает. В этой статье мы подробно разберем, почему так происходит, какие механизмы платформы влияют на это поведение и как правильно реализовать контроль изменений без нарушения бизнес-логики системы.

В чем суть проблемы?

Рассмотрим конкретную техническую ситуацию. В конфигурации создана подписка на событие ПередЗаписью для документов. Цель подписки — принудительно перезаписывать реквизит Ответственный значением текущего пользователя при каждом сохранении объекта. Ручное редактирование реквизита на форме заблокировано.

Сценарий сбоя выглядит следующим образом:

  1. Пользователь открывает существующий документ «Реализация товаров и услуг» и изменяет в нем сумму.
  2. При проведении реализации система выдает служебное сообщение: «Реквизиты СФ будут заполнены автоматически».
  3. Сумма в подчиненном документе «Счет-фактура выданный» успешно обновляется (документ перезаписывается программно), однако реквизит Ответственный в самом счете-фактуре остается старым, несмотря на наличие общей подписки на событие ПередЗаписью.

Давайте подробно проанализируем причины этого явления.

Причина 1: Флаг режима загрузки данных (ОбменДанными.Загрузка)

Самая распространенная причина, по которой кастомные подписки на события «пролетают» мимо выполнения при программной записи подчиненных документов, заключается в использовании режима обмена данными. При программном обновлении реквизитов связанных объектов разработчики типовых решений часто отключают лишние обработчики, чтобы ускорить транзакцию и избежать коллизий.

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


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

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

Причина 2: Специфика обновления Счетов-фактур при проведении Реализации

Выясним, как именно типовая конфигурация обновляет подчиненные счета-фактуры. При проведении документа продажи вызывается специализированный механизм соответствия реквизитов (например, процедура УчетНДС.ПроверитьСоответствиеРеквизитовСчетаФактуры). Внутри этого механизма выполняются следующие шаги:

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

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

Кроме того, если документ «Счет-фактура выданный» по какой-то причине был случайно или намеренно исключен из списка источников вашей подписки (в метаданных не установлена галочка напротив этого типа документа), то код подписки для него не выполнится никогда.

Причина 3: Транзакции и фоновое выполнение

Когда перезапись подчиненного документа происходит внутри транзакции проведения родительского документа, изменяется контекст выполнения кода:

Почему принудительное изменение «Ответственного» — это архитектурная ошибка?

Попытка использовать стандартный реквизит Ответственный в качестве технического лога («кто последний изменил документ») ведет к ряду серьезных проблем в учете и правах доступа:

  1. Нарушение прав доступа (ограничения RLS): Во многих базах настроен доступ по уровню записей (RLS). Менеджеры видят только «свои» документы, где они указаны как Ответственный. Если главный бухгалтер или администратор базы запустит групповое перепроведение документов за прошлый период (например, для восстановления последовательности), то подписка автоматически перезапишет ответственного во всех документах на администратора/бухгалтера. В результате обычные менеджеры полностью потеряют видимость и доступ к своим документам.
  2. Искажение печатных форм: Реквизит Ответственный часто выводится в печатные формы документов (в поля «Отпустил», «Ответственный за оформление» и т.д.). Если документ перепроведет другой сотрудник спустя месяц, печатная форма исказится — на ней будет фигурировать имя человека, который просто перепровел документ в конце месяца, а не того, кто реально совершил хозяйственную операцию.

Как правильно решить задачу отслеживания изменений?

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

Решение А: Использование схемы «Автор» и «Редактор»

Это классический и самый надежный способ разделения ответственности. Вместо одного реквизита создаются два дополнительных реквизита (или используются дополнительные свойства БСП):

Рассмотрим пример кода подписки на событие ПередЗаписью, реализующей эту схему:


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

Решение Б: Встроенное версионирование объектов (БСП)

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

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

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

Решение В: Использование Журнала регистрации

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

Для поиска виновного достаточно открыть Журнал регистрации, установить отбор по метаданным конкретного документа (или по его уникальному идентификатору / представлению) и отфильтровать события по действиям «Данные.Изменение» или «Данные.Проведение». Журнал регистрации зафиксирует реальную учетную запись операционной системы или пользователя 1С, под которой была выполнена транзакция, независимо от того, какие значения записаны внутри самого документа.

← На главную