Как предотвратить автоматическое перепроведение документов в 1С при нажатии "Провести и закрыть" без реальных изменений?

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

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

Почему форма становится модифицированной без видимых изменений?

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

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

  2. Особенности поведения управляемых форм: В управляемых формах 1С при работе с элементами формы (полями ввода, табличными частями) могут вызываться события, которые, в свою очередь, влияют на флаг Модифицированность. Иногда даже простое перемещение по полям ввода или активация элемента управления может косвенно привести к изменению этого флага, особенно если в конфигурации есть доработки, реагирующие на такие события.

  3. Команды формы и их свойства: Типовые команды формы, такие как "Провести и закрыть" или "Записать", часто имеют свойство "Изменять сохраняемые данные". Если это свойство установлено, то при вызове такой команды платформа автоматически считает, что данные были изменены, и устанавливает Модифицированность формы в Истина еще до того, как будет вызван обработчик ПередЗаписью. Это сделано для того, чтобы гарантировать, что документ будет записан и проведен, даже если явных изменений не было, но, например, требовалось перепроведение по какой-либо причине (например, для актуализации взаиморасчетов).

Решение 1: Создание собственной кнопки "Закрыть" или переопределение стандартной

Один из самых распространенных и эффективных способов, который был успешно применен автором исходной темы, — это замена или модификация стандартной кнопки "Провести и закрыть". Мы рассмотрим этот подход как наиболее практичный.

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

  2. Создание новой команды и кнопки: Затем мы добавляем на форму новую команду и связанную с ней кнопку. Эту кнопку мы можем назвать, например, "Закрыть (с проверкой проведения)" или просто "Закрыть". Размещаем ее на месте скрытой типовой кнопки или в другом удобном для пользователя месте.

  3. Логика обработки: В обработчике нажатия новой кнопки мы реализуем логику проверки флага Модифицированность формы. Если форма не модифицирована, мы просто закрываем ее без проведения. Если же модифицированность установлена, это означает, что пользователь действительно внес изменения, и мы можем вызвать типовую процедуру проведения и закрытия документа.

    Рассмотрим пример кода для обработчика новой команды:

    
    &НаКлиенте
    Процедура ЗакрытьСПроверкой(Команда)
        Если ЭтаФорма.Модифицированность Тогда
            // Если документ действительно был изменен (Модифицированность = Истина),
            // вызываем типовую процедуру проведения и закрытия.
            // Название процедуры может отличаться в зависимости от конфигурации.
            // Например, для УТ/КА/ERP часто используется ОбщегоНазначенияУТКлиент.ПровестиИЗакрыть
            ОбщегоНазначенияУТКлиент.ПровестиИЗакрыть(ЭтаФорма, "ПровестиИЗакрыть"); 
        Иначе
            // Если изменений нет (Модифицированность = Ложь), просто закрываем форму.
            ЭтаФорма.Закрыть();
        КонецЕсли;
    КонецПроцедуры
    
  4. Важный момент: Необходимо убедиться, что вызов типовой процедуры проведения и закрытия (как в примере ОбщегоНазначенияУТКлиент.ПровестиИЗакрыть) корректно обрабатывает все необходимые параметры и контекст формы. Это гарантирует сохранение всего стандартного функционала проведения.

Решение 2: Глубокая проверка фактических изменений документа

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

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

    Примерная логика может выглядеть так (реализация функции сравнения будет зависеть от сложности документа):

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

Решение 3: Подписка на событие "ПередЗаписью"

Мы можем использовать механизм подписок на события для контроля проведения документов. Это позволяет вмешаться в процесс записи/проведения на уровне объекта, до того как изменения будут зафиксированы в базе данных.

  1. Создание подписки: Создаем подписку на событие ПередЗаписью для всех документов или конкретных типов документов, где возникает проблема.

  2. Логика в обработчике: В обработчике подписки мы проверяем флаг Модифицированность объекта-источника, а также (желательно) проводим более глубокую проверку фактических изменений, как описано в Решении 2. Если модифицированность установлена, но реальных изменений не обнаружено, мы можем отменить проведение документа.

    Пример обработчика подписки:

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

Решение 4: Информирование и подтверждение действия пользователя

Этот подход не является программным предотвращением, а скорее направлен на изменение поведения пользователя через дополнительные запросы подтверждения. Цель — приучить пользователей внимательнее относиться к нажатию кнопок.

  1. Вопрос перед перепроведением: При нажатии на кнопку "Провести и закрыть" для уже проведенного документа, если Модифицированность формы установлена, можно выводить пользователю вопрос: "Документ уже проведен. Вы хотите перепровести его?". Пользователю будут предложены кнопки "Да" и "Нет". Если он выберет "Нет", форма закроется без перепроведения.

  2. Ограничения и рекомендации: Хотя этот метод может помочь в обучении пользователей, на практике он часто сталкивается с "эффектом Долиной", когда пользователи бездумно нажимают первую удобную кнопку, игнорируя текст сообщения. Чрезмерное количество подтверждений также может вызывать раздражение и снижать продуктивность. Мы рекомендуем использовать это решение в комбинации с другими, более строгими методами контроля.

Мы рассмотрели несколько подходов к решению проблемы нежелательного перепроведения документов в 1С. Выбор конкретного решения или их комбинации будет зависеть от специфики вашей конфигурации, требований к безопасности, сложности документа и желаемого уровня контроля над действиями пользователей.

← На главную