К статье
Практический материал

Разработка и Конфигурация · 13 мин

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

Как программно изменить движения документа в 1С: работа с набором записей, обработчик ОбработкаПроведения, перепроведение, типичные ошибки и примеры кода.

Движения документа в 1С — это записи в регистрах (накопления, сведений, бухгалтерии, расчёта), которые документ формирует при проведении. Иногда стандартного алгоритма проведения недостаточно: нужно добавить движения из внешних данных, скорректировать их по условиям обмена или вовсе записать вручную без перепроведения документа. Платформа 1С:Предприятие 8 даёт для этого несколько механизмов, и выбор между ними определяет устойчивость решения при обновлениях.

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

Ниже разобраны рабочие приёмы с примерами кода, границы безопасного применения и контрольные точки для проверки результата. Материал ориентирован на разработчиков и внедренцев, работающих с управляемыми и обычными формами на платформе 8.3.

Как устроены движения документа и почему их нельзя править «в лоб»

Каждый документ, у которого в конфигураторе отмечены регистры-приёмники, при проведении формирует наборы записей. Они доступны через коллекцию Движения объекта документа. Физически записи хранятся в таблицах регистров, а связь с документом обеспечивается полем «Регистратор». Пока документ проведён, набор записей принадлежит ему, и платформа управляет этим набором целиком: при отмене проведения движения удаляются, при перепроведении — очищаются и формируются заново.

Из этого следует главное ограничение: любые ручные правки записей регистра, сделанные в обход механизма проведения, живут только до ближайшего перепроведения документа. Групповое перепроведение за месяц, восстановление последовательностей или обработка «Проведение документов» уничтожат ручные корректировки без предупреждения. Поэтому устойчивое решение всегда строится вокруг логики проведения, а не вокруг разовых правок таблиц.

Способ 1. Изменение движений в обработчике ОбработкаПроведения

Штатная точка вмешательства — событие ОбработкаПроведения в модуле объекта документа. Здесь движения ещё не записаны в базу: вы работаете с наборами записей в памяти, можете добавлять, изменять и удалять строки, а платформа зафиксирует результат в той же транзакции, что и сам документ. Это самый безопасный и предсказуемый вариант.

Типовой приём — сначала сформировать движения стандартным кодом, затем скорректировать их по своим условиям. Например, добавить аналитику или изменить количество в уже подготовленных строках набора:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

// ... стандартное формирование движений ...

// Корректировка сформированных движений

Для Каждого Запись Из Движения.ТоварыНаСкладах Цикл

Если Запись.Номенклатура.ВесовойТовар Тогда

Запись.Количество = Запись.Количество * КоэффициентПересчета;

КонецЕсли;

КонецЦикла;

// Добавление новой строки в другой регистр

НоваяЗапись = Движения.ПартииТоваров.Добавить();

НоваяЗапись.Период = Дата;

НоваяЗапись.ВидДвижения = ВидДвиженияНакопления.Приход;

НоваяЗапись.Номенклатура = НоменклатураПоУмолчанию;

НоваяЗапись.Количество = 1;

КонецПроцедуры

Если менять типовой модуль нежелательно (конфигурация на поддержке), обработчик выносят в расширение конфигурации с аннотацией &После("ОбработкаПроведения") или &ИзменениеИКонтроль. Это сохраняет возможность обновления типовой конфигурации без ручного сравнения модулей.

Способ 2. Программная запись в регистр с отбором по регистратору

Когда проведение документа по каким-то причинам не подходит (например, движения грузятся из внешней системы, а документ служит только «оболочкой»-регистратором), набор записей формируют вручную через менеджер регистра. Ключевой момент — обязательная установка отбора по регистратору, иначе запись затронет весь регистр.

НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();

НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);

НоваяЗапись = НаборЗаписей.Добавить();

НоваяЗапись.Период = ДокументСсылка.Дата;

НоваяЗапись.ВидДвижения = ВидДвиженияНакопления.Приход;

НоваяЗапись.Номенклатура = Номенклатура;

НоваяЗапись.Склад = Склад;

НоваяЗапись.Количество = Количество;

НаборЗаписей.Записать(Истина); // Истина — с замещением существующих движений

Параметр Замещение = Истина в методе Записать() означает, что старые движения этого регистратора в данном регистре будут полностью удалены и заменены новым набором. Если передать Ложь, записи добавятся к существующим — это почти никогда не нужно для регистров, подчинённых регистратору, и приводит к задвоению движений.

Помните про признак активности: у записей, созданных вручную, поле Активность по умолчанию истинно при записи набора, но если вы читаете и перезаписываете существующий набор, проверьте, что активность не сброшена — неактивные записи не участвуют в итогах и отчётах.

bsl
НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
	Запись.Количество = Запись.Количество * 2;
КонецЦикла;
НаборЗаписей.Записать(Истина);

Способ 3. Перепроведение документа программно

Если логика проведения уже содержит нужный алгоритм (например, вы изменили обработчик в расширении и хотите применить его к существующим документам), достаточно перепровести документ. Для этого объект получают по ссылке и записывают в режиме проведения:

ДокументОбъект = ДокументСсылка.ПолучитьОбъект();

ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);

Режим проведения имеет значение: Оперативный доступен только для документов с оперативным проведением и текущей датой, для массовой обработки старых документов используйте Неоперативный. При отказе (например, контроль остатков не пройден) метод выбросит исключение — оборачивайте вызов в Попытка...Исключение и фиксируйте проблемные документы в журнале или таблице ошибок.

Для массового перепроведения за период в типовых конфигурациях есть штатные обработки («Групповое перепроведение документов», «Проведение по партиям» в ERP/УТ). Программно аналогичную задачу решают выборкой документов запросом с упорядочиванием по дате и циклом записи — порядок важен, чтобы последовательности и расчёты по партиям шли хронологически.

Порядок безопасного изменения движений
  1. 1
    Сделайте резервную копию базы или выполняйте работу на копии
  2. 2
    Определите, какой механизм подходит: обработчик проведения, запись набора или перепроведение
  3. 3
    Реализуйте изменение и протестируйте на одном документе
  4. 4
    Проверьте движения через отчёт по регистру и стандартные отчёты
  5. 5
    Только после проверки запускайте массовую обработку с логированием ошибок

Выбор способа под задачу

Единого «лучшего» способа нет — решение зависит от того, кто является источником истины для движений и как часто документ будет перепроводиться. Таблица ниже помогает сопоставить критерии.

КритерийОбработчик проведенияЗапись набора вручнуюПерепроведение
Устойчивость к перепроведениюПолнаяТеряется при перепроведенииНе меняет логику, только применяет
Транзакция с документомЕдинаяОтдельнаяЕдиная
Контроль остатков и проверкиШтатныеОтсутствуютШтатные
Типовой сценарийИзменение логики навсегдаЗагрузка из внешних системПрименение новой логики к старым данным
Маршрут решения

Как выбрать действие

Нужно навсегда изменить алгоритм формирования движенийМеняйте ОбработкаПроведения в модуле объекта или расширении
Движения приходят из внешней системы и документ не проводится штатноПишите набор записей с отбором по регистратору и Замещение = Истина
Логика уже исправлена, нужно обновить старые документыВыполните перепроведение в хронологическом порядке
Нужна разовая правка одной ошибкиИсправьте данные документа и перепроведите его, а не правьте регистр напрямую

Как проверить результат изменения движений

После любого вмешательства проверяйте не только сам набор записей, но и производные данные: итоги регистров, отчёты, взаиморасчёты. Быстрый способ увидеть движения конкретного документа — открыть его в режиме предприятия и использовать кнопку перехода к движениям (в типовых интерфейсах — «Ещё → Движения документа» или панель навигации).

Программно объём движений проверяют запросом к таблице регистра с отбором по регистратору. Полезно сравнить количество строк и суммы до и после изменения — расхождение покажет, что корректировка сработала. Для регистров накопления дополнительно сверьте остатки на дату документа в отчёте: ручная запись в обход проведения часто проявляется именно как «лишний» или «недостающий» остаток.

Контрольные точки

Как проверить результат

Движения документа в режиме предприятия
Норма

Строки соответствуют ожидаемому алгоритму, активность включена

Тревожный признак

Строк нет, они неактивны или задвоены

Остатки по регистру на дату документа
Норма

Остатки изменились ровно на сумму движений

Тревожный признак

Остатки не изменились или изменились вдвое

Повторное перепроведение документа
Норма

Движения воспроизводятся идентично

Тревожный признак

После перепроведения ручные правки исчезли

Отчёты и взаиморасчёты
Норма

Данные согласованы с движениями

Тревожный признак

Отчёт показывает суммы, отличные от регистра

Типичные ошибки и ограничения

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

Вторая группа ошибок — игнорирование транзакционности. Если вы пишете движения отдельно от записи документа и между этими операциями происходит сбой, база остаётся в несогласованном состоянии: документ проведён, а движения старые (или наоборот). Связанные изменения выполняйте в одной транзакции через НачатьТранзакцию() / ЗафиксироватьТранзакцию() с обработкой исключений.

Также учитывайте блокировки: массовое перепроведение в многопользовательской базе создаёт управляемые блокировки на регистрах и может вызывать конфликты с работой пользователей. Такие обработки запускайте в нерабочее время или в монопольном режиме на копии с последующей загрузкой.

Типичные ошибки
01
Запись набора без отбора по регистратору — очищается весь регистр
02
Записать(Ложь) для регистра с регистратором — движения задваиваются
03
Ручная правка регистра без изменения логики проведения — правки теряются при перепроведении
04
Перепроведение без Попытка/Исключение — обработка падает на первом проблемном документе
05
Игнорирование признака Активность — записи не попадают в итоги и отчёты

Часто задаваемые вопросы

Можно ли изменить движения документа, не перепроводя его?

Да, через запись набора записей регистра с отбором по регистратору. Но такие изменения не защищены: при следующем перепроведении документа платформа пересформирует движения по алгоритму проведения, и ручные правки исчезнут. Для постоянного эффекта меняйте логику в ОбработкаПроведения.

Почему после моей записи в регистр отчёт показывает старые данные?

Чаще всего у записей сброшен признак активности или запись выполнена с ошибкой отбора. Проверьте поле Активность в наборе записей и убедитесь, что период записей попадает в диапазон отчёта. Также убедитесь, что транзакция была зафиксирована.

Как удалить все движения документа программно?

Создайте набор записей нужного регистра, установите отбор по регистратору и вызовите Записать(Истина) без добавления строк — пустой набор с замещением удалит существующие движения. Альтернатива — записать документ в режиме ОтменаПроведения, что штатно очистит все его движения.

Чем отличается Записать(Истина) от Записать(Ложь) у набора записей?

Параметр определяет режим замещения. Истина — существующие записи регистратора удаляются и заменяются новым набором. Ложь — новые строки добавляются к уже существующим. Для регистров, подчинённых регистратору, вариант «Ложь» почти всегда ошибочен и приводит к дублям.

Как изменить движения в типовой конфигурации, не снимая её с поддержки?

Используйте расширение конфигурации: заимствуйте обработчик ОбработкаПроведения с аннотацией &После или &ИзменениеИКонтроль и добавьте свою логику корректировки движений. Типовой модуль при этом не изменяется, и обновления конфигурации проходят без ручного объединения кода.

Опасно ли массовое перепроведение документов?

Да, при неправильной организации: контроль остатков может отказать на части документов, обмены могут выгрузить промежуточные состояния, а блокировки — остановить работу пользователей. Выполняйте перепроведение на копии или в нерабочее время, в хронологическом порядке, с логированием отказов и обязательной резервной копией.

Итог

Что важно запомнить

Устойчивый способ изменить движения — правка логики в ОбработкаПроведения (в модуле или расширении). Ручная запись набора с отбором по регистратору подходит для интеграций, но не переживает перепроведение. Всегда устанавливайте отбор по регистратору, используйте замещение и проверяйте результат по движениям и остаткам.