| @@ -35,11 +35,16 @@ import java.math.RoundingMode | |||||
| import java.time.Year | import java.time.Year | ||||
| import javax.swing.plaf.synth.Region | import javax.swing.plaf.synth.Region | ||||
| import kotlin.collections.ArrayList | import kotlin.collections.ArrayList | ||||
| import kotlin.collections.HashMap | |||||
| data class DayInfo(val date: String?, val weekday: String?) | data class DayInfo(val date: String?, val weekday: String?) | ||||
| data class TsData(var manhour: Double, var cost: Double) | data class TsData(var manhour: Double, var cost: Double) | ||||
| data class InOut(var In: TsData, var Out: TsData) | data class InOut(var In: TsData, var Out: TsData) | ||||
| data class CrossTeamP4InOut( | |||||
| // String = "${staffCode} ${staffName} (${teamCode})" | |||||
| var In: MutableMap<String, MutableMap<String, TsData>>, | |||||
| ) | |||||
| @Service | @Service | ||||
| open class ReportService( | open class ReportService( | ||||
| @@ -71,7 +76,14 @@ open class ReportService( | |||||
| private fun cellBorderArgs(top: Int, bottom: Int, left: Int, right: Int): MutableMap<String, Any> { | private fun cellBorderArgs(top: Int, bottom: Int, left: Int, right: Int): MutableMap<String, Any> { | ||||
| var cellBorderArgs = mutableMapOf<String, Any>() | var cellBorderArgs = mutableMapOf<String, Any>() | ||||
| when (top) { | |||||
| // val thicknessMap = mapOf( | |||||
| // 1 to BorderStyle.THIN, | |||||
| // 2 to BorderStyle.THICK, | |||||
| // ) | |||||
| // if (top > 0) { | |||||
| // cellBorderArgs.put(CellUtil.BORDER_TOP, thicknessMap[top]) | |||||
| // } | |||||
| when (top ) { | |||||
| 1 -> cellBorderArgs.put(CellUtil.BORDER_TOP, BorderStyle.THIN) | 1 -> cellBorderArgs.put(CellUtil.BORDER_TOP, BorderStyle.THIN) | ||||
| 2 -> cellBorderArgs.put(CellUtil.BORDER_TOP, BorderStyle.THICK) | 2 -> cellBorderArgs.put(CellUtil.BORDER_TOP, BorderStyle.THICK) | ||||
| } | } | ||||
| @@ -90,22 +102,30 @@ open class ReportService( | |||||
| return cellBorderArgs | return cellBorderArgs | ||||
| } | } | ||||
| private fun setRegionBorders(top: Int, bottom: Int, left: Int, right: Int, region: CellRangeAddress, sheet: Sheet) { | private fun setRegionBorders(top: Int, bottom: Int, left: Int, right: Int, region: CellRangeAddress, sheet: Sheet) { | ||||
| when (top) { | |||||
| 1 -> RegionUtil.setBorderTop(BorderStyle.THIN, region, sheet) | |||||
| 2 -> RegionUtil.setBorderTop(BorderStyle.THICK, region, sheet) | |||||
| } | |||||
| when (bottom) { | |||||
| 1 -> RegionUtil.setBorderBottom(BorderStyle.THIN, region, sheet) | |||||
| 2 -> RegionUtil.setBorderBottom(BorderStyle.THICK, region, sheet) | |||||
| } | |||||
| when (left) { | |||||
| 1 -> RegionUtil.setBorderLeft(BorderStyle.THIN, region, sheet) | |||||
| 2 -> RegionUtil.setBorderLeft(BorderStyle.THICK, region, sheet) | |||||
| } | |||||
| when (right) { | |||||
| 1 -> RegionUtil.setBorderRight(BorderStyle.THIN, region, sheet) | |||||
| 2 -> RegionUtil.setBorderRight(BorderStyle.THICK, region, sheet) | |||||
| } | |||||
| val thicknessMap = mapOf( | |||||
| 1 to BorderStyle.THIN, | |||||
| 2 to BorderStyle.THICK, | |||||
| ) | |||||
| RegionUtil.setBorderTop(thicknessMap[top], region, sheet) | |||||
| RegionUtil.setBorderBottom(thicknessMap[bottom], region, sheet) | |||||
| RegionUtil.setBorderLeft(thicknessMap[left], region, sheet) | |||||
| RegionUtil.setBorderRight(thicknessMap[right], region, sheet) | |||||
| // when (top) { | |||||
| // 1 -> RegionUtil.setBorderTop(thicknessMap[1], region, sheet) | |||||
| // 2 -> RegionUtil.setBorderTop(BorderStyle.THICK, region, sheet) | |||||
| // } | |||||
| // when (bottom) { | |||||
| // 1 -> RegionUtil.setBorderBottom(BorderStyle.THIN, region, sheet) | |||||
| // 2 -> RegionUtil.setBorderBottom(BorderStyle.THICK, region, sheet) | |||||
| // } | |||||
| // when (left) { | |||||
| // 1 -> RegionUtil.setBorderLeft(BorderStyle.THIN, region, sheet) | |||||
| // 2 -> RegionUtil.setBorderLeft(BorderStyle.THICK, region, sheet) | |||||
| // } | |||||
| // when (right) { | |||||
| // 1 -> RegionUtil.setBorderRight(BorderStyle.THIN, region, sheet) | |||||
| // 2 -> RegionUtil.setBorderRight(BorderStyle.THICK, region, sheet) | |||||
| // } | |||||
| } | } | ||||
| private val chargeFee = 1.15 | private val chargeFee = 1.15 | ||||
| @@ -3600,9 +3620,9 @@ open class ReportService( | |||||
| return jdbcDao.queryForList(sql.toString(), args) | return jdbcDao.queryForList(sql.toString(), args) | ||||
| } | } | ||||
| private fun generateTeamBlock( | |||||
| private fun generateTeamsInOutMap( | |||||
| teams: List<Team>, | teams: List<Team>, | ||||
| sortedTeams: MutableList<Team>, | |||||
| desiredTeam: MutableList<Team>, | |||||
| grades: List<Grade>, | grades: List<Grade>, | ||||
| timesheets: List<Timesheet>, | timesheets: List<Timesheet>, | ||||
| gradeLog: List<GradeLog>, | gradeLog: List<GradeLog>, | ||||
| @@ -3632,63 +3652,60 @@ open class ReportService( | |||||
| }.toMutableMap() | }.toMutableMap() | ||||
| } | } | ||||
| } | } | ||||
| println("teamsMap") | |||||
| println(gradeMap) | |||||
| // teamsMap["TW"]!!["1"]!!.In.manhour += 1000 | |||||
| println(teamsMap) | |||||
| sortedTeams.forEach { team -> | |||||
| val currentTeam = team.code | |||||
| val _timesheets = timesheets.filter { ts -> | |||||
| // for after team log is implemented | |||||
| // val thisStaffTeam = teamlog.filter { | |||||
| // it.from.isBefore(ts.recordDate) | |||||
| // && it.to != null | |||||
| // && it.staff.id == ts.staff!!.id | |||||
| // }.maxByOrNull { it.from } | |||||
| // val thisProjectTeam = teamlog.filter { | |||||
| // it.from.isBefore(ts.recordDate) | |||||
| // && it.to != null | |||||
| // && it.staff.id == ts.project!!.teamLead!!.team.id | |||||
| // }.maxByOrNull { it.from } | |||||
| var _timesheets: List<Timesheet> | |||||
| // if have target team, desiredTeams should only be that team | |||||
| if (desiredTeam.size == 1) { | |||||
| val team = desiredTeam[0] | |||||
| val targetTeam = team.code | |||||
| _timesheets = timesheets.filter { ts -> | |||||
| val staffTeam = ts.staff!!.team.code | val staffTeam = ts.staff!!.team.code | ||||
| val projectTeam = ts.project!!.teamLead!!.team.code | val projectTeam = ts.project!!.teamLead!!.team.code | ||||
| (staffTeam == currentTeam && projectTeam != staffTeam) | |||||
| || (projectTeam == currentTeam && projectTeam != staffTeam) // check isCrossTeam | |||||
| // ts.project!!.teamLead!!.team.id != thisStaffTeam!!.team.id // for team log | |||||
| projectTeam != staffTeam && | |||||
| (staffTeam == targetTeam || projectTeam == targetTeam ) | |||||
| } | } | ||||
| _timesheets.forEach {ts -> | |||||
| // this team charging others | |||||
| // get the grade and salary data of the record | |||||
| val _grade = gradeLog.find { it.staff.id == ts.staff!!.id } | |||||
| val gradeCode = _grade!!.grade.code | |||||
| val otMultiplier = 1.15 | |||||
| val thisSE = salaryEffective.filter { | |||||
| it.staff.id == ts.staff!!.id | |||||
| && | |||||
| it.date.isBefore(ts.recordDate) | |||||
| }.maxByOrNull { it.date } | |||||
| val normalHour = ts.normalConsumed ?: 0.0 | |||||
| val otHour = ts.otConsumed ?: 0.0 | |||||
| val normalCost = normalHour.times(thisSE!!.salary.hourlyRate.toDouble()) | |||||
| val otCost = otHour.times(thisSE.salary.hourlyRate.toDouble()).times(otMultiplier) | |||||
| //assigning data | |||||
| val projectTeam = ts.project!!.teamLead!!.team.code | |||||
| } else { | |||||
| _timesheets = timesheets.filter { ts -> | |||||
| val staffTeam = ts.staff!!.team.code | val staffTeam = ts.staff!!.team.code | ||||
| // write in | |||||
| println("putting in") | |||||
| var tsInData = teamsMap[projectTeam]!![gradeCode]!!.In | |||||
| println(tsInData) | |||||
| tsInData.manhour += normalHour + otHour | |||||
| tsInData.cost += normalCost + otCost | |||||
| // write out | |||||
| println("putting out") | |||||
| val tsOutData = teamsMap[staffTeam]!!.get(gradeCode)!!.Out | |||||
| tsOutData.manhour += normalHour + otHour | |||||
| tsOutData.cost += normalCost + otCost | |||||
| val projectTeam = ts.project!!.teamLead!!.team.code | |||||
| projectTeam != staffTeam | |||||
| } | } | ||||
| } | } | ||||
| println("all team - gradeMap") | |||||
| println(teamsMap) | |||||
| _timesheets.forEach {ts -> | |||||
| // this team charging others | |||||
| // get the grade and salary data of the record | |||||
| val _grade = gradeLog.find { | |||||
| it.staff.id == ts.staff!!.id | |||||
| && | |||||
| it.from.isBefore(ts.recordDate) && (it.to == null || it.to.isAfter(ts.recordDate)) | |||||
| && | |||||
| it.deleted == false | |||||
| } | |||||
| val gradeCode = _grade!!.grade.code | |||||
| val otMultiplier = 1.15 | |||||
| val thisSE = salaryEffective.find { | |||||
| it.staff.id == ts.staff!!.id | |||||
| && | |||||
| it.startDate.isBefore(ts.recordDate) && (it.endDate.isAfter(ts.recordDate) || it.endDate == null) | |||||
| } | |||||
| val normalHour = ts.normalConsumed ?: 0.0 | |||||
| val otHour = ts.otConsumed ?: 0.0 | |||||
| val normalCost = normalHour.times(thisSE!!.salary.hourlyRate.toDouble()) | |||||
| val otCost = otHour.times(thisSE.salary.hourlyRate.toDouble()).times(otMultiplier) | |||||
| //assigning data | |||||
| val projectTeam = ts.project!!.teamLead!!.team.code | |||||
| val staffTeam = ts.staff!!.team.code | |||||
| // write in | |||||
| //println("putting in") | |||||
| var tsInData = teamsMap[projectTeam]!![gradeCode]!!.In | |||||
| tsInData.manhour += normalHour + otHour | |||||
| tsInData.cost += normalCost + otCost | |||||
| // write out | |||||
| //println("putting out") | |||||
| val tsOutData = teamsMap[staffTeam]!!.get(gradeCode)!!.Out | |||||
| tsOutData.manhour += normalHour + otHour | |||||
| tsOutData.cost += normalCost + otCost | |||||
| } | |||||
| return teamsMap | return teamsMap | ||||
| } | } | ||||
| @@ -3697,6 +3714,23 @@ open class ReportService( | |||||
| CellUtil.setVerticalAlignment(tempCell, VerticalAlignment.TOP) | CellUtil.setVerticalAlignment(tempCell, VerticalAlignment.TOP) | ||||
| CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) | CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) | ||||
| } | } | ||||
| private fun setAlignment(cell: Cell, verticalAlignment: String, horizontalAlignment: String) { | |||||
| val verticalAlignmentMap = mapOf( | |||||
| "top" to VerticalAlignment.TOP, | |||||
| "center" to VerticalAlignment.CENTER, | |||||
| "bottom" to VerticalAlignment.BOTTOM, | |||||
| ) | |||||
| val horizontalAlignmentMap = mapOf( | |||||
| "left" to HorizontalAlignment.LEFT, | |||||
| "center" to HorizontalAlignment.CENTER, | |||||
| "right" to HorizontalAlignment.RIGHT, | |||||
| "fill" to HorizontalAlignment.FILL, | |||||
| "justify" to HorizontalAlignment.JUSTIFY, | |||||
| ) | |||||
| CellUtil.setVerticalAlignment(cell, verticalAlignmentMap[verticalAlignment]) | |||||
| CellUtil.setAlignment(cell, horizontalAlignmentMap[horizontalAlignment]) | |||||
| } | |||||
| private fun createCrossTeamForm( | private fun createCrossTeamForm( | ||||
| workbook: Workbook, | workbook: Workbook, | ||||
| sheet: Sheet, | sheet: Sheet, | ||||
| @@ -3914,15 +3948,15 @@ open class ReportService( | |||||
| sheet.getRow(rowIndex).getCell(columnIndex).apply { | sheet.getRow(rowIndex).getCell(columnIndex).apply { | ||||
| setCellValue(convertReportMonth) | setCellValue(convertReportMonth) | ||||
| } | } | ||||
| var sortedTeams = teams.toMutableList() | |||||
| var desiredTeam = teams.toMutableList() | |||||
| if (teamId.lowercase() != "all") { | if (teamId.lowercase() != "all") { | ||||
| // sortedTeams = teams.sortedWith(compareBy { if (it.id == teamId.toLong()) 0 else 1 }).toMutableList() | |||||
| sortedTeams = mutableListOf(teams.find { teamId.toLong() == it.id }!!) | |||||
| // desiredTeam = teams.sortedWith(compareBy { if (it.id == teamId.toLong()) 0 else 1 }).toMutableList() | |||||
| desiredTeam = mutableListOf(teams.find { teamId.toLong() == it.id }!!) | |||||
| } | } | ||||
| //// generate info map ///// | //// generate info map ///// | ||||
| val teamsInOutMap: MutableMap<String, MutableMap<String, InOut>> = generateTeamBlock( | |||||
| val teamsInOutMap: MutableMap<String, MutableMap<String, InOut>> = generateTeamsInOutMap( | |||||
| teams, | teams, | ||||
| sortedTeams, | |||||
| desiredTeam, | |||||
| grades, | grades, | ||||
| timesheets, | timesheets, | ||||
| gradeLog, | gradeLog, | ||||
| @@ -3942,6 +3976,306 @@ open class ReportService( | |||||
| sheet.setColumnWidth(i, 20 * 256) | sheet.setColumnWidth(i, 20 * 256) | ||||
| } | } | ||||
| } | } | ||||
| private fun createCrossTeamForm4TH( | |||||
| workbook: Workbook, | |||||
| sheet: Sheet, | |||||
| teamsMap: MutableMap<String, CrossTeamP4InOut> | |||||
| ) { | |||||
| var rowIndex = 2 | |||||
| var columnIndex = 0 | |||||
| var tempRow: Row | |||||
| var tempCell: Cell | |||||
| val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") | |||||
| fun dataFormatArgs(accountingStyle: Short): MutableMap<String, Any> { | |||||
| val dataFormatArgs = mutableMapOf<String, Any>( | |||||
| CellUtil.DATA_FORMAT to accountingStyle | |||||
| ) | |||||
| return dataFormatArgs | |||||
| } | |||||
| fun fontArgs(fontName: String, isBold: Boolean, isWrap: Boolean): MutableMap<String, Any>{ | |||||
| val font = sheet.workbook.createFont() | |||||
| font.bold = isBold | |||||
| font.fontName = fontName | |||||
| val fontArgs = mutableMapOf<String, Any>( | |||||
| CellUtil.FONT to font.index, | |||||
| CellUtil.WRAP_TEXT to isWrap, | |||||
| ) | |||||
| return fontArgs | |||||
| } | |||||
| for ((teamCode, crossTeamP4InOut) in teamsMap) { | |||||
| columnIndex = 0 | |||||
| rowIndex++ | |||||
| tempRow = getOrCreateRow(sheet, rowIndex) | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue("Team") | |||||
| alignTopCenter(tempCell) | |||||
| CellUtil.setCellStyleProperties( | |||||
| tempCell, | |||||
| fontArgs("Times New Roman", true, true) | |||||
| + cellBorderArgs(2,2,1,1) | |||||
| ) | |||||
| columnIndex = 1 | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue("Cross Team Staffs") | |||||
| alignTopCenter(tempCell) | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| fontArgs("Times New Roman", true, true) | |||||
| + cellBorderArgs(2,2,1,1) | |||||
| ) | |||||
| ////// getting unique header list with columnIndex /////// | |||||
| var projectList = mutableListOf<String>() | |||||
| for ((_, projectTsDataMap) in crossTeamP4InOut.In) { | |||||
| for(key in projectTsDataMap.keys) { | |||||
| if (key !in projectList) { | |||||
| projectList.add(key) | |||||
| } | |||||
| } | |||||
| } | |||||
| tempRow = getOrCreateRow(sheet, rowIndex) | |||||
| columnIndex = 2 | |||||
| projectList.forEach{ str -> | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue(str) | |||||
| CellUtil.setCellStyleProperties(tempCell, fontArgs("Times New Roman", true, true)) | |||||
| alignTopCenter(tempCell) | |||||
| val titleRegion = CellRangeAddress(rowIndex, rowIndex,columnIndex,columnIndex+1) | |||||
| sheet.addMergedRegion(titleRegion) | |||||
| setRegionBorders(2,2,1,1,titleRegion, sheet) | |||||
| columnIndex += 2 | |||||
| } | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue("Total By Staff") | |||||
| CellUtil.setCellStyleProperties(tempCell, fontArgs("Times New Roman", true, true)) | |||||
| alignTopCenter(tempCell) | |||||
| val titleRegion = CellRangeAddress(rowIndex, rowIndex,columnIndex,columnIndex+1) | |||||
| sheet.addMergedRegion(titleRegion) | |||||
| setRegionBorders(2,2,2,2,titleRegion, sheet) | |||||
| alignTopCenter(tempCell) | |||||
| /////////////////////////////////////////////////////////////////////////////////// | |||||
| // total column = columnIndex + list.size | |||||
| rowIndex++ | |||||
| columnIndex = 0 | |||||
| tempRow = getOrCreateRow(sheet, rowIndex) | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue(teamCode) // team column | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| fontArgs("Times New Roman", false, false) | |||||
| ) | |||||
| setAlignment(tempCell, "top", "center") | |||||
| var startingRow = rowIndex | |||||
| for ((staff, projectTsDataMap) in crossTeamP4InOut.In) { | |||||
| columnIndex = 1 | |||||
| tempRow = getOrCreateRow(sheet, rowIndex) | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue(staff) // team column | |||||
| setAlignment(tempCell, "top", "center") | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| cellBorderArgs(1,1,1,1) | |||||
| + fontArgs("Times New Roman", false, false) | |||||
| ) | |||||
| var pidx = 0 | |||||
| var manhourFormula = mutableListOf<String>() | |||||
| var costFormula = mutableListOf<String>() | |||||
| while (pidx < projectList.size) { | |||||
| var manhour = 0.0 | |||||
| var cost = 0.0 | |||||
| if (projectTsDataMap.containsKey(projectList[pidx])) { | |||||
| manhour = projectTsDataMap[projectList[pidx]]?.manhour ?: 0.0 | |||||
| cost = projectTsDataMap[projectList[pidx]]?.cost ?: 0.0 | |||||
| } | |||||
| columnIndex++ | |||||
| val manhourLetter = CellReference.convertNumToColString(columnIndex) | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue(manhour) | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| cellBorderArgs(1,1,1,1) | |||||
| + fontArgs("Times New Roman", false, false) | |||||
| + dataFormatArgs(accountingStyle) | |||||
| ) | |||||
| manhourFormula.add("${manhourLetter}${rowIndex+1}") | |||||
| columnIndex++ | |||||
| val costLetter = CellReference.convertNumToColString(columnIndex) | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue(cost) | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| cellBorderArgs(1,1,1,1) | |||||
| + fontArgs("Times New Roman", false, false) | |||||
| + dataFormatArgs(accountingStyle) | |||||
| ) | |||||
| costFormula.add("${costLetter}${rowIndex+1}") | |||||
| pidx++ | |||||
| } | |||||
| // total by staff | |||||
| columnIndex++ | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| cellBorderArgs(1,1,2,1) | |||||
| + fontArgs("Times New Roman", false, false) | |||||
| + dataFormatArgs(accountingStyle) | |||||
| ) | |||||
| tempCell.cellFormula = manhourFormula.joinToString(separator = "+") | |||||
| columnIndex++ | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| cellBorderArgs(1,1,1,1) | |||||
| + fontArgs("Times New Roman", false, false) | |||||
| + dataFormatArgs(accountingStyle) | |||||
| ) | |||||
| tempCell.cellFormula = costFormula.joinToString(separator = "+") | |||||
| rowIndex++ | |||||
| } | |||||
| columnIndex = 0 | |||||
| val teamCodeRegion = CellRangeAddress(startingRow, rowIndex, columnIndex, columnIndex) | |||||
| sheet.addMergedRegion(teamCodeRegion) | |||||
| setRegionBorders(2,2,1,1, teamCodeRegion, sheet) | |||||
| columnIndex = 1 | |||||
| tempRow = getOrCreateRow(sheet, rowIndex) | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| tempCell.setCellValue("Total by Project:") | |||||
| setAlignment(tempCell, "top", "center") | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| cellBorderArgs(1,2,1,1) | |||||
| + fontArgs("Times New Roman", true, false) | |||||
| ) | |||||
| // (project title + total by staff) * 2 | |||||
| columnIndex = 2 | |||||
| val numberOfColumns = (projectList.size + 1) * 2 | |||||
| var i = 0 | |||||
| while (i < numberOfColumns) { | |||||
| var leftBorder = 1 | |||||
| if (i == numberOfColumns - 2) { | |||||
| leftBorder = 2 | |||||
| } | |||||
| tempCell = getOrCreateCell(tempRow, columnIndex) | |||||
| val columnLetter = CellReference.convertNumToColString(columnIndex) | |||||
| tempCell.cellFormula = "SUM(${columnLetter}${startingRow+1}:${columnLetter}${rowIndex})" | |||||
| CellUtil.setCellStyleProperties(tempCell, | |||||
| cellBorderArgs(1,2,leftBorder,1) | |||||
| + fontArgs("Times New Roman", false, false) | |||||
| + dataFormatArgs(accountingStyle) | |||||
| ) | |||||
| columnIndex++ | |||||
| i++ | |||||
| } | |||||
| rowIndex++ | |||||
| } | |||||
| } | |||||
| private fun generatePageFourTeamsInOutMap( | |||||
| teams: List<Team>, | |||||
| desiredTeams: MutableList<Team>, | |||||
| grades: List<Grade>, | |||||
| timesheets: List<Timesheet>, | |||||
| gradeLog: List<GradeLog>, | |||||
| salaryEffective: List<SalaryEffective>, | |||||
| ): MutableMap<String, CrossTeamP4InOut> { | |||||
| var teamsMap: MutableMap<String, CrossTeamP4InOut> = mutableMapOf() | |||||
| // teams.forEach { team -> | |||||
| // val key = team.code | |||||
| // if (key !in teamsMap) { | |||||
| // teamsMap[key] = CrossTeamP4InOut( | |||||
| // In = mutableMapOf(), | |||||
| // ) | |||||
| // } | |||||
| // } | |||||
| var _timesheets: List<Timesheet> | |||||
| // if have target team, desiredTeams should only be that team | |||||
| if (desiredTeams.size == 1) { | |||||
| val team = desiredTeams[0] | |||||
| val targetTeam = team.code | |||||
| _timesheets = timesheets.filter { ts -> | |||||
| val staffTeam = ts.staff!!.team.code | |||||
| val projectTeam = ts.project!!.teamLead!!.team.code | |||||
| projectTeam != staffTeam && | |||||
| (staffTeam == targetTeam || projectTeam == targetTeam ) | |||||
| } | |||||
| } else { | |||||
| _timesheets = timesheets.filter { ts -> | |||||
| val staffTeam = ts.staff!!.team.code | |||||
| val projectTeam = ts.project!!.teamLead!!.team.code | |||||
| projectTeam != staffTeam | |||||
| } | |||||
| } | |||||
| _timesheets.forEach { ts -> | |||||
| val otMultiplier = 1.15 | |||||
| val thisSE = salaryEffective.filter { | |||||
| it.staff.id == ts.staff!!.id | |||||
| && | |||||
| it.date.isBefore(ts.recordDate) | |||||
| }.maxByOrNull { it.date } | |||||
| val normalHour = ts.normalConsumed ?: 0.0 | |||||
| val otHour = ts.otConsumed ?: 0.0 | |||||
| val normalCost = normalHour.times(thisSE!!.salary.hourlyRate.toDouble()) | |||||
| val otCost = otHour.times(thisSE.salary.hourlyRate.toDouble()).times(otMultiplier) | |||||
| val staff = ts.staff!! | |||||
| val project = ts.project!! | |||||
| val projectNameCode = "${project.code}\n${project.name}" | |||||
| val projectTeam = project.teamLead!!.team.code | |||||
| val inOut_Key = "${staff.staffId} ${staff.name} (${staff.team.code})" | |||||
| if (!teamsMap.containsKey(projectTeam)) { | |||||
| teamsMap.put(projectTeam, CrossTeamP4InOut( | |||||
| In = mutableMapOf(), | |||||
| )) | |||||
| } | |||||
| val tsInData = teamsMap[projectTeam]!!.In | |||||
| if (!tsInData.containsKey(inOut_Key)) { | |||||
| tsInData.put(inOut_Key, mutableMapOf(projectNameCode to TsData(0.0, 0.0))) | |||||
| } | |||||
| if (!tsInData[inOut_Key]!!.containsKey(projectNameCode)) { | |||||
| tsInData[inOut_Key]!!.put(projectNameCode, TsData(0.0, 0.0)) | |||||
| } | |||||
| tsInData[inOut_Key]!![projectNameCode]!!.manhour += normalHour + otHour | |||||
| tsInData[inOut_Key]!![projectNameCode]!!.cost += normalCost + otCost | |||||
| } | |||||
| return teamsMap | |||||
| } | |||||
| private fun createFourthSheetTeamChargeReport( | |||||
| month: String, | |||||
| workbook: Workbook, | |||||
| timesheets: List<Timesheet>, | |||||
| teams: List<Team>, | |||||
| grades: List<Grade>, | |||||
| teamId: String, | |||||
| gradeLog: List<GradeLog>, | |||||
| salaryEffective: List<SalaryEffective>, | |||||
| ) { | |||||
| var sheet: Sheet = workbook.getSheetAt(3) | |||||
| val rowIndex = 1 // Assuming the location is in (1,2), which is the report date field | |||||
| val columnIndex = 2 | |||||
| val monthFormat = DateTimeFormatter.ofPattern("MMMM yyyy", Locale.ENGLISH) | |||||
| val reportMonth = YearMonth.parse(month, DateTimeFormatter.ofPattern("yyyy-MM")) | |||||
| val convertReportMonth = YearMonth.of(reportMonth.year, reportMonth.month).format(monthFormat) | |||||
| sheet.getRow(rowIndex).getCell(columnIndex).apply { | |||||
| setCellValue(convertReportMonth) | |||||
| } | |||||
| val _teams = teams | |||||
| var desiredTeams = teams.toMutableList() | |||||
| if (teamId.lowercase() != "all") { | |||||
| desiredTeams = mutableListOf(teams.find { teamId.toLong() == it.id }!!) | |||||
| _teams.sortedWith(compareBy { if (it.id == teamId.toLong()) 0 else 1 }) | |||||
| } | |||||
| val teamsInOutMap: MutableMap<String, CrossTeamP4InOut> = generatePageFourTeamsInOutMap( | |||||
| _teams, | |||||
| desiredTeams, | |||||
| grades, | |||||
| timesheets, | |||||
| gradeLog, | |||||
| salaryEffective, | |||||
| ) | |||||
| println("4th ------- teamsInOutMap") | |||||
| println(teamsInOutMap) | |||||
| createCrossTeamForm4TH( | |||||
| workbook, | |||||
| sheet, | |||||
| teamsInOutMap | |||||
| ) | |||||
| } | |||||
| @Throws(IOException::class) | @Throws(IOException::class) | ||||
| private fun createCrossTeamChargeReport( | private fun createCrossTeamChargeReport( | ||||
| month: String, | month: String, | ||||
| @@ -4530,6 +4864,17 @@ open class ReportService( | |||||
| gradeLog, | gradeLog, | ||||
| salaryEffective | salaryEffective | ||||
| ) | ) | ||||
| // page 4 | |||||
| createFourthSheetTeamChargeReport( | |||||
| month, | |||||
| workbook, | |||||
| timesheets, | |||||
| _teams, | |||||
| grades, | |||||
| teamId, | |||||
| gradeLog, | |||||
| salaryEffective | |||||
| ) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| // Use to Calculate cummunlative expenditure | // Use to Calculate cummunlative expenditure | ||||