Refactor report generation and enhance integration tests
- Updated ReportService to streamline Excel report merging logic by introducing a new method for conditional merging. - Enhanced integration tests to include fiscal period handling and ensure correct artifact generation, particularly for scenarios with empty forecast sections. - Improved test assertions to validate the presence of expected artifacts and their properties in the generated reports.
This commit is contained in:
parent
661d78a225
commit
a01aa46f3e
|
|
@ -201,11 +201,11 @@ public class ReportService {
|
|||
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)));
|
||||
mergeIfNeeded(sheet, 0, columnCount);
|
||||
|
||||
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)));
|
||||
mergeIfNeeded(sheet, 1, columnCount);
|
||||
|
||||
if (rows.isEmpty()) {
|
||||
Row emptyRow = sheet.createRow(3);
|
||||
|
|
@ -347,6 +347,12 @@ public class ReportService {
|
|||
cell.setCellStyle(style);
|
||||
}
|
||||
|
||||
private void mergeIfNeeded(Sheet sheet, int rowIndex, int columnCount) {
|
||||
if (columnCount > 1) {
|
||||
sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 0, columnCount - 1));
|
||||
}
|
||||
}
|
||||
|
||||
private CellStyle styleForKey(Map<String, CellStyle> styles, String key) {
|
||||
return key.toLowerCase().contains("ratio") ? styles.get("ratio") : styles.get("number");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.hanwha.nexacrodemo.upload.TestWorkbookFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -20,12 +21,14 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
class ConsolidationIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
|
|
@ -39,24 +42,27 @@ class ConsolidationIntegrationTest {
|
|||
|
||||
@Test
|
||||
void validUploadsCanBeConsolidatedAndReported() throws Exception {
|
||||
String fiscalPeriod = "2026-04";
|
||||
MockHttpSession session = login("operator", "demo1234");
|
||||
|
||||
upload(session, "trial-balance", "tb-valid.xlsx", TestWorkbookFactory.trialBalanceValid());
|
||||
upload(session, "forecast", "forecast-valid.xlsx", TestWorkbookFactory.forecastValid());
|
||||
upload(session, "trial-balance", fiscalPeriod, "tb-valid.xlsx", withFiscalPeriod(TestWorkbookFactory.trialBalanceValid(), fiscalPeriod));
|
||||
upload(session, "forecast", fiscalPeriod, "forecast-valid.xlsx", withFiscalPeriod(TestWorkbookFactory.forecastValid(), fiscalPeriod));
|
||||
|
||||
MvcResult runResult = mockMvc.perform(post("/api/consolidations/runs")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.session(session)
|
||||
.content("""
|
||||
{
|
||||
"fiscalPeriod": "2026-03",
|
||||
"fiscalPeriod": "%s",
|
||||
"reportCurrency": "KRW"
|
||||
}
|
||||
"""))
|
||||
""".formatted(fiscalPeriod)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.statusCode").value("REQUESTED"))
|
||||
.andReturn();
|
||||
|
||||
long runId = objectMapper.readTree(runResult.getResponse().getContentAsByteArray()).path("id").asLong();
|
||||
|
||||
consolidationService.processPendingRuns("test-worker");
|
||||
|
||||
mockMvc.perform(get("/api/tx/consolidations/overview").session(session))
|
||||
|
|
@ -65,20 +71,24 @@ class ConsolidationIntegrationTest {
|
|||
|
||||
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())
|
||||
.andReturn();
|
||||
|
||||
JsonNode artifacts = objectMapper.readTree(overviewResult.getResponse().getContentAsByteArray())
|
||||
.path("datasets")
|
||||
.path("artifacts");
|
||||
int artifactCountForRun = 0;
|
||||
long excelArtifactId = -1L;
|
||||
for (JsonNode artifact : artifacts) {
|
||||
if (artifact.path("runId").asLong() != runId) {
|
||||
continue;
|
||||
}
|
||||
artifactCountForRun++;
|
||||
if ("EXCEL".equals(artifact.path("artifactType").asText())) {
|
||||
excelArtifactId = artifact.path("id").asLong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assertions.assertEquals(2, artifactCountForRun);
|
||||
Assertions.assertTrue(excelArtifactId > 0, "EXCEL artifact should exist");
|
||||
|
||||
MvcResult excelDownload = mockMvc.perform(get("/api/reports/{artifactId}/download", excelArtifactId).session(session))
|
||||
|
|
@ -92,7 +102,61 @@ class ConsolidationIntegrationTest {
|
|||
}
|
||||
}
|
||||
|
||||
private void upload(MockHttpSession session, String templateCode, String fileName, byte[] content) throws Exception {
|
||||
@Test
|
||||
void consolidationStillSucceedsWhenForecastSectionIsEmpty() throws Exception {
|
||||
String fiscalPeriod = "2026-03";
|
||||
MockHttpSession session = login("operator", "demo1234");
|
||||
|
||||
upload(session, "trial-balance", fiscalPeriod, "tb-valid.xlsx", TestWorkbookFactory.trialBalanceValid());
|
||||
|
||||
MvcResult runResult = mockMvc.perform(post("/api/consolidations/runs")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.session(session)
|
||||
.content("""
|
||||
{
|
||||
"fiscalPeriod": "%s",
|
||||
"reportCurrency": "KRW"
|
||||
}
|
||||
""".formatted(fiscalPeriod)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.statusCode").value("REQUESTED"))
|
||||
.andReturn();
|
||||
|
||||
long runId = objectMapper.readTree(runResult.getResponse().getContentAsByteArray()).path("id").asLong();
|
||||
|
||||
consolidationService.processPendingRuns("test-worker");
|
||||
|
||||
MvcResult overviewResult = mockMvc.perform(get("/api/tx/reports/overview").session(session))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
JsonNode artifacts = objectMapper.readTree(overviewResult.getResponse().getContentAsByteArray())
|
||||
.path("datasets")
|
||||
.path("artifacts");
|
||||
int artifactCountForRun = 0;
|
||||
long excelArtifactId = -1L;
|
||||
for (JsonNode artifact : artifacts) {
|
||||
if (artifact.path("runId").asLong() != runId) {
|
||||
continue;
|
||||
}
|
||||
artifactCountForRun++;
|
||||
if ("EXCEL".equals(artifact.path("artifactType").asText())) {
|
||||
excelArtifactId = artifact.path("id").asLong();
|
||||
}
|
||||
}
|
||||
Assertions.assertEquals(2, artifactCountForRun);
|
||||
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("No data available", workbook.getSheet("Forecast").getRow(3).getCell(0).getStringCellValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void upload(MockHttpSession session, String templateCode, String fiscalPeriod, String fileName, byte[] content) throws Exception {
|
||||
MockMultipartFile file = new MockMultipartFile(
|
||||
"file",
|
||||
fileName,
|
||||
|
|
@ -103,12 +167,27 @@ class ConsolidationIntegrationTest {
|
|||
mockMvc.perform(multipart("/api/uploads")
|
||||
.file(file)
|
||||
.param("templateCode", templateCode)
|
||||
.param("fiscalPeriod", "2026-03")
|
||||
.param("fiscalPeriod", fiscalPeriod)
|
||||
.session(session))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.statusCode").value("ACCEPTED"));
|
||||
}
|
||||
|
||||
private byte[] withFiscalPeriod(byte[] content, String fiscalPeriod) throws Exception {
|
||||
try (var workbook = WorkbookFactory.create(new ByteArrayInputStream(content))) {
|
||||
var dataSheet = workbook.getSheet("DATA");
|
||||
for (int rowIndex = 1; rowIndex <= dataSheet.getLastRowNum(); rowIndex++) {
|
||||
var row = dataSheet.getRow(rowIndex);
|
||||
if (row != null && row.getCell(0) != null) {
|
||||
row.getCell(0).setCellValue(fiscalPeriod);
|
||||
}
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
workbook.write(outputStream);
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private MockHttpSession login(String username, String password) throws Exception {
|
||||
MvcResult result = mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
|
|||
Loading…
Reference in New Issue