При работе в системе 1С у многих разработчиков и продвинутых пользователей возникает задача программного удаления документов. Это может потребоваться в различных сценариях: от исправления ошибок массового ввода до реализации специфических бизнес-процессов. Особый интерес представляет удаление документа непосредственно из его формы по нажатию кнопки. Давайте разберем этот вопрос подробно, рассмотрим все нюансы и предложим рабочие решения.
Прежде всего, важно понимать, что в 1С существует два принципиально разных подхода к "удалению" документов:
В этой статье мы подробно рассмотрим оба подхода, уделив особое внимание прямому программному удалению документа из его формы, так как именно этот сценарий чаще всего вызывает затруднения.
Если ваша задача состоит в том, чтобы документ перестал отображаться в рабочих списках, но при этом оставалась возможность его восстановления или анализа в будущем, а также вы хотите избежать проблем со ссылочной целостностью, то механизм пометки на удаление — это ваш выбор. Этот метод является стандартным и наиболее безопасным в 1С.
При пометке на удаление документ не исчезает из базы данных. Вместо этого у него устанавливается специальный флаг (реквизит объекта) ПометкаУдаления в значение Истина. Системные списки и отчеты могут быть настроены так, чтобы не отображать помеченные объекты. Физическое удаление таких объектов происходит позднее с помощью регламентной операции "Удаление помеченных объектов". Этот механизм обеспечивает проверку ссылочной целостности: система не позволит удалить объект, на который существуют ссылки из других объектов, пока эти ссылки не будут изменены или удалены.
Для реализации пометки на удаление из формы документа по нажатию кнопки, мы можем использовать следующий код. Предположим, у нас есть кнопка "Пометить на удаление" на форме документа.
&НаКлиенте
Процедура УдалитьДокумент(Команда)
// Вызываем серверную процедуру для выполнения операций с данными
ПометитьНаУдалениеНаСервере();
// Закрываем форму текущего документа
ЭтаФорма.Закрыть();
КонецПроцедуры
&НаСервере
Процедура ПометитьНаУдалениеНаСервере()
// Перед пометкой на удаление, если документ был проведен,
// желательно отменить его проведение, чтобы очистить движения по регистрам.
// Это не обязательный шаг, но рекомендованный для корректной работы.
Если Объект.Проведен Тогда
Записать(Новый Структура("РежимЗаписи", РежимЗаписиДокумента.ОтменаПроведения));
КонецЕсли;
// Устанавливаем флаг пометки на удаление
Объект.ПометкаУдаления = Истина;
// Записываем объект с установленной пометкой
Объект.Записать();
КонецПроцедуры
После выполнения этого кода документ будет помечен на удаление и форма закроется. Чтобы увидеть изменения в списках, возможно, потребуется обновить список документов (например, повторно открыть журнал или нажать кнопку "Обновить").
Иногда требуется именно физическое удаление документа, а не просто пометка. Например, если документ был создан ошибочно, не имеет никаких связей с другими объектами и должен быть полностью стерт из истории. Этот метод требует глубокого понимания принципов работы 1С и потенциальных рисков.
Для прямого удаления объекта в 1С используется метод Удалить(). Этот метод вызывается у объекта документа, который предварительно необходимо получить из базы данных. Мы не можем удалить документ напрямую из его формы, если объект еще не записан или находится в режиме редактирования. Нам потребуется получить актуальный объект из базы данных.
ПолучитьОбъект(), который возвращает объект документа по ссылке.Удалить(): После получения объекта мы вызываем у него метод Удалить().Пример базового кода на сервере:
&НаСервере
Процедура УдалитьОбъектНаСервере(СсылкаНаДокумент)
// Получаем объект документа по ссылке
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
Если ДокОбъект <> Неопределено Тогда
// Вызываем метод Удалить()
ДокОбъект.Удалить();
КонецЕсли;
КонецПроцедуры
Для выполнения операции прямого удаления у пользователя должны быть соответствующие права. Если у пользователя недостаточно прав на "Интерактивное удаление документа" или полных прав на документ, система выдаст ошибку, и код не будет выполнен. В некоторых случаях, особенно при выполнении операций, которые должны игнорировать стандартные ограничения прав текущего пользователя (например, в фоновом режиме или для административных задач), можно использовать метод УстановитьПривилегированныйРежим().
УстановитьПривилегированныйРежим(Истина) временно предоставляет текущему сеансу полные права, позволяя выполнить операции, на которые у пользователя по умолчанию нет разрешений.УстановитьПривилегированныйРежим(Ложь).Пример использования:
&НаСервере
Процедура УдалитьОбъектПривилегированно(СсылкаНаДокумент)
УстановитьПривилегированныйРежим(Истина); // Включаем привилегированный режим
Попытка
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
Если ДокОбъект <> Неопределено Тогда
ДокОбъект.Удалить();
КонецЕсли;
Исключение
Сообщить("Ошибка при удалении документа: " + ОписаниеОшибки());
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь); // Выключаем привилегированный режим
КонецПроцедуры
Используйте привилегированный режим с максимальной осторожностью, поскольку это может создать потенциальные уязвимости в безопасности системы.
ОбменДанными.ЗагрузкаДанных = ИстинаПри прямом удалении документа методом Удалить() иногда необходимо установить свойство ОбменДанными.ЗагрузкаДанных = Истина; у объекта документа. Это свойство отключает стандартные проверки, которые выполняются при записи или удалении объектов, и имитирует загрузку данных из внешнего источника.
Зачем это нужно: В некоторых случаях внутренние механизмы платформы или конфигурации могут препятствовать удалению документа (например, если есть специфические проверки при записи/удалении). Установка ОбменДанными.ЗагрузкаДанных = Истина позволяет обойти эти проверки. Однако, это также существенно повышает риск нарушения целостности данных, так как вы фактически "обманываете" систему.
Пример использования:
&НаСервере
Процедура УдалитьОбъектЧерезОбменДанными(СсылкаНаДокумент)
УстановитьПривилегированныйРежим(Истина);
Попытка
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
Если ДокОбъект <> Неопределено Тогда
ДокОбъект.ОбменДанными.ЗагрузкаДанных = Истина; // Отключаем проверки
ДокОбъект.Удалить();
КонецЕсли;
Исключение
Сообщить("Ошибка при удалении документа: " + ОписаниеОшибки());
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры
Когда вы физически удаляете документ, который формировал движения по регистрам (накопления, бухгалтерии, сведений), эти движения обычно удаляются автоматически вместе с документом. Платформа 1С самостоятельно отслеживает связи между документами и их движениями. Однако, в сложных или нетиповых конфигурациях, а также при использовании нестандартных механизмов формирования движений, рекомендуется убедиться, что все связанные данные удалены корректно. При возникновении проблем с остаточными записями регистраторов пригодится обработка для удаления движений по битым ссылкам.
Это критически важный шаг перед прямым физическим удалением любого объекта. Если на удаляемый документ существуют ссылки из других объектов (например, этот документ указан как реквизит в другом документе, справочнике или регистре), его прямое удаление приведет к появлению "битых" ссылок в базе данных. Это может вызвать серьезные ошибки в работе системы и некорректное отображение данных.
Перед удалением необходимо проверить наличие таких ссылок и, если они есть, либо удалить/изменить ссылающиеся объекты, либо пересмотреть необходимость прямого удаления. Для комплексного анализа зависимостей и выборочной очистки данных можно использовать обработку для удаления документов с автоматическим контролем связанных объектов.
Для проверки ссылочной целостности в типовых конфигурациях 1С (особенно построенных на БСП - Библиотеке стандартных подсистем) часто используется функция ОбщегоНазначения.ЕстьСсылкиНаОбъект(). Эта функция позволяет узнать, ссылаются ли на данный объект другие элементы базы данных.
Пример использования:
&НаСервере
Функция ПроверитьСсылкиИУдалить(СсылкаНаДокумент)
// Проверяем наличие ссылок на документ
Если ОбщегоНазначения.ЕстьСсылкиНаОбъект(СсылкаНаДокумент) Тогда
Сообщить("Невозможно удалить документ. На него существуют ссылки из других объектов.");
Возврат Ложь;
КонецЕсли;
// Если ссылок нет, приступаем к удалению
УстановитьПривилегированныйРежим(Истина);
Попытка
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
Если ДокОбъект <> Неопределено Тогда
ДокОбъект.ОбменДанными.ЗагрузкаДанных = Истина;
ДокОбъект.Удалить();
Сообщить("Документ успешно удален.");
Возврат Истина;
Иначе
Сообщить("Документ не найден.");
Возврат Ложь;
КонецЕсли;
Исключение
Сообщить("Ошибка при удалении документа: " + ОписаниеОшибки());
Возврат Ложь;
КонецПопытки;
КонецПопытки; // Опечатка, должно быть End Try, но в 1С нет такой конструкции, просто конец Попытки-Исключения.
УстановитьПривилегированныйРежим(Ложь);
КонецФункции
Теперь давайте объединим все рассмотренные шаги в одном комплексном примере, который можно применить для удаления текущего документа из его формы по нажатию кнопки. Предположим, у нас есть кнопка "УдалитьТекущийДокумент" на форме документа.
&НаКлиенте
Процедура УдалитьТекущийДокумент(Команда)
// Предупреждаем пользователя о безвозвратности операции
Ответ = Вопрос("Вы уверены, что хотите безвозвратно удалить этот документ? Операция необратима и может привести к проблемам с данными, если на документ есть ссылки.", РежимДиалогаВопрос.ДаНет, 0);
Если Ответ = КодВозвратаДиалога.Нет Тогда
Возврат;
КонецЕсли;
// Вызываем серверную процедуру для выполнения удаления
Если УдалитьОбъектПолностьюНаСервере() Тогда
// Если удаление прошло успешно, закрываем форму
ЭтаФорма.Закрыть();
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция УдалитьОбъектПолностьюНаСервере()
// Ссылка на текущий объект формы
СсылкаНаТекущийДокумент = Объект.Ссылка;
// 1. Проверяем наличие ссылок на документ
Если ОбщегоНазначения.ЕстьСсылкиНаОбъект(СсылкаНаТекущийДокумент) Тогда
Сообщить("ОШИБКА: Невозможно удалить документ. На него существуют ссылки из других объектов. "+
"Пожалуйста, проверьте связанные объекты или используйте пометку на удаление.");
Возврат Ложь;
КонецЕсли;
// 2. Включаем привилегированный режим и отключаем проверки
УстановитьПривилегированныйРежим(Истина);
Попытка
// Получаем объект документа по ссылке
ДокОбъект = СсылкаНаТекущийДокумент.ПолучитьОбъект();
Если ДокОбъект <> Неопределено Тогда
// Отменяем проведение, если документ был проведен.
// Это желательно для корректной очистки движений, хотя при прямом удалении они тоже удалятся.
Если ДокОбъект.Проведен Тогда
ДокОбъект.Записать(Новый Структура("РежимЗаписи", РежимЗаписиДокумента.ОтменаПроведения));
КонецЕсли;
// Отключаем стандартные проверки для имитации загрузки данных
ДокОбъект.ОбменДанными.ЗагрузкаДанных = Истина;
// Вызываем метод Удалить()
ДокОбъект.Удалить();
Сообщить("Документ '" + СсылкаНаТекущийДокумент + "' успешно удален из базы.");
Возврат Истина;
Иначе
Сообщить("ОШИБКА: Документ по ссылке не найден в базе данных.");
Возврат Ложь;
КонецЕсли;
Исключение
Сообщить("ОШИБКА при удалении документа: " + ОписаниеОшибки());
Возврат Ложь;
КонецПопытки;
// 3. Важно: отключаем привилегированный режим
УстановитьПривилегированныйРежим(Ложь);
Возврат Ложь; // Возвращаем Ложь, если что-то пошло не так
КонецФункции
Этот код обеспечивает комплексный подход к прямому удалению, учитывая права, ссылочную целостность и необходимость обхода стандартных проверок. Однако, помните, что использовать его следует только при полной уверенности в необходимости такого действия.
В управляемых формах 1С важно понимать разницу между клиентским и серверным контекстом выполнения кода. Операции, которые взаимодействуют с базой данных (запись, чтение, удаление объектов), всегда должны выполняться на сервере. Клиентский код предназначен для взаимодействия с пользовательским интерфейсом (например, отображение форм, реакция на нажатия кнопок).
&НаКлиенте, выполняются на клиентской стороне.&НаСервере (или без директивы в модуле объекта/формы при вызове с клиента), выполняются на сервере.В наших примерах мы видим, что нажатие кнопки на форме (клиент) вызывает серверную процедуру, которая уже непосредственно работает с объектами базы данных. Такой подход является правильным и необходимым для корректной работы.
Мы настоятельно рекомендуем тщательно взвесить все "за" и "против" перед использованием прямого физического удаления документов.
В целом, подход "скрыть, но не удалить" часто является более предпочтительным с точки зрения безопасности данных и гибкости системы.
Мы рассмотрели различные аспекты программного удаления документов в 1С. Выяснили, что самый безопасный способ — это пометка на удаление, но при необходимости прямого физического удаления можно использовать методы объекта Удалить() в сочетании с ПолучитьОбъект(), привилегированным режимом УстановитьПривилегированныйРежим() и отключением проверок через ОбменДанными.ЗагрузкаДанных = Истина. Самое главное — всегда выполняйте проверку ссылочной целостности с помощью функций вроде ОбщегоНазначения.ЕстьСсылкиНаОбъект(). Помните, что каждое такое действие может иметь серьезные последствия для данных вашей информационной системы.
Всегда подходите к программному удалению с максимальной ответственностью, тестируйте код в тестовой базе и убедитесь, что вы полностью понимаете все возможные последствия своих действий.