diff --git a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt index 075384c..9fccc85 100644 --- a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt +++ b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt @@ -16,6 +16,7 @@ import java.io.IOException import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.* +import org.apache.poi.ss.util.CellAddress data class DayInfo(val date: String?, val weekday: String?) @Service @@ -26,6 +27,7 @@ open class ReportService { private val PROJECT_CASH_FLOW_REPORT = "templates/report/EX02_Project Cash Flow Report.xlsx" private val MONTHLY_WORK_HOURS_ANALYSIS_REPORT = "templates/report/AR08_Monthly Work Hours Analysis Report.xlsx" private val SALART_LIST_TEMPLATE = "templates/report/Salary Template.xlsx" + private val LATE_START_REPORT = "templates/report/AR01_Late Start Report v01.xlsx" // ==============================|| GENERATE REPORT ||============================== // @Throws(IOException::class) @@ -67,6 +69,15 @@ open class ReportService { return outputStream.toByteArray() } + @Throws(IOException::class) + fun generateLateStartReport(project: Project): ByteArray { + val workbook: Workbook = createLateStartReport(project,LATE_START_REPORT) + val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() + workbook.write(outputStream) + workbook.close() + return outputStream.toByteArray() + } + // ==============================|| CREATE REPORT ||============================== // @Throws(IOException::class) private fun createProjectCashFlowReport( @@ -83,7 +94,7 @@ open class ReportService { val sheet: Sheet = workbook.getSheetAt(0) // accounting style + comma style - val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") + val accountingStyle = workbook.createDataFormat() .getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") var rowIndex = 1 // Assuming the location is in (1,2), which is the report date field var columnIndex = 2 @@ -529,4 +540,75 @@ open class ReportService { return workbook } + private fun createLateStartReport( + project: Project, + templatePath: String + ):Workbook{ + + project + val resource = ClassPathResource(templatePath) + val templateInputStream = resource.inputStream + val workbook: Workbook = XSSFWorkbook(templateInputStream) + val sheet = workbook.getSheetAt(0) + + // Formatting the current date to "YYYY/MM/DD" and setting it to cell C2 + val formattedToday = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")) + val dateCell = sheet.getRow(1)?.getCell(2) ?: sheet.getRow(1).createCell(2) + dateCell.setCellValue(formattedToday) + + // Styling for cell A1: Font size 16 and bold + val headerFont = workbook.createFont().apply { + bold = true + fontHeightInPoints = 16 + } + val headerCellStyle = workbook.createCellStyle().apply { + setFont(headerFont) + } + val headerCell = sheet.getRow(0)?.getCell(0) ?: sheet.getRow(0).createCell(0) + headerCell.cellStyle = headerCellStyle + headerCell.setCellValue("Report Title") + + // Apply styles from A2 to A4 (bold) + val boldFont = workbook.createFont().apply { bold = true } + val boldCellStyle = workbook.createCellStyle().apply { setFont(boldFont) } + listOf(1, 2, 3).forEach { rowIndex -> + val row = sheet.getRow(rowIndex) + val cell = row?.getCell(0) ?: row.createCell(0) + cell.cellStyle = boldCellStyle + } + + // Apply styles from A6 to J6 (bold, bottom border, center alignment) + val styleA6ToJ6 = workbook.createCellStyle().apply { + setFont(boldFont) + alignment = HorizontalAlignment.CENTER + borderBottom = BorderStyle.THIN + } + for (colIndex in 0..9) { + val cellAddress = CellAddress(5, colIndex) // Row 6 (0-based index), Columns A to J + val row = sheet.getRow(cellAddress.row) + val cell = row?.getCell(cellAddress.column) ?: row.createCell(cellAddress.column) + cell.cellStyle = styleA6ToJ6 + } + + // Setting column widths dynamically based on content length (example logic) + val maxContentWidths = IntArray(10) { 8 } // Initial widths for A to J + for (rowIndex in 0..sheet.lastRowNum) { + val row = sheet.getRow(rowIndex) + for (colIndex in 0..9) { + val cell = row.getCell(colIndex) + if (cell != null) { + val length = cell.toString().length + if (length > maxContentWidths[colIndex]) { + maxContentWidths[colIndex] = length + } + } + } + } + for (colIndex in 0..9) { + sheet.setColumnWidth(colIndex, (maxContentWidths[colIndex] + 2) * 256) // Set the width for each column + } + + return workbook + } + } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt b/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt index 3fa4166..12e1ec9 100644 --- a/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt +++ b/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt @@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType import java.io.IOException import java.time.LocalDate @@ -80,4 +82,18 @@ class ReportController( val project = projectRepository.findById(id).orElseThrow() return invoiceService.findAllByProjectAndPaidAmountIsNotNull(project) } + + @PostMapping("/downloadLateStartReport") + fun downloadLateStartReport(): ResponseEntity { + val reportBytes = excelReportService.generateLateStartReport() + val headers = HttpHeaders() + headers.add("Content-Disposition", "attachment; filename=Late_Start_Report_${LocalDate.now()}.xlsx") + + return ResponseEntity.ok() + .headers(headers) + .contentLength(reportBytes.size.toLong()) + .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) + .body(ByteArrayResource(reportBytes)) + } + } \ No newline at end of file