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

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

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

Причина возникновения проблемы

Прежде чем перейти к решениям, проанализируем ситуацию. В 1С 7.7 модель работы с объектами жестко связана с контекстом. Когда мы открываем форму документа, система резервирует этот объект для редактирования. Любая попытка изменить статус пометки удаления через программный код внутри этой же формы конфликтует с самой формой, которая «держит» этот документ. Таким образом, чтобы пометить документ на удаление, нам нужно сначала закрыть форму или выполнить действие в момент, когда блокировка уже снята.

Способ 1: Использование обработки ожидания

Этот метод считается классическим для «клюшек» (1С 7.7). Суть заключается в том, чтобы дать команду системе выполнить удаление через секунду после того, как форма будет закрыта. Разберем по шагам реализацию этого механизма.

В глобальном модуле необходимо объявить переменную и процедуру, которая будет выполнять удаление:


Перем ГлДокДляУдаления Экспорт;

Процедура ГлПометитьНаУдаление() Экспорт
    Если ПустоеЗначение(ГлДокДляУдаления) = 0 Тогда
        Если ГлДокДляУдаления.Выбран() = 1 Тогда
            // Пытаемся заблокировать, чтобы убедиться, что форма закрыта
            Если ГлДокДляУдаления.Блокировка(1) = 1 Тогда 
                ГлДокДляУдаления.Удалить(0); // 0 - пометка на удаление, 1 - физическое удаление
                ГлДокДляУдаления.Блокировка(0);
                ГлДокДляУдаления = "";
                // Выключаем обработку ожидания
                ОбработкаОжидания("ГлПометитьНаУдаление", 0);
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Затем в модуле формы документа, в процедуре, отвечающей за закрытие или по нажатию кнопки «Удалить», пишем следующий код:


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

Важно: Мы используем метод Блокировка(1), чтобы проверить, освободила ли форма объект. Если форма еще закрывается, блокировка не установится, и процедура просто сработает на следующем такте обработки ожидания.

Способ 2: Использование модального вызова и контекста

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

В форме документа (в кнопке удаления или ПриЗакрытии):


Процедура ПриНажатииКнопкиУдалить()
    // Передаем флаг удаления через параметр формы
    Форма.Параметр = "УдалитьДокумент";
    Форма.Закрыть(0);
КонецПроцедуры

В вызывающей обработке (откуда открывали документ):


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

Способ 3: Метод «копирования» (Сеньора)

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

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


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

Способ 4: Использование внешних компонент (FormEx)

Если в вашей конфигурации используется компонента FormEx, задача упрощается. Мы можем сгенерировать внешнее событие, которое отработает сразу после закрытия формы, когда объект уже разблокирован. Это позволяет избежать «мигания» окон и использования обработок ожидания.

Процесс выглядит так:

  1. В модуле формы вызываем метод компоненты для генерации события.
  2. В ОбработкаВнешнегоСобытия ловим этот сигнал.
  3. Выполняем Удалить(0).

Рекомендации

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

Важные замечания:

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

← На главную