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