Как сформировать поступление из другого документа в управляемых формах 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При переходе на управляемые формы разработчики нередко сталкиваются с ситуацией, когда код создания подчиненного документа или документа-основания написан, кнопка на форму выведена, но при нажатии ничего не происходит — новый документ не появляется в списке. Разберем типичные ошибки реализации клиент-серверной архитектуры в управляемом интерфейсе 1С, выясним причину сбоя и рассмотрим корректные способы программного создания документов.

Анализ типовой ошибки при вызове команды формы

Рассмотрим фрагмент кода, с которого часто начинаются подобные проблемы:


&НаСервере
Процедура СформироватьПоступление(Команда)
    Если Не ЗначениеЗаполнено(Объект.Поступление) Тогда
        Док = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
    Иначе
        Док = Объект.Поступление.ПолучитьОбъект();
        Док.Товары.Очистить();
        Док.Услуги.Очистить();
    КонецЕсли;
    
    Док.Дата = Объект.Дата;
    Док.Организация = Объект.Организация;
    // Заполнение остальных реквизитов...

    Попытка
        Док.Комментарий = "Заполнен на основании " + Объект.Ссылка;
        Док.Записать();
        Поступление = Док.Ссылка;
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;
    Сообщить("Создано: " + Объект.Поступление);
    Док.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры

Проанализируем, почему этот код не отрабатывает при нажатии на кнопку:

  1. Неправильная директива компиляции у обработчика команды: Команды пользовательского интерфейса в управляемых формах должны начинать свое выполнение строго в контексте клиента. Если назначить процедуру с директивой &НаСервере непосредственно в качестве обработчика команды формы, платформа 1С просто не сможет ее инициировать при клике пользователя.
  2. Ошибки в логике присвоения ссылок: Строка Поступление = Док.Ссылка; обращается к локальной необъявленной переменной или несуществующему контексту, а не к реквизиту текущего объекта на форме. Правильное обращение к реквизиту формы — Объект.Поступление = Док.Ссылка;.
  3. Повторный вызов записи: Вызов Док.Записать(РежимЗаписиДокумента.Запись); после блока Попытка ... Исключение дублирует операцию, а в случае возникновения ошибки внутри попытки вызовет аварийное прерывание работы модуля без управляемого перехвата.
  4. Несохраненный исходный документ: Если документ, из которого создается поступление, еще не записан в базу данных, Объект.Ссылка вернет пустую ссылку. В результате связь между документами не сформируется.

Способ 1. Корректное разделение на процедуры &НаКлиенте и &НаСервере

Разберем, как правильно организовать клиент-серверный вызов при программном формировании документа.

В свойствах команды формы в качестве обработчика необходимо указать процедуру с директивой &НаКлиенте. В ней мы выполняем клиентские проверки, сохраняем исходный документ (если он модифицирован или еще не записан), после чего передаем управление на сервер.

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


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

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

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

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

Разберем по шагам, как это реализовать через параметры открытия формы:


&НаКлиенте
Процедура СоздатьПоступлениеИнтерактивно(Команда)
    
    Если Объект.Ссылка.Пустая() Или Модифицированность Тогда
        Если Не ЗаписатьВФорме() Тогда
            Возврат;
        КонецЕсли;
    КонецЕсли;
    
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("Основание", Объект.Ссылка);
    
    ОткрытьФорму("Документ.ПоступлениеТоваровУслуг.ФормаОбъекта", ПараметрыОткрытия, ЭтотОбъект);
    
КонецПроцедуры

Чтобы этот способ сработал штатно, в документе ПоступлениеТоваровУслуг должен быть настроен ввод на основании. Логика переноса строк и реквизитов при этом описывается в модуле объекта создаваемого документа в обработчике ОбработкаЗаполнения:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.Закупка") Тогда
        // Заполняем реквизиты из документа-основания
        Организация = ДанныеЗаполнения.Организация;
        Комментарий = "Создан на основании " + Строка(ДанныеЗаполнения);
        
        // Заполнение табличной части
        Для Каждого Стр Из ДанныеЗаполнения.Товары Цикл
            НоваяСтрока = Товары.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяСтрока, Стр);
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

Почему созданный документ может не отображаться в журнале

Если код создания отработал без ошибок, но при открытии журнала «Поступление (акты, накладные)» новый документ не виден, необходимо проверить следующие факторы:

  1. Интервал видимости журнала: Дата созданного документа может не попадать в период, установленный в настройках формы списка.
  2. Отборы динамического списка: В журнале могут быть включены отборы по конкретной организации, контрагенту или подразделению. Если эти поля в новом документе не заполнены или отличаются от условий отбора, документ скрывается из видимости.
  3. Вид операции: В типовых конфигурациях журнал документов поступления часто фильтрует записи по реквизиту вида или хозяйственной операции (например, ВидОперации). Если он не проинициализирован при программном создании, документ не будет квалифицирован динамическим списком.
  4. Оповещение интерфейса: При фоновой серверной записи открытые на клиенте списки не всегда обновляются автоматически. Использование метода ОповеститьОбИзменении(Ссылка) решает эту проблему, заставляя динамические списки перечитать данные.
← На главную