Refactor report generation logic and enhance Excel/PDF output formatting
- Updated the ReportService to improve the structure of Excel and PDF report generation, including the addition of fiscal period parameters. - Refactored methods to build summary and detail sheets in Excel, enhancing readability and styling. - Improved PDF document layout and added titles for better presentation of report data. - Enhanced integration tests to verify the correctness of generated reports and ensure the presence of expected artifacts.
This commit is contained in:
parent
114c58737f
commit
661d78a225
|
|
@ -8,15 +8,36 @@ import com.hanwha.nexacrodemo.consolidation.ConsolidationPayload;
|
|||
import com.hanwha.nexacrodemo.minio.ObjectStorageService;
|
||||
import com.hanwha.nexacrodemo.minio.StoredObject;
|
||||
import com.lowagie.text.Document;
|
||||
import com.lowagie.text.Element;
|
||||
import com.lowagie.text.Font;
|
||||
import com.lowagie.text.FontFactory;
|
||||
import com.lowagie.text.PageSize;
|
||||
import com.lowagie.text.Paragraph;
|
||||
import com.lowagie.text.Phrase;
|
||||
import com.lowagie.text.Rectangle;
|
||||
import com.lowagie.text.pdf.PdfPCell;
|
||||
import com.lowagie.text.pdf.PdfPTable;
|
||||
import com.lowagie.text.pdf.PdfWriter;
|
||||
import java.awt.Color;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.FontUnderline;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
|
@ -27,6 +48,10 @@ import org.springframework.stereotype.Service;
|
|||
@Service
|
||||
public class ReportService {
|
||||
|
||||
private static final DateTimeFormatter REPORT_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
private static final DecimalFormat AMOUNT_FORMAT = new DecimalFormat("#,##0.00");
|
||||
private static final Map<String, String> LABELS = buildLabels();
|
||||
|
||||
private final ReportMapper reportMapper;
|
||||
private final ConsolidationMapper consolidationMapper;
|
||||
private final ObjectStorageService objectStorageService;
|
||||
|
|
@ -53,7 +78,7 @@ public class ReportService {
|
|||
|
||||
public void generateReports(Long runId, String fiscalPeriod, ConsolidationPayload payload) {
|
||||
try {
|
||||
byte[] excelBytes = buildExcel(payload);
|
||||
byte[] excelBytes = buildExcel(fiscalPeriod, payload);
|
||||
byte[] pdfBytes = buildPdf(fiscalPeriod, payload);
|
||||
|
||||
ReportArtifactCommand excelArtifact = new ReportArtifactCommand();
|
||||
|
|
@ -93,19 +118,13 @@ public class ReportService {
|
|||
.body(new ByteArrayResource(storedObject.getBytes()));
|
||||
}
|
||||
|
||||
private byte[] buildExcel(ConsolidationPayload payload) throws IOException {
|
||||
private byte[] buildExcel(String fiscalPeriod, ConsolidationPayload payload) throws IOException {
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
|
||||
Sheet summarySheet = workbook.createSheet("Summary");
|
||||
int rowIndex = 0;
|
||||
for (Map.Entry<String, BigDecimal> metric : payload.getMetrics().entrySet()) {
|
||||
Row row = summarySheet.createRow(rowIndex++);
|
||||
row.createCell(0).setCellValue(metric.getKey());
|
||||
row.createCell(1).setCellValue(metric.getValue().doubleValue());
|
||||
}
|
||||
|
||||
writeRows(workbook.createSheet("Contributions"), payload.getContributionRows());
|
||||
writeRows(workbook.createSheet("Eliminations"), payload.getEliminationRows());
|
||||
writeRows(workbook.createSheet("Forecast"), payload.getForecastRows());
|
||||
Map<String, CellStyle> styles = createExcelStyles(workbook);
|
||||
buildSummarySheet(workbook, fiscalPeriod, payload, styles);
|
||||
buildDetailSheet(workbook, "Contributions", fiscalPeriod, payload.getContributionRows(), styles);
|
||||
buildDetailSheet(workbook, "Eliminations", fiscalPeriod, payload.getEliminationRows(), styles);
|
||||
buildDetailSheet(workbook, "Forecast", fiscalPeriod, payload.getForecastRows(), styles);
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
workbook.write(outputStream);
|
||||
|
|
@ -115,39 +134,352 @@ public class ReportService {
|
|||
|
||||
private byte[] buildPdf(String fiscalPeriod, ConsolidationPayload payload) throws IOException {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
Document document = new Document();
|
||||
Document document = new Document(PageSize.A4.rotate(), 36, 36, 36, 36);
|
||||
PdfWriter.getInstance(document, outputStream);
|
||||
document.open();
|
||||
document.add(new Paragraph("Hanwha Consolidation Demo"));
|
||||
document.add(new Paragraph("Fiscal period: " + fiscalPeriod));
|
||||
addPdfTitle(document, "Hanwha Consolidation Summary", 18, new Color(24, 54, 93));
|
||||
addPdfTitle(document, "Fiscal period " + fiscalPeriod + " | Generated " + generatedAt(), 10, new Color(90, 96, 106));
|
||||
document.add(new Paragraph(" "));
|
||||
for (Map.Entry<String, BigDecimal> metric : payload.getMetrics().entrySet()) {
|
||||
document.add(new Paragraph(metric.getKey() + ": " + metric.getValue()));
|
||||
}
|
||||
addSummaryTable(document, payload.getMetrics());
|
||||
addDetailTable(document, "Contributions", payload.getContributionRows(), 8);
|
||||
addDetailTable(document, "Eliminations", payload.getEliminationRows(), 8);
|
||||
addDetailTable(document, "Forecast", payload.getForecastRows(), 8);
|
||||
document.close();
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
private void writeRows(Sheet sheet, List<Map<String, Object>> rows) {
|
||||
private void buildSummarySheet(
|
||||
XSSFWorkbook workbook,
|
||||
String fiscalPeriod,
|
||||
ConsolidationPayload payload,
|
||||
Map<String, CellStyle> styles
|
||||
) {
|
||||
Sheet sheet = workbook.createSheet("Summary");
|
||||
sheet.setDisplayGridlines(false);
|
||||
|
||||
Row titleRow = sheet.createRow(0);
|
||||
titleRow.setHeightInPoints(28);
|
||||
createCell(titleRow, 0, "Hanwha Consolidation Summary", styles.get("title"));
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
|
||||
|
||||
Row subtitleRow = sheet.createRow(1);
|
||||
createCell(subtitleRow, 0, "Fiscal period " + fiscalPeriod + " | Generated " + generatedAt(), styles.get("subtitle"));
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 3));
|
||||
|
||||
Row sectionRow = sheet.createRow(3);
|
||||
createCell(sectionRow, 0, "Performance Snapshot", styles.get("section"));
|
||||
|
||||
Row headerRow = sheet.createRow(4);
|
||||
createCell(headerRow, 0, "Metric", styles.get("header"));
|
||||
createCell(headerRow, 1, "Value", styles.get("header"));
|
||||
|
||||
int rowIndex = 5;
|
||||
for (Map.Entry<String, BigDecimal> metric : payload.getMetrics().entrySet()) {
|
||||
Row row = sheet.createRow(rowIndex++);
|
||||
createCell(row, 0, label(metric.getKey()), styles.get("text"));
|
||||
createNumericCell(row, 1, metric.getValue(), styleForKey(styles, metric.getKey()));
|
||||
}
|
||||
|
||||
sheet.createFreezePane(0, 5);
|
||||
sheet.setColumnWidth(0, 26 * 256);
|
||||
sheet.setColumnWidth(1, 18 * 256);
|
||||
sheet.setColumnWidth(2, 18 * 256);
|
||||
sheet.setColumnWidth(3, 18 * 256);
|
||||
}
|
||||
|
||||
private void buildDetailSheet(
|
||||
XSSFWorkbook workbook,
|
||||
String sheetName,
|
||||
String fiscalPeriod,
|
||||
List<Map<String, Object>> rows,
|
||||
Map<String, CellStyle> styles
|
||||
) {
|
||||
Sheet sheet = workbook.createSheet(sheetName);
|
||||
sheet.setDisplayGridlines(false);
|
||||
int columnCount = rows.isEmpty() ? 1 : rows.get(0).size();
|
||||
|
||||
Row titleRow = sheet.createRow(0);
|
||||
titleRow.setHeightInPoints(24);
|
||||
createCell(titleRow, 0, sheetName + " Detail", styles.get("title"));
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, Math.max(0, columnCount - 1)));
|
||||
|
||||
Row subtitleRow = sheet.createRow(1);
|
||||
createCell(subtitleRow, 0, "Fiscal period " + fiscalPeriod + " | Rows " + rows.size(), styles.get("subtitle"));
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, Math.max(0, columnCount - 1)));
|
||||
|
||||
if (rows.isEmpty()) {
|
||||
Row row = sheet.createRow(0);
|
||||
row.createCell(0).setCellValue("No data");
|
||||
Row emptyRow = sheet.createRow(3);
|
||||
createCell(emptyRow, 0, "No data available", styles.get("empty"));
|
||||
sheet.setColumnWidth(0, 24 * 256);
|
||||
return;
|
||||
}
|
||||
|
||||
Row header = sheet.createRow(0);
|
||||
int cellIndex = 0;
|
||||
for (String key : rows.get(0).keySet()) {
|
||||
header.createCell(cellIndex++).setCellValue(key);
|
||||
List<String> keys = List.copyOf(rows.get(0).keySet());
|
||||
Row headerRow = sheet.createRow(3);
|
||||
for (int index = 0; index < keys.size(); index++) {
|
||||
createCell(headerRow, index, label(keys.get(index)), styles.get("header"));
|
||||
}
|
||||
|
||||
int rowIndex = 1;
|
||||
int rowIndex = 4;
|
||||
for (Map<String, Object> item : rows) {
|
||||
Row row = sheet.createRow(rowIndex++);
|
||||
int valueIndex = 0;
|
||||
for (Object value : item.values()) {
|
||||
row.createCell(valueIndex++).setCellValue(value == null ? "" : String.valueOf(value));
|
||||
for (int cellIndex = 0; cellIndex < keys.size(); cellIndex++) {
|
||||
String key = keys.get(cellIndex);
|
||||
writeValueCell(row, cellIndex, key, item.get(key), styles);
|
||||
}
|
||||
}
|
||||
|
||||
sheet.createFreezePane(0, 4);
|
||||
sheet.setAutoFilter(new CellRangeAddress(3, rowIndex - 1, 0, keys.size() - 1));
|
||||
for (int index = 0; index < keys.size(); index++) {
|
||||
sheet.autoSizeColumn(index);
|
||||
int currentWidth = sheet.getColumnWidth(index);
|
||||
sheet.setColumnWidth(index, Math.min(currentWidth + 1024, 28 * 256));
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, CellStyle> createExcelStyles(XSSFWorkbook workbook) {
|
||||
Map<String, CellStyle> styles = new LinkedHashMap<>();
|
||||
short amountFormat = workbook.createDataFormat().getFormat("#,##0.00");
|
||||
short percentFormat = workbook.createDataFormat().getFormat("0.00%");
|
||||
|
||||
var titleFont = workbook.createFont();
|
||||
titleFont.setBold(true);
|
||||
titleFont.setColor(org.apache.poi.ss.usermodel.IndexedColors.WHITE.getIndex());
|
||||
titleFont.setFontHeightInPoints((short) 14);
|
||||
|
||||
var subtitleFont = workbook.createFont();
|
||||
subtitleFont.setColor(org.apache.poi.ss.usermodel.IndexedColors.GREY_80_PERCENT.getIndex());
|
||||
|
||||
var sectionFont = workbook.createFont();
|
||||
sectionFont.setBold(true);
|
||||
sectionFont.setColor(org.apache.poi.ss.usermodel.IndexedColors.DARK_BLUE.getIndex());
|
||||
|
||||
var headerFont = workbook.createFont();
|
||||
headerFont.setBold(true);
|
||||
headerFont.setColor(org.apache.poi.ss.usermodel.IndexedColors.WHITE.getIndex());
|
||||
|
||||
var emptyFont = workbook.createFont();
|
||||
emptyFont.setItalic(true);
|
||||
emptyFont.setUnderline(FontUnderline.SINGLE);
|
||||
emptyFont.setColor(org.apache.poi.ss.usermodel.IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
|
||||
CellStyle title = workbook.createCellStyle();
|
||||
title.setFont(titleFont);
|
||||
title.setFillForegroundColor(org.apache.poi.ss.usermodel.IndexedColors.DARK_BLUE.getIndex());
|
||||
title.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
title.setAlignment(HorizontalAlignment.LEFT);
|
||||
title.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
title.setBorderBottom(BorderStyle.THIN);
|
||||
styles.put("title", title);
|
||||
|
||||
CellStyle subtitle = workbook.createCellStyle();
|
||||
subtitle.setFont(subtitleFont);
|
||||
subtitle.setAlignment(HorizontalAlignment.LEFT);
|
||||
styles.put("subtitle", subtitle);
|
||||
|
||||
CellStyle section = workbook.createCellStyle();
|
||||
section.setFont(sectionFont);
|
||||
section.setAlignment(HorizontalAlignment.LEFT);
|
||||
styles.put("section", section);
|
||||
|
||||
CellStyle header = workbook.createCellStyle();
|
||||
header.setFont(headerFont);
|
||||
header.setFillForegroundColor(org.apache.poi.ss.usermodel.IndexedColors.ORANGE.getIndex());
|
||||
header.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
header.setAlignment(HorizontalAlignment.CENTER);
|
||||
header.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
applyBorder(header);
|
||||
styles.put("header", header);
|
||||
|
||||
CellStyle text = workbook.createCellStyle();
|
||||
text.setAlignment(HorizontalAlignment.LEFT);
|
||||
text.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
applyBorder(text);
|
||||
styles.put("text", text);
|
||||
|
||||
CellStyle number = workbook.createCellStyle();
|
||||
number.cloneStyleFrom(text);
|
||||
number.setAlignment(HorizontalAlignment.RIGHT);
|
||||
number.setDataFormat(amountFormat);
|
||||
styles.put("number", number);
|
||||
|
||||
CellStyle ratio = workbook.createCellStyle();
|
||||
ratio.cloneStyleFrom(number);
|
||||
ratio.setDataFormat(percentFormat);
|
||||
styles.put("ratio", ratio);
|
||||
|
||||
CellStyle empty = workbook.createCellStyle();
|
||||
empty.setFont(emptyFont);
|
||||
styles.put("empty", empty);
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
private void applyBorder(CellStyle style) {
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
}
|
||||
|
||||
private void writeValueCell(Row row, int cellIndex, String key, Object value, Map<String, CellStyle> styles) {
|
||||
if (value instanceof BigDecimal decimal) {
|
||||
createNumericCell(row, cellIndex, decimal, styleForKey(styles, key));
|
||||
return;
|
||||
}
|
||||
if (value instanceof Number number) {
|
||||
createNumericCell(row, cellIndex, BigDecimal.valueOf(number.doubleValue()), styleForKey(styles, key));
|
||||
return;
|
||||
}
|
||||
createCell(row, cellIndex, value == null ? "" : String.valueOf(value), styles.get("text"));
|
||||
}
|
||||
|
||||
private void createCell(Row row, int index, String value, CellStyle style) {
|
||||
var cell = row.createCell(index);
|
||||
cell.setCellValue(value);
|
||||
cell.setCellStyle(style);
|
||||
}
|
||||
|
||||
private void createNumericCell(Row row, int index, BigDecimal value, CellStyle style) {
|
||||
var cell = row.createCell(index);
|
||||
cell.setCellValue(value.doubleValue());
|
||||
cell.setCellStyle(style);
|
||||
}
|
||||
|
||||
private CellStyle styleForKey(Map<String, CellStyle> styles, String key) {
|
||||
return key.toLowerCase().contains("ratio") ? styles.get("ratio") : styles.get("number");
|
||||
}
|
||||
|
||||
private void addPdfTitle(Document document, String text, int size, Color color) {
|
||||
Font font = FontFactory.getFont(FontFactory.HELVETICA_BOLD, size, color);
|
||||
Paragraph paragraph = new Paragraph(text, font);
|
||||
paragraph.setAlignment(Element.ALIGN_LEFT);
|
||||
paragraph.setSpacingAfter(4f);
|
||||
document.add(paragraph);
|
||||
}
|
||||
|
||||
private void addSummaryTable(Document document, Map<String, BigDecimal> metrics) {
|
||||
PdfPTable table = new PdfPTable(new float[] {3f, 1.3f});
|
||||
table.setWidthPercentage(100f);
|
||||
table.setSpacingBefore(6f);
|
||||
table.setSpacingAfter(12f);
|
||||
table.addCell(pdfHeaderCell("Metric"));
|
||||
table.addCell(pdfHeaderCell("Value"));
|
||||
for (Map.Entry<String, BigDecimal> metric : metrics.entrySet()) {
|
||||
table.addCell(pdfBodyCell(label(metric.getKey()), Element.ALIGN_LEFT));
|
||||
table.addCell(pdfBodyCell(format(metric.getValue(), metric.getKey()), Element.ALIGN_RIGHT));
|
||||
}
|
||||
document.add(table);
|
||||
}
|
||||
|
||||
private void addDetailTable(Document document, String title, List<Map<String, Object>> rows, int maxRows) {
|
||||
Font sectionFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 12, new Color(24, 54, 93));
|
||||
Paragraph section = new Paragraph(title, sectionFont);
|
||||
section.setSpacingBefore(8f);
|
||||
section.setSpacingAfter(6f);
|
||||
document.add(section);
|
||||
|
||||
if (rows.isEmpty()) {
|
||||
document.add(new Paragraph("No data available", FontFactory.getFont(FontFactory.HELVETICA_OBLIQUE, 10, new Color(120, 120, 120))));
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> keys = List.copyOf(rows.get(0).keySet());
|
||||
PdfPTable table = new PdfPTable(keys.size());
|
||||
table.setWidthPercentage(100f);
|
||||
table.setSpacingAfter(8f);
|
||||
for (String key : keys) {
|
||||
table.addCell(pdfHeaderCell(label(key)));
|
||||
}
|
||||
|
||||
int visibleRows = Math.min(maxRows, rows.size());
|
||||
for (int rowIndex = 0; rowIndex < visibleRows; rowIndex++) {
|
||||
Map<String, Object> row = rows.get(rowIndex);
|
||||
for (String key : keys) {
|
||||
int alignment = isNumericValue(row.get(key)) ? Element.ALIGN_RIGHT : Element.ALIGN_LEFT;
|
||||
table.addCell(pdfBodyCell(format(row.get(key), key), alignment));
|
||||
}
|
||||
}
|
||||
document.add(table);
|
||||
|
||||
if (rows.size() > maxRows) {
|
||||
document.add(new Paragraph(
|
||||
"Showing first " + maxRows + " of " + rows.size() + " rows.",
|
||||
FontFactory.getFont(FontFactory.HELVETICA_OBLIQUE, 9, new Color(120, 120, 120))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private PdfPCell pdfHeaderCell(String text) {
|
||||
PdfPCell cell = new PdfPCell(new Phrase(text, FontFactory.getFont(FontFactory.HELVETICA_BOLD, 9, Color.WHITE)));
|
||||
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
|
||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
|
||||
cell.setBackgroundColor(new Color(243, 127, 32));
|
||||
cell.setBorderColor(new Color(220, 220, 220));
|
||||
cell.setPadding(6f);
|
||||
return cell;
|
||||
}
|
||||
|
||||
private PdfPCell pdfBodyCell(String text, int alignment) {
|
||||
PdfPCell cell = new PdfPCell(new Phrase(text, FontFactory.getFont(FontFactory.HELVETICA, 9, Color.DARK_GRAY)));
|
||||
cell.setHorizontalAlignment(alignment);
|
||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
|
||||
cell.setBorderColor(new Color(226, 229, 233));
|
||||
cell.setPadding(5f);
|
||||
return cell;
|
||||
}
|
||||
|
||||
private boolean isNumericValue(Object value) {
|
||||
return value instanceof Number || value instanceof BigDecimal;
|
||||
}
|
||||
|
||||
private String format(Object value, String key) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
if (value instanceof BigDecimal decimal) {
|
||||
return format(decimal, key);
|
||||
}
|
||||
if (value instanceof Number number) {
|
||||
return format(BigDecimal.valueOf(number.doubleValue()), key);
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
private String format(BigDecimal value, String key) {
|
||||
if (key.toLowerCase().contains("ratio")) {
|
||||
return AMOUNT_FORMAT.format(value.multiply(BigDecimal.valueOf(100))) + "%";
|
||||
}
|
||||
return AMOUNT_FORMAT.format(value);
|
||||
}
|
||||
|
||||
private String label(String key) {
|
||||
return LABELS.getOrDefault(key, key);
|
||||
}
|
||||
|
||||
private String generatedAt() {
|
||||
return ZonedDateTime.now(ZoneId.of("Asia/Seoul")).format(REPORT_TIME_FORMAT);
|
||||
}
|
||||
|
||||
private static Map<String, String> buildLabels() {
|
||||
Map<String, String> labels = new LinkedHashMap<>();
|
||||
labels.put("acceptedTrialRows", "Accepted Trial Rows");
|
||||
labels.put("acceptedForecastRows", "Accepted Forecast Rows");
|
||||
labels.put("grossContributionKrw", "Gross Contribution (KRW)");
|
||||
labels.put("eliminationKrw", "Elimination (KRW)");
|
||||
labels.put("forecastKrw", "Forecast (KRW)");
|
||||
labels.put("netContributionKrw", "Net Contribution (KRW)");
|
||||
labels.put("entityCode", "Entity Code");
|
||||
labels.put("accountCode", "Account Code");
|
||||
labels.put("partnerEntityCode", "Partner Entity");
|
||||
labels.put("translatedAmount", "Translated Amount");
|
||||
labels.put("ownershipRatio", "Ownership Ratio");
|
||||
labels.put("finalAmount", "Final Amount");
|
||||
labels.put("internalTrade", "Internal Trade");
|
||||
labels.put("eliminationAmount", "Elimination Amount");
|
||||
labels.put("note", "Note");
|
||||
labels.put("scenarioCode", "Scenario");
|
||||
return labels;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.hanwha.nexacrodemo.upload.TestWorkbookFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
|
|
@ -29,6 +34,9 @@ class ConsolidationIntegrationTest {
|
|||
@Autowired
|
||||
private ConsolidationService consolidationService;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Test
|
||||
void validUploadsCanBeConsolidatedAndReported() throws Exception {
|
||||
MockHttpSession session = login("operator", "demo1234");
|
||||
|
|
@ -55,10 +63,33 @@ class ConsolidationIntegrationTest {
|
|||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.datasets.runs[0].statusCode").value("SUCCESS"));
|
||||
|
||||
mockMvc.perform(get("/api/tx/reports/overview").session(session))
|
||||
MvcResult overviewResult = mockMvc.perform(get("/api/tx/reports/overview").session(session))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.datasets.artifacts.length()").value(2))
|
||||
.andExpect(jsonPath("$.datasets.jobLogs[0].logLevel").exists());
|
||||
.andExpect(jsonPath("$.datasets.jobLogs[0].logLevel").exists())
|
||||
.andReturn();
|
||||
|
||||
JsonNode artifacts = objectMapper.readTree(overviewResult.getResponse().getContentAsByteArray())
|
||||
.path("datasets")
|
||||
.path("artifacts");
|
||||
long excelArtifactId = -1L;
|
||||
for (JsonNode artifact : artifacts) {
|
||||
if ("EXCEL".equals(artifact.path("artifactType").asText())) {
|
||||
excelArtifactId = artifact.path("id").asLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assertions.assertTrue(excelArtifactId > 0, "EXCEL artifact should exist");
|
||||
|
||||
MvcResult excelDownload = mockMvc.perform(get("/api/reports/{artifactId}/download", excelArtifactId).session(session))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
try (var workbook = WorkbookFactory.create(new ByteArrayInputStream(excelDownload.getResponse().getContentAsByteArray()))) {
|
||||
Assertions.assertEquals("Hanwha Consolidation Summary", workbook.getSheet("Summary").getRow(0).getCell(0).getStringCellValue());
|
||||
Assertions.assertEquals("Entity Code", workbook.getSheet("Contributions").getRow(3).getCell(0).getStringCellValue());
|
||||
Assertions.assertNotNull(workbook.getSheet("Forecast"));
|
||||
}
|
||||
}
|
||||
|
||||
private void upload(MockHttpSession session, String templateCode, String fileName, byte[] content) throws Exception {
|
||||
|
|
|
|||
Loading…
Reference in New Issue