Browse Source

update report

tags/Baseline_30082024_BACKEND_UAT
MSI\derek 1 year ago
parent
commit
fac00ee648
3 changed files with 102 additions and 29 deletions
  1. +96
    -28
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  2. +4
    -1
      src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt
  3. +2
    -0
      src/main/java/com/ffii/tsms/modules/timesheet/entity/LeaveRepository.kt

+ 96
- 28
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt View File

@@ -4,6 +4,7 @@ import com.ffii.tsms.modules.data.entity.Salary
import com.ffii.tsms.modules.data.entity.Staff import com.ffii.tsms.modules.data.entity.Staff
import com.ffii.tsms.modules.project.entity.Invoice import com.ffii.tsms.modules.project.entity.Invoice
import com.ffii.tsms.modules.project.entity.Project 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.Timesheet
import org.apache.poi.ss.usermodel.* import org.apache.poi.ss.usermodel.*
import org.apache.poi.ss.util.CellRangeAddress import org.apache.poi.ss.util.CellRangeAddress
@@ -41,9 +42,9 @@ open class ReportService {
} }


@Throws(IOException::class) @Throws(IOException::class)
fun generateStaffMonthlyWorkHourAnalysisReport(month: LocalDate, staff: Staff, timesheets: List<Timesheet>, projectList: List<String>): ByteArray {
fun generateStaffMonthlyWorkHourAnalysisReport(month: LocalDate, staff: Staff, timesheets: List<Timesheet>, leaves: List<Leave>, projectList: List<String>): ByteArray {
// Generate the Excel report with query results // Generate the Excel report with query results
val workbook: Workbook = createStaffMonthlyWorkHourAnalysisReport(month, staff, timesheets, 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 // Write the workbook to a ByteArrayOutputStream
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
@@ -251,6 +252,7 @@ open class ReportService {
month: LocalDate, month: LocalDate,
staff: Staff, staff: Staff,
timesheets: List<Timesheet>, timesheets: List<Timesheet>,
leaves: List<Leave>,
projectList: List<String>, projectList: List<String>,
templatePath: String, templatePath: String,
): Workbook { ): Workbook {
@@ -261,6 +263,7 @@ open class ReportService {


val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") 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 daysOfMonth = (1..month.lengthOfMonth()).map { day -> val daysOfMonth = (1..month.lengthOfMonth()).map { day ->
val date = month.withDayOfMonth(day) val date = month.withDayOfMonth(day)
@@ -281,6 +284,7 @@ open class ReportService {
var rowSize = 0 var rowSize = 0
var columnSize = 0 var columnSize = 0


var dayInt = 0
// tempCell = tempRow.createCell(columnIndex) // tempCell = tempRow.createCell(columnIndex)
sheet.getRow(rowIndex).getCell(columnIndex).apply { sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(FORMATTED_TODAY) setCellValue(FORMATTED_TODAY)
@@ -310,13 +314,12 @@ open class ReportService {


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
rowIndex = 7 rowIndex = 7
println(daysOfMonth)
daysOfMonth.forEach { dayInfo -> daysOfMonth.forEach { dayInfo ->
rowIndex++ rowIndex++
rowSize++ rowSize++
println(dayInfo)
sheet.getRow(rowIndex).getCell(0).apply { sheet.getRow(rowIndex).getCell(0).apply {
setCellValue(dayInfo.date) setCellValue(dayInfo.date)
cellStyle.dataFormat = dateStyle
cellStyle.setFont(boldFont) cellStyle.setFont(boldFont)
} }
sheet.getRow(rowIndex).getCell(1).apply { sheet.getRow(rowIndex).getCell(1).apply {
@@ -329,6 +332,8 @@ open class ReportService {
sheet.getRow(rowIndex).getCell(0).apply { sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Sub-total") setCellValue("Sub-total")
cellStyle.setFont(boldFont) cellStyle.setFont(boldFont)
// cellStyle.borderTop = BorderStyle.THIN
// cellStyle.borderBottom = BorderStyle.DOUBLE
cellStyle.alignment = HorizontalAlignment.CENTER cellStyle.alignment = HorizontalAlignment.CENTER
} }
sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
@@ -339,22 +344,63 @@ open class ReportService {
// cellStyle.setFont(boldFont) // cellStyle.setFont(boldFont)
cellStyle.alignment = HorizontalAlignment.CENTER cellStyle.alignment = 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!!
}
}
sheet.getRow(rowIndex).getCell(2).apply {
setCellValue(normalConsumed)
cellStyle.alignment = HorizontalAlignment.CENTER
cellStyle.dataFormat = accountingStyle
}
sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1)) sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
// //
rowIndex += 1 rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply { sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Total Other Hours [B]") setCellValue("Total Other Hours [B]")
sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
cellStyle.setFont(boldFont) cellStyle.setFont(boldFont)
cellStyle.alignment = HorizontalAlignment.CENTER cellStyle.alignment = HorizontalAlignment.CENTER
} }
sheet.getRow(rowIndex).getCell(2).apply {
setCellValue(otConsumed)
cellStyle.alignment = HorizontalAlignment.CENTER
cellStyle.dataFormat = accountingStyle
}

sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))


rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Total Leave Hours")
cellStyle.alignment = HorizontalAlignment.CENTER
}
if (leaves.isNotEmpty()) {
leaves.forEach { l ->
leaveHours += l.leaveHours!!
}
}
sheet.getRow(rowIndex).getCell(2).apply {
setCellValue(leaveHours)
cellStyle.dataFormat = accountingStyle
}
rowIndex += 1 rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply { sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Total Spent Manhours [A+B]") setCellValue("Total Spent Manhours [A+B]")
// cellStyle.setFont(boldFont)
cellStyle.setFont(boldFont)
cellStyle.alignment = HorizontalAlignment.CENTER cellStyle.alignment = HorizontalAlignment.CENTER
cellStyle.borderBottom = BorderStyle.DOUBLE
// 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)) sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -364,6 +410,26 @@ open class ReportService {
sheet.getRow(7).getCell(columnIndex + index).apply { sheet.getRow(7).getCell(columnIndex + index).apply {
setCellValue(title) setCellValue(title)
} }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (timesheets.isNotEmpty()) {
projectList.forEach { _ ->
timesheets.forEach { timesheet ->
dayInt = timesheet.recordDate!!.dayOfMonth
sheet.getRow(dayInt.plus(7)).getCell(columnIndex).apply {
setCellValue(timesheet.normalConsumed!!)
}
}
columnIndex++
}
}
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 { sheet.getRow(rowIndex).apply {
@@ -377,47 +443,49 @@ open class ReportService {
} }
sheet.addMergedRegion(CellRangeAddress(6,6 , 2, columnIndex)) sheet.addMergedRegion(CellRangeAddress(6,6 , 2, columnIndex))
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
for (i in 2 ..columnIndex) {
for (i in 2 until columnIndex) {
for (k in 0 until rowSize) { for (k in 0 until rowSize) {
sheet.getRow(8+k).getCell(i).apply { sheet.getRow(8+k).getCell(i).apply {
setCellValue(" - ")
setCellValue(0.0)
cellStyle.dataFormat = accountingStyle cellStyle.dataFormat = accountingStyle
} }
} }
} }


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (timesheets.isNotEmpty()) {
projectList.forEachIndexed { i, _ ->
timesheets.forEach { timesheet ->
val dayInt = timesheet.recordDate!!.dayOfMonth
sheet.getRow(dayInt.plus(7)).getCell(columnIndex + i).apply {
setCellValue(timesheet.normalConsumed!!)
}
}
}
}

rowIndex = 8 rowIndex = 8
// println("rowSize is: $rowSize")
if (sheet.getRow(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) { 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?.cellFormula = "SUM(${getColumnAlphabet(2)}${rowIndex+1}:${getColumnAlphabet(columnIndex)}${rowIndex+1})" // should columnIndex - 2 cell?.cellFormula = "SUM(${getColumnAlphabet(2)}${rowIndex+1}:${getColumnAlphabet(columnIndex)}${rowIndex+1})" // should columnIndex - 2
rowIndex++ rowIndex++
// cell?.setCellValue("testing")
// rowIndex++
} }
// println(columnSize)
// cal subtotal
for (i in 0 until columnSize) { // minus last col for (i in 0 until columnSize) { // minus last col
val cell = sheet.getRow(rowIndex)?.getCell(2) ?: sheet.getRow(rowIndex)?.createCell(2) 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?.dataFormat = accountingStyle
cell?.cellStyle?.setFont(boldFont) cell?.cellStyle?.setFont(boldFont)
// cell?.cellStyle.borderBottom = border
// cell?.cellStyle?.borderTop = BorderStyle.THIN
// cell?.cellStyle?.borderBottom = BorderStyle.DOUBLE
}
} 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)
cell?.setCellValue("daily spent manhour")
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
} }
} }

return workbook return workbook
} }




+ 4
- 1
src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt View File

@@ -7,6 +7,7 @@ import com.ffii.tsms.modules.report.service.ReportService
import com.ffii.tsms.modules.project.service.InvoiceService import com.ffii.tsms.modules.project.service.InvoiceService
import com.ffii.tsms.modules.report.web.model.ProjectCashFlowReportRequest import com.ffii.tsms.modules.report.web.model.ProjectCashFlowReportRequest
import com.ffii.tsms.modules.report.web.model.StaffMonthlyWorkHourAnalysisReportRequest 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.TimesheetRepository
import jakarta.validation.Valid import jakarta.validation.Valid
import org.springframework.core.io.ByteArrayResource import org.springframework.core.io.ByteArrayResource
@@ -33,6 +34,7 @@ class ReportController(
private val timesheetRepository: TimesheetRepository, private val timesheetRepository: TimesheetRepository,
private val projectTaskRepository: ProjectTaskRepository, private val projectTaskRepository: ProjectTaskRepository,
private val staffRepository: StaffRepository, private val staffRepository: StaffRepository,
private val leaveRepository: LeaveRepository,
private val invoiceService: InvoiceService) { private val invoiceService: InvoiceService) {


@PostMapping("/ProjectCashFlowReport") @PostMapping("/ProjectCashFlowReport")
@@ -60,11 +62,12 @@ class ReportController(


val staff = staffRepository.findById(request.id).orElseThrow() val staff = staffRepository.findById(request.id).orElseThrow()
val timesheets = timesheetRepository.findByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth) val timesheets = timesheetRepository.findByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth)
val leaves = leaveRepository.findByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth)


val projects = timesheetRepository.findDistinctProjectTaskByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth) val projects = timesheetRepository.findDistinctProjectTaskByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth)
val projectList: List<String> = projects.map { p -> "${p.projectTask!!.project!!.code}\n ${p.projectTask!!.project!!.name}" } val projectList: List<String> = projects.map { p -> "${p.projectTask!!.project!!.code}\n ${p.projectTask!!.project!!.name}" }


val reportResult: ByteArray = excelReportService.generateStaffMonthlyWorkHourAnalysisReport(thisMonth, staff, timesheets, projectList)
val reportResult: ByteArray = excelReportService.generateStaffMonthlyWorkHourAnalysisReport(thisMonth, staff, timesheets, leaves, projectList)
// val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") // val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
return ResponseEntity.ok() return ResponseEntity.ok()
// .contentType(mediaType) // .contentType(mediaType)


+ 2
- 0
src/main/java/com/ffii/tsms/modules/timesheet/entity/LeaveRepository.kt View File

@@ -8,4 +8,6 @@ interface LeaveRepository : AbstractRepository<Leave, Long> {
fun findAllByStaff(staff: Staff): List<Leave> fun findAllByStaff(staff: Staff): List<Leave>


fun deleteAllByStaffAndRecordDate(staff: Staff, recordDate: LocalDate) fun deleteAllByStaffAndRecordDate(staff: Staff, recordDate: LocalDate)

fun findByStaffAndRecordDateBetweenOrderByRecordDate(staff: Staff, start: LocalDate, end: LocalDate): List<Leave>
} }

Loading…
Cancel
Save