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