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