Как в 1С 7.7 программно изменить дату и провести документ прямо из его формы

Программист 1С v7.7
← На главную

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

Почему возникает ошибка блокировки

Проанализируем архитектуру платформы 7.7. Когда пользователь открывает форму документа, система создает интерактивный объект, который накладывает блокировку на соответствующую запись в базе данных. Любые попытки создать новый объект через СоздатьОбъект("Документ.Вид") и найти в нем этот же документ (пока форма открыта) будут натыкаться на конфликт: база данных «видит», что документ уже редактируется (заблокирован формой). Именно поэтому методы Записать() или СделатьНеПроведенным() внутри кода формы не позволяют выполнить операции, требующие монопольного доступа к записи документа в транзакции.

Решение 1: Использование механизма ОбработкаОжидания

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

Шаг 1. Подготовка в Глобальном модуле. Нам необходимо создать экспортную процедуру, которая выполнит «грязную работу», и переменную для хранения ссылки на документ.


Перем глДокументДляОбработки Экспорт;

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

Шаг 2. Вызов из модуля формы документа. В процедуре нажатия кнопки мы подготавливаем данные и закрываем форму.


Процедура НажатьКнопкуПерепроведения()
    глДокументДляОбработки = ТекущийДокумент();
    // Запускаем ожидание на 1 секунду. Этого достаточно, чтобы форма успела закрыться.
    ОбработкаОжидания("глПерепровестиДокументТекущейДатой", 1);
    Форма.Закрыть(0); // Закрываем без вопросов о сохранении
КонецПроцедуры

Решение 2: Использование внешней обработки (ERT)

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

В модуле формы документа пишем:


Процедура ВыполнитьПерепроведение()
    Параметр = СоздатьОбъект("СписокЗначений");
    Параметр.ДобавитьЗначение(ТекущийДокумент(), "Документ");
    ОткрытьФорму("Отчет", Параметр, КаталогИБ() + "ExtForms\FixDoc.ert");
    Форма.Закрыть(0);
КонецПроцедуры

В самой обработке FixDoc.ert в процедуре ПриОткрытии() реализуем следующую логику:


Процедура ПриОткрытии()
    ТекДок = Форма.Параметр.Получить("Документ");
    // Здесь также лучше использовать ОбработкаОжидания внутри обработки,
    // чтобы дать время форме документа окончательно освободить объект.
    // Либо выполнять действия, если форма гарантированно закрыта.
    // ... код изменения и проведения ...
    СтатусВозврата(0); // Закрываем саму обработку после выполнения
КонецПроцедуры

Решение 3: Метод открытия на просмотр

Выясним еще одну интересную особенность 1С 7.7. Если документ открыт в режиме просмотра, он не блокируется так жестко, как при редактировании. Посмотрим, как это можно использовать. Мы можем программно закрыть форму и тут же открыть ее программно в режиме просмотра через ОткрытьФорму(Контекст, 0). В некоторых конфигурациях это позволяет избежать использования глобальных переменных, так как объект становится доступен для изменения через СоздатьОбъект.

Важные нюансы и рекомендации

При реализации подобных механизмов стоит учитывать следующие моменты:

  1. Транзакции: Операция смены даты и проведения должна быть атомарной. Если проведение не удалось, у вас останется непроведенный документ с измененной датой. Рекомендуем использовать конструкцию Попытка...Исключение.
  2. Права доступа: Помните, что программное проведение игнорирует некоторые интерактивные проверки, но права пользователя на проведение документов все равно должны быть соблюдены.
  3. Зацикливание: При использовании ОбработкаОжидания всегда первой строкой отключайте ее (вторым параметром 0), иначе процедура будет вызываться бесконечно с заданным интервалом.
  4. Блокировка интерфейса: Метод с закрытием и открытием формы может «моргать» перед глазами пользователя. Это нормальное поведение для платформы 7.7, так как по-другому обойти блокировку открытого объекта невозможно.

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

← На главную