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 a940609..b38b07a 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,9 @@ 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.entity.projections.MonthlyLeave +import com.ffii.tsms.modules.timesheet.entity.projections.ProjectMonthlyHoursWithDate +import com.ffii.tsms.modules.timesheet.entity.projections.TimesheetHours import com.ffii.tsms.modules.timesheet.web.models.LeaveEntry import org.apache.commons.logging.Log import org.apache.commons.logging.LogFactory @@ -20,6 +23,7 @@ import org.springframework.stereotype.Service import java.io.ByteArrayOutputStream import java.io.IOException import java.math.BigDecimal +import java.sql.Time import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.* @@ -121,9 +125,8 @@ open class ReportService( fun generateStaffMonthlyWorkHourAnalysisReport( month: LocalDate, staff: Staff, - timesheets: List, - leaves: List, - projectList: List + timesheets: List>, + leaves: List>, ): ByteArray { // Generate the Excel report with query results val workbook: Workbook = createStaffMonthlyWorkHourAnalysisReport( @@ -131,7 +134,6 @@ open class ReportService( staff, timesheets, leaves, - projectList, MONTHLY_WORK_HOURS_ANALYSIS_REPORT ) @@ -718,21 +720,35 @@ open class ReportService( private fun createStaffMonthlyWorkHourAnalysisReport( month: LocalDate, staff: Staff, - timesheets: List, - leaves: List, - projectList: List, + timesheets: List>, + leaves: List>, templatePath: String, ): Workbook { -// val yearMonth = YearMonth.of(2022, 5) // May 2022 - println("t $timesheets") - println("l $leaves") - println("p $projectList") + var projectList: List = listOf() + println("----timesheets-----") + println(timesheets) + // result = timesheet record mapped + var result: Map = mapOf() + if (timesheets.isNotEmpty()) { + projectList = timesheets.map{ "${it["code"]}\n ${it["name"]}"}.toList() + result = timesheets.groupBy( + { it["id"].toString() }, + { mapOf( + "date" to it["recordDate"], + "normalConsumed" to it["normalConsumed"], + "otConsumed" to it["otConsumed"], + ) } + ) + } + println("---result---") + println(result) + println("l $projectList") val resource = ClassPathResource(templatePath) val templateInputStream = resource.inputStream val workbook: Workbook = XSSFWorkbook(templateInputStream) val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") - val monthStyle = workbook.createDataFormat().getFormat("mmm, yyyy") + val monthStyle = workbook.createDataFormat().getFormat("MMM YYYY") val dateStyle = workbook.createDataFormat().getFormat("dd/mm/yyyy") val boldStyle = workbook.createCellStyle() @@ -748,8 +764,6 @@ open class ReportService( val sheet: Sheet = workbook.getSheetAt(0) -// sheet.forceFormulaRecalculation = true; //Calculate formulas - var rowIndex = 1 // Assuming the location is in (1,2), which is the report date field var columnIndex = 1 @@ -766,7 +780,6 @@ open class ReportService( rowIndex = 2 sheet.getRow(rowIndex).getCell(columnIndex).apply { setCellValue(month) -// cellStyle.setFont(boldStyle) cellStyle.dataFormat = monthStyle } @@ -801,11 +814,9 @@ open class ReportService( tempCell.setCellValue(dayInfo.date) tempCell.cellStyle = boldStyle tempCell.cellStyle.dataFormat = dateStyle -// cellStyle.alignment = HorizontalAlignment.LEFT tempCell = sheet.getRow(rowIndex).createCell(1) tempCell.setCellValue(dayInfo.weekday) tempCell.cellStyle = boldStyle -// cellStyle.alignment = HorizontalAlignment.LEFT } rowIndex += 1 @@ -827,10 +838,11 @@ open class ReportService( var normalConsumed = 0.0 var otConsumed = 0.0 var leaveHours = 0.0 + // normalConsumed data if (timesheets.isNotEmpty()) { timesheets.forEach { t -> - normalConsumed += t.normalConsumed!! - otConsumed += t.otConsumed ?: 0.0 + normalConsumed += t["normalConsumed"] as Double + otConsumed += t["otConsumed"] as Double } } tempCell = sheet.getRow(rowIndex).createCell(2) @@ -858,9 +870,10 @@ open class ReportService( tempCell.cellStyle = boldStyle CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) + // cal total leave hour if (leaves.isNotEmpty()) { leaves.forEach { l -> - leaveHours += l.leaveHours!! + leaveHours += l["leaveHours"] as Double } } tempCell = sheet.getRow(rowIndex).createCell(2) @@ -905,28 +918,30 @@ open class ReportService( tempCell.setCellValue(0.0) tempCell.cellStyle.dataFormat = accountingStyle } - timesheets.forEach { timesheet -> - dayInt = timesheet.recordDate!!.dayOfMonth - tempCell = sheet.getRow(dayInt.plus(7)).createCell(columnIndex) - tempCell.setCellValue(timesheet.normalConsumed!!) - + result.forEach{(id, list) -> + for (i in 0 until id.toInt()) { + val temp: List> = list as List> + temp.forEachIndexed { i, _ -> + dayInt = temp[i]["date"].toString().toInt() + tempCell = sheet.getRow(dayInt.plus(7)).createCell(columnIndex) + tempCell.setCellValue(temp[i]["normalConsumed"] as Double) + } + } } columnIndex++ } } - // dates + // leave hours data if (leaves.isNotEmpty()) { leaves.forEach { leave -> for (i in 0 until rowSize) { tempCell = sheet.getRow(8 + i).createCell(columnIndex) tempCell.setCellValue(0.0) tempCell.cellStyle.dataFormat = accountingStyle - } - dayInt = leave.recordDate!!.dayOfMonth + dayInt = leave["recordDate"].toString().toInt() tempCell = sheet.getRow(dayInt.plus(7)).createCell(columnIndex) - tempCell.setCellValue(leave.leaveHours!!) - + tempCell.setCellValue(leave["leaveHours"] as Double) } } ///////////////////////////////////////////////////////// Leave Hours //////////////////////////////////////////////////////////////////// @@ -1126,4 +1141,37 @@ open class ReportService( return jdbcDao.queryForList(sql.toString(), args) } -} \ No newline at end of file + open fun getTimesheet(args: Map): List> { + val sql = StringBuilder( + "SELECT" + + " p.id," + + " p.name," + + " p.code," + + " CAST(DATE_FORMAT(t.recordDate, '%d') AS SIGNED) AS recordDate," + + " sum(t.normalConsumed) as normalConsumed," + + " IFNULL(sum(t.otConsumed), 0.0) as otConsumed" + + " from timesheet t" + + " left join project_task pt on t.projectTaskId = pt.id" + + " left join project p on p.id = pt.project_id" + + " where t.staffId = :staffId" + + " group by p.id, t.recordDate" + + " order by p.id, t.recordDate" + + " and t.recordDate BETWEEN :startDate and :endDate" + ) + return jdbcDao.queryForList(sql.toString(), args) + } + open fun getLeaves(args: Map): List> { + val sql = StringBuilder( + " SELECT " + + " sum(leaveHours) as leaveHours, " + + " CAST(DATE_FORMAT(recordDate, '%d') AS SIGNED) AS recordDate " + + " from `leave` " + + " where staffId = :staffId " + + " and recordDate BETWEEN :startDate and :endDate " + + " group by recordDate " + + " order by recordDate " + ) + return jdbcDao.queryForList(sql.toString(), args) + } + +} 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 1173a10..a097ba4 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 @@ -11,6 +11,7 @@ import com.ffii.tsms.modules.report.web.model.ProjectCashFlowReportRequest import com.ffii.tsms.modules.report.web.model.StaffMonthlyWorkHourAnalysisReportRequest import com.ffii.tsms.modules.timesheet.entity.LeaveRepository import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository +import com.ffii.tsms.modules.timesheet.entity.projections.ProjectMonthlyHoursWithDate import jakarta.validation.Valid import org.springframework.core.io.ByteArrayResource import org.springframework.core.io.Resource @@ -78,14 +79,15 @@ class ReportController( val nextMonth = request.yearMonth.plusMonths(1).atDay(1) val staff = staffRepository.findById(request.id).orElseThrow() - val timesheets = timesheetRepository.findByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth) - val leaves = leaveRepository.findByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth) - - 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 args: Map = mutableMapOf( + "staffId" to request.id, + "startDate" to thisMonth, + "endDate" to nextMonth, + ) + val timesheets= excelReportService.getTimesheet(args) + val leaves= excelReportService.getLeaves(args) + + val reportResult: ByteArray = excelReportService.generateStaffMonthlyWorkHourAnalysisReport(thisMonth, staff, timesheets, leaves) // val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") return ResponseEntity.ok() // .contentType(mediaType) diff --git a/src/main/java/com/ffii/tsms/modules/timesheet/entity/projections/MonthlyHours.kt b/src/main/java/com/ffii/tsms/modules/timesheet/entity/projections/MonthlyHours.kt index ea5f40a..1509171 100644 --- a/src/main/java/com/ffii/tsms/modules/timesheet/entity/projections/MonthlyHours.kt +++ b/src/main/java/com/ffii/tsms/modules/timesheet/entity/projections/MonthlyHours.kt @@ -2,7 +2,16 @@ package com.ffii.tsms.modules.timesheet.entity.projections import java.time.LocalDate -data class MonthlyHours( +data class MonthlyLeave( val date: LocalDate, - val nomralConsumed: Number + val leaveHours: Double ) + +data class ProjectMonthlyHoursWithDate( + val id: Long, + val name: String, + val code: String, + val date: LocalDate, + val normalConsumed: Double, + val otConsumed: Double, + ) \ No newline at end of file diff --git a/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx b/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx index 001d546..08129d7 100644 Binary files a/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx and b/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx differ