Как в 1С 7.7 отменить проведение связанных документов перед проведением текущего документа?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

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

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

Почему возникает ошибка «Занят журнал документов»?

Проанализируем внутреннее поведение платформы 1С 7.7 при проведении:

  1. Монопольная транзакция и блокировка таблиц: В момент старта процедуры ОбработкаПроведения() платформа открывает неявную системную транзакцию и блокирует таблицы журнала документов (1CJOURN) и регистров. Любая попытка вызвать методы СделатьНеПроведенным(), Провести() или Записать() для другого документа из этого контекста блокируется ядром СУБД.
  2. Управление Точкой Актуальности (ТА): В компоненте «Оперативный учет» проведение документа задним числом или в реальном времени управляет положением ТА. Изменение состояния сторонних документов внутри чужой транзакции проведения нарушает монопольное управление последовательностью документов.

Вариант 1. Архитектурно правильное решение: закрытие остатков регистрами

Прежде чем вмешиваться в штатные механизмы проведения, выясним бизнес-логику задачи. Часто снятие заказа с проведения требуется для того, чтобы «освободить» зарезервированный товар. В типовых конфигурациях 1С 7.7 («Торговля и склад», «Комплексная конфигурация») снятие резерва реализуется не отменой проведения заказа, а регистрационными движениями расхода.

Рассмотрим, как это работает на уровне регистров:

  1. Документ-заказ при проведении делает приходное движение в регистр РезервыТМЦ.
  2. Документ отгрузки (Реализация) в процедуре ОбработкаПроведения() формирует расходное движение по регистру РезервыТМЦ с указанием документа-основания (заказа/счета), тем самым списывая резерв в ноль.
  3. При необходимости отмены резерва без отгрузки используется специализированный документ (например, «Снятие резерва» или «Отмена заявки»), который также формирует расходные движения по регистру.

Такой подход сохраняет целостность цепочки документов, не блокирует журнал и оставляет прозрачную историю взаиморасчетов и складских остатков.

Вариант 2. Выполнение логики в процедуре ПриЗаписи() формы документа

Если бизнес-процесс обязательно требует именно отмены проведения сторонних документов, вынесем эту операцию из процедуры проведения в событие модуля формы ПриЗаписи(), которое выполняется до открытия системной транзакции проведения.

Разберем пример реализации по шагам:


Процедура ПриЗаписи()
    // Проверяем заполненность основания без вызова ТекущийДокумент()
    Если ПустоеЗначение(ДокОснование) = 0 Тогда
        
        НачатьТранзакцию();
        Попытка
            ДокЗаказ = СоздатьОбъект("Документ");
            ДокЗаказ.ВыбратьПодчиненныеДокументы( , , ДокОснование);
            
            Пока ДокЗаказ.ПолучитьДокумент() = 1 Цикл
                Если ДокЗаказ.Вид() = "ЗаказНаСклад" Тогда
                    Если ДокЗаказ.Проведен() = 1 Тогда
                        // Снимаем с проведения найденный подчиненный заказ
                        ДокЗаказ.СделатьНеПроведенным();
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
            
            ЗафиксироватьТранзакцию();
        Исключение
            ОтменитьТранзакцию();
            Предупреждение("Не удалось отменить проведение заказов: " + ОписаниеОшибки());
            СтатусВозврата(0);
            Возврат;
        КонецПопытки;
        
    КонецЕсли;
КонецПроцедуры

Важные правила при реализации такого подхода:

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

Вариант 3. Переопределение действия кнопки «Провести»

По умолчанию кнопка диалога формы 1С 7.7 имеет формулу #Записать Провести. Мы можем заменить системное действие на вызов собственной процедуры, которая сначала выполнит все подготовительные действия со сторонними объектами базы данных, а затем инициирует штатную запись и проведение текущего документа.

Посмотрим на пример организации пользовательской процедуры проведения:


Процедура ПоКнопкеПровести()
    // 1. Выполняем предварительную обработку и распроведение
    Если ОбработатьСвязанныеДокументы() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // 2. Инициируем стандартное проведение
    ЗаписатьВФорме();
    Провести();
    Форма.Закрыть(0);
КонецПроцедуры

Вариант 4. Использование механизма «ложного закрытия» формы

В сложных сценариях, когда требуется полностью освободить контекст блокировок формы перед вызовом других диалогов или длительных обработок, применяется метод «ложного закрытия»:

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

Подводя итог: в 1С 7.7 наиболее стабильным и масштабируемым решением всегда является управление остатками через регистры внутри процедуры ОбработкаПроведения(). Если же распроведение сторонних документов неизбежно, выносите весь код в процедуру ПриЗаписи() модуля формы с обязательным контролем транзакций.

← На главную