Как программно провести документ по одному регистру накопления, не затрагивая другие записи

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Основная концепция: работа с набором записей

В 1С документ является регистратором для наборов записей различных регистров. Чтобы изменить движения, нам не обязательно открывать сам документ как объект. Мы можем работать напрямую с объектом НаборЗаписей конкретного регистра. Проанализируем, почему этот метод является наиболее быстрым и безопасным.

Когда мы работаем через НаборЗаписей, система не выполняет код модуля документа. Она лишь открывает транзакцию на запись в конкретную таблицу базы данных. Это позволяет избежать блокировок по другим таблицам и исключить выполнение лишних вычислений. Для интерактивного изменения таких записей без написания кода можно использовать обработку для редактирования движений документа.

Пошаговый алгоритм реализации точечного проведения

Рассмотрим по шагам, как реализовать программное обновление движений для конкретного документа и регистра.

Шаг 1. Создание набора записей и установка отбора.
Для начала необходимо создать объект набора записей регистра и ограничить его только данными нашего документа-регистратора. Рассмотрим пример кода:


// Создаем набор записей для нужного регистра
Набор = РегистрыНакопления.ИмяВашегоРегистра.СоздатьНаборЗаписей();

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

Шаг 2. Формирование новых данных.
Здесь у нас есть два пути: либо полностью очистить движения (вызвав метод Записать() у пустого набора), либо заполнить его новыми данными. Для формирования новых записей проанализируем данные документа. Чтобы не тратить время на чтение всего объекта, рекомендуется использовать запрос к табличным частям документа.


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

Шаг 3. Запись набора с оптимизацией.
Для максимального ускорения процесса и обхода лишних проверок (например, подписок на события), используем свойство ОбменДанными.Загрузка.


Набор.ОбменДанными.Загрузка = Истина;
Набор.Записать(Истина); // Параметр Истина означает замещение существующих записей

Методы вынесения логики для повторного использования

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

  1. Экспортная процедура в модуле менеджера регистра. Вынесем логику подготовки таблицы движений в модуль менеджера соответствующего регистра. Это позволит вызывать ее как из модуля документа, так и из любой внешней обработки.
  2. Процедура в модуле объекта документа. Если логика сильно завязана на реквизиты документа, создадим экспортную процедуру СформироватьДвиженияПоРегиструХ() в модуле самого документа. Тогда из обработки нам достаточно будет получить объект и вызвать эту процедуру, после чего записать только конкретную коллекцию из свойства Движения.

Посмотрим на пример вызова через объект документа:


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

Оптимизация производительности при массовой обработке

Выясним, как ускорить процесс, если нам нужно перепровести тысячи документов по одному регистру. Основная нагрузка при записи наборов идет на транзакции СУБД. Чтобы минимизировать издержки, воспользуемся следующими правилами:

  1. Пакетная запись в одной транзакции. Объединяйте обработку нескольких документов (например, по 100-500 штук) в одну явную транзакцию с помощью операторов НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Это сократит количество обращений к диску.
  2. Использование запросов вместо объектов. Как уже упоминалось, Ссылка.ПолучитьОбъект() — тяжелая операция. Если структура движений позволяет, соберите данные по всем нужным документам одним большим запросом, а затем в цикле создавайте и записывайте наборы записей.
  3. Отключение итогов. Если объем данных огромен, в некоторых случаях (в монопольном режиме) можно временно отключить использование итогов для регистра, записать все данные и включить итоги обратно. Это значительно быстрее, чем пересчитывать итоги при каждой записи набора.

Важные предостережения и риски

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

Риск 1: Рассинхронизация данных.
В типовых конфигурациях многие регистры взаимосвязаны. Например, "Продажи" и "НДС Продажи". Если вы обновите один и не тронете другой, отчеты могут начать показывать противоречивые данные. Всегда проверяйте, не является ли исправляемый регистр базой для расчетов в других подсистемах.

Риск 2: Флаги актуальности.
В конфигурациях на обычных формах (УТ 10.3) часто используются реквизиты вроде Проведен или специфические флаги в дополнительных свойствах. Программная запись набора записей не меняет статус документа. Если пользователь позже вручную перепроведет документ из формы, ваши программно внесенные правки будут затерты стандартным алгоритмом проведения.

Риск 3: Блокировки.
Даже при записи одного регистра 1С накладывает блокировки. Если во время вашей обработки пользователи будут пытаться проводить те же документы штатными средствами, могут возникнуть конфликты блокировок (Deadlock). Рекомендуется выполнять такие операции в периоды минимальной активности пользователей.

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

← На главную