Как удалить движения документа в базе-приемнике при нетиповом обмене 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Рассмотрим достаточно частую проблему, с которой сталкиваются разработчики при настройке собственных (самописных) планов обмена без использования правил конвертации (КД) и с отключенной авторегистрацией. Проблема заключается в следующем: мы снимаем документ с проведения в базе-источнике, выгружаем изменения через XML (например, передаем веб-сервисом) и загружаем в базу-приемник. Документ в приемнике становится непроведенным, но его движения по регистрам накопления остаются на месте. Посмотрим, почему так происходит и разберем по шагам, как правильно передавать удаление движений.

Почему не работает платформенное УдалениеОбъекта?

Многие разработчики пытаются решить задачу "в лоб" и передать удаление записей через платформенный элемент сообщения обмена, используя метод УдалениеОбъекта, передавая в него набор записей. В результате всегда возникает ошибка несоответствия параметра. Выясним причину такого поведения.

В платформе 1С метод УдалениеОбъекта предназначен исключительно для ссылочных типов данных (справочников, документов, планов видов характеристик и т.д.). НаборЗаписей регистра (накопления, сведений, бухгалтерии) ссылочным типом не является. Он идентифицируется не ссылкой, а своим отбором (как правило, по регистратору). Именно поэтому попытка передать набор записей как объект для удаления вызывает ошибку типизации.

Истинный механизм удаления движений: пустой набор записей

Проанализируем ситуацию с архитектурной точки зрения 1С. В системе не существует понятия "удаление объекта регистра" в том виде, в каком оно есть для справочников. Удаление движений документа — это, по сути, запись набора записей по данному документу-регистратору, в котором количество строк (самих записей) равно нулю.

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

Важное условие: при записи набора на стороне приемника свойство Замещать должно быть установлено в значение Истина (обычно оно установлено так по умолчанию).

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

Особенности при отключенной авторегистрации

Если в вашем плане обмена авторегистрация отключена, вам необходимо вручную регистрировать изменения для обмена. При отмене проведения документа платформенные обработчики источника очищают набор записей в базе-источнике.

Чтобы приемник узнал об этом, нужно зарегистрировать не только сам измененный документ, но и сам набор записей регистра. В момент обработки отмены проведения нужно программно создать набор, установить отбор по регистратору и передать его в метод ПланыОбмена.ЗарегистрироватьИзменения().

Программная очистка движений на стороне приемника

Разберем альтернативные подходы, если вы обрабатываете загруженные данные вручную на стороне приемника (например, при парсинге XML или обработке загруженного объекта). Мы можем программно очистить движения документа после его чтения.

Вариант 1. Запись с режимом отмены проведения

Если мы видим, что пришедший документ имеет статус непроведенного, мы можем сымитировать стандартное поведение системы:


Если Объект.Проведен = Ложь Тогда
    Объект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;

Этот код заставит платформу выполнить обработку отмены проведения в приемнике и автоматически зачистить все регистры, которые указаны в свойствах документа как очищаемые.

Вариант 2. Очистка движений с сохранением флага "Проведен"

Рассмотрим специфический случай бизнес-логики. Например, в конфигурации "Розница" после закрытия кассовой смены чеки остаются проведенными (свойство Проведен = Истина), но их движения по регистрам переносятся в сводный отчет о розничных продажах, а у самого чека они удаляются. В этом случае полагаться на статус проведения нельзя.

Если нам нужно принудительно очистить конкретный регистр у документа, оставив его проведенным, воспользуемся следующим методом:


ДокОбъект = Док.ПолучитьОбъект();
ДокОбъект.Движения.ТоварыНаСкладах.Очистить();
ДокОбъект.Движения.ТоварыНаСкладах.Записать();
ДокОбъект.Записать();

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

Вариант 3. Имитация перепроведения с очисткой

Еще один вариант достижения того же результата (очистить движения, но оставить документ проведенным):


ДокОбъект = Док.ПолучитьОбъект();
// Принудительно отменяем проведение (очищаются движения)
ДокОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
// Возвращаем признак проведения
ДокОбъект.Проведен = Истина;
// Записываем просто как объект, без режима проведения
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);

Подводя итог: для корректного обмена удаленными движениями через самописный план обмена, мы должны передавать в XML сериализованный пустой набор записей с отбором по регистратору. Если же бизнес-логика требует очистки движений у проведенных документов, следует передавать изменения самих наборов записей, либо прописывать явную программную очистку коллекций регистра в обработчиках загрузки базы-приемника.

← На главную