УстановитьПометкуУдаления и не только: пометка документа из кода
Содержание
Документ помечают на удаление программно методом объекта УстановитьПометкуУдаления(Истина): получаете объект через Ссылка.ПолучитьОбъект() и вызываете метод на сервере. У проведённого документа платформа при этом сама отменяет проведение, и движения по регистрам исчезают сразу, а не после удаления.
Частое заблуждение — считать, что пометка ничего не меняет в учёте до запуска удаления помеченных. Для справочника это почти так. Для проведённого документа — нет: остатки, обороты и отчёты пересчитываются в момент пометки. Всё ниже относится к платформе 8.3 и одинаково работает в любой типовой конфигурации: БП 3.0, ЗУП 3.1, УТ 11, ERP.
Пометка на удаление и физическое удаление: в чём разница
В 1С есть два разных действия, и их часто путают.
- 🏷️ Пометка удаления — это флаг
ПометкаУдаленияу объекта. Запись остаётся в базе, её видно в списке с перечёркнутой иконкой. Пометку можно снять. - 🗑️ Физическое удаление — запись стирается из таблицы. Вернуть её можно только из резервной копии.
Между ними стоит контроль ссылочной целостности. Обработка удаления помеченных проверяет, не ссылается ли на объект кто-то ещё: другой документ, справочник, регистр сведений . Если ссылки есть, объект не удаляется.
| Действие | Что происходит с документом | Движения | Можно отменить |
|---|---|---|---|
УстановитьПометкуУдаления(Истина) | Остаётся в базе с флагом | Удаляются (проведение отменено) | Да, снять пометку и провести заново |
УдалитьОбъекты(Массив, Истина) | Удаляется, если на него нет ссылок | Удаляются вместе с документом | Нет |
Объект.Удалить() | Удаляется сразу, без проверки ссылок | Удаляются | Нет |
Метод Удалить() не проверяет ссылки. После него в других документах останутся «битые» ссылки вида <Объект не найден>. В рабочем коде его почти не используют.
Как пометить документ на удаление из кода: синтаксис
Основной способ
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.УстановитьПометкуУдаления(Истина);
У документа метод принимает один параметр — Истина или Ложь. Второй параметр ВключаяПодчиненные есть только у иерархических справочников, для документов его нет.
Что делает платформа при вызове:
- Устанавливает
ПометкаУдаления = Истина. - Если документ проведён — записывает его в режиме отмены проведения. В модуле объекта срабатывает
ОбработкаУдаленияПроведения, а вПередЗаписьюприходитРежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения. - Удаляет движения документа по всем регистрам.
- Записывает документ. Отдельный вызов
Записать()не нужен.
Вызов из управляемой формы
Метод работает только на сервере. На клиенте у ссылки его нет, поэтому команду в форме списка разбивают на две части:
&НаКлиенте
Процедура ПометитьНаУдаление(Команда)
ТекущаяСсылка = Элементы.Список.ТекущаяСтрока;
Если ТекущаяСсылка = Неопределено Тогда
Возврат;
КонецЕсли;
ПометитьНаУдалениеНаСервере(ТекущаяСсылка);
Элементы.Список.Обновить();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПометитьНаУдалениеНаСервере(ДокументСсылка)
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.Заблокировать();
ДокументОбъект.УстановитьПометкуУдаления(Истина);
КонецПроцедуры
Заблокировать() ставит объектную блокировку. Если документ в этот момент открыт и изменён другим пользователем, вы получите понятное исключение до записи, а не конфликт версий после.
Через реквизит и Записать()
Можно установить флаг напрямую:
ДокументОбъект.ПометкаУдаления = Истина;
ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
Для проведённого документа режим ОтменаПроведения указывайте явно. Помеченный документ провести нельзя, а запись в обычном режиме оставит его в противоречивом состоянии «проведён и помечен». Метод УстановитьПометкуУдаления делает всё это за вас, поэтому он предпочтительнее.
Запроса вида UPDATE в языке запросов 1С нет. Пометку ставят только через объект, по одному документу за вызов.
Как снять пометку
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.УстановитьПометкуУдаления(Ложь);
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
После снятия пометки документ остаётся непроведённым. Проведение само не восстанавливается, его нужно выполнить вторым шагом.
Анализ ссылок перед пометкой документа
Пометка сама по себе ссылки не проверяет. Документ-основание помечается спокойно, даже если на нём построены пять реализаций. Проблема всплывёт позже, когда удаление помеченных откажется его стирать.
Если нужно заранее понять, что тянет за собой документ, используйте НайтиПоСсылкам:
Ссылки = Новый Массив;
Ссылки.Добавить(ДокументСсылка);
Найденные = НайтиПоСсылкам(Ссылки);
Для Каждого Строка Из Найденные Цикл
ЭтоСсылочный = Метаданные.Документы.Содержит(Строка.Метаданные)
Или Метаданные.Справочники.Содержит(Строка.Метаданные);
Если ЭтоСсылочный И Строка.Данные <> ДокументСсылка Тогда
Сообщить(СтрШаблон("Ссылается: %1", Строка.Данные));
КонецЕсли;
КонецЦикла;
Таблица результата содержит колонки Ссылка, Данные и Метаданные. В неё попадут и собственные движения документа: это наборы записей регистров, где он указан регистратором. Их фильтруем — при отмене проведения они удалятся сами.
НайтиПоСсылкам просматривает все таблицы базы. На базе в сотни гигабайт один вызов идёт минутами. В цикле по тысяче документов так не делайте: передайте массив всех ссылок одним вызовом.
Для ручной проверки удобнее отчёт «Структура подчинённости». Он открывается из формы документа, через группу команд «Связанные документы» или аналогичное меню в командной панели. Он показывает основания и документы, введённые на основании, в виде дерева.
Типичный сценарий практика — пометить документ вместе с подчинёнными. Для этого берите документы, у которых реквизит ДокументОснование равен исходной ссылке, и помечайте их первыми. Тогда при удалении помеченных цепочка уйдёт целиком.
Массовая пометка документов на удаление и скорость
Массовая пометка нужна при чистке тестовых данных, ошибочной загрузки или после неудачного обмена. Порядок такой: выбрать ссылки запросом, затем пройти по ним и пометить каждую.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.ПоступлениеТоваровУслуг КАК Док
|ГДЕ
| НЕ Док.ПометкаУдаления
| И Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));
Выборка = Запрос.Выполнить().Выбрать();
Помечено = 0;
Ошибки = Новый Массив;
Пока Выборка.Следующий() Цикл
Попытка
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДокОбъект.Заблокировать();
ДокОбъект.УстановитьПометкуУдаления(Истина);
Помечено = Помечено + 1;
Исключение
Текст = СтрШаблон("%1: %2", Выборка.Ссылка, ОписаниеОшибки());
Ошибки.Добавить(Текст);
ЗаписьЖурналаРегистрации("МассоваяПометкаУдаления",
УровеньЖурналаРегистрации.Ошибка, , Выборка.Ссылка, Текст);
КонецПопытки;
КонецЦикла;
Сообщить(СтрШаблон("Помечено: %1, ошибок: %2",
Формат(Помечено, "ЧГ=0"), Формат(Ошибки.Количество(), "ЧГ=0")));
Подставьте свой вид документа вместо ПоступлениеТоваровУслуг. Условие НЕ Док.ПометкаУдаления убирает лишние записи уже помеченных документов.
Почему не одна транзакция на всё
Каждая запись объекта и так идёт в своей транзакции. Если обернуть весь цикл в НачатьТранзакцию(), первая же ошибка испортит транзакцию. Дальше каждая запись будет падать с В данной транзакции уже происходили ошибки, а в конце откатится всё.
Общая транзакция нужна, только если требуется принцип «всё или ничего». Тогда при первом исключении вызывайте ОтменитьТранзакцию() и выходите из цикла.
Что ускоряет обработку
- ⏱️ Запускайте вне рабочего времени. Отмена проведения пишет в регистры, накладывает управляемые блокировки и мешает пользователям.
- 🔄 Выносите в фоновое задание.
ФоновыеЗадания.Выполнить("ОбщийМодуль.Процедура", Параметры)не держит клиент и не обрывается при закрытии формы. - 📦 Делите по периодам. Месяц за раз проще контролировать и перезапускать после сбоя.
- 📉 Отключайте итоги осторожно.
РегистрыНакопления.Имя.УстановитьИспользованиеИтогов(Ложь)ускоряет запись движений, но влияет на всех пользователей базы. После обработки итоги включают обратно, а пересчёт занимает время.
Что выбрать для своей задачи:
Отложенное удаление помеченных документов и архив
Пометка — первый шаг. Физически документы удаляются отдельно, обычно позже и централизованно.
Обработка в типовой конфигурации
В конфигурациях на БСП (БП 3.0, ЗУП 3.1, УТ 11) обработка находится в Администрирование → Обслуживание, группа «Корректировка данных», пункт «Удаление помеченных объектов». Там же можно включить удаление по расписанию: регламентное задание будет стирать помеченные объекты само, например по ночам.
Обработка показывает, какие объекты удалить нельзя и кто на них ссылается. Это то же самое, что НайтиПоСсылкам, только с удобным интерфейсом.
Удаление из кода
Помеченные = НайтиПомеченныеНаУдаление();
Попытка
УдалитьОбъекты(Помеченные, Истина);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
Второй параметр Истина включает контроль ссылочной целостности. Без него поведение равно Удалить() для каждого объекта. НайтиПомеченныеНаУдаление() возвращает все помеченные объекты базы, не только документы. Если нужно удалить строго свою выборку, передайте в УдалитьОбъекты собственный массив ссылок.
Перед удалением сделайте резервную копию базы (выгрузка .dt или бэкап СУБД). Удалённые документы из 1С не восстановить.
Зачем держать архив
Помеченный документ всё ещё можно открыть, посмотреть и восстановить. Поэтому многие компании ставят паузу между пометкой и удалением: неделю или месяц, чтобы ошибку успели заметить.
Удалять первичку в учётной базе нужно с оглядкой на сроки хранения. По закону о бухучёте первичные документы хранят не менее пяти лет после отчётного года, по НК РФ — четыре года. Перед чисткой закрытых периодов сохраните копию базы в архив и держите её весь этот срок.
Как отследить или запретить пометку документа
Иногда задача обратная: не пометить, а не дать пометить. Например, документы с отправленным в банк платежом или подписанные в ЭДО. Момент пометки ловят в ПередЗаписью модуля объекта.
Признак простой: в объекте флаг уже стоит, а в базе (через ссылку) ещё нет.
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если ПометкаУдаления И Не Ссылка.ПометкаУдаления Тогда
Если Не РольДоступна("ПолныеПрава") Тогда
Отказ = Истина;
Сообщить("Пометить этот документ может только администратор.");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
У нового документа ссылка пустая, и Ссылка.ПометкаУдаления вернёт Ложь. Ошибки не будет.
Код срабатывает и при интерактивной пометке, и при программной: оба пути проходят через запись объекта. Если Отказ = Истина, метод УстановитьПометкуУдаления вызовет исключение — его и поймает Попытка в массовой обработке.
Когда правило нужно сразу для многих документов
Не правьте модули объектов типовой конфигурации: это усложнит обновления. Для правила на несколько видов документов создайте в расширении подписку на событие «Перед записью» и укажите источником нужные документы. Обработчик в общем модуле получает объект первым параметром, проверка внутри та же.
Роль ПолныеПрава есть в типовых конфигурациях на БСП. В своей конфигурации подставьте имя роли, которая у вас отвечает за администрирование.
Ошибки при программной пометке на удаление
Отдельно — флаг ОбменДанными.Загрузка. При значении Истина типовые обработчики ПередЗаписью и ОбработкаУдаленияПроведения обычно выходят сразу, а проверки дат запрета и бизнес-логика пропускаются. Ставить его ради скорости пометки нельзя: можно получить документ с пометкой и неочищенными связанными данными, которые конфигурация обычно чистит в своих обработчиках.
Частые вопросы
Можно ли пометить документ на удаление запросом?
Попадает ли программная пометка в журнал регистрации?
Передаётся ли пометка удаления по обмену?
Чем пометка документа отличается от пометки справочника?
Можно ли проверить пометку без получения объекта?
Источники
- Федеральный закон от 06.12.2011 № 402-ФЗ «О бухгалтерском учёте», ст. 29
- Налоговый кодекс РФ, часть первая, ст. 23