При активном развитии и доработке типовой конфигурации «Торговля и Склад 7.7» (ТиС 9.2) разработчики часто сталкиваются с неудобством штатного отчета «Движения документа». Если в конфигурацию добавляется новый регистр или в существующем регистре меняется состав измерений или ресурсов, типовой отчет эти данные не отображает. Выясним причину такого поведения платформы и разберем архитектурно правильные способы решения этой задачи.
Проанализируем устройство типового отчета «Движения документа». В конфигурации ТиС 9.2 табличный макет отчета сверстан полностью статически. Для каждого типового регистра накопления («ОстаткиТМЦ», «ПартииТоваров», «ВзаиморасчетыПокупателей» и др.) в макете нарисованы заранее подготовленные жесткие секции шапки и строк. В программном коде отчета прописаны жесткие прямые обращения к этим именованным секциям. При добавлении нового нетипового регистра система просто не содержит секций для его рендеринга и не имеет универсального механизма генерации табличной сетки под неизвестные поля.
Разберем специфику работы с макетами на платформе 1С 7.7. В отличие от версии 8, встроенный объект Таблица в 1С 7.7 не поддерживает произвольное программное добавление ячеек по координатам без готовой разметки в макете. Построение отчета переменной ширины возможно только через механизм вертикально-горизонтальных секций (пересечений):
ВывестиСекцию().ПрисоединитьСекцию().Поскольку ширина шаблона в макете фиксирована, длинные текстовые значения могут обрезаться. Поэтому в универсальных решениях часто создают две разные секции присоединения: узкую — под числовые ресурсы, и широкую — под строковые измерения (например, наименования номенклатуры).
Рассмотрим по шагам программный алгоритм, позволяющий в цикле прочитать движения любого проведенного документа по всем доступным регистрам метаданных без модификации структуры конфигурации:
Перем Ном, Рег, МетаРег;
Перем ИндИзм, ИндРес, ИндРекв;
Перем ИмяПоля, ЗначениеПоля;
// 1. Обходим все регистры конфигурации
Для Ном = 1 По Метаданные.Регистр() Цикл
МетаРег = Метаданные.Регистр(Ном);
Рег = СоздатьОбъект("Регистр." + МетаРег.Идентификатор);
// 2. Инициализируем выборку движений по конкретному документу
Если Рег.ВыбратьДвиженияДокумента(ВыбДокумент) = 0 Тогда
Продолжить;
КонецЕсли;
// Проверяем, есть ли хотя бы одна запись
Если Рег.ПолучитьДвижение() = 0 Тогда
Продолжить;
КонецЕсли;
// Выводим шапку регистра (название и список колонок)
Таб.ВывестиСекцию("ШапкаРегистра|Фикс");
Для ИндИзм = 1 По МетаРег.Измерение() Цикл
ЗаголовокКолонки = МетаРег.Измерение(ИндИзм).Синоним;
Таб.ПрисоединитьСекцию("ШапкаРегистра|КолонкаДанных");
КонецЦикла;
Для ИндРес = 1 По МетаРег.Ресурс() Цикл
ЗаголовокКолонки = МетаРег.Ресурс(ИндРес).Синоним;
Таб.ПрисоединитьСекцию("ШапкаРегистра|КолонкаДанных");
КонецЦикла;
// 3. Обходим все строки движений регистра
Пока 1 = 1 Цикл
ФлагПрихода = Рег.Приход; // 1 - Приход, 0 - Расход
НомСтрокиДок = Рег.НомерСтрокиДокумента();
Таб.ВывестиСекцию("Строка|Фикс");
// Выводим значения измерений
Для ИндИзм = 1 По МетаРег.Измерение() Цикл
ИмяПоля = МетаРег.Измерение(ИндИзм).Идентификатор;
ЗначениеПоля = Рег.ПолучитьАтрибут(ИмяПоля);
Таб.ПрисоединитьСекцию("Строка|КолонкаДанных");
КонецЦикла;
// Выводим значения ресурсов
Для ИндРес = 1 По МетаРег.Ресурс() Цикл
ИмяПоля = МетаРег.Ресурс(ИндРес).Идентификатор;
ЗначениеПоля = Рег.ПолучитьАтрибут(ИмяПоля);
Таб.ПрисоединитьСекцию("Строка|КолонкаДанных");
КонецЦикла;
Если Рег.ПолучитьДвижение() = 0 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
КонецЦикла;
В приведенном коде метод ПолучитьАтрибут() позволяет динамически запрашивать значения реквизитов, измерений и ресурсов по их строковому имени, что избавляет от необходимости жестко прописывать свойства объекта в программном коде.
Рассмотрим альтернативные способы представления информации о движениях:
ТаблицаЗначений: Если задача сводится исключительно к анализу движений программистом или консультантом без необходимости печати на бумаге, удобнее использовать экранную форму с элементом управления ТаблицаЗначений. В ней колонки создаются динамически методом НоваяКолонка(), что полностью снимает проблему с обрезкой длинных наименований и избавляет от настройки шаблона макета. Регистры при этом удобно переключать через многостраничную панель или выпадающий список.RA<ID_Регистра> с фильтром по полю IDDOC = Документ. Это обеспечивает моментальный вывод данных без накладных расходов на последовательную инициализацию платформенных агрегатных объектов регистров.Разберем, как подключить универсальный отчет без вмешательства в формы каждого отдельного документа. В конфигурации «Торговля и Склад 7.7» вызов кнопки меню «Действия -> Движения документа» перенаправляется в единую глобальную процедуру:
// В Глобальном модуле конфигурации
Процедура глДвиженияДокумента(Конт) Экспорт
// Вместо вызова типового отчета перенаправляем на универсальный внешний отчет:
ОткрытьФорму("Отчет", Конт, КаталогИБ() + "ExtForms\УниверсальныеДвижения.ert");
КонецПроцедуры
Таким образом, внешняя обработка автоматически заменяет типовой вывод движений во всех журналах и документах системы, моментально реагируя на любые будущие изменения в структуре метаданных.