Как объединить внешнюю печатную форму и обработку в один файл 1С для вызова из разных мест и предотвращения расхождений в расчетах?

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

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

Давайте рассмотрим типовую ситуацию, когда у нас есть:

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

Основная проблема заключается в том, что процедура расчета отпусков часто модифицируется, и приходится вносить изменения в два разных файла. Цель — объединить эти два файла в один, чтобы обеспечить единую точку изменения кода и избежать расхождений, при этом сохранив возможность вызова функционала из разных мест: из карточки сотрудника и из общего списка дополнительных обработок с предварительным открытием формы параметров.

Анализируем исходную проблему и ставим цели

Прежде всего, давайте глубже проанализируем ситуацию, с которой столкнулся автор. Мы видим, что в конфигурации «Зарплата и Управление Персоналом» (ЗУП Проф 23.63) существует значительный объем бизнес-логики, касающейся расчета отпусков. Эта логика реализована в одной большой процедуре, которая является критически важной. Дублирование такой процедуры в двух разных внешних файлах – внешней печатной форме и внешней обработке – неизбежно приведет к проблемам поддержки и потенциальным ошибкам.

Основные вызовы, которые мы должны преодолеть:

  1. Дублирование кода: Это корень всех проблем. Каждое изменение в логике расчета требует синхронного обновления в двух местах, что крайне неэффективно и чревато ошибками.

  2. Различные точки вызова: Одна часть функционала должна быть доступна из контекста конкретного объекта (сотрудника), другая – из общего меню с возможностью выбора параметров.

  3. Различные макеты и форматы отчетов: Мы должны уметь выводить как персональный детальный отчет, так и сводный, который, в свою очередь, может иметь «простой» или «расширенный» вид.

  4. Ограничения среды: Автор упоминает, что использование расширений может быть проблематичным из-за большого количества баз (в том числе базовых версий, не поддерживающих расширения) и сложностей с обновлением. Это наводит нас на мысль, что решение должно быть реализовано в рамках одной внешней обработки/отчета.

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

Подходы к решению проблемы

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

Однако, как справедливо отметил автор, у расширений есть свои ограничения в определенных сценариях:

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

  2. Массовое обновление: Для большого количества баз (45+ в случае автора), поддержание расширений в актуальном состоянии может стать трудоемкой задачей, даже если это и решается средствами CI/CD. Внешние файлы (.epf или .erf) зачастую воспринимаются как более простые в обновлении для большого числа разрозненных баз.

Исходя из этих ограничений, наиболее оптимальным решением для нашего случая будет создание универсальной внешней обработки. Этот подход позволит нам объединить весь необходимый функционал в одном файле .epf, что полностью соответствует поставленной цели.

Детальный план реализации универсальной внешней обработки

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

Шаг 1: Создание основы внешней обработки

Начнем с создания нового внешнего файла обработки. В конфигураторе 1С мы создаем новую внешнюю обработку и сохраняем ее как файл .epf. Ключевым элементом, который делает внешнюю обработку такой гибкой, является экспортная функция СведенияОВнешнейОбработке(), расположенная в модуле объекта этой обработки.

Эта функция – наш "пункт управления" для системы 1С. Она сообщает системе, как наша внешняя обработка должна быть зарегистрирована, к каким объектам она привязывается и какие команды она предоставляет пользователю. В этой функции мы должны описать все возможности нашей обработки: что она является и дополнительным отчетом, и печатной формой, и привязывается как к сотрудникам, так и к подразделениям.

Шаг 2: Описание метаданных и команд с помощью СведенияОВнешнейОбработке()

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

  1. Вид: Определяет основной тип обработки. Поскольку наша обработка будет выполнять как печать, так и формирование сводного отчета с параметрами, мы можем выбрать "ДополнительныйОтчет" как наиболее универсальный вариант. Если бы основной функцией была строго печать из документа, можно было бы выбрать "ПечатнаяФорма", но "ДополнительныйОтчет" позволяет гибче управлять формой параметров.

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

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

    • Представление: Текст, который будет отображаться в меню пользователя (например, «Остатки отпусков сотрудника» или «Сводный отчет по отпускам»).

    • Идентификатор: Уникальное программное имя команды, которое мы будем использовать для различения команд внутри нашей обработки.

    • Использование: Определяет, как будет вызываться команда. Здесь у нас будет два основных варианта:

      • Для персонального отчета из карточки сотрудника: ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода(). Этот тип означает, что при выборе команды будет вызван метод на клиенте, который затем может передать управление на сервер для формирования печатной формы. При этом в качестве параметров будет передана ссылка на текущий объект (сотрудника).

      • Для сводного отчета из общего списка дополнительных обработок: ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы(). Этот тип указывает, что при выборе команды должна быть открыта форма нашей внешней обработки, где пользователь сможет задать необходимые параметры (период, подразделение, вид отчета и т.д.) перед формированием отчета.

Пример кода для функции СведенияОВнешнейОбработке() в модуле объекта:


Функция СведенияОВнешнейОбработке() Экспорт

    ПараметрыРегистрации = Новый Структура;
    ПараметрыРегистрации.Вставить("Вид", "ДополнительныйОтчет"); 
    
    // Указываем, к каким объектам будет привязана обработка
    ПараметрыРегистрации.Вставить("Назначение", Новый Массив);
    ПараметрыРегистрации.Назначение.Добавить("Справочник.Сотрудники");
    // Если нужно, можно добавить и подразделения, но для сводного отчета важнее форма параметров
    // ПараметрыРегистрации.Назначение.Добавить("Справочник.ПодразделенияОрганизации");

    // Описываем команды, которые будут доступны пользователю
    Команды = Новый Массив;

    // Команда для персонального отчета (вызывается из карточки сотрудника)
    КомандаПерсональный = ПараметрыРегистрации.Назначение[0].Команды.Добавить(); // Привязываем к первому назначению - Сотрудники
    КомандаПерсональный.Представление = "Остатки отпусков сотрудника (персонально)";
    КомандаПерсональный.Идентификатор = "ОстаткиОтпусковПерсонально";
    КомандаПерсональный.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
    Команды.Добавить(КомандаПерсональный);

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

    Возврат ПараметрыРегистрации;

КонецФункции

// Пример обработчика команды "ОстаткиОтпусковПерсонально"
// Эта процедура будет вызвана на клиенте при выборе команды
Процедура ОстаткиОтпусковПерсонально(Команда) Экспорт
    
    // Параметры.ОбъектыНазначения - это массив ссылок на выбранные объекты (в данном случае, на сотрудника)
    Если Команда.Параметры.ОбъектыНазначения.Количество() > 0 Тогда
        СсылкаНаСотрудника = Команда.Параметры.ОбъектыНазначения[0];
        
        // Вызываем серверную процедуру для формирования и показа отчета
        ПоказатьПерсональныйОтчетНаСервере(СсылкаНаСотрудника);
    КонецЕсли;

КонецПроцедуры

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

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

Шаг 3: Разработка формы параметров для сводного отчета

Для команды СводныйОтчетПоОтпускам, которая использует ТипКомандыОткрытиеФормы(), нам потребуется создать форму для нашей внешней обработки. Эта форма будет служить интерфейсом для пользователя, позволяющим выбрать параметры для сводного отчета. Мы разместим на ней следующие элементы:

  1. Поле ввода для выбора подразделения: Если отчет нужен по конкретному подразделению.

  2. Поле ввода для выбора сотрудника: Если отчет нужен сводный, но по одному сотруднику (как вариант "кратко" в условии). Это поле может быть опциональным или взаимоисключающим с выбором подразделения.

  3. Поле для указания даты отчета: На какую дату производить расчет остатков.

  4. Переключатель или флажок для выбора вида отчета: Например, «Простой» или «Расширенный».

  5. Кнопка «Сформировать»: По нажатию на которую будут получены параметры из формы и переданны в процедуру формирования отчета.

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

Пример структуры модуля формы:


&НаКлиенте
Процедура Сформировать(Команда)
    // Собираем параметры из полей формы
    ПараметрыОтчета = Новый Структура;
    ПараметрыОтчета.Вставить("ДатаОтчета", ДатаОтчета); // ДатаОтчета - реквизит формы
    ПараметрыОтчета.Вставить("Подразделение", Подразделение); // Подразделение - реквизит формы
    ПараметрыОтчета.Вставить("Сотрудник", Сотрудник); // Сотрудник - реквизит формы
    ПараметрыОтчета.Вставить("РасширенныйФормат", РасширенныйФормат); // РасширенныйФормат - реквизит формы (флажок)

    // Вызываем серверную процедуру для формирования сводного отчета
    СформироватьСводныйОтчетНаСервере(ПараметрыОтчета);
КонецПроцедуры

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

Шаг 4: Централизация процедуры расчета

Самый критичный шаг – это перенос нашей «очень-очень большой процедуры расчета остатков отпусков» в единое место. Лучшим местом для нее будет либо модуль объекта самой внешней обработки, либо внутренний общий модуль, который можно создать внутри файла .epf.

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

Преимущества централизации:

  1. Единая точка модификации: Любые изменения в алгоритме расчета теперь вносятся только в одном месте. Это гарантирует, что все отчеты, использующие эту логику, будут работать согласованно.

  2. Устранение дублирования: Мы полностью избавляемся от повторяющегося кода, что делает проект более чистым и легким в поддержке.

  3. Повышение надежности: Снижается риск ошибок, связанных с несвоевременным или неполным обновлением кода в разных файлах.

Процедура расчета должна быть экспортной, если она находится в общем модуле, или просто доступной из других процедур модуля объекта. Назовем ее, например, РассчитатьОстаткиОтпусков(ПараметрыРасчета).

Пример структуры модуля объекта или внутреннего общего модуля:


// МодульОбъекта или ОбщийМодуль_РасчетыОтпусков (если создали внутренний общий модуль)

// Глобальная процедура расчета остатков отпусков
// Она может быть экспортной, если в общем модуле, или внутренней
// если в модуле объекта и вызывается из других процедур модуля объекта
Функция РассчитатьОстаткиОтпусков(ПараметрыРасчета) Экспорт

    // ПараметрыРасчета - это структура с:
    //   - СсылкаНаСотрудника (если персональный отчет)
    //   - Подразделение (если сводный по подразделению)
    //   - ДатаОтчета
    //   - ДополнительныеФлаги (например, для детализации)

    // ... Очень-очень большая логика расчета остатков отпусков ...
    //   - Запросы к регистрам сведений, регистрам накопления
    //   - Циклы по рабочим годам
    //   - Учет различных видов отпусков
    //   - Расчет среднего заработка и т.д.
    
    // Результат расчета может быть таблицей значений или другим удобным объектом
    ТаблицаРезультатовРасчета = Новый ТаблицаЗначений; 
    // ... Заполнение ТаблицыРезультатовРасчета ...
    
    Возврат ТаблицаРезультатовРасчета;

КонецФункции

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

Шаг 5: Реализация логики формирования отчетов

Теперь, когда у нас есть централизованная процедура расчета и способы вызова, нам нужно реализовать процедуры, которые будут формировать табличные документы для печати. Эти процедуры будут вызывать РассчитатьОстаткиОтпусков() и затем компоновать результат в нужный макет.

Для персонального отчета (Макет 1):

Процедура ПолучитьПерсональныйОтчет(СсылкаНаСотрудника), вызванная из команды, будет выполнять следующее:

  1. Подготовит параметры для функции РассчитатьОстаткиОтпусков(), передав ссылку на сотрудника и дату (текущую или из настроек).

  2. Вызовет РассчитатьОстаткиОтпусков() для получения данных.

  3. Получит «Макет 1» из макетов обработки (подробнее об этом в следующем шаге).

  4. Заполнит табличный документ, используя секции макета и полученные данные.

Для сводного отчета (Макет 2):

Процедура ПолучитьСводныйОтчет(ПараметрыОтчета), вызванная из формы, будет:

  1. Проанализирует полученные ПараметрыОтчета (подразделение, сотрудник, дата, расширенный формат).

  2. В зависимости от выбора, сформирует список сотрудников (если выбрано подразделение) или использует выбранного сотрудника.

  3. Для каждого сотрудника (или для выбранного сотрудника) вызовет РассчитатьОстаткиОтпусков().

  4. Соберет все результаты в единую таблицу.

  5. Получит «Макет 2» из макетов обработки.

  6. Заполнит табличный документ. Здесь будет важный момент: в зависимости от флага РасширенныйФормат, мы будем выводить либо «простые» секции макета, либо «расширенные», отображая больше колонок.

Пример процедур формирования отчетов в модуле объекта:


&НаСервере
Функция ПолучитьПерсональныйОтчет(СсылкаНаСотрудника)
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.ИмяПараметровПечати = "ПараметрыПечатиОстатковОтпусков";

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

    // Вызов централизованной процедуры расчета
    ДанныеДляОтчета = РасчетыОтпусков.РассчитатьОстаткиОтпусков(ПараметрыРасчета); // Предполагаем, что РасчетыОтпусков - это наш внутренний общий модуль

    // Получаем макет
    Макет = ПолучитьМакет("МакетПерсональный"); // "МакетПерсональный" - имя макета в нашей обработке

    // Заполнение табличного документа
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьЗаголовок.Параметры.СотрудникФИО = СсылкаНаСотрудника.Наименование;
    ТабДок.Вывести(ОбластьЗаголовок);

    ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
    ТабДок.Вывести(ОбластьШапкаТаблицы);

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

    Возврат ТабДок;
КонецФункции

&НаСервере
Функция ПолучитьСводныйОтчет(ПараметрыОтчета)
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.ИмяПараметровПечати = "ПараметрыПечатиСводногоОтчетаОтпусков";

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

    Макет = ПолучитьМакет("МакетСводный"); // "МакетСводный" - имя макета

    ОбластьЗаголовок = Макет.ПолучитьОбласть("ЗаголовокСводный");
    ОбластьЗаголовок.Параметры.ДатаОтчета = ПараметрыОтчета.ДатаОтчета;
    ОбластьЗаголовок.Параметры.ПодразделениеНаименование = Строка(ПараметрыОтчета.Подразделение);
    ТабДок.Вывести(ОбластьЗаголовок);

    Если ПараметрыОтчета.РасширенныйФормат Тогда
        ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицыРасширенная");
    Иначе
        ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицыПростая");
    КонецЕсли;
    ТабДок.Вывести(ОбластьШапкаТаблицы);

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

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

    Возврат ТабДок;
КонецФункции

Шаг 6: Управление макетами

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

  1. «МакетПерсональный»: Для детального персонального отчета. Он может содержать секции для заголовка, шапки таблицы и детальной строки по каждому рабочему году или виду отпуска.

  2. «МакетСводный»: Для сводного отчета. В этом макете мы можем использовать различные секции для реализации «простого» и «расширенного» вида. Например:

    • Секция «ШапкаТаблицыПростая» и «ШапкаТаблицыРасширенная».

    • Секция «СтрокаСводногоОтчетаПростая» и «СтрокаСводногоОтчетаРасширенная».

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

Для добавления макетов: откройте внешнюю обработку в конфигураторе, в дереве объектов обработки найдите ветку «Макеты», добавьте новые макеты типа «Табличный документ» и спроектируйте их согласно потребностям.

Шаг 7: Регистрация внешней обработки в 1С

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

  1. Откройте режим 1С:Предприятие.

  2. Перейдите в раздел «Администрирование» (или аналогичный, в зависимости от конфигурации).

  3. Найдите пункт «Печатные формы, отчеты и обработки».

  4. Перейдите в «Дополнительные отчеты и обработки».

  5. Добавьте новый элемент, указав путь к нашему файлу .epf.

  6. После загрузки файла система 1С прочитает данные из функции СведенияОВнешнейОбработке() и предложит зарегистрировать команды. Убедитесь, что все команды (персональный и сводный отчет) правильно отображаются и привязаны к соответствующим объектам или доступны в общем списке.

  7. Проверьте, что команды доступны в карточке сотрудника и в общем меню «Дополнительные отчеты».

Преимущества такого подхода

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

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

  2. Упрощение модификации и поддержки: Любые изменения в алгоритме расчета или в структуре отчетов теперь вносятся только в одном месте, что значительно сокращает время на разработку и тестирование, а также минимизирует риски ошибок.

  3. Гибкость вызова: Мы сохраняем возможность вызова отчетов как из контекста конкретного объекта (сотрудника), так и из общего меню дополнительных обработок с предварительным запросом параметров.

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

  5. Независимость от расширений: Этот подход не требует использования расширений, что делает его совместимым с базовыми версиями конфигураций 1С и упрощает обновление в инфраструктурах с большим количеством разрозненных баз.

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

Заключение

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

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

← На главную