При программном создании документов (например, документа ПриходныйКассовыйОрдер на основании ПлатежноеПоручениеВходящее) разработчики часто сталкиваются с ситуацией, когда реквизит ДоговорКонтрагента не заполняется. Более того, при попытке интерактивного выбора договора в сформированном документе список оказывается пустым, а добавление или выбор договора приводит к ошибке «Индекс находится за пределами массива».
Рассмотрим подробно причины возникновения этой проблемы и разберем способы ее правильного решения в коде 1С.
Проанализируем, почему возникает расхождение между программным и интерактивным созданием документов в конфигурациях 1С:
ПриИзменении, ПриОткрытии), которые формируют списки допустимых видов договоров и устанавливают отборы. При вызове метода СоздатьДокумент() в коде контекст формы отсутствует, и обработчики формы не запускаются.ВидОперации. Если реквизит ВидОперации не заполнен или заполнен после выбора контрагента, внутренний массив видов договоров остается пустым. При попытке формы обратиться к первому элементу этого массива возникает ошибка обращения к несуществующему индексу.Организация, Контрагент, ВидОперации) должны быть заполнены strictly до присвоения значения реквизиту ДоговорКонтрагента. Если порядок нарушен, типовые механизмы очищают договор при последующей смене контрагента или вида операции.Разберем по шагам правильный порядок присвоения значений реквизитам создаваемого документа. Важно сначала задать организацию, вид операции и контрагента, и только затем подставлять договор:
НовыйДокумент = Документы.ПриходныйКассовыйОрдер.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
// 1. Устанавливаем организацию и вид операции
НовыйДокумент.Организация = Источник.Организация;
НовыйДокумент.ВидОперации = Перечисления.ВидыОперацийПКО.ОплатаПокупателя;
// 2. Устанавливаем контрагента
НовыйДокумент.Контрагент = Источник.Контрагент;
// 3. Только после этого задаем договор
НовыйДокумент.ДоговорКонтрагента = Источник.ДоговорКонтрагента;
Рассмотрим наиболее надежный способ создания документов на основании других объектов. Метод Заполнить() вызывает процедуру ОбработкаЗаполнения в модуле объекта нового документа. Это гарантирует правильное исполнение всей бизнес-логики конфигурации:
// Создаем новый документ и вызываем стандартное заполнение по основанию
НовыйДокумент = Документы.ПриходныйКассовыйОрдер.СоздатьДокумент();
НовыйДокумент.Заполнить(ДокументОснованиеСсылка);
// При необходимости дозаполняем или перезаписываем отдельные реквизиты
НовыйДокумент.Записать();
Если договор необходимо найти и подставить программно, проанализируем пример запроса, который выбирает подходящий договор с учетом владельца, организации и отсутствия пометки удаления:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов
|ГДЕ
| Владелец = &Контрагент
| И Организация = &Организация
| И Не ПометкаУдаления";
Запрос.УстановитьПараметр("Контрагент", НовыйДокумент.Контрагент);
Запрос.УстановитьПараметр("Организация", НовыйДокумент.Организация);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
НовыйДокумент.ДоговорКонтрагента = Выборка.Ссылка;
КонецЕсли;
Соблюдение правил инициализации реквизитов и использование встроенного метода Заполнить() позволяют избежать ошибок индексации массивов и обеспечивают корректное отображение договоров в форме документа.