Почему возникает ошибка Объект не найден при программном создании документа в 1С

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

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

Анализ проблемы: почему исчезает созданный документ

Типичный сценарий: при проведении или записи документа РеализацияТоваровУслуг требуется автоматически создать документ ПеремещениеТоваров, если на складе отгрузки не хватает остатка. Разработчик помещает создание и запись перемещения в процедуру ПередЗаписью модуля объекта реализации. Однако при попытке провести реализацию возникает ошибка нехватки остатка, а созданный документ перемещения бесследно исчезает.

Выясним причину такого поведения:

  1. Неявная системная транзакция: Любое событие записи объекта (включая ПередЗаписью, ПриЗаписи и ОбработкаПроведения модуля объекта) выполняется строго внутри неделимой системной транзакции.
  2. Откат транзакции (Rollback): Когда реализация не может провестись из-за контроля остатков, платформа устанавливает флаг Отказ = Истина. Это приводит к полному откату всей транзакции. Все данные, созданные, измененные и записанные внутри этого блока (в том числе новый документ перемещения), физически удаляются из таблиц СУБД.
  3. Природа битой ссылки: При вызове метода Записать() платформа генерирует для нового объекта уникальный идентификатор (GUID). Если транзакция откатилась, запись из базы стирается, но ссылка с этим идентификатором в памяти (или в открытой экранной форме) остается. Попытка прочитать такой объект и выдает <Объект не найден>.
  4. Интерактивные методы в транзакции: Вызовы открытия форм (например, ПолучитьФорму().Открыть()) в модуле объекта категорически недопустимы. Во время ожидания действий пользователя открытая транзакция держит исключительные блокировки таблиц базы данных, что блокирует параллельную работу пользователей и приводит к взаимоблокировкам (deadlocks).

Ошибки в типовом программном коде создания объекта

Посмотрим на пример избыточного кода, который часто пишут начинающие разработчики:


НовыйДокумент = Документы.ПеремещениеТоваров.СоздатьДокумент();
НовыйДокумент.Дата = ЭтотОбъект.Дата - 1;
НовыйДокумент.Записать(); // Лишняя предварительная запись

// Затем ссылка передается в процедуру, где снова берется объект:
ДокументПеремещения = СсылкаНаДокументПеремещения.ПолучитьОбъект();

Метод СоздатьДокумент() сразу возвращает готовый экземпляр ДокументОбъект. Нет никакой необходимости записывать пустой документ ради ссылки, а затем повторно считывать его через ПолучитьОбъект(). Заполнять реквизиты и табличные части следует сразу в созданном объекте перед его единственной записью.

Если же новому перемещению требуется передать ссылку на документ-основание, который сам еще не записан в базу, используем метод УстановитьСсылкуНового():


СсылкаНаРеализацию = Документы.РеализацияТоваровУслуг.ПолучитьСсылку();
ЭтотОбъект.УстановитьСсылкуНового(СсылкаНаРеализацию);
ДокументПеремещения.ДокументОснование = СсылкаНаРеализацию;

Способ 1. Перенос логики в модуль формы (разделение транзакций)

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

Перенесем обработку в событие ПередЗаписью модуля формы документа:


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

На сервере формируем и сразу проводим документ ПеремещениеТоваров:


&НаСервере
Функция СоздатьИПровестиПеремещениеНаСервере(ТаблицаПеремещений)
    
    ДокументПеремещения = Документы.ПеремещениеТоваров.СоздатьДокумент();
    ДокументПеремещения.Дата = Объект.Дата - 1;
    ДокументПеремещения.Организация = Объект.Организация;
    ДокументПеремещения.СкладПолучатель = Объект.Склад;
    ДокументПеремещения.СкладОтправитель = ПолучитьСкладОтправитель();
    ДокументПеремещения.ОтражатьВУправленческомУчете = Истина;
    ДокументПеремещения.Ответственный = ПараметрыСеанса.ТекущийПользователь;
    
    Для Каждого Стр Из ТаблицаПеремещений Цикл
        НоваяСтрока = ДокументПеремещения.Товары.Добавить();
        НоваяСтрока.Номенклатура = Стр.Товар;
        НоваяСтрока.Количество = Стр.КоличествоДляПеремещения;
        НоваяСтрока.ЕдиницаИзмерения = Стр.Товар.ЕдиницаХраненияОстатков;
        НоваяСтрока.Коэффициент = 1;
    КонецЦикла;
    
    Попытка
        ДокументПеремещения.Записать(РежимЗаписиДокумента.Проведение);
        Возврат ДокументПеремещения.Ссылка;
    Исключение
        Сообщить(ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

При таком подходе перемещение фиксируется в СУБД в своей собственной транзакции. Затем стартует проведение реализации, остаток на складе уже присутствует, и реализация проводится без ошибок.

Способ 2. Выделенная команда оформления документов

Если бизнес-процесс требует контроля со стороны менеджера, автоматическое создание документов в событиях записи лучше заменить на явное действие пользователя:

  1. Добавляем на форму реализации кнопку (например, Оформить перемещение и провести).
  2. По нажатию кнопки алгоритм рассчитывает потребность, формирует документ ПеремещениеТоваров и открывает его пользователю для проверки либо сразу проводит.
  3. После успешного проведения перемещения выполняется проведение текущего документа реализации.

Способ 3. Использование цепочки через Заказ покупателя

Рассмотрим типовой методологический подход конфигураций 1С (УТ, КА, ERP):

  1. Менеджер оформляет документ Заказ покупателя (или Заказ клиента).
  2. На основании заказа оформляется документ Перемещение товаров со статусом к обеспечению или отгрузке.
  3. После фактического перемещения товаров на склад отгрузки оформляется документ Реализация товаров и услуг.

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

← На главную