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

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

Разработка внешних обработок — одна из наиболее частых задач, с которыми сталкивается начинающий программист "1С:Предприятие 8.3". Внешние обработки позволяют расширить функционал типовой конфигурации, не изменяя саму структуру метаданных. Это существенно упрощает последующее обновление информационной базы.

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

Понимание архитектуры управляемого приложения: Клиент и Сервер

Прежде чем перейти к написанию кода, необходимо четко уяснить базовый принцип работы управляемых форм в 1С. Вся работа разделена на два контекста:

  1. Клиент (директива выполнения &НаКлиенте). Здесь происходит непосредственное взаимодействие с пользователем. На клиенте открываются формы, выдаются предупреждения, осуществляются интерактивные действия. В клиентском контексте нельзя работать с базой данных напрямую, выполнять запросы или получать объектные данные (например, изменять документы).
  2. Сервер (директива выполнения &НаСервере или &НаСервереБезКонтекста). Здесь выполняются все тяжелые операции: запросы к базе данных, создание и проведение документов, сложные математические расчеты. На сервере нет интерфейса, поэтому здесь нельзя вызывать диалоговые окна или открывать формы.

Для решения нашей задачи мы настроим четкое взаимодействие: пользователь нажимает кнопку на клиенте, управление передается на сервер, сервер выбирает данные из базы данных и возвращает их на клиентскую форму.

Шаг 1. Создание файла внешней обработки и управляемой формы

Разберем по шагам процесс создания структуры нашей обработки в конфигураторе:

  1. Откроем конфигуратор 1С. В главном меню выберем Файл — Новый, в появившемся списке выберем Внешняя обработка.
  2. В открывшемся окне свойств зададим имя обработки, например, ГрупповойПерерасчетСкидок. Синоним заполнится автоматически.
  3. Перейдем на вкладку Формы и нажмем кнопку добавления (иконка с лупой или плюсом), чтобы создать основную форму обработки. Оставим тип формы по умолчанию ("Форма обработки") и нажмем "Готово". Перед нами откроется конструктор управляемой формы.

Шаг 2. Проектирование реквизитов управляемой формы

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

  1. Добавим реквизит ДатаНачала с типом данных Дата. В свойствах укажем состав даты: "Дата".
  2. Добавим реквизит ДатаОкончания с типом данных Дата. Также укажем состав даты: "Дата".
  3. Добавим реквизит формы НовыйПроцентСкидки с типом данных Число (длина 5, точность 2), чтобы пользователь мог указать новое значение для документов.
  4. Теперь создадим реквизит, который будет хранить список найденных документов. Добавим новый реквизит и назовем его СписокДокументов. Изменим его тип данных на ТаблицаЗначений.
  5. Внутри таблицы значений СписокДокументов добавим две колонки:
    • Пометка — тип данных Булево. Данная колонка будет отображаться в виде флажка, позволяя пользователю выбирать нужные строки.
    • Документ — тип данных ДокументСсылка.ОказаниеУслуги (или ссылка на ваш конкретный документ, например, ДокументСсылка.РасходнаяНакладная).

После создания реквизитов перетащим их мышкой из правого верхнего окна ("Реквизиты") в левое верхнее окно ("Элементы"). Элемент управления для реквизита Пометка автоматически создастся как поле ввода. Изменим его свойство Вид на Поле флажка. Это позволит выводить классическую "галочку" на форме.

Шаг 3. Заполнение таблицы документов с помощью запроса на сервере

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

Рассмотрим правильный алгоритм получения данных. Для этого создадим на форме команду ЗаполнитьСписок, перетащим ее на форму в виде кнопки и определим для нее обработчик действия на клиенте и на сервере.

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


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

&НаСервере
Процедура ЗаполнитьСписокНаСервере()
    
    // Очищаем текущую таблицу на форме перед новым заполнением
    СписокДокументов.Очистить();
    
    // Создаем запрос к базе данных
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ЛОЖЬ КАК Пометка,
        |	ОказаниеУслуги.Ссылка КАК Документ
        |ИЗ
        |	Документ.ОказаниеУслуги КАК ОказаниеУслуги
        |ГДЕ
        |	ОказаниеУслуги.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
        |	И НЕ ОказаниеУслуги.ПометкаУдаления";
    
    // Устанавливаем параметры запроса с приведением дат к началу и концу дня
    Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала));
    Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаОкончания));
    
    РезультатЗапроса = Запрос.Выполнить();
    
    Если Не РезультатЗапроса.Пустой() Тогда
        // Выгружаем результат запроса во временную Таблицу Значений в памяти сервера
        ТаблицаДанных = РезультатЗапроса.Выгрузить();
        
        // Ключевой метод: преобразуем серверную Таблицу Значений в реквизит формы
        ЗначениеВРеквизитФормы(ТаблицаДанных, "СписокДокументов");
    Иначе
        ВызватьИсключение "Документы за указанный период не найдены!";
    КонецЕсли;
    
КонецПроцедуры

Обратите внимание на красивое решение в тексте запроса: конструкция ЛОЖЬ КАК Пометка позволяет нам сразу сформировать колонку булевого типа со значением по умолчанию. Метод ЗначениеВРеквизитФормы() быстро и без ручного обхода строк переносит подготовленную таблицу на форму.

Шаг 4. Групповое изменение и проведение документов

Теперь разберем вторую логическую часть задачи: обход отмеченных документов, изменение реквизитов и их проведение. При выполнении этой операции критически важно предусмотреть обработку ошибок. Если один из документов заблокирован другим пользователем или не может провестись по причине нехватки остатков на складе, программа не должна прерывать свою работу аварийно. Она должна пропустить проблемный документ, сообщить об ошибке пользователю и продолжить обработку остальных строк.

Добавим на форму команду ВыполнитьОбработку, разместим кнопку на форме и напишем следующий код в модуле формы:


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

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

Шаг 5. Интеграция внешней обработки в Библиотеку Стандартных Подсистем (БСП)

Для того чтобы конечные пользователи могли запускать нашу обработку непосредственно из интерфейса программы (например, "1С:Бухгалтерия" или "1С:Управление нашей фирмой"), не используя меню "Файл — Открыть", обработку необходимо зарегистрировать в справочнике "Дополнительные отчеты и обработки".

Для этого в Модуле объекта нашей внешней обработки (не в модуле формы!) обязательно нужно разместить экспортную функцию СведенияОВнешнейОбработке(). Проанализируем ее типовую структуру:


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

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

После добавления этого кода в модуль объекта, сохраните обработку в файл с расширением .epf. Теперь администратор системы сможет зайти в раздел Администрирование — Печатные формы, отчеты и обработки — Дополнительные отчеты и обработки, загрузить созданный файл и настроить права доступа для пользователей, которым необходим данный инструмент.

Рекомендации по оптимизации при работе с большими объемами данных

Если в вашей базе данных количество документов за выбранный период исчисляется тысячами, последовательное проведение в цикле может занять значительное время. В этот момент интерфейс программы у пользователя может казаться "зависшим". Чтобы избежать этого, рекомендуем придерживаться следующих правил профессиональной разработки:

Мы детально изучили процесс создания внешней обработки: от проектирования структуры управляемой формы и связывания данных с сервером до программного изменения объектов и интеграции решения в типовые конфигурации через механизмы БСП. Используя данные шаблоны кода, вы сможете решать широкий спектр аналогичных задач по автоматизации рутинных процессов в среде "1С:Предприятие 8.3".

← На главную