Ситуация, когда документ в системе имеет статус «Не проведен», но при этом по нему существуют записи в регистрах (движения), является одной из самых неприятных проблем для разработчика и администратора 1С. Это прямое нарушение логической целостности базы данных. В рамках данной статьи мы подробно проанализируем, почему это происходит, как на это влияют транзакции и какие настройки конфигурации могут привести к подобному результату.
Рассмотрим ситуацию, когда программист создает цепочку документов внутри одной транзакционной конструкции. Часто возникает заблуждение, что вложенные транзакции работают независимо. На самом деле, в платформе 1С реализована модель, где все вложенные вызовы НачатьТранзакцию() лишь увеличивают счетчик транзакций. Реальная фиксация данных в базе происходит только при выполнении самого последнего (внешнего) метода ЗафиксироватьТранзакцию().
Проанализируем типичный пример кода, который может привести к ошибкам, если не предусмотреть обработку исключений:
НачатьТранзакцию();
Попытка
// Создание и проведение первого документа
Заказ = Документы.ЗаказПокупателя.СоздатьДокумент();
// ... заполнение реквизитов ...
Заказ.Записать(РежимЗаписиДокумента.Проведение);
// Создание и проведение второго документа на основании первого
Реализация = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// ... заполнение реквизитов ...
Реализация.Записать(РежимЗаписиДокумента.Проведение);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Произошла ошибка, транзакция отменена: " + ОписаниеОшибки());
КонецПопытки;
Если в этой цепочке произойдет сбой, метод ОтменитьТранзакцию() должен откатить все изменения. Однако, если программист допустил ошибку в логике (например, забыл вызвать отмену или использовал вложенную транзакцию некорректно), данные могут зафиксироваться частично. Выясним причину: если внутри ОбработкаПроведения была открыта своя транзакция, и она не была явно отменена при ошибке, система может оказаться в неопределенном состоянии.
Одной из наиболее частых причин «фантомных» проводок в старых конфигурациях (например, УТ 10.3 или УПП 1.3) является настройка свойства документа Удаление движений. Разберем два варианта работы этого механизма:
Если установлено значение «Не удалять автоматически», и в модуле объекта в процедуре ОбработкаПроведения или ПередЗаписью не прописан код очистки, старые движения останутся в базе. Рассмотрим, как это выглядит программно:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Если здесь нет кода Движения.ИмяРегистра.Очистить(),
// старые записи могут сохраниться, если документ перепроводится
// или если проведение прервалось с ошибкой, но транзакция не откатилась.
Для Каждого СтрокаТЧ Из Товары Цикл
Движение = Движения.ОстаткиТоваров.Добавить();
// ... заполнение движения ...
КонецЦикла;
КонецПроцедуры
Еще одна критическая ситуация — использование прямой записи в регистры. Платформа 1С позволяет записать движения по любому документу-регистратору, даже если он не проведен. Выясним, как это происходит: разработчик создает объект РегистрНакопленияНаборЗаписей, устанавливает отбор по ссылке документа и вызывает метод Записать().
Посмотрим на пример опасного кода:
НаборЗаписей = РегистрыНакопления.ОстаткиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаНепроведенныйДокумент);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = ТекущаяДата();
// ... заполнение остальных полей ...
НаборЗаписей.Записать(Истина); // Запись произойдет успешно!
В данном случае документу не важно, проведен он или нет. Платформа запишет данные в таблицу регистра, и мы получим документ с проводками, который в списке будет отображаться как «черновик».
Проанализируем ситуацию с обменом данными. Когда в коде устанавливается флаг ОбменДанными.Загрузка = Истина, платформа отключает практически все стандартные проверки, включая процедуру ОбработкаПроведения. Если из внешней системы (например, через Конвертацию данных) приходят наборы записей регистров, но сам объект документа загружается со статусом «не проведен», 1С запишет их именно в таком виде.
Это часто случается при частичной выгрузке объектов или при возникновении коллизий в распределенных информационных базах (РИБ). В режиме загрузки 1С доверяет входящим данным и не проверяет, соответствует ли состояние «шапки» документа наличию записей в «таблицах движений».
Современные конфигурации активно используют Подписки на события. Рассмотрим сценарий: существует подписка на событие ПриЗаписи документа. Внутри этой подписки разработчик реализовал логику формирования движений по дополнительным регистрам. Если основная транзакция проведения столкнется с ошибкой уже после того, как сработала подписка и данные были переданы в СУБД, может возникнуть рассинхронизация (особенно при использовании неверно настроенных попыток-исключений внутри подписок).
Для предотвращения появления непроведенных документов с движениями, рекомендуем придерживаться следующих правил:
Попытка...Исключение с обязательным вызовом ОтменитьТранзакцию() в блоке ошибки.Движения.RecordSet, если это можно сделать через стандартный механизм ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение).Соблюдение этих принципов позволит сохранить чистоту данных и избежать ошибок в управленческом и бухгалтерском учете.