Как создать и открыть новый документ в 1С:Предприятии 8.3 (Управляемые формы) с автоматическим заполнением данных?

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

При разработке функционала в 1С:Предприятии 8.3 часто возникает потребность в программном создании и заполнении документов. Рассмотрим подробнее, как реализовать такую задачу для документа «Установка цен номенклатуры» (аналогично тому, как работает помощник установки цен при поступлении товара), включая автоматическое заполнение табличной части и проведение документа, а также правильное отображение его формы пользователю в управляемом приложении.

Наш сценарий будет следующим: у нас есть существующая обработка для работы с файлами. Мы хотим добавить новую команду (кнопку), которая при нажатии будет создавать новый документ «Установка цен номенклатуры». Этот документ должен автоматически заполняться данными (например, из ранее загруженного файла), а также выполнять дополнительные функции, такие как создание папки, подпапки, запись номенклатуры и артикула. В завершение документ должен быть проведен.

Основы взаимодействия клиента и сервера при создании документов

В управляемых формах 1С мы всегда работаем с разделением кода на клиентскую и серверную части. Клиентская часть отвечает за пользовательский интерфейс, а серверная – за работу с данными и объектами базы данных. Для создания документа и его записи в информационную базу нам потребуется выполнить серверный вызов.

Шаг 1: Создание кнопки и обработчика команды на клиенте

Для реализации удобного интерфейса часто требуются дополнительные кнопки заполнения, которые инициируют процесс формирования документов.

Начнем с создания кнопки на форме и привязки к ней команды. Обработчик команды будет размещен на клиенте и вызовет серверную функцию для основных действий.

Мы объявляем клиентскую процедуру, которая будет выполнена при нажатии на кнопку:


&НаКлиенте
Процедура СоздатьИОткрытьУстановкуЦен(Команда)
    // Здесь мы можем собрать параметры, которые нужны для заполнения документа на сервере
    // Например, данные из файла, которые уже были прочитаны клиентской процедурой.
    ПараметрыДляСозданияДокумента = Новый Структура;
    // Предположим, что МоиДанныеИзФайла содержит массив структур с информацией о номенклатуре и ценах.
    // Например: [{Номенклатура: СсылкаНаНоменклатуру1, Цена: 100}, {Номенклатура: СсылкаНаНоменклатуру2, Цена: 200}]
    ПараметрыДляСозданияДокумента.Вставить("ДанныеИзФайла", МоиДанныеИзФайла); 

    // Вызываем серверную функцию для создания, заполнения и записи документа
    СсылкаНаСозданныйДокумент = СоздатьИЗаполнитьДокументНаСервере(ПараметрыДляСозданияДокумента);

    // После успешного создания и записи документа на сервере,
    // мы можем открыть его форму на клиенте.
    Если СсылкаНаСозданныйДокумент <> Неопределено Тогда
        // Используем ПоказатьЗначение для открытия формы документа по ссылке
        ПоказатьЗначение(, СсылкаНаСозданныйДокумент);
    Иначе
        Сообщить("Не удалось создать или записать документ 'Установка цен номенклатуры'.");
    КонецЕсли;
КонецПроцедуры

Важный момент: Мы передаем параметры для создания документа на сервер через структуру. Это позволяет избежать повторного получения или чтения данных на сервере, если они уже были доступны на клиенте (например, после загрузки файла).

Шаг 2: Серверная функция для создания, заполнения и записи документа

Теперь рассмотрим серверную функцию СоздатьИЗаполнитьДокументНаСервере, которая выполнит основную работу:

  1. Создаст новый объект документа: Мы используем метод Документы.УстановкаЦенНоменклатуры.СоздатьДокумент().
  2. Заполнит основные реквизиты: Установим дату, организацию, вид цен и другие необходимые реквизиты.
  3. Заполнит табличную часть "Цены": Для каждой номенклатуры из наших данных (полученных из файла или при заполнении табличной части из поступлений) добавим новую строку в табличную часть Цены и заполним её.
  4. Запишет и проведет документ: После заполнения всех данных документ сохраняется в базе данных и сразу проводится.
  5. Вернет ссылку: Функция возвращает ссылку на созданный документ, чтобы клиент мог его открыть.

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

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

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

                    // Заполняем валюту. Можно получить из параметров или настроек.
                    НоваяСтрока.Валюта = Справочники.Валюты.НайтиПоКоду("643"); // Пример для рубля
                    
                    // Единица измерения. Если нет в данных, можно взять основную из номенклатуры.
                    Если СтрокаДанных.Свойство("ЕдиницаИзмерения") И ТипЗнч(СтрокаДанных.ЕдиницаИзмерения) = Тип("СправочникСсылка.ЕдиницыИзмерения") Тогда
                        НоваяСтрока.ЕдиницаИзмерения = СтрокаДанных.ЕдиницаИзмерения;
                    Иначе
                        // Берем основную единицу измерения номенклатуры, если она есть
                        Если ЗначениеЗаполнено(НоваяСтрока.Номенклатура) Тогда
                            НоваяСтрока.ЕдиницаИзмерения = НоваяСтрока.Номенклатура.ЕдиницаИзмерения;
                        КонецЕсли;
                    КонецЕсли;
                    
                    // Заполнить другие поля строки табличной части, если они требуются
                    // Например, если в документе есть поле 'ДатаДействияЦены' или 'ТипЦены'
                КонецЕсли;
            КонецЦикла;
        Иначе
            Сообщить("Нет данных для заполнения табличной части 'Цены' или они имеют неверный формат.");
        КонецЕсли;

        // 4. Записываем и проводим документ
        // РежимЗаписиДокумента.Проведение - записывает и сразу проводит документ.
        НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение); 
        
        // 5. Возвращаем ссылку на созданный документ
        Возврат НовыйДокумент.Ссылка;
    Исключение
        // Обработка ошибок. Желательно логировать ошибку в Журнал регистрации.
        ЗаписьЖурналаРегистрации("Создание документа УстановкаЦенНоменклатуры", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
        Сообщить("Произошла ошибка при создании или записи документа: " + ОписаниеОшибки());
        Возврат Неопределено; // Возвращаем Неопределено в случае ошибки
    КонецПопытки;
КонецФункции

Мы проанализируем важные моменты в этом коде:

  1. Использование блока Попытка...Исключение является критически важным для обработки возможных ошибок при записи или проведении документа, например, если не заполнены обязательные реквизиты или нарушены условия проведения.
  2. Метод Записать(РежимЗаписиДокумента.Проведение) позволяет одним вызовом и записать, и провести документ. Если документ не нужно проводить сразу, используйте НовыйДокумент.Записать().
  3. Передача данных из файла в табличную часть Цены осуществляется через структуру Параметры.ДанныеИзФайла. Обязательно убедитесь, что ссылки на номенклатуру, единицы измерения и другие справочники уже получены и передаются как ссылки, а не просто строковые наименования или коды. Это значительно упрощает код на сервере и делает его более надежным.

Шаг 3: Открытие формы созданного документа

После того как серверная функция успешно создала и записала документ, она возвращает его ссылку на клиент. На клиенте мы используем эту ссылку для открытия формы документа.

Существует несколько способов открыть форму:

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

Пример получения формы и её открытия с расширенными параметрами (менее типично для простого открытия, но полезно для сложных сценариев):


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

// На клиенте (после получения формы):
&НаКлиенте
Процедура СоздатьИОткрытьУстановкуЦен(Команда)
    // ... предыдущий код ...

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

Однако, для большинства случаев, где требуется просто открыть форму созданного документа, использование ПоказатьЗначение(, СсылкаНаСозданныйДокумент) является наиболее оптимальным и достаточным решением. Обратите внимание на синтаксис ПоказатьЗначение(, СсылкаНаСозданныйДокумент), где первый параметр - это владелец формы, который часто оставляют пустым.

Резюме и дополнительные советы

Мы рассмотрели комплексный подход к созданию и открытию документа в 1С:Предприятии 8.3 (управляемые формы) с автоматическим заполнением данных. Ключевые моменты, которые следует учитывать:

  1. Разделение клиент-сервер: Создание и запись объекта документа всегда происходит на сервере. Отображение формы документа – на клиенте.
  2. Передача параметров: Используйте структуры для передачи данных между клиентом и сервером. Это обеспечивает гибкость и предотвращает излишние запросы к базе данных.
  3. Обработка ошибок: Всегда используйте блоки Попытка...Исключение в серверном коде, особенно при работе с объектами базы данных, чтобы корректно реагировать на ошибки и информировать пользователя.
  4. Терминология: ПоказатьЗначение() или ОткрытьЗначение() используются для открытия формы по ссылке на объект. ПолучитьФорму() вызывается у объекта документа для получения ссылки на его форму, которую затем можно открыть методом Показать() или Открыть() с более тонкими настройками.
  5. Заполнение табличных частей: Убедитесь, что данные для табличных частей (например, номенклатура) передаются как ссылки на элементы справочников, а не просто текстом. Это повышает надежность и производительность.
  6. Проведение документа: Используйте НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение) для одновременной записи и проведения документа.

Мы надеемся, что это подробное руководство поможет вам успешно реализовать функционал по созданию и заполнению документов в ваших конфигурациях 1С.

← На главную