ソースを参照

cross team individual 2

add_swagger
MSI\derek 10ヶ月前
コミット
3f3cd02481
2個のファイルの変更420行の追加75行の削除
  1. +420
    -75
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  2. バイナリ
      src/main/resources/templates/report/Cross Team Charge Report.xlsx

+ 420
- 75
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt ファイルの表示

@@ -35,11 +35,16 @@ import java.math.RoundingMode
import java.time.Year
import javax.swing.plaf.synth.Region
import kotlin.collections.ArrayList
import kotlin.collections.HashMap


data class DayInfo(val date: String?, val weekday: String?)
data class TsData(var manhour: Double, var cost: Double)
data class InOut(var In: TsData, var Out: TsData)
data class CrossTeamP4InOut(
// String = "${staffCode} ${staffName} (${teamCode})"
var In: MutableMap<String, MutableMap<String, TsData>>,
)

@Service
open class ReportService(
@@ -71,7 +76,14 @@ open class ReportService(

private fun cellBorderArgs(top: Int, bottom: Int, left: Int, right: Int): MutableMap<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)
2 -> cellBorderArgs.put(CellUtil.BORDER_TOP, BorderStyle.THICK)
}
@@ -90,22 +102,30 @@ open class ReportService(
return cellBorderArgs
}
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
@@ -3600,9 +3620,9 @@ open class ReportService(
return jdbcDao.queryForList(sql.toString(), args)
}

private fun generateTeamBlock(
private fun generateTeamsInOutMap(
teams: List<Team>,
sortedTeams: MutableList<Team>,
desiredTeam: MutableList<Team>,
grades: List<Grade>,
timesheets: List<Timesheet>,
gradeLog: List<GradeLog>,
@@ -3632,63 +3652,60 @@ open class ReportService(
}.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 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
// 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
}

@@ -3697,6 +3714,23 @@ open class ReportService(
CellUtil.setVerticalAlignment(tempCell, VerticalAlignment.TOP)
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(
workbook: Workbook,
sheet: Sheet,
@@ -3914,15 +3948,15 @@ open class ReportService(
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(convertReportMonth)
}
var sortedTeams = teams.toMutableList()
var desiredTeam = teams.toMutableList()
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 /////
val teamsInOutMap: MutableMap<String, MutableMap<String, InOut>> = generateTeamBlock(
val teamsInOutMap: MutableMap<String, MutableMap<String, InOut>> = generateTeamsInOutMap(
teams,
sortedTeams,
desiredTeam,
grades,
timesheets,
gradeLog,
@@ -3942,6 +3976,306 @@ open class ReportService(
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)
private fun createCrossTeamChargeReport(
month: String,
@@ -4530,6 +4864,17 @@ open class ReportService(
gradeLog,
salaryEffective
)
// page 4
createFourthSheetTeamChargeReport(
month,
workbook,
timesheets,
_teams,
grades,
teamId,
gradeLog,
salaryEffective
)
return workbook
}
// Use to Calculate cummunlative expenditure


バイナリ
src/main/resources/templates/report/Cross Team Charge Report.xlsx ファイルの表示


読み込み中…
キャンセル
保存