|
@@ -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 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|