Как программно нажать кнопку «Провести и закрыть» в форме документа 1С?

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

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

Давайте подробно проанализируем, почему возникает эта проблема, как ее решить "в лоб" с помощью вызова методов формы, и как правильно исправить ситуацию архитектурно.

Почему проведение из формы отличается от проведения программно?

Выясним причину такого поведения. Фундаментальное отличие заключается в том, какие обработчики событий запускает платформа при различных способах записи.

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

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

Кроме того, при интерактивном проведении из формы платформа сама определяет режим проведения (оперативный или неоперативный) в зависимости от текущего времени и даты документа. При программном коде мы обычно жестко задаем этот параметр, что тоже может влиять на контроль остатков.

Решение 1: Эмуляция кнопки «Провести и закрыть» через методы формы

Если времени на рефакторинг чужого кода нет и нужно срочно провести документы так, как это делает пользователь, рассмотрим программное использование контекста формы. Чтобы имитировать нажатие кнопки «Провести и закрыть», нам нужно вызвать метод Записать() самой формы, передав туда необходимые параметры, а затем закрыть окно.

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


ПараметрыЗаписи = Новый Структура();
ПараметрыЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Проведение);

Попытка
    Успех = Форма.Записать(ПараметрыЗаписи);
    Если Успех Тогда
        Форма.Закрыть();
    КонецЕсли;
Исключение
    Сообщить("Ошибка при записи документа: " + ОписаниеОшибки());
КонецПопытки;

Если стоит задача обработать массив документов без их визуального вывода на экран, мы можем получить форму программно в фоновом режиме:


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

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

Решение 2: Архитектурно правильный подход

Разберем по шагам, как избавиться от этой проблемы навсегда. Наличие бизнес-логики (заполнение данных, влияние на проводки) в модуле формы — это грубое нарушение стандартов разработки 1С. Вся логика должна находиться в модуле объекта или менеджера. Для выявления и исправления подобных отступлений от правил подойдёт обработка для проверки кода на соответствие стандартам 1С.

Чтобы исправить ситуацию, проанализируем текущий алгоритм:

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

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


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

Таким образом, использование методов формы для записи — это временный "костыль" для решения срочной задачи. Стратегически правильным решением всегда остается нормализация кода и перенос бизнес-логики в модуль объекта.

← На главную