From d18f4c0a6bc2da3819f087867c732e56bbf95719 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Thu, 16 May 2024 18:22:04 +0800 Subject: [PATCH 1/4] update --- .../modules/data/entity/StaffRepository.java | 3 +- .../modules/data/service/StaffsService.kt | 2 +- .../modules/report/service/ReportService.kt | 301 +++++++++++------- 3 files changed, 184 insertions(+), 122 deletions(-) diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java index 46eb775..3b0b4d1 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java @@ -5,6 +5,7 @@ import com.ffii.core.support.AbstractRepository; import com.ffii.tsms.modules.data.entity.projections.StaffSearchInfo; import org.springframework.data.repository.query.Param; +import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.Optional; @@ -13,7 +14,7 @@ public interface StaffRepository extends AbstractRepository { List findStaffSearchInfoByAndDeletedFalse(); List findStaffSearchInfoByAndDeletedFalseAndTeamIdIsNull(); - List findAllStaffSearchInfoByIdIn(List ids); + List findAllStaffSearchInfoByIdIn(List ids); Optional findByStaffId(@Param("staffId") String staffId); Optional findStaffSearchInfoById(@Param("id") Long id); diff --git a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt index 9fd341f..14dccc6 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt @@ -35,7 +35,7 @@ open class StaffsService( ) : AbstractBaseEntityService(jdbcDao, staffRepository) { open fun getTeamLeads(): List { // TODO: Replace by actual logic - val teamIds = teamRepository.findAll().map { team -> team.staff.id } + val teamIds = teamRepository.findAll().filter { team -> team.deleted == false }.map { team -> team.staff.id } return staffRepository.findAllStaffSearchInfoByIdIn(teamIds) } 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 373e7ac..c249c81 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 @@ -7,6 +7,7 @@ import com.ffii.tsms.modules.project.entity.Invoice import com.ffii.tsms.modules.project.entity.Project import com.ffii.tsms.modules.timesheet.entity.Leave import com.ffii.tsms.modules.timesheet.entity.Timesheet +import com.ffii.tsms.modules.timesheet.web.models.LeaveEntry import org.apache.commons.logging.Log import org.apache.commons.logging.LogFactory import org.apache.poi.ss.usermodel.* @@ -20,13 +21,14 @@ import java.io.IOException import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.* +import kotlin.time.times data class DayInfo(val date: String?, val weekday: String?) + @Service -open class ReportService ( +open class ReportService( private val jdbcDao: JdbcDao, - ) -{ +) { private val logger: Log = LogFactory.getLog(javaClass) private val DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd") private val FORMATTED_TODAY = LocalDate.now().format(DATE_FORMATTER) @@ -48,8 +50,13 @@ open class ReportService ( return outputStream.toByteArray() } + @Throws(IOException::class) - fun generateProjectCashFlowReport(project: Project, invoices: List, timesheets: List): ByteArray { + fun generateProjectCashFlowReport( + project: Project, + invoices: List, + timesheets: List + ): ByteArray { // Generate the Excel report with query results val workbook: Workbook = createProjectCashFlowReport(project, invoices, timesheets, PROJECT_CASH_FLOW_REPORT) @@ -62,9 +69,22 @@ open class ReportService ( } @Throws(IOException::class) - fun generateStaffMonthlyWorkHourAnalysisReport(month: LocalDate, staff: Staff, timesheets: List, leaves: List, projectList: List): ByteArray { + fun generateStaffMonthlyWorkHourAnalysisReport( + month: LocalDate, + staff: Staff, + timesheets: List, + leaves: List, + projectList: List + ): ByteArray { // Generate the Excel report with query results - val workbook: Workbook = createStaffMonthlyWorkHourAnalysisReport(month, staff, timesheets, leaves, projectList, MONTHLY_WORK_HOURS_ANALYSIS_REPORT) + val workbook: Workbook = createStaffMonthlyWorkHourAnalysisReport( + month, + staff, + timesheets, + leaves, + projectList, + MONTHLY_WORK_HOURS_ANALYSIS_REPORT + ) // Write the workbook to a ByteArrayOutputStream val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() @@ -89,7 +109,7 @@ open class ReportService ( @Throws(IOException::class) fun generateLateStartReport(project: Project): ByteArray { - val workbook: Workbook = createLateStartReport(project,LATE_START_REPORT) + val workbook: Workbook = createLateStartReport(project, LATE_START_REPORT) val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() workbook.write(outputStream) workbook.close() @@ -102,7 +122,7 @@ open class ReportService ( private fun createFinancialStatusReport( templatePath: String, projectId: Long, - ) : Workbook { + ): Workbook { val resource = ClassPathResource(templatePath) val templateInputStream = resource.inputStream val workbook: Workbook = XSSFWorkbook(templateInputStream) @@ -125,42 +145,42 @@ 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 - sheet.getRow(rowIndex).getCell(columnIndex).apply { + sheet.getRow(rowIndex).createCell(columnIndex).apply { setCellValue(FORMATTED_TODAY) } rowIndex = 2 - sheet.getRow(rowIndex).getCell(columnIndex).apply { + sheet.getRow(rowIndex).createCell(columnIndex).apply { setCellValue(project.code) } rowIndex = 3 - sheet.getRow(rowIndex).getCell(columnIndex).apply { + sheet.getRow(rowIndex).createCell(columnIndex).apply { setCellValue(project.name) } rowIndex = 4 - sheet.getRow(rowIndex).getCell(columnIndex).apply { + sheet.getRow(rowIndex).createCell(columnIndex).apply { setCellValue(if (project.customer?.name == null) "N/A" else project.customer?.name) } rowIndex = 5 - sheet.getRow(rowIndex).getCell(columnIndex).apply { + sheet.getRow(rowIndex).createCell(columnIndex).apply { setCellValue(if (project.teamLead?.team?.name == null) "N/A" else project.teamLead?.team?.name) } rowIndex = 9 sheet.getRow(rowIndex).apply { - getCell(1).apply { + createCell(1).apply { setCellValue(project.expectedTotalFee!!) cellStyle.dataFormat = accountingStyle } - getCell(2).apply { + createCell(2).apply { setCellValue(project.expectedTotalFee!! / 0.8) cellStyle.dataFormat = accountingStyle } @@ -168,15 +188,17 @@ open class ReportService ( rowIndex = 10 val actualIncome = invoices.sumOf { invoice -> invoice.paidAmount!! } - val actualExpenditure = timesheets.sumOf { timesheet -> timesheet.staff!!.salary.hourlyRate.toDouble() * ((timesheet.normalConsumed ?: 0.0) + (timesheet.otConsumed ?: 0.0)) } + val actualExpenditure = timesheets.sumOf { timesheet -> + timesheet.staff!!.salary.hourlyRate.toDouble() * ((timesheet.normalConsumed ?: 0.0) + (timesheet.otConsumed + ?: 0.0)) + } sheet.getRow(rowIndex).apply { - getCell(1).apply { - // TODO: Replace by actual expenditure + createCell(1).apply { setCellValue(actualExpenditure) cellStyle.dataFormat = accountingStyle } - getCell(2).apply { + createCell(2).apply { setCellValue(actualIncome.toDouble()) cellStyle.dataFormat = accountingStyle } @@ -184,102 +206,137 @@ open class ReportService ( rowIndex = 11 sheet.getRow(rowIndex).apply { - getCell(1).apply { - // TODO: Replace by actual expenditure + createCell(1).apply { cellFormula = "B10-B11" cellStyle.dataFormat = accountingStyle } - getCell(2).apply { + createCell(2).apply { cellFormula = "C10-C11" cellStyle.dataFormat = accountingStyle } } - // TODO: Add expenditure rowIndex = 15 - val combinedResults = (invoices.map { it.receiptDate } + timesheets.map { it.recordDate }).filterNotNull().sortedBy { it } - logger.info("combinedResults-------------- $combinedResults") - invoices.forEach{ - logger.info("Invoice--------- $it. \n") - } + + val dateFormatter = DateTimeFormatter.ofPattern("MMM YYYY") - combinedResults.forEach { result: LocalDate -> - val invoice = invoices.find { invoice: Invoice -> invoice.receiptDate == result } - val timesheet = timesheets.find { timesheet: Timesheet -> timesheet.recordDate == result} - - logger.info("result--------------: $result") - if (invoice != null) { - sheet.getRow(rowIndex++)?.apply { - - logger.info("INVOICE NOT NULL--------------:") - logger.info("getCell(0)--------------: ${getCell(0)}") - logger.info("dateFormatter--------------: $dateFormatter") - logger.info("result.format--------------: ${result.format(dateFormatter)}") - getCell(0)?.apply { - setCellValue(result.format(dateFormatter).toString()) + val combinedResults = + (invoices.map { it.receiptDate } + timesheets.map { it.recordDate }).filterNotNull().sortedBy { it } + .map { it.format(dateFormatter) }.distinct() + val groupedTimesheets = timesheets.sortedBy { it.recordDate } + .groupBy { timesheetEntry -> timesheetEntry.recordDate?.format(dateFormatter).toString() } + .mapValues { (_, timesheetEntries) -> + timesheetEntries.map { timesheet -> + if (timesheet.normalConsumed != null) { + timesheet.normalConsumed!!.plus(timesheet.otConsumed ?: 0.0).times(timesheet.staff!!.salary.hourlyRate.toDouble()) + } else if (timesheet.otConsumed != null) { + timesheet.otConsumed!!.plus(timesheet.normalConsumed ?: 0.0).times(timesheet.staff!!.salary.hourlyRate.toDouble()) + } else { + 0.0 } + } + } - getCell(1)?.apply { - setCellValue(0.0) - cellStyle.dataFormat = accountingStyle - } + val groupedInvoices = invoices.sortedBy { it.receiptDate }.filter { it.paidAmount != null } + .groupBy { invoiceEntry -> invoiceEntry.invoiceDate?.format(dateFormatter).toString() } + .mapValues { (_, invoiceEntries) -> + invoiceEntries.map { invoice -> + mapOf( + "paidAmount" to invoice.paidAmount?.toDouble(), + "description" to invoice.milestonePayment?.description + ) + } + } - logger.info("invoice.paidAmount------------: ${invoice.paidAmount}") - logger.info("invoice.paidAmount------------: ${invoice.paidAmount!!.toDouble()}") - getCell(2)?.apply { - setCellValue(invoice.paidAmount!!.toDouble()) - cellStyle.dataFormat = accountingStyle - } + groupedTimesheets.entries.forEach { (key, value) -> + logger.info("key: $key") + logger.info("value: " + value.sumOf { it }) + } - getCell(3)?.apply { - val lastRow = rowIndex - 1 - if (lastRow == 15) { - cellFormula = "C{currentRow}-B{currentRow}".replace("{currentRow}", rowIndex.toString()) - } else { - cellFormula = "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace("{currentRow}", rowIndex.toString()).replace("{lastRow}", lastRow.toString()) + groupedInvoices.entries.forEach { (key, value) -> + logger.info("key: $key") + logger.info("value: " + value) + groupedInvoices[key]!!.forEachIndexed { index, invoice -> + logger.info("index: $index") + logger.info("invoice: $invoice") + invoice.get("paidAmount") + } + } + + combinedResults.forEach { result: String -> + + if (groupedInvoices.containsKey(result)) { + groupedInvoices[result]!!.forEachIndexed { _, invoice -> + sheet.getRow(rowIndex++).apply { + createCell(0).apply { + setCellValue(result) + } + + createCell(1).apply { + setCellValue(0.0) + cellStyle.dataFormat = accountingStyle + } + + createCell(2).apply { + setCellValue(invoice["paidAmount"] as Double) + cellStyle.dataFormat = accountingStyle } - cellStyle.dataFormat = accountingStyle - } - getCell(4)?.apply { - setCellValue(invoice.milestonePayment!!.description!!) + createCell(3).apply { + val lastRow = rowIndex - 1 + if (lastRow == 15) { + cellFormula = + "C{currentRow}-B{currentRow}".replace("{currentRow}", rowIndex.toString()) + } else { + cellFormula = + "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace( + "{currentRow}", + rowIndex.toString() + ).replace("{lastRow}", lastRow.toString()) + } + cellStyle.dataFormat = accountingStyle + } + + createCell(4)?.apply { + setCellValue(invoice["description"].toString()) + } } } } - if (timesheet != null) { - sheet.getRow(rowIndex++)?.apply { + if (groupedTimesheets.containsKey(result)) { + sheet.getRow(rowIndex++).apply { - logger.info("TIMESHEET NOT NULL--------------:") - logger.info("getCell(0)--------------: ${getCell(0)}") - logger.info("dateFormatter--------------: $dateFormatter") - logger.info("result.format--------------: ${result.format(dateFormatter)}") - getCell(0)?.apply { + createCell(0).apply { setCellValue(result.format(dateFormatter)) } - getCell(1)?.apply { - setCellValue(timesheet.staff!!.salary.hourlyRate.toDouble() * ((timesheet.normalConsumed ?: 0.0) + (timesheet.otConsumed ?: 0.0))) + createCell(1).apply { + setCellValue(groupedTimesheets[result]!!.sum()) cellStyle.dataFormat = accountingStyle } - getCell(2)?.apply { + createCell(2).apply { setCellValue(0.0) cellStyle.dataFormat = accountingStyle } - getCell(3)?.apply { + createCell(3).apply { val lastRow = rowIndex - 1 if (lastRow == 15) { cellFormula = "C{currentRow}-B{currentRow}".replace("{currentRow}", rowIndex.toString()) } else { - cellFormula = "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace("{currentRow}", rowIndex.toString()).replace("{lastRow}", lastRow.toString()) + cellFormula = + "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace( + "{currentRow}", + rowIndex.toString() + ).replace("{lastRow}", lastRow.toString()) } cellStyle.dataFormat = accountingStyle } - getCell(4)?.apply { + createCell(4).apply { setCellValue("Monthly Manpower Expenditure") } } @@ -392,7 +449,7 @@ open class ReportService ( // cellStyle.borderBottom = BorderStyle.DOUBLE cellStyle.alignment = HorizontalAlignment.CENTER } - sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) + sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) // rowIndex += 1 sheet.getRow(rowIndex).getCell(0).apply { @@ -414,7 +471,7 @@ open class ReportService ( cellStyle.alignment = HorizontalAlignment.CENTER cellStyle.dataFormat = accountingStyle } - sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) + sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) // rowIndex += 1 sheet.getRow(rowIndex).getCell(0).apply { @@ -428,7 +485,7 @@ open class ReportService ( cellStyle.dataFormat = accountingStyle } - sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) + sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) rowIndex += 1 sheet.getRow(rowIndex).getCell(0).apply { @@ -453,12 +510,12 @@ open class ReportService ( // cellStyle.borderBottom = BorderStyle.DOUBLE } sheet.getRow(rowIndex).getCell(2).apply { - cellFormula = "C${rowIndex-2}+C${rowIndex-1}" + cellFormula = "C${rowIndex - 2}+C${rowIndex - 1}" cellStyle.dataFormat = accountingStyle // cellStyle.borderTop = BorderStyle.THIN // cellStyle.borderBottom = BorderStyle.DOUBLE } - sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) + sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// rowIndex = 7 columnIndex = 2 @@ -487,21 +544,21 @@ open class ReportService ( } } } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - sheet.getRow(rowIndex).apply { - getCell(columnIndex).setCellValue("Leave Hours") - getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + sheet.getRow(rowIndex).apply { + getCell(columnIndex).setCellValue("Leave Hours") + getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER - columnIndex += 1 - getCell(columnIndex).setCellValue("Daily Manhour Spent\n" + "(Excluding Leave Hours)") - getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER - columnSize = columnIndex - } - sheet.addMergedRegion(CellRangeAddress(6,6 , 2, columnIndex)) + columnIndex += 1 + getCell(columnIndex).setCellValue("Daily Manhour Spent\n" + "(Excluding Leave Hours)") + getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER + columnSize = columnIndex + } + sheet.addMergedRegion(CellRangeAddress(6, 6, 2, columnIndex)) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// for (i in 2 until columnIndex) { for (k in 0 until rowSize) { - sheet.getRow(8+k).getCell(i).apply { + sheet.getRow(8 + k).getCell(i).apply { setCellValue(0.0) cellStyle.dataFormat = accountingStyle } @@ -512,14 +569,17 @@ open class ReportService ( if (sheet.getRow(rowIndex - 1).getCell(2).stringCellValue != "Leave Hours") { // cal daily spent manhour for (i in 0 until rowSize) { - val cell = sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex) - cell?.cellFormula = "SUM(${getColumnAlphabet(2)}${rowIndex+1}:${getColumnAlphabet(columnIndex)}${rowIndex+1})" // should columnIndex - 2 + val cell = + sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex) + cell?.cellFormula = + "SUM(${getColumnAlphabet(2)}${rowIndex + 1}:${getColumnAlphabet(columnIndex)}${rowIndex + 1})" // should columnIndex - 2 rowIndex++ } // cal subtotal for (i in 0 until columnSize) { // minus last col val cell = sheet.getRow(rowIndex)?.getCell(2) ?: sheet.getRow(rowIndex)?.createCell(2) - cell?.cellFormula = "SUM(${getColumnAlphabet(2)}${rowIndex}:${getColumnAlphabet(columnIndex + i)}${rowIndex})" + cell?.cellFormula = + "SUM(${getColumnAlphabet(2)}${rowIndex}:${getColumnAlphabet(columnIndex + i)}${rowIndex})" cell?.cellStyle?.dataFormat = accountingStyle cell?.cellStyle?.setFont(boldFont) // cell?.cellStyle?.borderTop = BorderStyle.THIN @@ -528,7 +588,8 @@ open class ReportService ( } else { // just for preview when no data // cal daily spent manhour for (i in 0 until rowSize) { - val cell = sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex) + val cell = + sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex) cell?.setCellValue("daily spent manhour") rowIndex++ } @@ -548,7 +609,7 @@ open class ReportService ( @Throws(IOException::class) private fun createSalaryList( - salarys : List, + salarys: List, templatePath: String, ): Workbook { @@ -588,19 +649,19 @@ open class ReportService ( private fun createLateStartReport( project: Project, templatePath: String - ):Workbook{ + ): 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 @@ -612,7 +673,7 @@ open class ReportService ( 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) } @@ -621,7 +682,7 @@ open class ReportService ( 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) @@ -634,7 +695,7 @@ open class ReportService ( 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) { @@ -652,31 +713,31 @@ open class ReportService ( for (colIndex in 0..9) { sheet.setColumnWidth(colIndex, (maxContentWidths[colIndex] + 2) * 256) // Set the width for each column } - + return workbook } open fun getFinancialStatus(projectId: Long?): List> { val sql = StringBuilder( "with cte_invoice as (select p.code, sum(i.issueAmount) as sumIssuedAmount , sum(i.paidAmount) as sumPaidAmount" - + "from invoice i" - + "left join project p on p.code = i.projectCode" - + "group by p.code" - + ")" - + " Select p.code, p.description, c.name, t2.name, p.planStart , p.planEnd , p.expectedTotalFee ," - + " s.name , IFNULL(t.normalConsumed, 0) as normalConsumed, IFNULL(t.otConsumed , 0) as otConsumed, s2.hourlyRate," - + " cte_i.sumIssuedAmount, cte_i.sumPaidAmount" - + " from timesheet t" - + " left join project_task pt on pt.id = t.projectTaskId" - + " left join project p ON p.id = pt.project_id" - + " left join staff s on s.id = t.staffId" - + " left join salary s2 on s.salaryId = s2.salaryPoint" - + " left join customer c on c.id = p.customerId" - + " left join team t2 on t2.id = s.teamId" - + " left join cte_invoice cte_i on cte_i.code = p.code" + + "from invoice i" + + "left join project p on p.code = i.projectCode" + + "group by p.code" + + ")" + + " Select p.code, p.description, c.name, t2.name, p.planStart , p.planEnd , p.expectedTotalFee ," + + " s.name , IFNULL(t.normalConsumed, 0) as normalConsumed, IFNULL(t.otConsumed , 0) as otConsumed, s2.hourlyRate," + + " cte_i.sumIssuedAmount, cte_i.sumPaidAmount" + + " from timesheet t" + + " left join project_task pt on pt.id = t.projectTaskId" + + " left join project p ON p.id = pt.project_id" + + " left join staff s on s.id = t.staffId" + + " left join salary s2 on s.salaryId = s2.salaryPoint" + + " left join customer c on c.id = p.customerId" + + " left join team t2 on t2.id = s.teamId" + + " left join cte_invoice cte_i on cte_i.code = p.code" ) - if (projectId!! > 0){ + if (projectId!! > 0) { sql.append(" where p.id = :projectId ") } sql.append(" order by p.code") From 7337f70d3eceb474db87c015acf0b61b436bde27 Mon Sep 17 00:00:00 2001 From: leoho2fi Date: Thu, 16 May 2024 18:30:24 +0800 Subject: [PATCH 2/4] report update --- .../tsms/modules/report/service/ReportService.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 ee8df33..f862e6b 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 @@ -567,8 +567,7 @@ open class ReportService { project: Project, templatePath: String ):Workbook{ - - project + val resource = ClassPathResource(templatePath) val templateInputStream = resource.inputStream val workbook: Workbook = XSSFWorkbook(templateInputStream) @@ -578,6 +577,19 @@ open class ReportService { 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) + + // Start populating project data starting at row 7 + val startRow = 6 // 0-based index for row 7 + val projectDataRow = sheet.createRow(startRow) + + // Populate the row with project data + projectDataRow.createCell(1).setCellValue(project.code) // Column B + projectDataRow.createCell(2).setCellValue(project.name) // Column C + projectDataRow.createCell(3).setCellValue(project.teamLead?.name) // Column D + projectDataRow.createCell(4).setCellValue(project.custLeadName) // Column E + projectDataRow.createCell(5).setCellValue( + project.planStart?.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")) ?: "N/A" // Column F + ) // Styling for cell A1: Font size 16 and bold val headerFont = workbook.createFont().apply { From 59ef02e1d08c6ac1085f664583f39e7272e802f0 Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Thu, 16 May 2024 19:17:29 +0800 Subject: [PATCH 3/4] update --- .../modules/data/entity/SalaryRepository.java | 4 + .../modules/data/service/StaffsService.kt | 2 +- .../entity/StaffAllocationRepository.kt | 3 + .../modules/report/service/ReportService.kt | 279 +++++++++--------- .../modules/report/web/ReportController.kt | 3 +- .../tsms/modules/user/web/UserController.java | 24 +- 6 files changed, 166 insertions(+), 149 deletions(-) diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/SalaryRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/SalaryRepository.java index 42f9824..e5fa9de 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/SalaryRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/SalaryRepository.java @@ -2,9 +2,13 @@ package com.ffii.tsms.modules.data.entity; import com.ffii.core.support.AbstractRepository; import com.ffii.tsms.modules.data.entity.projections.SalarySearchInfo; +import org.springframework.data.repository.query.Param; import java.util.List; +import java.util.Optional; public interface SalaryRepository extends AbstractRepository { List findSalarySearchInfoByOrderBySalaryPoint(); + + Optional findBySalaryPoint(@Param("salaryPoint") Long salaryPoint); } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt index 14dccc6..aaefa49 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt @@ -107,7 +107,7 @@ open class StaffsService( val company = companyRepository.findById(req.companyId).orElseThrow() val grade = if (req.gradeId != null && req.gradeId > 0L) gradeRepository.findById(req.gradeId).orElseThrow() else null val team = if (req.teamId != null && req.teamId > 0L) teamRepository.findById(req.teamId).orElseThrow() else null - val salary = salaryRepository.findById(req.salaryId).orElseThrow() + val salary = salaryRepository.findBySalaryPoint(req.salaryId).orElseThrow() // val salaryEffective = salaryEffectiveRepository.findById(req.salaryEffId).orElseThrow() val department = departmentRepository.findById(req.departmentId).orElseThrow() diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/StaffAllocationRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/StaffAllocationRepository.kt index 3048ded..31ca9b8 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/StaffAllocationRepository.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/StaffAllocationRepository.kt @@ -2,8 +2,11 @@ package com.ffii.tsms.modules.project.entity; import com.ffii.core.support.AbstractRepository import com.ffii.tsms.modules.data.entity.Staff +import com.ffii.tsms.modules.data.entity.projections.StaffSearchInfo +import java.time.LocalDate interface StaffAllocationRepository : AbstractRepository { fun findAssignedProjectsByStaff(staff: Staff): List + fun findByProject(project: Project): List } \ No newline at end of file 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 1515f24..87c8035 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 @@ -21,10 +21,10 @@ import java.io.IOException import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.* +import org.apache.poi.ss.util.CellUtil import kotlin.time.times data class DayInfo(val date: String?, val weekday: String?) - @Service open class ReportService( private val jdbcDao: JdbcDao, @@ -108,8 +108,8 @@ open class ReportService( } @Throws(IOException::class) - fun generateLateStartReport(project: Project): ByteArray { - val workbook: Workbook = createLateStartReport(project, LATE_START_REPORT) + fun generateLateStartReport(project: Project?): ByteArray { + val workbook: Workbook = createLateStartReport(project,LATE_START_REPORT) val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() workbook.write(outputStream) workbook.close() @@ -370,6 +370,9 @@ open class ReportService( templatePath: String, ): Workbook { // val yearMonth = YearMonth.of(2022, 5) // May 2022 + println("t $timesheets") + println("l $leaves") + println("p $projectList") val resource = ClassPathResource(templatePath) val templateInputStream = resource.inputStream val workbook: Workbook = XSSFWorkbook(templateInputStream) @@ -398,210 +401,195 @@ open class ReportService( var columnSize = 0 var dayInt = 0 -// tempCell = tempRow.createCell(columnIndex) - sheet.getRow(rowIndex).getCell(columnIndex).apply { - setCellValue(FORMATTED_TODAY) - } - println(sheet.getRow(1).getCell(2)) + var tempCell: Cell + + tempCell = sheet.getRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue(FORMATTED_TODAY) rowIndex = 2 - sheet.getRow(rowIndex).getCell(columnIndex).apply { - setCellValue(month) - cellStyle.dataFormat = monthStyle - } + tempCell = sheet.getRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue(month) + tempCell.cellStyle.dataFormat = monthStyle rowIndex = 3 - sheet.getRow(rowIndex).getCell(columnIndex).apply { - setCellValue(staff.name) - } + tempCell. sheet.getRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue(staff.name) rowIndex = 4 - sheet.getRow(rowIndex).getCell(columnIndex).apply { - setCellValue(staff.team.name) - } + tempCell.sheet.getRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue(staff.team.name) + rowIndex = 5 - sheet.getRow(rowIndex).getCell(columnIndex).apply { - setCellValue(staff.grade.code) - } + tempCell = sheet.getRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue(staff.grade.code) + + val DoubleBorderBottom: MutableMap = mutableMapOf() + DoubleBorderBottom["borderTop"] = BorderStyle.THIN + DoubleBorderBottom["borderBottom"] = BorderStyle.DOUBLE + val ThinBorderBottom: MutableMap = mutableMapOf() + ThinBorderBottom["borderBottom"] = BorderStyle.THIN ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// rowIndex = 7 daysOfMonth.forEach { dayInfo -> rowIndex++ rowSize++ - sheet.getRow(rowIndex).getCell(0).apply { - setCellValue(dayInfo.date) - cellStyle.dataFormat = dateStyle - cellStyle.setFont(boldFont) - } - sheet.getRow(rowIndex).getCell(1).apply { - setCellValue(dayInfo.weekday) - cellStyle.setFont(boldFont) - } + tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell.setCellValue(dayInfo.date) + tempCell.cellStyle.dataFormat = dateStyle + tempCell.cellStyle.setFont(boldFont) +// cellStyle.alignment = HorizontalAlignment.LEFT + tempCell = sheet.createRow(rowIndex).createCell(1) + tempCell.setCellValue(dayInfo.weekday) + tempCell.cellStyle.setFont(boldFont) +// cellStyle.alignment = HorizontalAlignment.LEFT } rowIndex += 1 - sheet.getRow(rowIndex).getCell(0).apply { - setCellValue("Sub-total") - cellStyle.setFont(boldFont) -// cellStyle.borderTop = BorderStyle.THIN -// cellStyle.borderBottom = BorderStyle.DOUBLE - cellStyle.alignment = HorizontalAlignment.CENTER - } - sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) - // + tempCell = sheet.createRow(rowIndex).createCell(0) + sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) + tempCell.setCellValue("Sub-total") + tempCell.cellStyle.setFont(boldFont) + CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) + CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) + tempCell = sheet.createRow(rowIndex).createCell(1) + CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) + rowIndex += 1 - sheet.getRow(rowIndex).getCell(0).apply { - setCellValue("Total Normal Hours [A]") -// cellStyle.setFont(boldFont) - cellStyle.alignment = HorizontalAlignment.CENTER - } + tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell.setCellValue("Total Normal Hours [A]") + CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) + var normalConsumed = 0.0 var otConsumed = 0.0 var leaveHours = 0.0 if (timesheets.isNotEmpty()) { timesheets.forEach { t -> normalConsumed += t.normalConsumed!! - otConsumed += t.otConsumed!! + otConsumed += t.otConsumed ?: 0.0 } } - sheet.getRow(rowIndex).getCell(2).apply { - setCellValue(normalConsumed) - cellStyle.alignment = HorizontalAlignment.CENTER - cellStyle.dataFormat = accountingStyle - } - sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) + tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell.setCellValue(normalConsumed) + tempCell.cellStyle.dataFormat = accountingStyle + + sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) // rowIndex += 1 - sheet.getRow(rowIndex).getCell(0).apply { - setCellValue("Total Other Hours [B]") - cellStyle.setFont(boldFont) - cellStyle.alignment = HorizontalAlignment.CENTER - } - sheet.getRow(rowIndex).getCell(2).apply { - setCellValue(otConsumed) - cellStyle.alignment = HorizontalAlignment.CENTER - cellStyle.dataFormat = accountingStyle - } + tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell.setCellValue("Total Other Hours [B]") + CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) + tempCell.cellStyle.setFont(boldFont) + tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell.setCellValue(otConsumed) + tempCell.cellStyle.dataFormat = accountingStyle + sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) + // Total Leave Hours rowIndex += 1 - sheet.getRow(rowIndex).getCell(0).apply { - setCellValue("Total Leave Hours") - cellStyle.alignment = HorizontalAlignment.CENTER - } + tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell.setCellValue("Total Leave Hours") + CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) + sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) if (leaves.isNotEmpty()) { leaves.forEach { l -> leaveHours += l.leaveHours!! } } - sheet.getRow(rowIndex).getCell(2).apply { - setCellValue(leaveHours) - cellStyle.dataFormat = accountingStyle - } + tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell.setCellValue(leaveHours) + tempCell.cellStyle.dataFormat = accountingStyle + + // Total Spent Manhours rowIndex += 1 - sheet.getRow(rowIndex).getCell(0).apply { - setCellValue("Total Spent Manhours [A+B]") - cellStyle.setFont(boldFont) - cellStyle.alignment = HorizontalAlignment.CENTER -// cellStyle.borderTop = BorderStyle.THIN -// cellStyle.borderBottom = BorderStyle.DOUBLE - } - sheet.getRow(rowIndex).getCell(2).apply { - cellFormula = "C${rowIndex - 2}+C${rowIndex - 1}" - cellStyle.dataFormat = accountingStyle -// cellStyle.borderTop = BorderStyle.THIN -// cellStyle.borderBottom = BorderStyle.DOUBLE - } - sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1)) + tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell.setCellValue("Total Spent Manhours [A+B]") + tempCell.cellStyle.setFont(boldFont) + CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) + CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) + tempCell = sheet.createRow(rowIndex).createCell(1) + CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) + CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) + + tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell.cellFormula = "C${rowIndex-2}+C${rowIndex-1}" + tempCell.cellStyle.dataFormat = accountingStyle + CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) + + sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// rowIndex = 7 columnIndex = 2 projectList.forEachIndexed { index, title -> - sheet.getRow(7).getCell(columnIndex + index).apply { - setCellValue(title) - } + tempCell = sheet.createRow(7).createCell(columnIndex + index) + tempCell.setCellValue(title) + CellUtil.setAlignment(tempCell, HorizontalAlignment.RIGHT) + CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (timesheets.isNotEmpty()) { projectList.forEach { _ -> + for (i in 0 until rowSize) { + tempCell = sheet.createRow(8 + i).createCell(columnIndex) + tempCell.setCellValue(0.0) + tempCell.cellStyle.dataFormat = accountingStyle + } timesheets.forEach { timesheet -> dayInt = timesheet.recordDate!!.dayOfMonth - sheet.getRow(dayInt.plus(7)).getCell(columnIndex).apply { - setCellValue(timesheet.normalConsumed!!) - } + tempCell = sheet.createRow(dayInt.plus(7)).createCell(columnIndex) + tempCell.setCellValue(timesheet.normalConsumed!!) + } columnIndex++ } } + // dates if (leaves.isNotEmpty()) { leaves.forEach { leave -> - dayInt = leave.recordDate!!.dayOfMonth - sheet.getRow(dayInt.plus(7)).getCell(columnIndex).apply { - setCellValue(leave.leaveHours!!) - } - } - } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - sheet.getRow(rowIndex).apply { - getCell(columnIndex).setCellValue("Leave Hours") - getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER + for (i in 0 until rowSize) { + tempCell = sheet.createRow(8 + i).createCell(columnIndex) + tempCell.setCellValue(0.0) + tempCell.cellStyle.dataFormat = accountingStyle - columnIndex += 1 - getCell(columnIndex).setCellValue("Daily Manhour Spent\n" + "(Excluding Leave Hours)") - getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER - columnSize = columnIndex - } - sheet.addMergedRegion(CellRangeAddress(6, 6, 2, columnIndex)) - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - for (i in 2 until columnIndex) { - for (k in 0 until rowSize) { - sheet.getRow(8 + k).getCell(i).apply { - setCellValue(0.0) - cellStyle.dataFormat = accountingStyle } + dayInt = leave.recordDate!!.dayOfMonth + tempCell = sheet.createRow(dayInt.plus(7)).createCell(columnIndex) + tempCell.setCellValue(leave.leaveHours!!) + } } + ///////////////////////////////////////////////////////// Leave Hours //////////////////////////////////////////////////////////////////// + tempCell = sheet.createRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue("Leave Hours") + CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) + columnIndex += 1 + tempCell = sheet.createRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue("Daily Manhour Spent\n(Excluding Leave Hours)") + CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) + + sheet.addMergedRegion(CellRangeAddress(6,6 , 2, columnIndex)) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// rowIndex = 8 - if (sheet.getRow(rowIndex - 1).getCell(2).stringCellValue != "Leave Hours") { - // cal daily spent manhour - for (i in 0 until rowSize) { - val cell = - sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex) - cell?.cellFormula = - "SUM(${getColumnAlphabet(2)}${rowIndex + 1}:${getColumnAlphabet(columnIndex)}${rowIndex + 1})" // should columnIndex - 2 - rowIndex++ - } - // cal subtotal - for (i in 0 until columnSize) { // minus last col - val cell = sheet.getRow(rowIndex)?.getCell(2) ?: sheet.getRow(rowIndex)?.createCell(2) - cell?.cellFormula = - "SUM(${getColumnAlphabet(2)}${rowIndex}:${getColumnAlphabet(columnIndex + i)}${rowIndex})" - cell?.cellStyle?.dataFormat = accountingStyle - cell?.cellStyle?.setFont(boldFont) -// cell?.cellStyle?.borderTop = BorderStyle.THIN -// cell?.cellStyle?.borderBottom = BorderStyle.DOUBLE - } - } else { // just for preview when no data +// if (sheet.createRow(rowIndex - 1).getCell(2).stringCellValue != "Leave Hours") { // cal daily spent manhour for (i in 0 until rowSize) { - val cell = - sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex) - cell?.setCellValue("daily spent manhour") + tempCell = sheet.createRow(rowIndex).createCell(columnIndex) + tempCell.cellFormula = "SUM(${getColumnAlphabet(2)}${rowIndex+1}:${getColumnAlphabet(columnIndex - 2)}${rowIndex+1})" // should columnIndex - 2 rowIndex++ } // cal subtotal - for (i in 0 until columnSize) { // minus last col - val cell = sheet.getRow(rowIndex)?.getCell(2) ?: sheet.getRow(rowIndex)?.createCell(2) - cell?.setCellValue("testing subtotal") - cell?.cellStyle?.dataFormat = accountingStyle - cell?.cellStyle?.setFont(boldFont) -// cell?.cellStyle?.borderTop = BorderStyle.THIN -// cell?.cellStyle?.borderBottom = BorderStyle.DOUBLE - } + println(rowIndex) + for (i in 0 until columnSize - 2) { // minus last col + tempCell = sheet.createRow(rowIndex).createCell(2 + i) + tempCell.cellFormula = "SUM(${getColumnAlphabet(2 + i)}9:${getColumnAlphabet(2 + i)}${rowIndex})" + tempCell.cellStyle.dataFormat = accountingStyle + tempCell.cellStyle.setFont(boldFont) + CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) +// } } return workbook } @@ -647,16 +635,15 @@ open class ReportService( } private fun createLateStartReport( - project: Project, + 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) @@ -674,7 +661,7 @@ open class ReportService( // projectDataRow.createCell(5).setCellValue( // project.planStart?.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")) ?: "N/A" // Column F // ) - + // Styling for cell A1: Font size 16 and bold val headerFont = workbook.createFont().apply { bold = true 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 3accd6d..fec6463 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 @@ -83,6 +83,7 @@ class ReportController( val projects = timesheetRepository.findDistinctProjectTaskByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth) val projectList: List = projects.map { p -> "${p.projectTask!!.project!!.code}\n ${p.projectTask!!.project!!.name}" } + val reportResult: ByteArray = excelReportService.generateStaffMonthlyWorkHourAnalysisReport(thisMonth, staff, timesheets, leaves, projectList) // val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") return ResponseEntity.ok() @@ -99,7 +100,7 @@ class ReportController( @PostMapping("/downloadLateStartReport") fun downloadLateStartReport(): ResponseEntity { - val reportBytes = excelReportService.generateLateStartReport(Project()) + val reportBytes = excelReportService.generateLateStartReport(null) val headers = HttpHeaders() headers.add("Content-Disposition", "attachment; filename=Late_Start_Report_${LocalDate.now()}.xlsx") diff --git a/src/main/java/com/ffii/tsms/modules/user/web/UserController.java b/src/main/java/com/ffii/tsms/modules/user/web/UserController.java index 9fd3af0..d939da1 100644 --- a/src/main/java/com/ffii/tsms/modules/user/web/UserController.java +++ b/src/main/java/com/ffii/tsms/modules/user/web/UserController.java @@ -131,7 +131,6 @@ public class UserController{ // }) @PatchMapping("/change-password") @ResponseStatus(HttpStatus.NO_CONTENT) - // @PreAuthorize("hasAuthority('MAINTAIN_USER')") public void changePassword(@RequestBody @Valid ChangePwdReq req) { long id = SecurityUtils.getUser().get().getId(); User instance = userService.find(id).orElseThrow(NotFoundException::new); @@ -151,6 +150,26 @@ public class UserController{ userService.save(instance); } + @PatchMapping("/admin-change-password") + @ResponseStatus(HttpStatus.NO_CONTENT) + @PreAuthorize("hasAuthority('MAINTAIN_USER')") + public void adminChangePassword(@RequestBody @Valid ChangePwdReq req) { + long id = req.getId(); + User instance = userService.find(id).orElseThrow(NotFoundException::new); + + logger.info("TEST req: "+req.getPassword()); + logger.info("TEST instance: "+instance.getPassword()); +// if (!passwordEncoder.matches(req.getPassword(), instance.getPassword())) { +// throw new BadRequestException(); +// } + PasswordRule rule = new PasswordRule(settingsService); + if (!PasswordUtils.checkPwd(req.getNewPassword(), rule)) { + throw new UnprocessableEntityException(ErrorCodes.USER_WRONG_NEW_PWD); + } + instance.setPassword(passwordEncoder.encode(req.getNewPassword())); + userService.save(instance); + } + // @Operation(summary = "reset password", responses = { // @ApiResponse(responseCode = "204"), // @ApiResponse(responseCode = "404", content = @Content), @@ -170,11 +189,14 @@ public class UserController{ } public static class ChangePwdReq { + private Long id; @NotBlank private String password; @NotBlank private String newPassword; + public Long getId() { return id; } + public Long setId(Long id) { return this.id = id; } public String getPassword() { return password; } From 514d2cdcfa8239b9f08e1eb99a847aed308be705 Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Thu, 16 May 2024 19:22:22 +0800 Subject: [PATCH 4/4] update --- .../modules/report/service/ReportService.kt | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) 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 87c8035..72c6c38 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 @@ -435,29 +435,29 @@ open class ReportService( daysOfMonth.forEach { dayInfo -> rowIndex++ rowSize++ - tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell = sheet.getRow(rowIndex).createCell(0) tempCell.setCellValue(dayInfo.date) tempCell.cellStyle.dataFormat = dateStyle tempCell.cellStyle.setFont(boldFont) // cellStyle.alignment = HorizontalAlignment.LEFT - tempCell = sheet.createRow(rowIndex).createCell(1) + tempCell = sheet.getRow(rowIndex).createCell(1) tempCell.setCellValue(dayInfo.weekday) tempCell.cellStyle.setFont(boldFont) // cellStyle.alignment = HorizontalAlignment.LEFT } rowIndex += 1 - tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell = sheet.getRow(rowIndex).createCell(0) sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) tempCell.setCellValue("Sub-total") tempCell.cellStyle.setFont(boldFont) CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) - tempCell = sheet.createRow(rowIndex).createCell(1) + tempCell = sheet.getRow(rowIndex).createCell(1) CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) rowIndex += 1 - tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell = sheet.getRow(rowIndex).createCell(0) tempCell.setCellValue("Total Normal Hours [A]") CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) @@ -467,21 +467,21 @@ open class ReportService( if (timesheets.isNotEmpty()) { timesheets.forEach { t -> normalConsumed += t.normalConsumed!! - otConsumed += t.otConsumed ?: 0.0 + otConsumed += t.otConsumed ?: 0.0 } } - tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell = sheet.getRow(rowIndex).createCell(2) tempCell.setCellValue(normalConsumed) tempCell.cellStyle.dataFormat = accountingStyle sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) // rowIndex += 1 - tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell = sheet.getRow(rowIndex).createCell(0) tempCell.setCellValue("Total Other Hours [B]") CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) tempCell.cellStyle.setFont(boldFont) - tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell = sheet.getRow(rowIndex).createCell(2) tempCell.setCellValue(otConsumed) tempCell.cellStyle.dataFormat = accountingStyle @@ -490,7 +490,7 @@ open class ReportService( // Total Leave Hours rowIndex += 1 - tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell = sheet.getRow(rowIndex).createCell(0) tempCell.setCellValue("Total Leave Hours") CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) @@ -499,22 +499,22 @@ open class ReportService( leaveHours += l.leaveHours!! } } - tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell = sheet.getRow(rowIndex).createCell(2) tempCell.setCellValue(leaveHours) tempCell.cellStyle.dataFormat = accountingStyle // Total Spent Manhours rowIndex += 1 - tempCell = sheet.createRow(rowIndex).createCell(0) + tempCell = sheet.getRow(rowIndex).createCell(0) tempCell.setCellValue("Total Spent Manhours [A+B]") tempCell.cellStyle.setFont(boldFont) CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) - tempCell = sheet.createRow(rowIndex).createCell(1) + tempCell = sheet.getRow(rowIndex).createCell(1) CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) - tempCell = sheet.createRow(rowIndex).createCell(2) + tempCell = sheet.getRow(rowIndex).createCell(2) tempCell.cellFormula = "C${rowIndex-2}+C${rowIndex-1}" tempCell.cellStyle.dataFormat = accountingStyle CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) @@ -524,7 +524,7 @@ open class ReportService( rowIndex = 7 columnIndex = 2 projectList.forEachIndexed { index, title -> - tempCell = sheet.createRow(7).createCell(columnIndex + index) + tempCell = sheet.getRow(7).createCell(columnIndex + index) tempCell.setCellValue(title) CellUtil.setAlignment(tempCell, HorizontalAlignment.RIGHT) CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) @@ -533,13 +533,13 @@ open class ReportService( if (timesheets.isNotEmpty()) { projectList.forEach { _ -> for (i in 0 until rowSize) { - tempCell = sheet.createRow(8 + i).createCell(columnIndex) + tempCell = sheet.getRow(8 + i).createCell(columnIndex) tempCell.setCellValue(0.0) tempCell.cellStyle.dataFormat = accountingStyle } timesheets.forEach { timesheet -> dayInt = timesheet.recordDate!!.dayOfMonth - tempCell = sheet.createRow(dayInt.plus(7)).createCell(columnIndex) + tempCell = sheet.getRow(dayInt.plus(7)).createCell(columnIndex) tempCell.setCellValue(timesheet.normalConsumed!!) } @@ -550,46 +550,46 @@ open class ReportService( if (leaves.isNotEmpty()) { leaves.forEach { leave -> for (i in 0 until rowSize) { - tempCell = sheet.createRow(8 + i).createCell(columnIndex) + tempCell = sheet.getRow(8 + i).createCell(columnIndex) tempCell.setCellValue(0.0) tempCell.cellStyle.dataFormat = accountingStyle } dayInt = leave.recordDate!!.dayOfMonth - tempCell = sheet.createRow(dayInt.plus(7)).createCell(columnIndex) + tempCell = sheet.getRow(dayInt.plus(7)).createCell(columnIndex) tempCell.setCellValue(leave.leaveHours!!) } } ///////////////////////////////////////////////////////// Leave Hours //////////////////////////////////////////////////////////////////// - tempCell = sheet.createRow(rowIndex).createCell(columnIndex) + tempCell = sheet.getRow(rowIndex).createCell(columnIndex) tempCell.setCellValue("Leave Hours") CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) columnIndex += 1 - tempCell = sheet.createRow(rowIndex).createCell(columnIndex) + tempCell = sheet.getRow(rowIndex).createCell(columnIndex) tempCell.setCellValue("Daily Manhour Spent\n(Excluding Leave Hours)") CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) sheet.addMergedRegion(CellRangeAddress(6,6 , 2, columnIndex)) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// rowIndex = 8 -// if (sheet.createRow(rowIndex - 1).getCell(2).stringCellValue != "Leave Hours") { + if (sheet.getRow(rowIndex - 1).getCell(2).stringCellValue != "Leave Hours") { // cal daily spent manhour for (i in 0 until rowSize) { - tempCell = sheet.createRow(rowIndex).createCell(columnIndex) + tempCell = sheet.getRow(rowIndex).createCell(columnIndex) tempCell.cellFormula = "SUM(${getColumnAlphabet(2)}${rowIndex+1}:${getColumnAlphabet(columnIndex - 2)}${rowIndex+1})" // should columnIndex - 2 rowIndex++ } // cal subtotal println(rowIndex) for (i in 0 until columnSize - 2) { // minus last col - tempCell = sheet.createRow(rowIndex).createCell(2 + i) + tempCell = sheet.getRow(rowIndex).createCell(2 + i) tempCell.cellFormula = "SUM(${getColumnAlphabet(2 + i)}9:${getColumnAlphabet(2 + i)}${rowIndex})" tempCell.cellStyle.dataFormat = accountingStyle tempCell.cellStyle.setFont(boldFont) CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) -// } + } } return workbook }