Многоколоночные отчеты.
Теги отчеты, программирование
Предисловие.
Чуть больше года назад написал простенький сабж движок. Признаться, сделано это было с одной стороны ради фана, а с другой стороны на случай если когда либо придется еще раз решать подобную задачу, то воспользоваться им, как отправной точкой. В этом уютном, новом бложике попробую презентовать его менее сумбурно, чем это было сделано тогда.
Для начала, нам нужно будет скачать приатаченный к посту файл. Писался он для чистой DAX 3 SP3, впрочем он не затрагивает никаких существующих объектов, так что можно смело грузить его как на трешку, так и на четверку. В последней вроде тоже проверял и даже, кажется, работало
Если у вас все импортировалось нормально, то можно продолжать.
Немного о структуре.
Не вдаваясь в подробности как оно все устроено изнутри, т.к. мне самому страшно влезать туда, спустя более года
, расскажу о базовых моментах, которых достаточно что бы начать использовать проект. Для создания нового отчета нам нужно будет наследоваться от класса SimpleSheetEngineData. В этом классе объявлены всего пять полей. Основными полями являются: reportDataMap, keyHeader, valueHeader. Первое поле представляет собой коллекцию(map) самих данных отчета, и ключ, и значение данной карты должны быть типа контейнер. Оставшиеся два поля, так же являются контейнерами и содержат информацию о заголовках полей ключа и значения, соответственно.
Создим простой пример.
Перекроем у данного класса метод fillReportDataMap следующим образом:
Создадим метод main для запуска нашего отчета:
Запустим наш отчет и получим форму предварительного просмотра данных.

Нажмем Функции/Печать и увидим сам отчет.

Обратите внимание, что я изменил ширину колонок в форме просмотра и ширина колонок в отчете изменилась соответственно (по аналогии с великими и ужасными отчетами ГК).
Реальное предназначение.
Приведенный выше пример иллюстрирует общий принцип работы данного движка, но создавался он все таки для многоколоночных отчетов "растущих в ширину", что и предлагаю реализовать, воспользовавшись примером ниже.
Оставим наших CEO и попробуем вывести в отчет поля и записи таблицы "План счетов". Новая реализация метода fillReportDataMap выглядит следующим образом:
Запустим наш отчет и получим примерно следующую картину.

Цветами отмечена группа переключателей, которая отвечает за режим вывода.Увы, в процессе написания текста, обнаружился баг для режима (вроде пофиксил)."Автомасштабирование" - не самый интересный режим, так как он предполагает вывод всех колонок на один лист и их дальнейший просмотр, вероятно, через увеличительное стекло
Более интересным является "Многостраничный вывод". Он последовательно отобразит колонки, расположив не поместившиеся из них, на следующих страницах - "в право". На скриншоте ниже я скрыл некоторые нулевые и пустые столбцы, и можно видеть, что оставшиеся поместились на два альбомных листа.

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

Заключение.
Данный проект ни в коем случае не претендует на законченное решение. Во первых, все это было написано за "один заход", то есть никакого рефакторинга и прочей "доводки до ума" не проводилось. Во вторых, в процессе написания поста нашелся баг, описанный выше. Так же, я совершенно не учитывал работу в 3-х звенной архитектуре, да и печатная форма, на данный момент, не имеет никаких заголовков, итогов и других атрибутов типичного документа. Так уж вышло, что в свое время, мне довелось создать не мало подобных отчетов, причем делалось это, как правило, в дедлайн и в разные промежутки времени. Каждый раз сталкиваясь с таким отчетом, хотелось иметь в запасе отправную точку, от которой можно было бы реализовывать конкретную задачу. Собственно так и появился сей скромный проектик.
p.s. Спасибо всем тем, кто дочитал до этого предложения
Чуть больше года назад написал простенький сабж движок. Признаться, сделано это было с одной стороны ради фана, а с другой стороны на случай если когда либо придется еще раз решать подобную задачу, то воспользоваться им, как отправной точкой. В этом уютном, новом бложике попробую презентовать его менее сумбурно, чем это было сделано тогда.
Для начала, нам нужно будет скачать приатаченный к посту файл. Писался он для чистой DAX 3 SP3, впрочем он не затрагивает никаких существующих объектов, так что можно смело грузить его как на трешку, так и на четверку. В последней вроде тоже проверял и даже, кажется, работало

Немного о структуре.
Не вдаваясь в подробности как оно все устроено изнутри, т.к. мне самому страшно влезать туда, спустя более года

Создим простой пример.
X++:
class VerySimpleReport extends SimpleSheetEngineData { }
X++:
void fillReportDataMap() { ; this.description("Hello CEO's report"); this.keyHeader(["Company", "CEO"]); this.valueHeader(["Salary", "Fortune"]); reportDataMap.insert(["Microsoft", "Стив Балмер"], [100000.0, 10000000.0]); reportDataMap.insert(["Apple", "Стив Джобс"], [50000.0, 30000000.0]); reportDataMap.insert(["Google", "Сергей Брин"], [30000.0, 14000000.0]); reportDataMap.insert(["Oracle", "Джозеф Эллисон"], [250000.0, 120000000.0]); }
X++:
static void main(Args _args) { VerySimpleReport verySimpleReport = new VerySimpleReport(); SimpleSheetEngine simpleSheetEngine; ; verySimpleReport.fillReportDataMap(); if (verySimpleReport.breakReport()) return; simpleSheetEngine = SimpleSheetEngine::construct(verySimpleReport); simpleSheetEngine.run(); }

Нажмем Функции/Печать и увидим сам отчет.

Обратите внимание, что я изменил ширину колонок в форме просмотра и ширина колонок в отчете изменилась соответственно (по аналогии с великими и ужасными отчетами ГК).
Реальное предназначение.
Приведенный выше пример иллюстрирует общий принцип работы данного движка, но создавался он все таки для многоколоночных отчетов "растущих в ширину", что и предлагаю реализовать, воспользовавшись примером ниже.
Оставим наших CEO и попробуем вывести в отчет поля и записи таблицы "План счетов". Новая реализация метода fillReportDataMap выглядит следующим образом:
X++:
#define.HeaderFieldCnt(3) #define.SkipedDimField1(9) #define.SkipedDimField2(22) #define.DemoRecCnt(30) void fillReportDataMap() { LedgerTable ledgerTable; DictTable dictTable; int intFieldNum; container key, val; int recNum; ; this.description("План счетов"); dictTable = new DictTable(tableNum(LedgerTable)); for(intFieldNum = 1; intFieldNum < dictTable.fieldCnt(); intFieldNum++) { if (intFieldNum == #SkipedDimField1 || intFieldNum == #SkipedDimField2) continue; if (intFieldNum < #HeaderFieldCnt) key += dictTable.fieldObject(dictTable.fieldCnt2Id(intFieldNum)).label(); else val += dictTable.fieldObject(dictTable.fieldCnt2Id(intFieldNum)).label(); } this.keyHeader(key); this.valueHeader(val); key = conNull(); val = conNull(); while select ledgerTable { for(intFieldNum = 1; intFieldNum < dictTable.fieldCnt(); intFieldNum++) { if (intFieldNum == #SkipedDimField1 || intFieldNum == #SkipedDimField2) continue; if (intFieldNum < #HeaderFieldCnt) key += ledgerTable.(dictTable.fieldCnt2Id(intFieldNum)); else val += ledgerTable.(dictTable.fieldCnt2Id(intFieldNum)); } reportDataMap.insert(key, val); key = conNull(); val = conNull(); recNum++; if (#demoRecCnt == recNum) break; } }

Цветами отмечена группа переключателей, которая отвечает за режим вывода.

Более интересным является "Многостраничный вывод". Он последовательно отобразит колонки, расположив не поместившиеся из них, на следующих страницах - "в право". На скриншоте ниже я скрыл некоторые нулевые и пустые столбцы, и можно видеть, что оставшиеся поместились на два альбомных листа.

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

Заключение.
Данный проект ни в коем случае не претендует на законченное решение. Во первых, все это было написано за "один заход", то есть никакого рефакторинга и прочей "доводки до ума" не проводилось. Во вторых, в процессе написания поста нашелся баг, описанный выше. Так же, я совершенно не учитывал работу в 3-х звенной архитектуре, да и печатная форма, на данный момент, не имеет никаких заголовков, итогов и других атрибутов типичного документа. Так уж вышло, что в свое время, мне довелось создать не мало подобных отчетов, причем делалось это, как правило, в дедлайн и в разные промежутки времени. Каждый раз сталкиваясь с таким отчетом, хотелось иметь в запасе отправную точку, от которой можно было бы реализовывать конкретную задачу. Собственно так и появился сей скромный проектик.
p.s. Спасибо всем тем, кто дочитал до этого предложения

Всего комментариев 0