Разработка и Конфигурация · 13 мин
Как программно очистить движения документа в 1С
Как программно очистить движения документа в 1С: методы Очистить(), УстановитьАктивность, запись набора записей, типичные ошибки и проверка результата.
Движения документа — это записи в регистрах (накопления, сведений, бухгалтерии, расчета), которые документ формирует при проведении. Задача очистить их программно возникает при исправлении ошибок проведения, переносе данных, отмене проведения без изменения самого документа, а также в обработках массового восстановления последовательностей. В 1С для этого есть несколько штатных механизмов, и выбор зависит от того, нужно ли очистить движения по всем регистрам сразу или только по одному.
Ключевой объект для работы — коллекция Движения объекта документа. Каждый элемент коллекции — это набор записей по конкретному регистру, у которого есть методы Очистить(), Записать() и свойство активности. Важно понимать: просто вызвать Очистить() недостаточно — набор записей нужно ещё и записать в базу, иначе изменения останутся только в памяти.
Ниже разобраны рабочие способы очистки: через распроведение документа, через очистку наборов записей вручную, через установку активности и через прямую запись пустых наборов. Отдельно рассмотрены отличия управляемых и обычных форм, права доступа и типичные ошибки, из-за которых движения «не очищаются».
Как устроены движения документа и когда их нужно очищать
При проведении документа платформа вызывает обработчик ОбработкаПроведения, в котором формируются записи в регистрах. Эти записи хранятся в таблицах регистров и связаны с документом через поле «Регистратор». Пока документ проведён, его движения активны и участвуют в расчёте итогов: остатков, оборотов, сальдо.
Очистка движений требуется в нескольких типовых сценариях:
- документ проведён с ошибками, и нужно убрать его влияние на регистры без удаления самого документа;
- выполняется массовое перепроведение, и перед повторным проведением нужно гарантированно удалить старые записи;
- обработка миграции данных переносит документы, но движения должны формироваться заново по новым правилам;
- нужно «заморозить» документ — оставить его в базе, но исключить из учёта.
Если цель — просто исключить документ из учёта, обычно достаточно штатной отмены проведения. Ручная очистка наборов записей оправдана, когда отмена проведения недоступна (например, документ находится в закрытом периоде, а обработка выполняется в привилегированном режиме) или когда нужно очистить движения только по части регистров.
Способ 1: отмена проведения — самый безопасный вариант
Штатный и рекомендуемый способ убрать все движения документа — записать его в режиме отмены проведения. Платформа сама очистит наборы записей по всем регистрам, по которым документ является регистратором, и снимет пометку проведения.
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
Преимущество этого способа в том, что срабатывают все встроенные проверки: контроль дат запрета изменения данных, проверка прав, подписки на события. Если документ находится в последовательности, платформа корректно обработает границу последовательности. Побочный эффект — документ становится непроведённым, что не всегда желательно.
Если нужно оставить документ проведённым, но очистить движения, отмена проведения не подходит — используйте ручную очистку наборов записей (следующий раздел). Учтите, что документ, оставшийся проведённым без движений, — аномальное состояние: при любом последующем перепроведении движения будут сформированы заново по текущим данным табличных частей.
Способ 2: очистка наборов записей через коллекцию Движения
Для точечной очистки движений без изменения статуса проведения используется цикл по коллекции Движения. Метод Очистить() удаляет строки набора в памяти, а метод Записать() фиксирует пустой набор в базе, физически удаляя записи регистра по этому регистратору.
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
Для Каждого НаборЗаписей Из ДокументОбъект.Движения Цикл
НаборЗаписей.Очистить();
НаборЗаписей.Записать(Истина);
КонецЦикла;
Параметр Истина в методе Записать() означает запись с замещением: существующие записи регистратора удаляются и заменяются содержимым набора (в данном случае — пустым). Если вызвать Записать() без параметра, замещение также выполняется по умолчанию, но явное указание делает код понятнее.
Если нужно очистить движения только по одному регистру, обращайтесь к набору по имени регистра:
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
Набор = ДокументОбъект.Движения.ОстаткиТоваров;
Набор.Очистить();
Набор.Записать(Истина);
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
Для Каждого НаборЗаписей Из ДокументОбъект.Движения Цикл
НаборЗаписей.Очистить();
НаборЗаписей.Записать(Истина);
КонецЦикла;Способ 3: прямая работа с набором записей регистра без объекта документа
Необязательно получать объект документа целиком. Можно создать набор записей регистра напрямую, установить отбор по регистратору и записать пустой набор. Это быстрее при массовой обработке, потому что не загружаются реквизиты и табличные части документа.
НаборЗаписей = РегистрыНакопления.ОстаткиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Записать(Истина);
Здесь набор изначально пустой — чтение существующих записей не выполняется. Запись с замещением удаляет все строки регистра по указанному регистратору. Это самый производительный способ, но у него есть ограничения: не срабатывают обработчики проведения документа, не контролируется статус проведения, а подписки на события записи регистра должны быть учтены отдельно.
Такой подход часто применяют в серверных процедурах пакетной обработки в привилегированном режиме (УстановитьПривилегированныйРежим(Истина)), когда нужно обойти даты запрета и ограничения прав на уровне записи. Использовать привилегированный режим следует осознанно: он отключает проверку прав, и ошибка в отборе затронет данные всех пользователей без возможности отката вне транзакции.
Как выбрать способ
Установка активности вместо удаления записей
Альтернатива физическому удалению — установить движениям признак неактивности. Неактивные записи остаются в таблице регистра, но не участвуют в расчёте итогов. Это полезно, когда нужно временно исключить влияние документа с возможностью быстрого восстановления.
НаборЗаписей = РегистрыНакопления.ОстаткиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
НаборЗаписей.УстановитьАктивность(Ложь);
НаборЗаписей.Записать();
Здесь важен порядок: сначала Прочитать(), чтобы загрузить существующие записи, затем УстановитьАктивность(Ложь), затем запись. Если пропустить чтение, набор будет пустым и записывать активность будет нечему. Обратное включение выполняется тем же кодом с параметром Истина.
Удаление или деактивация
Записи физически удаляются из регистра. Подходит для исправления ошибок и перепроведения. Восстановить движения можно только перепроведением документа.
Записи остаются в базе, но исключаются из итогов. Подходит для временного отключения. Легко откатить, но таблица регистра не уменьшается.
Штатный режим: удаляет движения и снимает пометку проведения. Самый безопасный, но меняет статус документа.
Проверка результата и работа в транзакции
После очистки убедитесь, что записи действительно удалены. Проще всего выполнить запрос к регистру с отбором по регистратору и проверить, что результат пустой:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 * ИЗ РегистрНакопления.ОстаткиТоваров
|ГДЕ Регистратор = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
Если Запрос.Выполнить().Пустой() Тогда
// движения очищены
КонецЕсли;
При массовой обработке оборачивайте изменения каждого документа (или пакета документов) в транзакцию через НачатьТранзакцию() и ЗафиксироватьТранзакцию() с обработкой исключений через ОтменитьТранзакцию(). Это гарантирует, что при ошибке на середине цикла не останется документов с частично очищенными движениями — например, очищен регистр товаров, но не очищен регистр расчётов с контрагентами.
Дополнительно проверьте итоги: после очистки движений по регистрам накопления с имеющимися итогами отчёты должны перестать показывать влияние документа. Если итоги не изменились, возможно, запись набора не выполнилась из-за исключения, перехваченного без сообщения, или очищался не тот регистратор.
Как проверить результат
Запрос с отбором по регистратору возвращает пустой результат
Записи остались — запись набора не выполнилась или очищён другой регистр
Статус соответствует замыслу: непроведён после ОтменаПроведения или проведён после ручной очистки
Документ проведён, движений нет, а по логике задачи он должен был стать непроведённым
Остатки и обороты пересчитались без влияния документа
Отчёт показывает старые цифры — проверьте актуальность итогов регистра
Типичные ошибки и ограничения
Самая частая ошибка — вызвать Очистить() и забыть Записать(). Набор очищается только в памяти, в базе записи остаются. Вторая по частоте ошибка — попытка очистить движения через ДокументОбъект.Движения, когда документ не проводится по нужному регистру: обращение к несуществующему для данного вида документа набору вызовет исключение, поэтому в универсальных обработках проверяйте наличие регистра в метаданных документа через ДокументСсылка.Метаданные().Движения.
Ещё несколько ограничений, о которых нужно помнить:
- при записи наборов срабатывают подписки на события регистров — если в них есть логика, рассчитанная на непустой набор, возможны ошибки;
- запись наборов документа, находящегося в закрытом периоде, блокируется датой запрета изменения данных — обходите через привилегированный режим только осознанно;
- если документ входит в последовательность, очистка движений не сдвигает границу последовательности автоматически — восстанавливайте её отдельно;
- в регистрах бухгалтерии наборы записей могут быть связаны с корреспонденциями и субконто — прямая очистка допустима, но проверяйте отчёты по счетам после обработки.
FAQ
Можно ли очистить движения, не получая объект документа?
Да. Создайте набор записей нужного регистра через менеджер регистра, установите отбор по регистратору и вызовите Записать(Истина). Это быстрее, чем ПолучитьОбъект(), потому что не загружаются реквизиты и табличные части документа.
Почему после Очистить() записи остались в регистре?
Метод Очистить() удаляет строки только в памяти. Чтобы изменения попали в базу, нужно вызвать Записать(Истина) у того же набора записей. Также проверьте, что запись не завершается исключением, которое перехватывается без сообщения.
Чем отличается Записать(Истина) от Записать(Ложь) у набора записей?
Параметр управляет замещением. Записать(Истина) сначала удаляет существующие записи по регистратору, затем записывает содержимое набора. Записать(Ложь) добавляет записи без удаления существующих, что для регистров с уникальным регистратором обычно приводит к конфликту или дублям.
Как очистить движения у большого количества документов без падения производительности?
Используйте прямые наборы записей без получения объектов документов, обрабатывайте документы пакетами, фиксируйте транзакцию порциями и выполняйте обработку на сервере. Избегайте интерактивных вызовов и проверок внутри цикла.
Можно ли восстановить очищенные движения?
Если документ сохранил данные, движения восстанавливаются перепроведением: Записать(РежимЗаписиДокумента.Проведение). Если записи были деактивированы через УстановитьАктивность(Ложь), достаточно прочитать набор и установить активность обратно в Истина.
Очистка движений влияет на границу последовательности?
Прямая запись наборов не пересчитывает границу последовательности автоматически. После массовой очистки документов, входящих в последовательность, границу нужно восстановить отдельно — штатной обработкой проведения по последовательностям или программно через менеджер последовательности.
Что важно запомнить
Очистка движений выполняется либо штатной отменой проведения, либо записью пустых наборов записей с замещением. Очистить() без Записать() не меняет данные в базе. Для массовой обработки используйте прямые наборы записей и транзакции, а перед запуском — резервную копию. Если влияние документа нужно отключить временно, используйте УстановитьАктивность(Ложь) вместо удаления записей.