Как сделать универсальный отчет по движениям документа через метаданные в 1С 7.7?

Программист 1С v7.7 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При активном развитии и доработке типовой конфигурации «Торговля и Склад 7.7» (ТиС 9.2) разработчики часто сталкиваются с неудобством штатного отчета «Движения документа». Если в конфигурацию добавляется новый регистр или в существующем регистре меняется состав измерений или ресурсов, типовой отчет эти данные не отображает. Выясним причину такого поведения платформы и разберем архитектурно правильные способы решения этой задачи.

Архитектурная причина проблемы в типовой «Торговля и Склад 7.7»

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

Ограничения платформы 1С 7.7 и динамическое формирование таблицы

Разберем специфику работы с макетами на платформе 1С 7.7. В отличие от версии 8, встроенный объект Таблица в 1С 7.7 не поддерживает произвольное программное добавление ячеек по координатам без готовой разметки в макете. Построение отчета переменной ширины возможно только через механизм вертикально-горизонтальных секций (пересечений):

  1. Макет делится по вертикали и горизонтали на фиксированную левую часть (например, вид движения, номер строки документа) и динамическую колонку данных.
  2. Сначала выводится фиксированная секция вызовом метода ВывестиСекцию().
  3. Затем в цикле по полям регистра (измерениям и ресурсам) колонка наращивается вправо методом ПрисоединитьСекцию().

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

Штатный программный алгоритм обхода метаданных и чтения движений

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


Перем Ном, Рег, МетаРег;
Перем ИндИзм, ИндРес, ИндРекв;
Перем ИмяПоля, ЗначениеПоля;

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

В приведенном коде метод ПолучитьАтрибут() позволяет динамически запрашивать значения реквизитов, измерений и ресурсов по их строковому имени, что избавляет от необходимости жестко прописывать свойства объекта в программном коде.

Варианты визуализации: табличный документ против Таблицы Значений

Рассмотрим альтернативные способы представления информации о движениях:

  1. Интерактивный просмотр через объект ТаблицаЗначений: Если задача сводится исключительно к анализу движений программистом или консультантом без необходимости печати на бумаге, удобнее использовать экранную форму с элементом управления ТаблицаЗначений. В ней колонки создаются динамически методом НоваяКолонка(), что полностью снимает проблему с обрезкой длинных наименований и избавляет от настройки шаблона макета. Регистры при этом удобно переключать через многостраничную панель или выпадающий список.
  2. Прямые SQL-запросы: В базах данных формата SQL при наличии специализированных внешних компонент прямого доступа к таблицам движения можно извлекать прямым запросом к физическим таблицам RA<ID_Регистра> с фильтром по полю IDDOC = Документ. Это обеспечивает моментальный вывод данных без накладных расходов на последовательную инициализацию платформенных агрегатных объектов регистров.

Бесшовное встраивание универсального отчета в типовую конфигурацию

Разберем, как подключить универсальный отчет без вмешательства в формы каждого отдельного документа. В конфигурации «Торговля и Склад 7.7» вызов кнопки меню «Действия -> Движения документа» перенаправляется в единую глобальную процедуру:


// В Глобальном модуле конфигурации
Процедура глДвиженияДокумента(Конт) Экспорт
    // Вместо вызова типового отчета перенаправляем на универсальный внешний отчет:
    ОткрытьФорму("Отчет", Конт, КаталогИБ() + "ExtForms\УниверсальныеДвижения.ert");
КонецПроцедуры

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

← На главную