fun genFinancialStatusReport(teamLeadId: Long): ByteArray {
fun genFinancialStatusReport(teamLeadId: Long, startMonth: String, endMonth: String): ByteArray {
val financialStatus: List<Map<String, Any>> = getFinancialStatus(teamLeadId)
val manhoursSpent = getManHoursSpentByTeam(teamLeadId)
val financialStatus: List<Map<String, Any>> = getFinancialStatus(teamLeadId, startMonth, endMonth)
val manhoursSpent = getManHoursSpentByTeam(teamLeadId, startMonth, endMonth)
val salaryEffectiveMap = getSalaryEffectiveByTeamLead(teamLeadId)
val salaryEffectiveMap = getSalaryEffectiveByTeamLead(teamLeadId)
val updatedTimesheetData = updateTimesheetDataWithEffectiveSalary(manhoursSpent, salaryEffectiveMap)
val updatedTimesheetData = updateTimesheetDataWithEffectiveSalary(manhoursSpent, salaryEffectiveMap)
val projectsExpenditure = calculateProjectExpenditures(updatedTimesheetData)
val projectsExpenditure = calculateProjectExpenditures(updatedTimesheetData)
@@ -213,7 +213,7 @@ open class ReportService(
}
}
}
}
val workbook: Workbook = createFinancialStatusReport(FINANCIAL_STATUS_REPORT, updatedList, teamLeadId)
val workbook: Workbook = createFinancialStatusReport(FINANCIAL_STATUS_REPORT, updatedList, teamLeadId, startMonth, endMonth)
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
workbook.write(outputStream)
workbook.write(outputStream)
@@ -444,7 +444,9 @@ open class ReportService(
private fun createFinancialStatusReport(
private fun createFinancialStatusReport(
templatePath: String,
templatePath: String,
projects: List<Map<String, Any>>,
projects: List<Map<String, Any>>,
teamLeadId: Long
teamLeadId: Long,
startMonth: String,
endMonth: String,
): Workbook {
): Workbook {
val resource = ClassPathResource(templatePath)
val resource = ClassPathResource(templatePath)
@@ -468,7 +470,7 @@ open class ReportService(
val boldFontCellStyle = workbook.createCellStyle()
val boldFontCellStyle = workbook.createCellStyle()
boldFontCellStyle.setFont(boldFont)
boldFontCellStyle.setFont(boldFont)
var rowNum = 14
var rowNum = 16
if (projects.isEmpty()) {
if (projects.isEmpty()) {
// Fill the cell in Row 2-12 with thr calculated sum
// Fill the cell in Row 2-12 with thr calculated sum
@@ -496,10 +498,15 @@ open class ReportService(
setCellValue("$code - $name")
setCellValue("$code - $name")
}
}
rowNum = 4
val row4: Row = sheet.getRow(rowNum)
val row4Cell = row4.createCell(2)
row4Cell.setCellValue(projects.size.toString())
rowNum = 3
val row3: Row = sheet.getRow(rowNum)
val row3Cell = row3.createCell(2)
row3Cell.setCellValue("$startMonth - $endMonth")
rowNum = 4+1
val row5: Row = sheet.getRow(rowNum)
val row5Cell = row5.createCell(2)
row5Cell.setCellValue(projects.size.toString())
return workbook
return workbook
}
}
@@ -543,9 +550,11 @@ open class ReportService(
setCellValue(totalFee)
setCellValue(totalFee)
cellStyle.dataFormat = accountingStyle
cellStyle.dataFormat = accountingStyle
}
}
// subContractFee is count in fee
// val fee = (item["expectedTotalFee"]?.let { it as Double } ?: 0.0) - (item["subContractFee"]?.let { it as Double }
// ?: 0.0)
val fee = (item["expectedTotalFee"]?.let { it as Double } ?: 0.0) - (item["subContractFee"]?.let { it as Double }
?: 0.0)
val fee = (item["expectedTotalFee"]?.let { it as Double } ?: 0.0)
val budgetCell = row.createCell(8)
val budgetCell = row.createCell(8)
budgetCell.apply {
budgetCell.apply {
@@ -759,16 +768,21 @@ open class ReportService(
row2Cell.setCellValue("All")
row2Cell.setCellValue("All")
} else {
} else {
row2Cell.apply {
row2Cell.apply {
cellFormula = "E15"
cellFormula = "E16"
}
}
}
}
rowNum = 4
rowNum = 3
val row3: Row = sheet.getRow(rowNum)
val row3Cell = row3.createCell(2)
row3Cell.setCellValue("$startMonth - $endMonth")
rowNum = 4+1
val row4: Row = sheet.getRow(rowNum)
val row4: Row = sheet.getRow(rowNum)
val row4Cell = row4.createCell(2)
val row4Cell = row4.createCell(2)
row4Cell.setCellValue(projects.size.toString())
row4Cell.setCellValue(projects.size.toString())
rowNum = 5
rowNum = 5+1
val row5: Row = sheet.getRow(rowNum)
val row5: Row = sheet.getRow(rowNum)
val cell1 = row5.createCell(2)
val cell1 = row5.createCell(2)
cell1.apply {
cell1.apply {
@@ -776,7 +790,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
cellStyle.dataFormat = accountingStyle
}
}
rowNum = 6
rowNum = 6+1
val row6: Row = sheet.getRow(rowNum)
val row6: Row = sheet.getRow(rowNum)
val cell2 = row6.createCell(2)
val cell2 = row6.createCell(2)
cell2.apply {
cell2.apply {
@@ -784,7 +798,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
cellStyle.dataFormat = accountingStyle
}
}
rowNum = 7
rowNum = 7+1
val row7: Row = sheet.getRow(rowNum)
val row7: Row = sheet.getRow(rowNum)
val cell3 = row7.createCell(2)
val cell3 = row7.createCell(2)
cell3.apply {
cell3.apply {
@@ -792,7 +806,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
cellStyle.dataFormat = accountingStyle
}
}
rowNum = 8
rowNum = 8+1
val row8: Row = sheet.getRow(rowNum)
val row8: Row = sheet.getRow(rowNum)
val cell4 = row8.createCell(2)
val cell4 = row8.createCell(2)
cell4.apply {
cell4.apply {
@@ -800,7 +814,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
cellStyle.dataFormat = accountingStyle
}
}
rowNum = 9
rowNum = 9+1
val row9: Row = sheet.getRow(rowNum)
val row9: Row = sheet.getRow(rowNum)
val cell5 = row9.createCell(2)
val cell5 = row9.createCell(2)
cell5.apply {
cell5.apply {
@@ -808,7 +822,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
cellStyle.dataFormat = accountingStyle
}
}
rowNum = 10
rowNum = 10+1
val row10: Row = sheet.getRow(rowNum)
val row10: Row = sheet.getRow(rowNum)
val cell6 = row10.createCell(2)
val cell6 = row10.createCell(2)
cell6.apply {
cell6.apply {
@@ -816,7 +830,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
cellStyle.dataFormat = accountingStyle
}
}
rowNum = 11
rowNum = 11+1
val row11: Row = sheet.getRow(rowNum)
val row11: Row = sheet.getRow(rowNum)
val cell7 = row11.createCell(2)
val cell7 = row11.createCell(2)
cell7.apply {
cell7.apply {
@@ -2179,7 +2193,16 @@ open class ReportService(
}
}
}
}
open fun getFinancialStatus(teamLeadId: Long?): List<Map<String, Any>> {
open fun getFinancialStatus(teamLeadId: Long?, startMonth: String, endMonth: String): List<Map<String, Any>> {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val startYearMonth = YearMonth.parse(startMonth)
val startDate = startYearMonth.atDay(1)
val startDateString = startDate.format(formatter)
val endYearMonth = YearMonth.parse(endMonth)
val endDate = endYearMonth.atEndOfMonth()
val endDateString = endDate.format(formatter)
val sql = StringBuilder(
val sql = StringBuilder(
// " with cte_timesheet as ("
// " with cte_timesheet as ("
// + " Select p.code, s.name as staff, IFNULL(t.normalConsumed, 0) as normalConsumed, IFNULL(t.otConsumed , 0) as otConsumed, s2.hourlyRate"
// + " Select p.code, s.name as staff, IFNULL(t.normalConsumed, 0) as normalConsumed, IFNULL(t.otConsumed , 0) as otConsumed, s2.hourlyRate"
@@ -2191,21 +2214,46 @@ open class ReportService(
// + " left join team t2 on t2.id = s.teamId"
// + " left join team t2 on t2.id = s.teamId"
// + " ),"
// + " ),"
" With cte_invoice as ("
" With cte_invoice as ("
+ " select p.code, sum(i.issueAmount) as sumIssuedAmount , sum(i.paidAmount) as sumPaidAmount"
+ " select p.code, sum(i.issueAmount) as sumIssuedAmount "
+ " from invoice i"
+ " left join project p on p.code = i.projectCode"
+ " where i.deleted = false "
+ " and p.deleted = false "
+ " and i.invoiceDate >= :startMonth and i.invoiceDate <= :endMonth "
+ " group by p.code"
+ " ),"
+ " cte_rinvoice as ("
+ " select p.code, sum(i.paidAmount) as sumPaidAmount"
+ " from invoice i"
+ " from invoice i"
+ " left join project p on p.code = i.projectCode"
+ " left join project p on p.code = i.projectCode"
+ " where i.deleted = false "
+ " where i.deleted = false "
+ " and p.deleted = false "
+ " and p.deleted = false "
+ " and i.receiptDate >= :startMonth and i.receiptDate <= :endMonth "
+ " group by p.code"
+ " group by p.code"
+ " ),"
+ " ),"
+ " cte_expense as ( "
+ " cte_expense as ( "
+ " select IFNULL(sum(pe.amount),0) as amount, pe.projectId "
+ " select IFNULL(sum(pe.amount),0) as amount, pe.projectId "
+ " from project_expense pe "
+ " from project_expense pe "
+ " where pe.deleted = false "
+ " where pe.deleted = false "
+ " and pe.issueDate >= :startMonth and pe.issueDate <= :endMonth "
+ " group by projectId "
+ " group by projectId "
+ " ), "
+ " cte_fee as ( "
+ " select IFNULL(sum(mp.amount),0) as expectedTotalFee, p.id as projectId "
+ " from milestone_payment mp "
+ " left join milestone m on mp.milestoneId = m.id "
+ " left join project p on p.id = m.projectId "
+ " where p.status = 'On-going' "
+ " and p.deleted = false "
+ " and coalesce(p.actualStart, p.planStart) <= :endMonth "
+ " and mp.`date` >= :startMonth and mp.`date` <= :endMonth "
+ " and p.teamLead = :teamLeadId"
+ " group by p.id"
+ " ) "
+ " ) "
+ " select p.code, p.name, p.description, c.name as client, IFNULL(s2.name, \"N/A\") as subsidiary, concat(t.code, \' - \', t.name) as teamLead, p.planStart , p.planEnd , p.expectedTotalFee, ifnull(p.subContractFee, 0) as subContractFee, "
+ " IFNULL(cte_i.sumIssuedAmount, 0) as sumIssuedAmount, IFNULL(cte_i.sumPaidAmount, 0) as sumPaidAmount"
+ " select p.code, p.name, p.description, c.name as client, IFNULL(s2.name, \"N/A\") as subsidiary, concat(t.code, \' - \', t.name) as teamLead, "
+ " p.planStart , p.planEnd ,"
+ " IFNULL(cte_f.expectedTotalFee, 0) as expectedTotalFee, ifnull(p.subContractFee, 0) as subContractFee, "
+ " IFNULL(cte_i.sumIssuedAmount, 0) as sumIssuedAmount, IFNULL(cte_ri.sumPaidAmount, 0) as sumPaidAmount"
+ " ,0 as totalCumulativeExpenditure, IFNULL(cte_e.amount,0) as projectExpense "
+ " ,0 as totalCumulativeExpenditure, IFNULL(cte_e.amount,0) as projectExpense "
+ " from project p"
+ " from project p"
// + " left join cte_timesheet cte_ts on p.code = cte_ts.code"
// + " left join cte_timesheet cte_ts on p.code = cte_ts.code"
@@ -2214,15 +2262,18 @@ open class ReportService(
+ " left join subsidiary s2 on s2.id = cs.subsidiaryId "
+ " left join subsidiary s2 on s2.id = cs.subsidiaryId "
+ " left join tsmsdb.team t on t.teamLead = p.teamLead"
+ " left join tsmsdb.team t on t.teamLead = p.teamLead"
+ " left join cte_invoice cte_i on cte_i.code = p.code"
+ " left join cte_invoice cte_i on cte_i.code = p.code"
+ " left join cte_rinvoice cte_ri on cte_ri.code = p.code"
+ " left join cte_expense cte_e on cte_e.projectId = p.id "
+ " left join cte_expense cte_e on cte_e.projectId = p.id "
+ " left join cte_fee cte_f on cte_f.projectId = p.id "
+ " where p.status = \'On-going\'"
+ " where p.status = \'On-going\'"
+ " and p.deleted = false "
+ " and p.deleted = false "
+ " and coalesce(p.actualStart, p.planStart) <= :endMonth"
)
)
if (teamLeadId!! > 0) {
if (teamLeadId!! > 0) {
sql.append(" and p.teamLead = :teamLeadId ")
sql.append(" and p.teamLead = :teamLeadId ")
}
}
sql.append(" order by p.code")
sql.append(" order by p.code")
val args = mapOf("teamLeadId" to teamLeadId)
val args = mapOf("teamLeadId" to teamLeadId, "startMonth" to startDateString, "endMonth" to endDateString )
return jdbcDao.queryForList(sql.toString(), args)
return jdbcDao.queryForList(sql.toString(), args)
}
}
@@ -3437,7 +3488,9 @@ open class ReportService(
"clientId" to clientId,
"clientId" to clientId,
"teamLeadId" to teamId
"teamLeadId" to teamId
)
)
val manhoursSpent = getManHoursSpentByTeam(teamId)
val formatter = DateTimeFormatter.ofPattern("yyyy-MM")
val manhoursSpent = getManHoursSpentByTeam(teamId, "1970-01", LocalDate.now().format(formatter))
val salaryEffectiveMap = getSalaryEffectiveByTeamLead(teamId)
val salaryEffectiveMap = getSalaryEffectiveByTeamLead(teamId)
val updatedTimesheetData = updateTimesheetDataWithEffectiveSalary(manhoursSpent, salaryEffectiveMap)
val updatedTimesheetData = updateTimesheetDataWithEffectiveSalary(manhoursSpent, salaryEffectiveMap)
val projectsExpenditure = calculateProjectExpenditures(updatedTimesheetData)
val projectsExpenditure = calculateProjectExpenditures(updatedTimesheetData)
@@ -5223,7 +5276,16 @@ open class ReportService(
}
}
// Get all the timesheet data by Team Lead
// Get all the timesheet data by Team Lead
fun getManHoursSpentByTeam(teamLeadId: Long?): List<TimesheetData>{
fun getManHoursSpentByTeam(teamLeadId: Long?, startMonth: String, endMonth: String): List<TimesheetData>{
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val startYearMonth = YearMonth.parse(startMonth)
val startDate = startYearMonth.atDay(1)
val startDateString = startDate.format(formatter)
val endYearMonth = YearMonth.parse(endMonth)
val endDate = endYearMonth.atEndOfMonth()
val endDateString = endDate.format(formatter)
val sql = StringBuilder(
val sql = StringBuilder(
"select coalesce(t.normalConsumed, 0) as normalConsumed, coalesce(t.otConsumed, 0) as otConsumed, t.recordDate, t.staffId, s2.hourlyRate, s2.salaryPoint, p.code, p.planStart, p.planEnd"
"select coalesce(t.normalConsumed, 0) as normalConsumed, coalesce(t.otConsumed, 0) as otConsumed, t.recordDate, t.staffId, s2.hourlyRate, s2.salaryPoint, p.code, p.planStart, p.planEnd"
// For later calculating cross team charge
// For later calculating cross team charge
@@ -5236,7 +5298,8 @@ open class ReportService(
+ " left join project p on t.projectId = p.id"
+ " left join project p on t.projectId = p.id"
+ " left join staff s on t.staffId = s.id"
+ " left join staff s on t.staffId = s.id"
+ " left join salary s2 on s.salaryId = s2.salaryPoint"
+ " left join salary s2 on s.salaryId = s2.salaryPoint"
+ " where t.projectId in"
+ " where t.recordDate >= :startMonth and t.recordDate <= :endMonth "
+ " and t.projectId in"
+ " ("
+ " ("
+ " select p.id from project p"
+ " select p.id from project p"
+ " where p.status = 'On-going'"
+ " where p.status = 'On-going'"
@@ -5248,7 +5311,7 @@ open class ReportService(
sql.append(") order by code, recordDate, staffId; ")
sql.append(") order by code, recordDate, staffId; ")
val results = jdbcDao.queryForList(sql.toString(), mapOf("teamLeadId" to teamLeadId)).map {
val results = jdbcDao.queryForList(sql.toString(), mapOf("teamLeadId" to teamLeadId, "startMonth" to startDateString, "endMonth" to endDateString )).map {
result ->
result ->
TimesheetData(
TimesheetData(
result["normalConsumed"] as Double,
result["normalConsumed"] as Double,
@@ -5312,7 +5375,8 @@ open class ReportService(
// Find the nearest effective date that is less than or equal to the record date
// Find the nearest effective date that is less than or equal to the record date