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