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

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

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

Анализ исходного кода проведения

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Отказ = СуммыППиПОСовпадают(); // Проверка логики
    ДатаПроведения = ТекущаяДатаСеанса();
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
                   |    ПланФинансированияРасходыПоПлатежам.ФКР,
                   |    ПланФинансированияРасходыПоПлатежам.ЭКР,
                   |    СУММА(ПланФинансированияРасходыПоПлатежам.Январь) КАК Январь,
                   |    ...
                   |ИЗ
                   |    Документ.ИзмененияПланаФинансированияПоРасходам.ТЧРасходыПоПлатежам КАК ПланФинансированияРасходыПоПлатежам
                   |ГДЕ
                   |    ПланФинансированияРасходыПоПлатежам.Ссылка = &Ссылка
                   |    И ПланФинансированияРасходыПоПлатежам.Январь + ... + ПланФинансированияРасходыПоПлатежам.Декабрь <> 0";
                   
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    ВыборкаПоПлатежам = Запрос.Выполнить().Выбрать();
    
    Движения.ПланПоБюджетуФинансированияПоПлатежам.Записывать = Истина;
    
    Пока ВыборкаПоПлатежам.Следующий() Цикл
        // Формирование движений
        Движение = Движения.ПланПоБюджетуФинансированияПоПлатежам.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
        // ... заполнение остальных полей
    КонецЦикла;
КонецПроцедуры

Причина 1: Фильтрация нулевых значений и логика запроса

Проанализируем условие ГДЕ в тексте запроса. Программист добавил проверку, чтобы строки с нулевой суммой за все месяцы не попадали в регистр: ПланФинансированияРасходыПоПлатежам.Январь + ... + ПланФинансированияРасходыПоПлатежам.Декабрь <> 0.

В чем заключается ловушка: При копировании документа пользователь может изменить только часть данных или оставить некоторые поля пустыми. Если в результате копирования или программной обработки в полях сумм оказывается значение NULL (что возможно при сложных соединениях или некорректном программном создании объекта), то результат математического сложения с NULL всегда будет NULL. В языке запросов 1С условие NULL <> 0 не является истинным, и такая строка будет проигнорирована запросом.

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

Причина 2: Обращение к данным в базе данных (Ссылка)

Это самая критичная архитектурная особенность проведения в 1С. Рассмотрим строку Запрос.УстановитьПараметр("Ссылка", Ссылка);. В этот момент запрос обращается к физической таблице на SQL-сервере: Документ.ИзмененияПланаФинансированияПоРасходам.ТЧРасходыПоПлатежам.

Разберем ситуацию по шагам:

  1. Пользователь нажимает «Скопировать». Создается новый объект в памяти.
  2. Пользователь нажимает «Провести».
  3. Запускается транзакция проведения.
  4. Выполняется запрос к базе данных по Ссылке.

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

Рекомендуемое решение через передачу Табличной Части

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


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

Причина 3: Нюансы функции «ПриКопировании»

Выясним причину, связанную с предопределенными процедурами. В модуле объекта может существовать процедура ПриКопировании(ОбъектКопирования). Часто разработчики очищают в ней ключевые реквизиты, чтобы они не дублировались (например, дату, номер или специфические статусы). Если в этой процедуре случайно очищается реквизит, участвующий в связи параметров или измерениях регистров (например, Организация или ФКР), то запрос в ОбработкаПроведения также не найдет нужных соответствий.

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

Причина 4: Использование внешних функций без контроля «Отказ»

В тексте сообщения 2 мы видим строку: Отказ = СуммыППиПОСовпадают();. Рассмотрим подробнее, что здесь происходит. Это функция, которая, скорее всего, проверяет равенство сумм по платежам и обязательствам. Если в скопированном документе из-за особенностей округления или неполного переноса данных суммы не совпали хотя бы на копейку, функция вернет Истина в переменную Отказ.

В 1С, если в процедуре проведения Отказ = Истина, система прерывает транзакцию. Однако, если внутри функции СуммыППиПОСовпадают() не прописан вывод сообщения пользователю (Сообщить()), то внешне это выглядит так: вы нажали «Провести», форма закрылась или осталась открытой, но записи в регистрах не появились. Всегда проверяйте возвращаемые значения подобных проверок.

Резюме и советы по исправлению

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

  1. Проверьте запрос в отладчике: Убедитесь, что Выборка.Следующий() возвращает Истина. Если выборка пуста — проблема в условиях ГДЕ или в том, что данные еще не записаны в БД.
  2. Очистите условия от фильтров: Временно уберите проверку на <> 0. Если движения появились — значит, логика суммирования в запросе некорректна для скопированных данных.
  3. Используйте ЕСТЬNULL: В запросах всегда оборачивайте числовые поля в функцию ЕСТЬNULL(Поле, 0), особенно при сложении нескольких колонок.
  4. Проверьте режим записи: Если вы используете запросы к таблицам БД, убедитесь, что документ физически существует в базе с актуальными данными ТЧ перед началом формирования движений.

Соблюдение этих правил позволит сделать механизм проведения надежным и независимым от способа создания документа в системе.

← На главную