mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
QQQ-42 checkpoint of qqq reports
This commit is contained in:
@ -22,7 +22,6 @@
|
|||||||
package com.kingsrook.qqq.backend.core.actions.reporting;
|
package com.kingsrook.qqq.backend.core.actions.reporting;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@ -67,7 +66,8 @@ public class ExcelExportStreamer implements ExportStreamerInterface
|
|||||||
|
|
||||||
private Workbook workbook;
|
private Workbook workbook;
|
||||||
private Worksheet worksheet;
|
private Worksheet worksheet;
|
||||||
private int row = 0;
|
private int row = 0;
|
||||||
|
private int sheetCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -112,6 +112,7 @@ public class ExcelExportStreamer implements ExportStreamerInterface
|
|||||||
table = exportInput.getTable();
|
table = exportInput.getTable();
|
||||||
outputStream = this.exportInput.getReportOutputStream();
|
outputStream = this.exportInput.getReportOutputStream();
|
||||||
this.row = 0;
|
this.row = 0;
|
||||||
|
this.sheetCount++;
|
||||||
|
|
||||||
if(workbook == null)
|
if(workbook == null)
|
||||||
{
|
{
|
||||||
@ -127,11 +128,11 @@ public class ExcelExportStreamer implements ExportStreamerInterface
|
|||||||
worksheet.finish();
|
worksheet.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet = workbook.newWorksheet(label);
|
worksheet = workbook.newWorksheet(Objects.requireNonNullElse(label, "Sheet " + sheetCount));
|
||||||
|
|
||||||
writeReportHeaderRow();
|
writeReportHeaderRow();
|
||||||
}
|
}
|
||||||
catch(IOException e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
throw (new QReportingException("Error starting worksheet", e));
|
throw (new QReportingException("Error starting worksheet", e));
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QFormulaException;
|
|||||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||||
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
|
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
|
||||||
|
|
||||||
@ -154,17 +155,17 @@ public class FormulaInterpreter
|
|||||||
case "ADD":
|
case "ADD":
|
||||||
{
|
{
|
||||||
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
return nullIfAnyNullArgsElse(numbers, () -> numbers.get(0).add(numbers.get(1)));
|
return nullIfAnyNullArgsElseBigDecimal(numbers, () -> numbers.get(0).add(numbers.get(1)));
|
||||||
}
|
}
|
||||||
case "MINUS":
|
case "MINUS":
|
||||||
{
|
{
|
||||||
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
return nullIfAnyNullArgsElse(numbers, () -> numbers.get(0).subtract(numbers.get(1)));
|
return nullIfAnyNullArgsElseBigDecimal(numbers, () -> numbers.get(0).subtract(numbers.get(1)));
|
||||||
}
|
}
|
||||||
case "MULTIPLY":
|
case "MULTIPLY":
|
||||||
{
|
{
|
||||||
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
return nullIfAnyNullArgsElse(numbers, () -> numbers.get(0).multiply(numbers.get(1)));
|
return nullIfAnyNullArgsElseBigDecimal(numbers, () -> numbers.get(0).multiply(numbers.get(1)));
|
||||||
}
|
}
|
||||||
case "DIVIDE":
|
case "DIVIDE":
|
||||||
{
|
{
|
||||||
@ -173,7 +174,7 @@ public class FormulaInterpreter
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return nullIfAnyNullArgsElse(numbers, () -> numbers.get(0).divide(numbers.get(1), 4, RoundingMode.HALF_UP));
|
return nullIfAnyNullArgsElseBigDecimal(numbers, () -> numbers.get(0).divide(numbers.get(1), 4, RoundingMode.HALF_UP));
|
||||||
}
|
}
|
||||||
case "DIVIDE_SCALE":
|
case "DIVIDE_SCALE":
|
||||||
{
|
{
|
||||||
@ -182,23 +183,83 @@ public class FormulaInterpreter
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return nullIfAnyNullArgsElse(numbers, () -> numbers.get(0).divide(numbers.get(1), numbers.get(2).intValue(), RoundingMode.HALF_UP));
|
return nullIfAnyNullArgsElseBigDecimal(numbers, () -> numbers.get(0).divide(numbers.get(1), numbers.get(2).intValue(), RoundingMode.HALF_UP));
|
||||||
}
|
}
|
||||||
case "ROUND":
|
case "ROUND":
|
||||||
{
|
{
|
||||||
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
return nullIfAnyNullArgsElse(numbers, () -> numbers.get(0).round(new MathContext(numbers.get(1).intValue())));
|
return nullIfAnyNullArgsElseBigDecimal(numbers, () -> numbers.get(0).round(new MathContext(numbers.get(1).intValue())));
|
||||||
}
|
}
|
||||||
case "SCALE":
|
case "SCALE":
|
||||||
{
|
{
|
||||||
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
return nullIfAnyNullArgsElse(numbers, () -> numbers.get(0).setScale(numbers.get(1).intValue(), RoundingMode.HALF_UP));
|
return nullIfAnyNullArgsElseBigDecimal(numbers, () -> numbers.get(0).setScale(numbers.get(1).intValue(), RoundingMode.HALF_UP));
|
||||||
}
|
}
|
||||||
case "NVL":
|
case "NVL":
|
||||||
{
|
{
|
||||||
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
return Objects.requireNonNullElse(numbers.get(0), numbers.get(1));
|
return Objects.requireNonNullElse(numbers.get(0), numbers.get(1));
|
||||||
}
|
}
|
||||||
|
case "IF":
|
||||||
|
{
|
||||||
|
// IF(CONDITION,TRUE,ELSE)
|
||||||
|
List<Serializable> actualArgs = getArgumentList(args, 3, variableInterpreter);
|
||||||
|
Serializable condition = actualArgs.get(0);
|
||||||
|
boolean conditionBoolean;
|
||||||
|
if(condition == null)
|
||||||
|
{
|
||||||
|
conditionBoolean = false;
|
||||||
|
}
|
||||||
|
else if(condition instanceof Boolean b)
|
||||||
|
{
|
||||||
|
conditionBoolean = b;
|
||||||
|
}
|
||||||
|
else if(condition instanceof BigDecimal bd)
|
||||||
|
{
|
||||||
|
conditionBoolean = (bd.compareTo(BigDecimal.ZERO) != 0);
|
||||||
|
}
|
||||||
|
else if(condition instanceof String s)
|
||||||
|
{
|
||||||
|
if("true".equalsIgnoreCase(s))
|
||||||
|
{
|
||||||
|
conditionBoolean = true;
|
||||||
|
}
|
||||||
|
else if("false".equalsIgnoreCase(s))
|
||||||
|
{
|
||||||
|
conditionBoolean = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conditionBoolean = StringUtils.hasContent(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conditionBoolean = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conditionBoolean ? actualArgs.get(1) : actualArgs.get(2);
|
||||||
|
}
|
||||||
|
case "LT":
|
||||||
|
{
|
||||||
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
|
return nullIfAnyNullArgsElseBoolean(numbers, () -> numbers.get(0).compareTo(numbers.get(1)) < 0);
|
||||||
|
}
|
||||||
|
case "LTE":
|
||||||
|
{
|
||||||
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
|
return nullIfAnyNullArgsElseBoolean(numbers, () -> numbers.get(0).compareTo(numbers.get(1)) <= 0);
|
||||||
|
}
|
||||||
|
case "GT":
|
||||||
|
{
|
||||||
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
|
return nullIfAnyNullArgsElseBoolean(numbers, () -> numbers.get(0).compareTo(numbers.get(1)) > 0);
|
||||||
|
}
|
||||||
|
case "GTE":
|
||||||
|
{
|
||||||
|
List<BigDecimal> numbers = getNumberArgumentList(args, 2, variableInterpreter);
|
||||||
|
return nullIfAnyNullArgsElseBoolean(numbers, () -> numbers.get(0).compareTo(numbers.get(1)) >= 0);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -235,7 +296,21 @@ public class FormulaInterpreter
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private static Serializable nullIfAnyNullArgsElse(List<BigDecimal> numbers, Supplier<BigDecimal> supplier)
|
private static Serializable nullIfAnyNullArgsElseBigDecimal(List<BigDecimal> numbers, Supplier<BigDecimal> supplier)
|
||||||
|
{
|
||||||
|
if(numbers.stream().anyMatch(Objects::isNull))
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static Serializable nullIfAnyNullArgsElseBoolean(List<BigDecimal> numbers, Supplier<Boolean> supplier)
|
||||||
{
|
{
|
||||||
if(numbers.stream().anyMatch(Objects::isNull))
|
if(numbers.stream().anyMatch(Objects::isNull))
|
||||||
{
|
{
|
||||||
@ -275,4 +350,35 @@ public class FormulaInterpreter
|
|||||||
return (rs);
|
return (rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static List<Serializable> getArgumentList(List<Serializable> originalArgs, Integer howMany, QMetaDataVariableInterpreter variableInterpreter) throws QFormulaException
|
||||||
|
{
|
||||||
|
if(howMany != null)
|
||||||
|
{
|
||||||
|
if(!howMany.equals(originalArgs.size()))
|
||||||
|
{
|
||||||
|
throw (new QFormulaException("Wrong number of arguments (required: " + howMany + ", received: " + originalArgs.size() + ")"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Serializable> rs = new ArrayList<>();
|
||||||
|
for(Serializable originalArg : originalArgs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Serializable interpretedArg = variableInterpreter.interpretForObject(ValueUtils.getValueAsString(originalArg), null);
|
||||||
|
rs.add(interpretedArg);
|
||||||
|
}
|
||||||
|
catch(QValueException e)
|
||||||
|
{
|
||||||
|
throw (new QFormulaException("Could not process [" + originalArg + "] as a number"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (rs);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -469,6 +469,9 @@ public class GenerateReportAction
|
|||||||
Map<String, AggregatesInterface<?>> fieldAggregates = entry.getValue();
|
Map<String, AggregatesInterface<?>> fieldAggregates = entry.getValue();
|
||||||
variableInterpreter.addValueMap("pivot", getPivotValuesForInterpreter(fieldAggregates));
|
variableInterpreter.addValueMap("pivot", getPivotValuesForInterpreter(fieldAggregates));
|
||||||
|
|
||||||
|
HashMap<String, Serializable> thisRowValues = new HashMap<>();
|
||||||
|
variableInterpreter.addValueMap("thisRow", thisRowValues);
|
||||||
|
|
||||||
if(!variancePivotAggregates.isEmpty())
|
if(!variancePivotAggregates.isEmpty())
|
||||||
{
|
{
|
||||||
Map<PivotKey, Map<String, AggregatesInterface<?>>> varianceMap = variancePivotAggregates.getOrDefault(view.getName(), Collections.emptyMap());
|
Map<PivotKey, Map<String, AggregatesInterface<?>>> varianceMap = variancePivotAggregates.getOrDefault(view.getName(), Collections.emptyMap());
|
||||||
@ -503,6 +506,7 @@ public class GenerateReportAction
|
|||||||
{
|
{
|
||||||
Serializable serializable = getValueForColumn(variableInterpreter, column);
|
Serializable serializable = getValueForColumn(variableInterpreter, column);
|
||||||
pivotRow.setValue(column.getName(), serializable);
|
pivotRow.setValue(column.getName(), serializable);
|
||||||
|
thisRowValues.put(column.getName(), serializable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,14 +587,17 @@ public class GenerateReportAction
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private Serializable getValueForColumn(QMetaDataVariableInterpreter variableInterpreter, QReportField column) throws QFormulaException
|
private Serializable getValueForColumn(QMetaDataVariableInterpreter variableInterpreter, QReportField column) throws QFormulaException
|
||||||
{
|
{
|
||||||
String formula = column.getFormula();
|
String formula = column.getFormula();
|
||||||
Serializable serializable = variableInterpreter.interpretForObject(formula);
|
Serializable result;
|
||||||
if(formula.startsWith("=") && formula.length() > 1)
|
if(formula.startsWith("=") && formula.length() > 1)
|
||||||
{
|
{
|
||||||
// serializable = interpretFormula(variableInterpreter, formula);
|
result = FormulaInterpreter.interpretFormula(variableInterpreter, formula.substring(1));
|
||||||
serializable = FormulaInterpreter.interpretFormula(variableInterpreter, formula.substring(1));
|
|
||||||
}
|
}
|
||||||
return serializable;
|
else
|
||||||
|
{
|
||||||
|
result = variableInterpreter.interpretForObject(formula, null);
|
||||||
|
}
|
||||||
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -558,17 +558,17 @@ public class QInstanceEnricher
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// create an identity section for the id and any fields in the record label //
|
// create an identity section for the id and any fields in the record label //
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
QAppSection defaultSection = new QAppSection(app.getName(), app.getLabel(), new QIcon("badge"), new ArrayList<>(), new ArrayList<>());
|
QAppSection defaultSection = new QAppSection(app.getName(), app.getLabel(), new QIcon("badge"), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||||
|
|
||||||
boolean foundNonAppChild = false;
|
boolean foundNonAppChild = false;
|
||||||
if(CollectionUtils.nullSafeHasContents(app.getChildren()))
|
if(CollectionUtils.nullSafeHasContents(app.getChildren()))
|
||||||
{
|
{
|
||||||
for(QAppChildMetaData child : app.getChildren())
|
for(QAppChildMetaData child : app.getChildren())
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// only tables and processes are allowed to be in sections at this time, apps //
|
// only tables, processes, and reports are allowed to be in sections at this time, apps //
|
||||||
// might be children but not in sections so keep track if we find any non-app //
|
// might be children but not in sections so keep track if we find any non-app //
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if(child.getClass().equals(QTableMetaData.class))
|
if(child.getClass().equals(QTableMetaData.class))
|
||||||
{
|
{
|
||||||
defaultSection.getTables().add(child.getName());
|
defaultSection.getTables().add(child.getName());
|
||||||
@ -579,6 +579,11 @@ public class QInstanceEnricher
|
|||||||
defaultSection.getProcesses().add(child.getName());
|
defaultSection.getProcesses().add(child.getName());
|
||||||
foundNonAppChild = true;
|
foundNonAppChild = true;
|
||||||
}
|
}
|
||||||
|
else if(child.getClass().equals(QReportMetaData.class))
|
||||||
|
{
|
||||||
|
defaultSection.getReports().add(child.getName());
|
||||||
|
foundNonAppChild = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +510,8 @@ public class QInstanceValidator
|
|||||||
assertCondition(StringUtils.hasContent(section.getLabel()), "Missing a label for a section in app " + app.getLabel() + ".");
|
assertCondition(StringUtils.hasContent(section.getLabel()), "Missing a label for a section in app " + app.getLabel() + ".");
|
||||||
boolean hasTables = CollectionUtils.nullSafeHasContents(section.getTables());
|
boolean hasTables = CollectionUtils.nullSafeHasContents(section.getTables());
|
||||||
boolean hasProcesses = CollectionUtils.nullSafeHasContents(section.getProcesses());
|
boolean hasProcesses = CollectionUtils.nullSafeHasContents(section.getProcesses());
|
||||||
if(assertCondition(hasTables || hasProcesses, "App " + app.getName() + " section " + section.getName() + " does not have any children."))
|
boolean hasReports = CollectionUtils.nullSafeHasContents(section.getReports());
|
||||||
|
if(assertCondition(hasTables || hasProcesses || hasReports, "App " + app.getName() + " section " + section.getName() + " does not have any children."))
|
||||||
{
|
{
|
||||||
if(hasTables)
|
if(hasTables)
|
||||||
{
|
{
|
||||||
@ -532,6 +533,16 @@ public class QInstanceValidator
|
|||||||
childNamesInSections.add(processName);
|
childNamesInSections.add(processName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(hasReports)
|
||||||
|
{
|
||||||
|
for(String reportName : section.getReports())
|
||||||
|
{
|
||||||
|
assertCondition(app.getChildren().stream().anyMatch(c -> c.getName().equals(reportName)), "App " + app.getName() + " section " + section.getName() + " specifies report " + reportName + ", which is not a child of this app.");
|
||||||
|
assertCondition(!childNamesInSections.contains(reportName), "App " + app.getName() + " has report " + reportName + " listed more than once in its sections.");
|
||||||
|
|
||||||
|
childNamesInSections.add(reportName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ public class QAppSection
|
|||||||
|
|
||||||
private List<String> tables;
|
private List<String> tables;
|
||||||
private List<String> processes;
|
private List<String> processes;
|
||||||
|
private List<String> reports;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -51,13 +52,14 @@ public class QAppSection
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public QAppSection(String name, String label, QIcon icon, List<String> tables, List<String> processes)
|
public QAppSection(String name, String label, QIcon icon, List<String> tables, List<String> processes, List<String> reports)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
this.tables = tables;
|
this.tables = tables;
|
||||||
this.processes = processes;
|
this.processes = processes;
|
||||||
|
this.reports = reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -198,6 +200,40 @@ public class QAppSection
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for reports
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<String> getReports()
|
||||||
|
{
|
||||||
|
return reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for reports
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setReports(List<String> reports)
|
||||||
|
{
|
||||||
|
this.reports = reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for reports
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QAppSection withReports(List<String> reports)
|
||||||
|
{
|
||||||
|
this.reports = reports;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for icon
|
** Getter for icon
|
||||||
**
|
**
|
||||||
|
@ -36,6 +36,7 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInpu
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -50,8 +51,9 @@ public class ExecuteReportStep implements BackendStep
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
String reportName = runBackendStepInput.getValueString("reportName");
|
String reportName = runBackendStepInput.getValueString("reportName");
|
||||||
File tmpFile = File.createTempFile(reportName, ".xlsx", new File("/tmp/"));
|
QReportMetaData report = runBackendStepInput.getInstance().getReport(reportName);
|
||||||
|
File tmpFile = File.createTempFile(reportName, ".xlsx", new File("/tmp/"));
|
||||||
|
|
||||||
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
|
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
|
||||||
|
|
||||||
@ -71,7 +73,7 @@ public class ExecuteReportStep implements BackendStep
|
|||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmm").withZone(ZoneId.systemDefault());
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmm").withZone(ZoneId.systemDefault());
|
||||||
String datePart = formatter.format(Instant.now());
|
String datePart = formatter.format(Instant.now());
|
||||||
|
|
||||||
runBackendStepOutput.addValue("downloadFileName", reportName + "-" + datePart + ".xlsx");
|
runBackendStepOutput.addValue("downloadFileName", report.getLabel() + " " + datePart + ".xlsx");
|
||||||
runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath());
|
runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,9 @@ import static com.kingsrook.qqq.backend.core.actions.reporting.FormulaInterprete
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -140,4 +142,55 @@ class FormulaInterpreterTest
|
|||||||
assertEquals(new BigDecimal("27.78"), interpretFormula(vi, "SCALE(MULTIPLY(100,DIVIDE_SCALE(${pivot.sum.noOfShoes},${total.sum.noOfShoes},6)),2)"));
|
assertEquals(new BigDecimal("27.78"), interpretFormula(vi, "SCALE(MULTIPLY(100,DIVIDE_SCALE(${pivot.sum.noOfShoes},${total.sum.noOfShoes},6)),2)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testComparisons() throws QFormulaException
|
||||||
|
{
|
||||||
|
QMetaDataVariableInterpreter vi = new QMetaDataVariableInterpreter();
|
||||||
|
vi.addValueMap("input", Map.of("one", 1, "two", 2, "foo", "bar"));
|
||||||
|
|
||||||
|
assertTrue((Boolean) interpretFormula(vi, "LT(${input.one},${input.two})"));
|
||||||
|
assertFalse((Boolean) interpretFormula(vi, "LT(${input.two},${input.one})"));
|
||||||
|
|
||||||
|
assertFalse((Boolean) interpretFormula(vi, "GT(${input.one},${input.two})"));
|
||||||
|
assertTrue((Boolean) interpretFormula(vi, "GT(${input.two},${input.one})"));
|
||||||
|
|
||||||
|
assertTrue((Boolean) interpretFormula(vi, "LTE(${input.one},${input.two})"));
|
||||||
|
assertTrue((Boolean) interpretFormula(vi, "LTE(${input.one},${input.one})"));
|
||||||
|
assertFalse((Boolean) interpretFormula(vi, "LTE(${input.two},${input.one})"));
|
||||||
|
|
||||||
|
assertFalse((Boolean) interpretFormula(vi, "GTE(${input.one},${input.two})"));
|
||||||
|
assertTrue((Boolean) interpretFormula(vi, "GTE(${input.one},${input.one})"));
|
||||||
|
assertTrue((Boolean) interpretFormula(vi, "GTE(${input.two},${input.one})"));
|
||||||
|
|
||||||
|
// todo - google sheets compares strings differently...
|
||||||
|
assertThatThrownBy(() -> interpretFormula(vi, "LT(${input.foo},${input.one})")).hasMessageContaining("[bar] as a number");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testConditionals() throws QFormulaException
|
||||||
|
{
|
||||||
|
QMetaDataVariableInterpreter vi = new QMetaDataVariableInterpreter();
|
||||||
|
vi.addValueMap("input", Map.of("one", 1, "two", 2, "three", 3, "foo", "bar"));
|
||||||
|
|
||||||
|
assertEquals("A", interpretFormula(vi, "IF(LT(${input.one},${input.two}),A,B)"));
|
||||||
|
assertEquals("B", interpretFormula(vi, "IF(GT(${input.one},${input.two}),A,B)"));
|
||||||
|
|
||||||
|
assertEquals("C", interpretFormula(vi, "IF(GT(${input.one},${input.two}),A,IF(GT(${input.two},${input.three}),B,C))"));
|
||||||
|
assertEquals("B", interpretFormula(vi, "IF(GT(${input.one},${input.two}),A,IF(LT(${input.two},${input.three}),B,C))"));
|
||||||
|
assertEquals("A", interpretFormula(vi, "IF(GT(${input.two},${input.one}),A,IF(LT(${input.two},${input.three}),B,C))"));
|
||||||
|
|
||||||
|
assertEquals("Yes", interpretFormula(vi, "IF(GT(${input.one},0),Yes,No)"));
|
||||||
|
assertEquals("No", interpretFormula(vi, "IF(LT(${input.one},0),Yes,No)"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -59,7 +59,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Unit test for GenerateReportAction
|
** Unit test for GenerateReportAction
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
class GenerateReportActionTest
|
public class GenerateReportActionTest
|
||||||
{
|
{
|
||||||
private static final String REPORT_NAME = "personReport1";
|
private static final String REPORT_NAME = "personReport1";
|
||||||
|
|
||||||
@ -243,32 +243,32 @@ class GenerateReportActionTest
|
|||||||
Map<String, String> row = iterator.next();
|
Map<String, String> row = iterator.next();
|
||||||
assertEquals(6, list.size());
|
assertEquals(6, list.size());
|
||||||
|
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("1");
|
assertThat(row.get("Home State Id")).isEqualTo("IL");
|
||||||
assertThat(row.get("Last Name")).isEqualTo("Jonson");
|
assertThat(row.get("Last Name")).isEqualTo("Jonson");
|
||||||
assertThat(row.get("Quantity")).isNull();
|
assertThat(row.get("Quantity")).isNull();
|
||||||
|
|
||||||
row = iterator.next();
|
row = iterator.next();
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("1");
|
assertThat(row.get("Home State Id")).isEqualTo("IL");
|
||||||
assertThat(row.get("Last Name")).isEqualTo("Jones");
|
assertThat(row.get("Last Name")).isEqualTo("Jones");
|
||||||
assertThat(row.get("Quantity")).isEqualTo("3");
|
assertThat(row.get("Quantity")).isEqualTo("3");
|
||||||
|
|
||||||
row = iterator.next();
|
row = iterator.next();
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("1");
|
assertThat(row.get("Home State Id")).isEqualTo("IL");
|
||||||
assertThat(row.get("Last Name")).isEqualTo("Kelly");
|
assertThat(row.get("Last Name")).isEqualTo("Kelly");
|
||||||
assertThat(row.get("Quantity")).isEqualTo("4");
|
assertThat(row.get("Quantity")).isEqualTo("4");
|
||||||
|
|
||||||
row = iterator.next();
|
row = iterator.next();
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("1");
|
assertThat(row.get("Home State Id")).isEqualTo("IL");
|
||||||
assertThat(row.get("Last Name")).isEqualTo("Keller");
|
assertThat(row.get("Last Name")).isEqualTo("Keller");
|
||||||
assertThat(row.get("Quantity")).isEqualTo("5");
|
assertThat(row.get("Quantity")).isEqualTo("5");
|
||||||
|
|
||||||
row = iterator.next();
|
row = iterator.next();
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("1");
|
assertThat(row.get("Home State Id")).isEqualTo("IL");
|
||||||
assertThat(row.get("Last Name")).isEqualTo("Kelkhoff");
|
assertThat(row.get("Last Name")).isEqualTo("Kelkhoff");
|
||||||
assertThat(row.get("Quantity")).isEqualTo("6");
|
assertThat(row.get("Quantity")).isEqualTo("6");
|
||||||
|
|
||||||
row = iterator.next();
|
row = iterator.next();
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("2");
|
assertThat(row.get("Home State Id")).isEqualTo("MO");
|
||||||
assertThat(row.get("Last Name")).isEqualTo("Kelkhoff");
|
assertThat(row.get("Last Name")).isEqualTo("Kelkhoff");
|
||||||
assertThat(row.get("Quantity")).isEqualTo("7");
|
assertThat(row.get("Quantity")).isEqualTo("7");
|
||||||
}
|
}
|
||||||
@ -297,15 +297,14 @@ class GenerateReportActionTest
|
|||||||
Iterator<Map<String, String>> iterator = list.iterator();
|
Iterator<Map<String, String>> iterator = list.iterator();
|
||||||
Map<String, String> row = iterator.next();
|
Map<String, String> row = iterator.next();
|
||||||
assertEquals(2, list.size());
|
assertEquals(2, list.size());
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("2");
|
assertThat(row.get("Home State Id")).isEqualTo("MO");
|
||||||
assertThat(row.get("Last Name")).isNull();
|
assertThat(row.get("Last Name")).isNull();
|
||||||
assertThat(row.get("Quantity")).isEqualTo("7");
|
assertThat(row.get("Quantity")).isEqualTo("7");
|
||||||
|
|
||||||
row = iterator.next();
|
row = iterator.next();
|
||||||
assertThat(row.get("Home State Id")).isEqualTo("1");
|
assertThat(row.get("Home State Id")).isEqualTo("IL");
|
||||||
assertThat(row.get("Last Name")).isNull();
|
assertThat(row.get("Last Name")).isNull();
|
||||||
assertThat(row.get("Quantity")).isEqualTo("18");
|
assertThat(row.get("Quantity")).isEqualTo("18");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -398,7 +397,7 @@ class GenerateReportActionTest
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private QReportMetaData defineReport(boolean includeTotalRow)
|
public static QReportMetaData defineReport(boolean includeTotalRow)
|
||||||
{
|
{
|
||||||
return new QReportMetaData()
|
return new QReportMetaData()
|
||||||
.withName(REPORT_NAME)
|
.withName(REPORT_NAME)
|
||||||
|
@ -584,7 +584,7 @@ class QInstanceValidatorTest
|
|||||||
{
|
{
|
||||||
QAppMetaData app = new QAppMetaData().withName("test")
|
QAppMetaData app = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection(null, "Section 1", new QIcon("person"), List.of("test"), null));
|
.withSection(new QAppSection(null, "Section 1", new QIcon("person"), List.of("test"), null, null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app), "Missing a name");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app), "Missing a name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,7 +598,7 @@ class QInstanceValidatorTest
|
|||||||
{
|
{
|
||||||
QAppMetaData app = new QAppMetaData().withName("test")
|
QAppMetaData app = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("Section 1", null, new QIcon("person"), List.of("test"), null));
|
.withSection(new QAppSection("Section 1", null, new QIcon("person"), List.of("test"), null, null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app), "Missing a label");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app), "Missing a label");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,12 +612,12 @@ class QInstanceValidatorTest
|
|||||||
{
|
{
|
||||||
QAppMetaData app1 = new QAppMetaData().withName("test")
|
QAppMetaData app1 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of(), List.of()));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of(), List.of(), null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app1), "section1 does not have any children", "child test is not listed in any app sections");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app1), "section1 does not have any children", "child test is not listed in any app sections");
|
||||||
|
|
||||||
QAppMetaData app2 = new QAppMetaData().withName("test")
|
QAppMetaData app2 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), null, null));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), null, null, null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app2), "section1 does not have any children", "child test is not listed in any app sections");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app2), "section1 does not have any children", "child test is not listed in any app sections");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,11 +631,11 @@ class QInstanceValidatorTest
|
|||||||
{
|
{
|
||||||
QAppMetaData app1 = new QAppMetaData().withName("test")
|
QAppMetaData app1 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test", "tset"), null));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test", "tset"), null, null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app1), "not a child of this app");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app1), "not a child of this app");
|
||||||
QAppMetaData app2 = new QAppMetaData().withName("test")
|
QAppMetaData app2 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), List.of("tset")));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), List.of("tset"), null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app2), "not a child of this app");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app2), "not a child of this app");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,23 +649,23 @@ class QInstanceValidatorTest
|
|||||||
{
|
{
|
||||||
QAppMetaData app1 = new QAppMetaData().withName("test")
|
QAppMetaData app1 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test", "test"), null));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test", "test"), null, null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app1), "more than once");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app1), "more than once");
|
||||||
|
|
||||||
QAppMetaData app2 = new QAppMetaData().withName("test")
|
QAppMetaData app2 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), null))
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), null, null))
|
||||||
.withSection(new QAppSection("section2", "Section 2", new QIcon("person"), List.of("test"), null));
|
.withSection(new QAppSection("section2", "Section 2", new QIcon("person"), List.of("test"), null, null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app2), "more than once");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app2), "more than once");
|
||||||
|
|
||||||
QAppMetaData app3 = new QAppMetaData().withName("test")
|
QAppMetaData app3 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), List.of("test")));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), List.of("test"), null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app3), "more than once");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app3), "more than once");
|
||||||
|
|
||||||
QAppMetaData app4 = new QAppMetaData().withName("test")
|
QAppMetaData app4 = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), null, List.of("test", "test")));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), null, List.of("test", "test"), null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app4), "more than once");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app4), "more than once");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,7 +687,7 @@ class QInstanceValidatorTest
|
|||||||
QAppMetaData app = new QAppMetaData().withName("test")
|
QAppMetaData app = new QAppMetaData().withName("test")
|
||||||
.withChild(new QTableMetaData().withName("tset"))
|
.withChild(new QTableMetaData().withName("tset"))
|
||||||
.withChild(new QTableMetaData().withName("test"))
|
.withChild(new QTableMetaData().withName("test"))
|
||||||
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), null));
|
.withSection(new QAppSection("section1", "Section 1", new QIcon("person"), List.of("test"), null, null));
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app), "not listed in any app sections");
|
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app), "not listed in any app sections");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,6 +200,29 @@ class QMetaDataVariableInterpreterTest
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testLooksLikeVariableButNotFound()
|
||||||
|
{
|
||||||
|
QMetaDataVariableInterpreter variableInterpreter = new QMetaDataVariableInterpreter();
|
||||||
|
variableInterpreter.addValueMap("input", Map.of("x", 1, "y", 2));
|
||||||
|
variableInterpreter.addValueMap("others", Map.of("foo", "bar"));
|
||||||
|
|
||||||
|
assertNull(variableInterpreter.interpretForObject("${input.notFound}", null));
|
||||||
|
assertEquals(0, variableInterpreter.interpretForObject("${input.notFound}", 0));
|
||||||
|
assertEquals("--", variableInterpreter.interpretForObject("${input.notFound}", "--"));
|
||||||
|
assertEquals("--", variableInterpreter.interpretForObject("${others.notFound}", "--"));
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// this one doesn't count as "looking like a variable" - because the "prefix" (notValid) isn't a value map... //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
assertEquals("${notValid.notFound}", variableInterpreter.interpretForObject("${notValid.notFound}", "--"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.processes.implementations.reports;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.Month;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportActionTest;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for BasicRunReportProcess
|
||||||
|
*******************************************************************************/
|
||||||
|
class BasicRunReportProcessTest
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testRunReport() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
QReportMetaData report = GenerateReportActionTest.defineReport(true);
|
||||||
|
QProcessMetaData runReportProcess = BasicRunReportProcess.defineProcessMetaData();
|
||||||
|
|
||||||
|
instance.addReport(report);
|
||||||
|
report.setProcessName(runReportProcess.getName());
|
||||||
|
instance.addProcess(runReportProcess);
|
||||||
|
|
||||||
|
RunProcessInput runProcessInput = new RunProcessInput(instance);
|
||||||
|
runProcessInput.setSession(TestUtils.getMockSession());
|
||||||
|
runProcessInput.setProcessName(report.getProcessName());
|
||||||
|
runProcessInput.addValue(BasicRunReportProcess.FIELD_REPORT_NAME, report.getName());
|
||||||
|
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||||
|
String processUUID = runProcessOutput.getProcessUUID();
|
||||||
|
assertThat(runProcessOutput.getProcessState().getNextStepName()).isPresent().get().isEqualTo(BasicRunReportProcess.STEP_NAME_INPUT);
|
||||||
|
|
||||||
|
runProcessInput.addValue("startDate", LocalDate.of(1980, Month.JANUARY, 1));
|
||||||
|
runProcessInput.addValue("endDate", LocalDate.of(2099, Month.DECEMBER, 31));
|
||||||
|
runProcessInput.setStartAfterStep(BasicRunReportProcess.STEP_NAME_INPUT);
|
||||||
|
runProcessInput.setProcessUUID(processUUID);
|
||||||
|
|
||||||
|
runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||||
|
assertThat(runProcessOutput.getProcessState().getNextStepName()).isPresent().get().isEqualTo(BasicRunReportProcess.STEP_NAME_ACCESS);
|
||||||
|
assertThat(runProcessOutput.getValues()).containsKeys("downloadFileName", "serverFilePath");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -451,8 +451,8 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
|||||||
@Test
|
@Test
|
||||||
void testExportFieldsQueryParam()
|
void testExportFieldsQueryParam()
|
||||||
{
|
{
|
||||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/export/People.csv?fields=id,birthDate").asString();
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/export/People.csv?fields=id,birthDate").asString();
|
||||||
String[] csvLines = response.getBody().split("\n");
|
String[] csvLines = response.getBody().split("\n");
|
||||||
assertEquals("""
|
assertEquals("""
|
||||||
"Id","Birth Date\"""", csvLines[0]);
|
"Id","Birth Date\"""", csvLines[0]);
|
||||||
}
|
}
|
||||||
@ -484,7 +484,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
|||||||
assertNotNull(jsonObject);
|
assertNotNull(jsonObject);
|
||||||
assertEquals("barChart", jsonObject.getString("type"));
|
assertEquals("barChart", jsonObject.getString("type"));
|
||||||
assertNotNull(jsonObject.getString("title"));
|
assertNotNull(jsonObject.getString("title"));
|
||||||
assertNotNull(jsonObject.getJSONObject("barChartData"));
|
assertNotNull(jsonObject.getJSONObject("chartData"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Unit test for PersonsByCreateDateBarChart
|
** Unit test for PersonsByCreateDateBarChart
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
class PersonsByCreateDateChartTestData
|
class PersonsByCreateDateBarChartTest
|
||||||
{
|
{
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -47,7 +47,7 @@ class PersonsByCreateDateChartTestData
|
|||||||
Object widgetData = new PersonsByCreateDateBarChart().render(SampleMetaDataProvider.defineInstance(), new QSession(), null);
|
Object widgetData = new PersonsByCreateDateBarChart().render(SampleMetaDataProvider.defineInstance(), new QSession(), null);
|
||||||
assertThat(widgetData).isInstanceOf(ChartData.class);
|
assertThat(widgetData).isInstanceOf(ChartData.class);
|
||||||
ChartData chartData = (ChartData) widgetData;
|
ChartData chartData = (ChartData) widgetData;
|
||||||
assertEquals("chartData", chartData.getType());
|
assertEquals("barChart", chartData.getType());
|
||||||
assertThat(chartData.getTitle()).isNotBlank();
|
assertThat(chartData.getTitle()).isNotBlank();
|
||||||
assertNotNull(chartData.getChartData());
|
assertNotNull(chartData.getChartData());
|
||||||
}
|
}
|
Reference in New Issue
Block a user