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

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

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

Механизм транзакций и миф о «вложенности»

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

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


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

    // Создание и проведение второго документа на основании первого
    Реализация = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
    // ... заполнение реквизитов ...
    Реализация.Записать(РежимЗаписиДокумента.Проведение);

    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    Сообщить("Произошла ошибка, транзакция отменена: " + ОписаниеОшибки());
КонецПопытки;

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

Влияние свойства «Удаление движений»

Одной из наиболее частых причин «фантомных» проводок в старых конфигурациях (например, УТ 10.3 или УПП 1.3) является настройка свойства документа Удаление движений. Разберем два варианта работы этого механизма:

  1. Удалять автоматически: Платформа сама очищает движения перед началом проведения или при отмене проведения.
  2. Не удалять автоматически: В этом режиме ответственность за очистку регистров полностью ложится на плечи программиста.

Если установлено значение «Не удалять автоматически», и в модуле объекта в процедуре ОбработкаПроведения или ПередЗаписью не прописан код очистки, старые движения останутся в базе. Рассмотрим, как это выглядит программно:


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

Прямая запись в набор записей (RecordSet)

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

Посмотрим на пример опасного кода:


НаборЗаписей = РегистрыНакопления.ОстаткиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаНепроведенныйДокумент);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = ТекущаяДата();
// ... заполнение остальных полей ...
НаборЗаписей.Записать(Истина); // Запись произойдет успешно!

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

Режим обмена данными (ОбменДанными.Загрузка)

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

Это часто случается при частичной выгрузке объектов или при возникновении коллизий в распределенных информационных базах (РИБ). В режиме загрузки 1С доверяет входящим данным и не проверяет, соответствует ли состояние «шапки» документа наличию записей в «таблицах движений».

Ошибки в подписках на события

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

Итоги и рекомендации

Для предотвращения появления непроведенных документов с движениями, рекомендуем придерживаться следующих правил:

  1. Контроль транзакций: Всегда оборачивайте цепочки создания документов в блок Попытка...Исключение с обязательным вызовом ОтменитьТранзакцию() в блоке ошибки.
  2. Настройка AutoDelete: В новых разработках старайтесь использовать режим «Удалять автоматически». Если же вы работаете с наследованным кодом, убедитесь, что в модулях реализована корректная очистка коллекций Движения.
  3. Валидация при обмене: При написании правил обмена следите за тем, чтобы статус документа (Проведен/Не проведен) всегда синхронизировался вместе с его движениями.
  4. Использование стандартных методов: Избегайте прямой записи в RecordSet, если это можно сделать через стандартный механизм ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение).

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

← На главную