| @@ -1404,50 +1404,54 @@ open class ReportService( | |||
| return workbook | |||
| } | |||
| //createLateStartReport | |||
| private fun createLateStartReport( | |||
| team: List<Team>, | |||
| customer: List<Customer>, | |||
| templatePath: String, | |||
| teamId: Long, | |||
| clientId: Long, | |||
| lateStartData: List<Map<String, Any>> | |||
| ): Workbook { | |||
| val resource = ClassPathResource(templatePath) | |||
| val templateInputStream = resource.inputStream | |||
| val workbook: Workbook = XSSFWorkbook(templateInputStream) | |||
| val sheet = workbook.getSheetAt(0) | |||
| val evaluator: FormulaEvaluator = workbook.creationHelper.createFormulaEvaluator() | |||
| // Apply standard and custom fonts | |||
| applyStandardAndCustomFonts(workbook, sheet) | |||
| // Formatting the date in cell C2 | |||
| setDateInCellC2(workbook, sheet) | |||
| setTeamAndClientIds(sheet, team, teamId, customer, clientId) | |||
| // Set data and conditional formatting in columns | |||
| setDataAndConditionalFormatting(workbook, sheet, lateStartData, evaluator) | |||
| // Auto-size columns to fit content | |||
| autoSizeColumns(sheet) | |||
| return workbook | |||
| } | |||
| //createLateStartReport | |||
| private fun createLateStartReport( | |||
| team: List<Team>, | |||
| customer: List<Customer>, | |||
| templatePath: String, | |||
| teamId: Long, | |||
| clientId: Long, | |||
| lateStartData: List<Map<String, Any>> | |||
| ): Workbook { | |||
| val resource = ClassPathResource(templatePath) | |||
| val templateInputStream = resource.inputStream | |||
| val workbook: Workbook = XSSFWorkbook(templateInputStream) | |||
| val sheet = workbook.getSheetAt(0) | |||
| val evaluator: FormulaEvaluator = workbook.creationHelper.createFormulaEvaluator() | |||
| // Apply standard and custom fonts | |||
| applyStandardAndCustomFonts(workbook, sheet) | |||
| // Set the current date in cell C2 | |||
| setDateInCellC2(workbook, sheet) | |||
| // Populate team and client information based on IDs | |||
| setTeamAndClientIds(sheet, team, teamId, customer, clientId) | |||
| // Process late start data, and apply data and conditional formatting to the sheet | |||
| setDataAndConditionalFormatting(workbook, sheet, lateStartData, evaluator) | |||
| // Automatically adjust column widths to fit content | |||
| autoSizeColumns(sheet) | |||
| return workbook | |||
| } | |||
| // Configures standard and custom fonts within the workbook and applies specific styles to cells. | |||
| private fun applyStandardAndCustomFonts(workbook: Workbook, sheet: Sheet) { | |||
| // Create and configure a bold Times New Roman font for general use | |||
| val timesNewRoman = workbook.createFont().apply { | |||
| fontName = "Times New Roman" | |||
| fontHeightInPoints = 12 | |||
| bold = true | |||
| } | |||
| // Create and configure a larger, bold Times New Roman font for prominent headers | |||
| val timesNewRomanLarge = workbook.createFont().apply { | |||
| fontName = "Times New Roman" | |||
| fontHeightInPoints = 16 | |||
| bold = true | |||
| } | |||
| // Apply custom font size for A1 | |||
| // Apply the larger custom font size to cell A1 for header emphasis | |||
| val rowA1 = sheet.getRow(0) ?: sheet.createRow(0) | |||
| val cellA1 = rowA1.getCell(0) ?: rowA1.createCell(0) | |||
| val cellStyleA1 = workbook.createCellStyle().apply { | |||
| @@ -1455,7 +1459,8 @@ private fun createLateStartReport( | |||
| setFont(timesNewRomanLarge) | |||
| } | |||
| cellA1.cellStyle = cellStyleA1 | |||
| // Apply styles from A2 to A4 (bold) | |||
| // Apply standard bold font to cells A2 to A4 | |||
| val boldCellStyle = workbook.createCellStyle().apply { setFont(timesNewRoman) } | |||
| listOf(1, 2, 3).forEach { rowIndex -> | |||
| val row = sheet.getRow(rowIndex) ?: sheet.createRow(rowIndex) | |||
| @@ -1463,39 +1468,42 @@ private fun createLateStartReport( | |||
| cell.cellStyle = boldCellStyle | |||
| } | |||
| // Apply styles from A6 to J6 (bold, bottom border, center alignment) | |||
| // Apply a bold, bottom-bordered, center-aligned style to header cells from A6 to J6 | |||
| val styleA6ToJ6 = workbook.createCellStyle().apply { | |||
| setFont(timesNewRoman) // Use the standard bold font for consistency | |||
| alignment = HorizontalAlignment.CENTER | |||
| borderBottom = BorderStyle.THIN | |||
| } | |||
| // Apply styleA6ToJ6 to cells A6 to J6 | |||
| val rowA6 = sheet.getRow(5) ?: sheet.createRow(5) | |||
| (0..9).forEach { colIndex -> | |||
| val cell = rowA6.getCell(colIndex) ?: rowA6.createCell(colIndex) | |||
| cell.cellStyle = styleA6ToJ6 | |||
| } | |||
| } | |||
| // Sets the current data in the Excel sheet at cell C2 using a specified date format | |||
| private fun setDateInCellC2(workbook: Workbook, sheet: Sheet) { | |||
| // Format the current date to "yyyy/MM/dd" and set 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) | |||
| } | |||
| // Populates the Excel sheet with late start data and applies conditional formatting based on criteria. | |||
| private fun setDataAndConditionalFormatting( | |||
| workbook: Workbook, | |||
| sheet: Sheet, | |||
| lateStartData: List<Map<String, Any>>, | |||
| evaluator: FormulaEvaluator | |||
| ) { | |||
| var dataRowIndex = 6 // Starting from row 7 | |||
| var dataRowIndex = 6 // Start populating data from row index 7 | |||
| lateStartData.forEachIndexed { index, data -> | |||
| val row = sheet.getRow(dataRowIndex) ?: sheet.createRow(dataRowIndex) | |||
| populateDataRow(workbook, sheet, row, data, index) | |||
| dataRowIndex++ | |||
| } | |||
| // Update conditional formatting to apply to the new range of column J | |||
| // Update and apply conditional formatting to highlight specific values in column J | |||
| val sheetCF = sheet.sheetConditionalFormatting | |||
| val rule1 = sheetCF.createConditionalFormattingRule("J7 < 60") | |||
| val pattern1 = rule1.createPatternFormatting().apply { | |||
| @@ -1510,34 +1518,37 @@ private fun createLateStartReport( | |||
| val region = CellRangeAddress(dataRowIndex - lateStartData.size, dataRowIndex - 1, 9, 9) // Column J | |||
| sheetCF.addConditionalFormatting(arrayOf(region), arrayOf(rule1, rule2)) | |||
| } | |||
| // Sets team and client IDs in the sheet to manage data visibility based on the selected team and client | |||
| private fun setTeamAndClientIds(sheet: Sheet, team: List<Team>, teamId: Long, customer: List<Customer>, clientId: Long) { | |||
| // Set the 'teamId' value in cell C3 | |||
| // Insert the team name or "All" if no specific team is selected in cell C3 | |||
| val teamIdRow = sheet.getRow(2) ?: sheet.createRow(2) | |||
| val teamIdCell = teamIdRow.getCell(2) ?: teamIdRow.createCell(2) | |||
| teamIdCell.setCellValue(if (teamId == 0L) "All" else team.getOrNull(0)?.name ?: "Unknown") | |||
| // Set the 'clientId' value in cell C4 | |||
| // Insert the client name or "All" if no specific client is selecred in cell C4 | |||
| val clientIdRow = sheet.getRow(3) ?: sheet.createRow(3) | |||
| val clientIdCell = clientIdRow.getCell(2) ?: clientIdRow.createCell(2) | |||
| clientIdCell.setCellValue(if (clientId == 0L) "All" else customer.getOrNull(0)?.name ?: "Unknown") | |||
| } | |||
| // Populates a single row with data from a map and applies formatting and formulas | |||
| private fun populateDataRow(workbook: Workbook, sheet: Sheet, row: Row, data: Map<String, Any>, index: Int) { | |||
| val dateFormat = workbook.creationHelper.createDataFormat().getFormat("yyyy/MM/dd") | |||
| // Define the font for general use (if not already defined elsewhere) | |||
| // Define a font for general use throughout the row | |||
| val generalFont = workbook.createFont().apply { | |||
| fontName = "Times New Roman" | |||
| fontHeightInPoints = 12 // Standard size | |||
| fontHeightInPoints = 12 // Standard size is 11 | |||
| } | |||
| // Create and apply a date format style for date cells | |||
| val dateCellStyle = workbook.createCellStyle().apply { | |||
| dataFormat = dateFormat | |||
| setFont(generalFont) // Apply the font here along with the date format | |||
| setFont(generalFont) // Maintain consistency in font usage | |||
| } | |||
| // Create a style for center alignment for column G | |||
| // Style for center alignment, used in calcalated columns | |||
| val centerAlignedStyle = workbook.createCellStyle().apply { | |||
| alignment = HorizontalAlignment.CENTER | |||
| setFont(generalFont) // Maintain font consistency | |||
| setFont(generalFont) // Ensure font consistency | |||
| } | |||
| // Column A: Sequential ID | |||
| @@ -1561,9 +1572,6 @@ private fun createLateStartReport( | |||
| customerNameCell.setCellValue(data["customer_name"] as String) | |||
| // // Column F: Project Plan Start Date | |||
| // val projectPlanStartCell = row.createCell(5) | |||
| // projectPlanStartCell.setCellValue(data["project_plan_start"].toString()) | |||
| // Parse the project start date and apply the date format | |||
| val projectPlanStartCell = row.createCell(5) | |||
| try { | |||
| @@ -1583,7 +1591,7 @@ private fun createLateStartReport( | |||
| val taskGroupNameCell = row.createCell(7) | |||
| taskGroupNameCell.setCellValue(data["task_group_name"] as String) | |||
| // // Column I: Milestone End Date | |||
| // Column I: Milestone End Date | |||
| val dateCell = row.createCell(8) // Milestone end date in column I | |||
| try { | |||
| val date = LocalDate.parse(data["milestone_end_date"].toString()) | |||
| @@ -1593,7 +1601,7 @@ private fun createLateStartReport( | |||
| } | |||
| dateCell.cellStyle = dateCellStyle | |||
| // Get the current date and parse the milestone end date | |||
| // Calculate the days between current date and milestone end date, and display in column J | |||
| val today = LocalDate.now() | |||
| val endDate = LocalDate.parse(data["milestone_end_date"].toString(), DateTimeFormatter.ISO_LOCAL_DATE) | |||
| val daysBetween = ChronoUnit.DAYS.between(today, endDate).toInt() // Calculate the difference in days | |||
| @@ -1601,12 +1609,12 @@ private fun createLateStartReport( | |||
| val daysDifferenceCellJ = row.createCell(9) | |||
| daysDifferenceCellJ.setCellValue(daysBetween.toDouble()) // Set as double for consistency | |||
| daysDifferenceCellJ.cellStyle = centerAlignedStyle | |||
| } | |||
| // Automatically adjusts the width if all columns in the sheet to fit their content optimally. | |||
| private fun autoSizeColumns(sheet: Sheet) { | |||
| for (colIndex in 0..9) { | |||
| sheet.autoSizeColumn(colIndex) | |||
| for (colIndex in 0..9) { // Iterate through columns A to J | |||
| sheet.autoSizeColumn(colIndex) // Auto-size each column based on its content | |||
| } | |||
| } | |||