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