Почему движения созданного программно документа появляются после движений документа-инициатора и как это исправить

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

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

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

Причины поведения платформы и хронология движений

Проанализируем, почему возникает смещение движений на оси времени:

  1. Оперативный режим проведения подчиненного документа: Если программно вызван метод Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Оперативный), платформа присваивает создаваемому документу текущую оперативную отметку времени. Она чаще всего оказывается строго больше даты и времени документа-инициатора, проводимого неоперативно.
  2. Порядок записи движений в транзакции: Вызов программного проведения дочернего документа выполняется в рамках той же транзакции записи. Однако если документ-инициатор получает оперативную отметку времени до совершения подчинённых действий, его движения в регистре формируются на момент этой отметки, что и приводит к нарушению хронологического порядка «сначала приход, потом расход».
  3. Запрос остатков на момент времени: В неоперативном режиме при выполнении запроса остатков с передачей параметра МоментВремени() виртуальная таблица считывает состояние регистра до момента проведения текущего документа. Чтобы учесть движения, записанные в той же транзакции с аналогичной датой, требуется явное переформирование границы времени.

Решение 1. Явная корректировка времени и неоперативное проведение

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

Рассмотрим пошаговый алгоритм решения:

  1. Устанавливаем дату создаваемого документа Перемещение на 1 секунду раньше даты основного документа (Дата - 1).
  2. Записываем и проводим документ неоперативно.
  3. Повторно запрашиваем остатки с учетом новой точки времени или обновленных данных.

Пример программного создания и проведения документа перемещения:


// Внутри процедуры ОбработкаПроведения расходного документа
ДокПеремещение = Документы.ПеремещениеТоваров.СоздатьДокумент();
ДокПеремещение.Дата = Дата - 1; // Сдвигаем время на 1 секунду назад
ДокПеремещение.СкладОтправитель = СкладЗакупок;
ДокПеремещение.СкладПолучатель = СкладПродаж;

// Заполнение табличной части необходимым количеством
СтрТаб = ДокПеремещение.Товары.Добавить();
СтрТаб.Номенклатура = ТекущаяНоменклатура;
СтрТаб.Количество = НеобходимоеКоличество;

ДокПеремещение.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);

За счет сдвига даты на Дата - 1 движения перемещения попадут на ось времени раньше движений расходной накладной, и расчет себестоимости и остатков пройдет корректно.

Решение 2. Архитектурно правильный подход (формирование до проведения)

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

Рассмотрим правильную организацию бизнес-логики:

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

НачнитеТранзакцию();

Попытка
    // 1. Создаем и проводим необходимые перемещения
    СоздатьИПровестиПеремещения();
    
    // 2. Проводим основной документ
    ЭтотОбъект.Записать(РежимЗаписиДокумента.Проведение);
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

Решение 3. Использование новой методики проведения

Разберем вариант с применением новой методики проведения, которая предотвращает лишние запросы к остаткам до записи движений:

  1. Документ сразу формирует свои движения по списанию со склада и записывает их в регистр без предварительной проверки.
  2. Выполняется запрос к виртуальной таблице остатков регистра с фильтром по отрицательным значениям.
  3. Если обнаружены отрицательные остатки, рассчитывается объем дефицита. В зависимости от задачи либо создаются недостающие приходные документы, либо транзакция отменяется с выводом понятного сообщения пользователю.

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

← На главную