В практике разработки на платформе 1С:Предприятие 8 часто возникает загадочная на первый взгляд ситуация: документ успешно переносится через обмен данными или создается программно, получает статус «Проведен» (зеленая галочка в списке), но при этом не формирует абсолютно никаких движений по регистрам накопления или сведений. При этом, если зайти в этот же документ интерактивно под учетной записью пользователя и нажать кнопку «Провести», все движения мгновенно и без ошибок появляются в базе данных.
Давайте подробно разберем, почему программное проведение через метод Записать(РежимЗаписиДокумента.Проведение) может игнорировать формирование движений, и как решить эту проблему раз и навсегда.
Это самая распространенная причина при реализации обменов между базами данных. Когда документ переносится из другой информационной базы с помощью планов обмена, XML-выгрузки или веб-сервисов, платформа автоматически устанавливает для загружаемого объекта признак загрузки данных:
ДокументОбъект.ОбменДанными.Загрузка = Истина;
В режиме ОбменДанными.Загрузка = Истина платформа 1С считает, что данные приходят из доверенного источника (где они уже были проверены и проведены корректно). Чтобы ускорить процесс загрузки и избежать циклических блокировок, платформа полностью блокирует выполнение стандартных обработчиков событий, включая предопределенную процедуру ОбработкаПроведения в модуле объекта. Документ записывается в базу данных «как есть» — с флагом проведенного, но физические таблицы регистров остаются пустыми.
Если после завершения обмена ваше регламентное задание или обработка пытается программно перепровести этот документ, но при этом объект считывается заново или флаг загрузки не сбрасывается, вызов метода проведения пройдет успешно, но движения снова не запишутся.
Решение проблемы: перед программным проведением документа в коде загрузки или регламентного задания необходимо явным образом отключать режим загрузки данных.
Рассмотрим пример правильного программного проведения объекта после его загрузки:
ДокументСсылка = Документы.НашДоработанныйДокумент.НайтиПоРеквизиту("УникальныйИдентификаторИсточника", ИД);
Если Не ДокументСсылка.Пустая() Тогда
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
// Обязательно сбрасываем флаг загрузки перед проведением
ДокументОбъект.ОбменДанными.Загрузка = Ложь;
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Исключение
ЗаписьЖурналаРегистрации("ОбменДанными.ОшибкаПроведения",
УровеньЖурналаРегистрации.Ошибка,
ДокументОбъект.Метаданные(),
ДокументОбъект.Ссылка,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЕсли;
Проанализируем архитектурную ошибку, которую часто совершают начинающие разработчики при доработке конфигураций. Если алгоритм заполнения движений или важные расчеты были прописаны в модуле формы документа (например, в обработчиках нажатия кнопок проведения или в процедуре формы ПослеЗаписиНаСервере), то при программном вызове этот код просто не запустится.
Когда вы вызываете Записать(РежимЗаписиДокумента.Проведение) на сервере без участия интерфейса, платформа работает исключительно с объектом базы данных. Форма документа при этом не создается, а значит, весь код модуля формы полностью игнорируется.
Решение проблемы: весь код, отвечающий за формирование движений по регистрам, проверку остатков и расчет сумм, должен располагаться исключительно внутри предопределенного обработчика ОбработкаПроведения в модуле объекта документа.
Еще одна неочевидная деталь кроется в настройках метаданных самого документа в конфигураторе. Откроем конфигуратор, найдем наш документ и перейдем на вкладку «Движения». Обратим внимание на свойство «Запись движений при проведении». Оно может принимать два значения:
Истина.При интерактивном проведении формы стандартные механизмы платформы или БСП могут автоматически инициализировать флаги записи регистров. Но при программном вызове, если у вас установлено свойство «Записывать выбранные», незаполненные свойства записи приведут к тому, что движения не сохранятся.
Решение проблемы: проанализируем код процедуры ОбработкаПроведения и убедимся, что для каждого используемого регистра перед формированием записей явно взводится флаг записи:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Обязательно взводим флаг записи для регистров
Движения.НашРегистрНакопления.Записывать = Истина;
// Алгоритм заполнения движений
НоваяСтрока = Движения.НашРегистрНакопления.Добавить();
НоваяСтрока.Период = Дата;
НоваяСтрока.Организация = Организация;
// ... заполнение остальных измерений и ресурсов
КонецПроцедуры
Если программное проведение выполняется в контексте регламентного (фонового) задания, оно запускается под определенным системным пользователем или без авторизации конкретного физического лица. В системе может быть настроен механизм RLS (Record Level Security — ограничение доступа на уровне записей).
Если у пользователя, под которым выполняется регламентное задание, нет прав на чтение связанных справочников, остатков по регистрам или других аналитик, запросы в вашей процедуре ОбработкаПроведения вернут пустой результат (например, запрос по остаткам товаров выдаст 0). Программа отработает без ошибок, не заполнит таблицу движений из-за «отсутствия» остатков и запишет пустой проведенный документ.
Решение проблемы: временно переведем выполнение алгоритма проведения в привилегированный режим, чтобы обойти ограничения прав доступа при выполнении фоновых процессов регламентного задания:
УстановитьПривилегированныйРежим(Истина);
// Выполняем программное проведение документа
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
УстановитьПривилегированныйРежим(Ложь);
Иногда разработчики добавляют в модуль объекта вызовы функций, которые прямо или косвенно зависят от клиентского контекста (например, обращение к параметрам сеанса, инициализируемым только в тонком клиенте, или попытки вызова диалоговых окон). При работе регламентного задания на сервере такие вызовы могут вызывать неявные исключения (ошибки), которые перехватываются внутренними защитными блоками транзакции 1С, аварийно прекращая работу обработчика проведения еще до момента записи движений.
Решение проблемы: тщательно проанализируем модуль объекта на наличие директив компиляции и вызовов функций, недоступных на чистом сервере или в контексте фонового задания.