Почему при программном проведении документа в 1С данные не попадают в регистр сведений?

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

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

Анализ первой причины: Логическая ошибка в цикле обработки

Рассмотрим фрагмент кода, который вызвал затруднения у автора темы. В процедуре ОбработкаПроведения была допущена критическая ошибка в структуре цикла. Проанализируем этот участок:


ВыборкаДетальныеЗаписи = Запрос.Выполнить().Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    // Вставить обработку выборки ВыборкаДетальныеЗаписи
КонецЦикла;

Если ВыборкаДетальныеЗаписи.Month = 1 Тогда
    Движение = Движения.RegistrCopySpending.Добавить();
    // ... заполнение реквизитов
Иначе
    // ...
КонецЕсли;

В данном примере мы видим классическую ошибку «пустого цикла». Программа обходит все записи выборки запроса внутри конструкции Пока ... КонецЦикла, ничего не делая. После завершения цикла указатель выборки встает в конечное положение. Попытка обратиться к ВыборкаДетальныеЗаписи.Month за пределами цикла либо приведет к ошибке, либо вернет данные только последней итерации (если выборка вообще была успешной). Чтобы движения записывались для всех данных из запроса, блок формирования записей регистра должен находиться внутри цикла.

Анализ второй причины: Запросы к «самому себе» внутри транзакции

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

Когда мы вызываем метод Записать(РежимЗаписиДокумента.Проведение), платформа открывает транзакцию базы данных. В этот момент измененные реквизиты объекта (например, признак Copy = Истина) уже находятся в оперативной памяти сервера, но еще не зафиксированы физически в таблицах базы данных. Запрос, выполняемый в ОбработкаПроведения, обращается именно к таблицам БД. В итоге запрос «видит» старое состояние документа, которое было до начала записи. Если ваша логика проведения зависит от условий в запросе (например, Где ПометкаУдаления = Ложь И Copy = Ложь), то при программном изменении Copy на Истина запрос может просто не выбрать текущий документ, и движения не создадутся.

Решение: Для формирования движений в процедуре ОбработкаПроведения следует обращаться к реквизитам документа напрямую через свойства ЭтотОбъект (или просто по именам реквизитов), не прибегая к запросам к таблице этого же документа.

Правильная реализация формирования движений

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // Очищаем старые движения, если это необходимо
    Движения.RegistrCopySpending.Записывать = Истина;
    Движения.RegistrCopySpending.Очистить();
    
    // Вместо сложного запроса к БД используем данные самого объекта
    Если ЭтотОбъект.Month = 1 Тогда 
        НовоеДвижение = Движения.RegistrCopySpending.Добавить();
        НовоеДвижение.Период = ЭтотОбъект.Дата;
        НовоеДвижение.Registrator = ЭтотОбъект.Ссылка;
        НовоеДвижение.Copy = ЭтотОбъект.Copy;
        // Заполнение остальных измерений и ресурсов
    КонецЕсли;

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

Обратите внимание на строку Движения.RegistrCopySpending.Записывать = Истина;. Это критически важный флаг. Если его не установить, платформа может «решить», что набор записей не изменился, и не сбросит данные в базу данных при завершении транзакции проведения.

Архитектурное решение: Регламентные задания

Как справедливо было замечено в обсуждении, выполнение операций копирования и массового перепроведения документов в общем модуле «на лету» — не самый надежный метод. Если бизнес-логика требует повторять Документ.РасходДенег каждого 1-го числа месяца, лучшим решением будет использование механизма РегламентныеЗадания.

Рассмотрим преимущества этого подхода:

  1. Автономность: Процесс запускается сервером автоматически в фоновом режиме (например, в 00:00:01 каждого дня), не требуя действий пользователя.
  2. Стабильность: Ошибки при создании одного документа не заблокируют работу пользователя в другом документе.
  3. Производительность: Массовые операции выполняются на стороне сервера, минимизируя нагрузку на клиентские рабочие места.

Пример логики для регламентного задания в общем модуле:


Процедура ВыполнитьКопированиеРасходов() Экспорт
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    РасходДенег.Ссылка КАК Ссылка
    |ИЗ
    |    Документ.РасходДенег КАК РасходДенег
    |ГДЕ
    |    РасходДенег.Copy = ЛОЖЬ
    |    И РасходДенег.Проведен = ИСТИНА";
    
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        
        СтарыйОбъект = Выборка.Ссылка.ПолучитьОбъект();
        
        // Создаем копию
        НовыйДокумент = СтарыйОбъект.Скопировать();
        НовыйДокумент.Дата = ТекущаяДата();
        НовыйДокумент.Copy = Ложь; // Новый документ сам станет источником для копии позже
        
        Попытка
            НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);
            
            // Помечаем старый документ, что с него копия уже снята
            СтарыйОбъект.Copy = Истина;
            СтарыйОбъект.Записать(РежимЗаписиДокумента.Запись); // Просто записываем признак
        Исключение
            ЗаписьЖурналаРегистрации("Ошибка копирования", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
        КонецПопытки;
        
    КонецЦикла;
    
КонецПроцедуры

Важные нюансы при программном проведении

Проанализируем еще несколько моментов, которые могут мешать записи данных в регистры:

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

← На главную