diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java index 4d220a59..84da01e0 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java @@ -130,7 +130,15 @@ public class GenerateReportAction { throw new QException("Report format was not specified."); } - reportStreamer = reportFormat.newReportStreamer(); + + if(reportInput.getOverrideExportStreamerSupplier() != null) + { + reportStreamer = reportInput.getOverrideExportStreamerSupplier().get(); + } + else + { + reportStreamer = reportFormat.newReportStreamer(); + } reportStreamer.preRun(reportInput.getReportDestination(), views); diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/fastexcel/PlainFastExcelStyler.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/fastexcel/PlainFastExcelStyler.java index 21254a3a..e42afe36 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/fastexcel/PlainFastExcelStyler.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/fastexcel/PlainFastExcelStyler.java @@ -22,10 +22,22 @@ package com.kingsrook.qqq.backend.core.actions.reporting.excel.fastexcel; +import org.dhatim.fastexcel.StyleSetter; + + /******************************************************************************* ** Excel styler that does nothing - just takes defaults (which are all no-op) from the interface. *******************************************************************************/ public class PlainFastExcelStyler implements FastExcelStylerInterface { + /******************************************************************************* + ** ... sorry, but adding this gives us test coverage on this class, even though + ** we're just deferring to super... + *******************************************************************************/ + @Override + public void styleHeaderRow(StyleSetter headerRowStyle) + { + FastExcelStylerInterface.super.styleHeaderRow(headerRowStyle); + } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/poi/ExcelPoiBasedStreamingExportStreamer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/poi/ExcelPoiBasedStreamingExportStreamer.java index 672a9203..670bcbba 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/poi/ExcelPoiBasedStreamingExportStreamer.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/excel/poi/ExcelPoiBasedStreamingExportStreamer.java @@ -90,7 +90,7 @@ public class ExcelPoiBasedStreamingExportStreamer implements ExportStreamerInter private OutputStream outputStream; private ZipOutputStream zipOutputStream; - private PoiExcelStylerInterface poiExcelStylerInterface = new PlainPoiExcelStyler(); + private PoiExcelStylerInterface poiExcelStylerInterface = getStylerInterface(); private Map excelCellFormats; private int rowNo = 0; @@ -335,7 +335,7 @@ public class ExcelPoiBasedStreamingExportStreamer implements ExportStreamerInter { CreationHelper createHelper = workbook.getCreationHelper(); - XSSFCellStyle dateStyle = workbook.createCellStyle(); + XSSFCellStyle dateStyle = workbook.createCellStyle(); dateStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy-MM-dd")); styles.put("date", dateStyle); @@ -508,8 +508,8 @@ public class ExcelPoiBasedStreamingExportStreamer implements ExportStreamerInter { sheetWriter.insertRow(rowNo++); - int styleIndex = -1; - int dateStyleIndex = styles.get("date").getIndex(); + int styleIndex = -1; + int dateStyleIndex = styles.get("date").getIndex(); int dateTimeStyleIndex = styles.get("datetime").getIndex(); if(isFooter) { @@ -748,4 +748,15 @@ public class ExcelPoiBasedStreamingExportStreamer implements ExportStreamerInter throw (new QReportingException("Error writing pivot table", e)); } } + + + + /******************************************************************************* + ** + *******************************************************************************/ + protected PoiExcelStylerInterface getStylerInterface() + { + return (new PlainPoiExcelStyler()); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/reporting/ReportInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/reporting/ReportInput.java index 2b081129..369cbc6a 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/reporting/ReportInput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/reporting/ReportInput.java @@ -25,6 +25,8 @@ package com.kingsrook.qqq.backend.core.model.actions.reporting; import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.function.Supplier; +import com.kingsrook.qqq.backend.core.actions.reporting.ExportStreamerInterface; import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData; @@ -41,6 +43,8 @@ public class ReportInput extends AbstractTableActionInput private ReportDestination reportDestination; + private Supplier overrideExportStreamerSupplier; + /******************************************************************************* @@ -140,6 +144,7 @@ public class ReportInput extends AbstractTableActionInput } + /******************************************************************************* ** Getter for reportMetaData *******************************************************************************/ @@ -170,4 +175,37 @@ public class ReportInput extends AbstractTableActionInput } + + /******************************************************************************* + ** Getter for overrideExportStreamerSupplier + ** + *******************************************************************************/ + public Supplier getOverrideExportStreamerSupplier() + { + return overrideExportStreamerSupplier; + } + + + + /******************************************************************************* + ** Setter for overrideExportStreamerSupplier + ** + *******************************************************************************/ + public void setOverrideExportStreamerSupplier(Supplier overrideExportStreamerSupplier) + { + this.overrideExportStreamerSupplier = overrideExportStreamerSupplier; + } + + + + /******************************************************************************* + ** Fluent setter for overrideExportStreamerSupplier + ** + *******************************************************************************/ + public ReportInput withOverrideExportStreamerSupplier(Supplier overrideExportStreamerSupplier) + { + this.overrideExportStreamerSupplier = overrideExportStreamerSupplier; + return (this); + } + } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java index fca34aa3..e78c8306 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java @@ -35,6 +35,10 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import com.kingsrook.qqq.backend.core.BaseTest; +import com.kingsrook.qqq.backend.core.actions.reporting.excel.fastexcel.ExcelFastexcelExportStreamer; +import com.kingsrook.qqq.backend.core.actions.reporting.excel.poi.BoldHeaderAndFooterPoiExcelStyler; +import com.kingsrook.qqq.backend.core.actions.reporting.excel.poi.ExcelPoiBasedStreamingExportStreamer; +import com.kingsrook.qqq.backend.core.actions.reporting.excel.poi.PoiExcelStylerInterface; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination; @@ -378,6 +382,76 @@ public class GenerateReportActionTest extends BaseTest + /******************************************************************************* + ** Keep some test coverage on the fastexcel library (as long as we keep it around) + *******************************************************************************/ + @Test + void runTableToXlsxFastexcel() throws Exception + { + ReportFormat format = ReportFormat.XLSX; + String name = "/tmp/report-fastexcel.xlsx"; + try(FileOutputStream fileOutputStream = new FileOutputStream(name)) + { + QInstance qInstance = QContext.getQInstance(); + qInstance.addReport(defineTableOnlyReport()); + insertPersonRecords(qInstance); + + ReportInput reportInput = new ReportInput(); + reportInput.setReportName(REPORT_NAME); + reportInput.setReportDestination(new ReportDestination().withReportFormat(format).withReportOutputStream(fileOutputStream)); + reportInput.setInputValues(Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now())); + reportInput.setOverrideExportStreamerSupplier(ExcelFastexcelExportStreamer::new); + new GenerateReportAction().execute(reportInput); + System.out.println("Wrote File: " + name); + + LocalMacDevUtils.mayOpenFiles = true; + LocalMacDevUtils.openFile(name); + } + } + + + + /******************************************************************************* + ** Imagine if we used the boldHeaderAndFooter styler + *******************************************************************************/ + @Test + void runTableToXlsxWithOverrideStyles() throws Exception + { + ReportFormat format = ReportFormat.XLSX; + String name = "/tmp/report-fastexcel.xlsx"; + try(FileOutputStream fileOutputStream = new FileOutputStream(name)) + { + QInstance qInstance = QContext.getQInstance(); + QReportMetaData reportMetaData = defineTableOnlyReport(); + reportMetaData.getViews().get(0).withTitleFormat("My Title"); + + qInstance.addReport(reportMetaData); + insertPersonRecords(qInstance); + + ReportInput reportInput = new ReportInput(); + reportInput.setReportName(REPORT_NAME); + reportInput.setReportDestination(new ReportDestination().withReportFormat(format).withReportOutputStream(fileOutputStream)); + reportInput.setInputValues(Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now())); + + reportInput.setOverrideExportStreamerSupplier(() -> new ExcelPoiBasedStreamingExportStreamer() + { + @Override + protected PoiExcelStylerInterface getStylerInterface() + { + return new BoldHeaderAndFooterPoiExcelStyler(); + } + }); + + new GenerateReportAction().execute(reportInput); + System.out.println("Wrote File: " + name); + + LocalMacDevUtils.mayOpenFiles = true; + LocalMacDevUtils.openFile(name); + } + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -488,7 +562,7 @@ public class GenerateReportActionTest extends BaseTest /******************************************************************************* ** *******************************************************************************/ - private void insertPersonRecords(QInstance qInstance) throws QException + public static void insertPersonRecords(QInstance qInstance) throws QException { TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of( new PersonQRecord().withFirstName("Darin").withLastName("Jonson").withBirthDate(LocalDate.of(1980, Month.JANUARY, 31)).withNoOfShoes(null).withHomeStateId(1).withPrice(null).withCost(new BigDecimal("0.50")), // wrong last initial