При работе с платформой 1С:Предприятие 8.3 у разработчиков часто возникает задача провести документ программно, но при этом не сохранять сам документ в базе данных. Такая потребность может возникнуть, например, при проведении различных расчетов, тестировании логики проведения документов, формировании предварительных отчетов или анализе планируемых движений без "засорения" рабочей базы фиктивными документами. Прямого метода "провести без записи" в платформе не существует, поскольку проведение документа по своей сути неразрывно связано с его существованием в информационной базе. Однако, существуют обходные пути, которые позволяют достичь желаемого результата.
Мы рассмотрим два основных подхода к решению этой задачи: использование транзакций с последующим откатом и эмуляцию проведения документа через прямые вызовы внутренних модулей конфигурации. Каждый из этих подходов имеет свои особенности, преимущества и недостатки, которые мы детально проанализируем, проведя сравнение методов проведения «в уме».
Первый и наиболее очевидный способ для разработчиков, знакомых с основами работы с базами данных, — это программное получение движений документа через транзакцию. Этот подход позволяет временно записать документ и сформировать движения, получить к ним доступ, а затем полностью отменить все изменения, как будто их никогда и не было.
Давайте разберем этот процесс по шагам:
НачатьТранзакцию() глобального контекста.Записать() для нашей копии документа, указывая режим записи РежимЗаписиДокумента.Проведение. В этом случае система сначала запишет сам объект документа в базу данных, а затем выполнит его проведение, сформировав соответствующие движения по регистрам.Движения объекта документа. Например, для получения движений по регистру накопления "ОстаткиТоваров", мы можем обратиться к ДокументОбъектКопия.Движения.ОстаткиТоваров. Мы можем перебрать эти движения, проанализировать их, собрать необходимую информацию. В некоторых сценариях для детального исследования структуры полей может быть полезен Универсальный редактор данных (УРД) (поможет универсальный редактор данных (УРД) для 1С), позволяющий наглядно сопоставлять реквизиты и движения.ОтменитьТранзакцию(). Этот метод аннулирует все изменения, которые произошли в рамках текущей транзакции. В результате, ни сам документ, ни его движения не будут сохранены в базе данных permanently. Система "откатит" состояние базы до момента вызова НачатьТранзакцию().Попытка...Исключение...КонецПопытки. Это позволит корректно отловить возможные ошибки при проведении и в любом случае выполнить откат транзакции, чтобы не оставить базу в некорректном состоянии.Рассмотрим пример кода:
// Предположим, ДокументОбъект - это существующий или созданный документ "Реализация товаров и услуг"
// который мы хотим "провести" без постоянной записи.
// Создаем копии документа в памяти, чтобы не затрагивать оригинал, если он есть
ДокументОбъектКопия = ДокументОбъект.Скопировать();
// Заполняем необходимые реквизиты копии, если они не были заполнены или требуют корректировки
// ДокументОбъектКопия.Дата = ТекущаяДата();
// ДокументОбъектКопия.Организация = Ссылки.Организации.НашаОрганизация;
// ... и так далее, все реквизиты, необходимые для корректного проведения
НачатьТранзакцию();
Попытка
ДокументОбъектКопия.Записать(РежимЗаписиДокумента.Проведение); // Документ временно записывается и проводится
// *** Здесь мы получаем и обрабатываем движения ***
// Например, для регистра накопления "ОстаткиТоваров"
Для Каждого Движение Из ДокументОбъектКопия.Движения.ОстаткиТоваров Цикл
Сообщить("Движение по ОстаткамТоваров: " + Движение.Период + ", Номенклатура: " + Движение.Номенклатура + ", Количество: " + Движение.Количество + ", Вид движения: " + Строка(Движение.ВидДвижения));
// Можем сохранить эти движения в какую-либо временную коллекцию или обработать их
КонецЦикла;
// Аналогично для других регистров, например, бухгалтерии или взаиморасчетов
// Для Каждого Движение Из ДокументОбъектКопия.Движения.Хозрасчетный Цикл
// Сообщить("Движение по Хозрасчетному: " + Движение.СчетДт + " - " + Движение.СчетКт + ", Сумма: " + Движение.Сумма);
// КонецЦикла;
Исключение
Сообщить("Ошибка при проведении документа: " + ОписаниеОшибки());
// В случае ошибки, также необходимо откатить транзакцию
ОтменитьТранзакцию();
Возврат; // Выходим из процедуры, так как проведение завершилось ошибкой
КонецПопытки;
// После успешного получения движений, откатываем транзакцию.
// Это гарантирует, что ДокументОбъектКопия и его движения не будут сохранены в базе.
ОтменитьТранзакцию();
Сообщить("Движения успешно проанализированы, документ не записан.");
Преимущества этого метода:
Недостатки и важные нюансы:
Этот метод является более сложным, но он позволяет осуществить эмуляцию проведения в 1С 8.3 и получить движения документа *без какой-либо записи* в базу данных, даже временной. Он основан на понимании внутренней архитектуры конфигурации и прямом вызове функций, которые отвечают за формирование движений документов. При работе с типовыми решениями ускорить процесс разработки поможет анализ конфигураций на наличие ошибок в общих модулях, так как логика проведения часто выносится именно туда.
Мы рассмотрим шаги для реализации этого подхода:
СоздатьДокумент() менеджера документа.ОбработкаПроведения() в модуле объекта нужного документа. Часто эта процедура делегирует основную логику проведения в общие модули.ОбработкаПроведения() в модуле объекта документа и поставить в ней точку останова. Значительно упростить этот процесс и сократить время на постоянные перезапуски среды поможет помощник отладки (мини Vanessa) (удобно через помощник отладки кода в режиме Предприятия).Важно: Некоторые функции могут принимать не сам объект документа, а лишь его данные или ссылку. Параметры могут сильно отличаться в зависимости от конфигурации и ее версии. Иногда функция возвращает набор движений, иногда заполняет их через параметр, переданный по ссылке, или записывает их в свойство Движения переданного объекта.
ДвиженияДокумента, который можно создать специально для этой цели. Ключевой момент: мы не вызываем НовыйДокумент.Движения.Записать(). Мы просто используем объект, содержащий движения, для анализа в памяти.Рассмотрим пример кода, демонстрирующий этот подход:
// 1. Создаем новый объект документа в памяти
НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// 2. Максимально полно и корректно заполняем все реквизиты документа,
// которые влияют на логику проведения. Это критически важно!
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Организация = Ссылки.Организации.НашаОрганизация;
НовыйДокумент.Контрагент = Ссылки.Контрагенты.Покупатель;
НовыйДокумент.ДоговорКонтрагента = Ссылки.ДоговорыКонтрагентов.ДоговорСПокупателем;
НовыйДокумент.Склад = Ссылки.Склады.ОсновнойСклад;
НовыйДокумент.Валюта = Константы.ВалютаРегламентированногоУчета.Получить();
НовыйДокумент.Курс = 1;
НовыйДокумент.Комментарий = "Тестовое проведение без записи";
// Заполняем табличную часть "Товары"
СтрокаТабличнойЧасти = НовыйДокумент.Товары.Добавить();
СтрокаТабличнойЧасти.Номенклатура = Ссылки.Номенклатура.Товар1;
СтрокаТабличнойЧасти.Количество = 10;
СтрокаТабличнойЧасти.Цена = 100;
СтрокаТабличнойЧасти.Сумма = 1000;
СтрокаТабличнойЧасти = НовыйДокумент.Товары.Добавить();
СтрокаТабличнойЧасти.Номенклатура = Ссылки.Номенклатура.Товар2;
СтрокаТабличнойЧасти.Количество = 5;
СтрокаТабличнойЧасти.Цена = 50;
СтрокаТабличнойЧасти.Сумма = 250;
// Устанавливаем режим проведения (важно для некоторых конфигураций)
РежимПроведения = РежимПроведенияДокумента.Оперативный;
// Инициализируем флаг отказа
Отказ = Ложь;
Попытка
// 4. Вызываем внутреннюю экспортную функцию общего модуля,
// ответственную за формирование движений.
// Допустим, мы нашли функцию:
ОбщийМодульПроведенияДокумента.СформироватьДвиженияРеализации(НовыйДокумент, Отказ, РежимПроведения);
Если НЕ Отказ Тогда
Сообщить("Движения успешно сформированы (без записи документа):");
// 5. Анализируем сформированные движения
// Пример анализа движений по регистру накопления "ОстаткиТоваров"
Для Каждого Движение Из НовыйДокумент.Движения.ОстаткиТоваров Цикл
Сообщить(" Регистр ОстаткиТоваров: " + Движение.Период + ", Номенклатура: " + Движение.Номенклатура + ", Количество: " + Движение.Количество + ", Вид движения: " + Строка(Движение.ВидДвижения));
КонецЦикла;
// Пример анализа движений по регистру бухгалтерии "Хозрасчетный"
Для Каждого ДвижениеБух Из НовыйДокумент.Движения.Хозрасчетный Цикл
Сообщить(" Регистр Хозрасчетный: Дт " + ДвижениеБух.СчетДт + " Кт " + ДвижениеБух.СчетКт + ", Сумма: " + ДвижениеБух.Сумма);
КонецЦикла;
Иначе
Сообщить("Проведение документа завершилось отказом. Причина: " + НовыйДокумент.Комментарий);
КонецЕсли;
Исключение
Сообщить("Произошла ошибка при эмуляции проведения: " + ОписаниеОшибки());
КонецПопытки;
// Важно: НовыйДокумент.Движения.Записать() здесь не вызывается
Преимущества этого метода:
Недостатки и важные нюансы:
Выбор между двумя представленными методами зависит от конкретных требований вашей задачи. Рекомендуем предварительно изучить аналитический обзор двух подходов, чтобы оценить плюсы и минусы для вашей ситуации.
В любом случае, мы рекомендуем выполнять такие операции в тестовой или отладочной базе, а не в продуктивной, чтобы избежать непредвиденных последствий, особенно при использовании второго, более сложного подхода.