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 updatedTimesheetData = updateTimesheetDataWithEffectiveSalary(manhoursSpent, salaryEffectiveMap)
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()
workbook.write(outputStream)
@@ -444,7 +444,9 @@ open class ReportService(
private fun createFinancialStatusReport(
templatePath: String,
projects: List<Map<String, Any>>,
teamLeadId: Long
teamLeadId: Long,
startMonth: String,
endMonth: String,
): Workbook {
val resource = ClassPathResource(templatePath)
@@ -468,7 +470,7 @@ open class ReportService(
val boldFontCellStyle = workbook.createCellStyle()
boldFontCellStyle.setFont(boldFont)
var rowNum = 14
var rowNum = 16
if (projects.isEmpty()) {
// Fill the cell in Row 2-12 with thr calculated sum
@@ -496,10 +498,15 @@ open class ReportService(
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
}
@@ -543,9 +550,11 @@ open class ReportService(
setCellValue(totalFee)
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)
budgetCell.apply {
@@ -759,16 +768,21 @@ open class ReportService(
row2Cell.setCellValue("All")
} else {
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 row4Cell = row4.createCell(2)
row4Cell.setCellValue(projects.size.toString())
rowNum = 5
rowNum = 5+1
val row5: Row = sheet.getRow(rowNum)
val cell1 = row5.createCell(2)
cell1.apply {
@@ -776,7 +790,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
}
rowNum = 6
rowNum = 6+1
val row6: Row = sheet.getRow(rowNum)
val cell2 = row6.createCell(2)
cell2.apply {
@@ -784,7 +798,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
}
rowNum = 7
rowNum = 7+1
val row7: Row = sheet.getRow(rowNum)
val cell3 = row7.createCell(2)
cell3.apply {
@@ -792,7 +806,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
}
rowNum = 8
rowNum = 8+1
val row8: Row = sheet.getRow(rowNum)
val cell4 = row8.createCell(2)
cell4.apply {
@@ -800,7 +814,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
}
rowNum = 9
rowNum = 9+1
val row9: Row = sheet.getRow(rowNum)
val cell5 = row9.createCell(2)
cell5.apply {
@@ -808,7 +822,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
}
rowNum = 10
rowNum = 10+1
val row10: Row = sheet.getRow(rowNum)
val cell6 = row10.createCell(2)
cell6.apply {
@@ -816,7 +830,7 @@ open class ReportService(
cellStyle.dataFormat = accountingStyle
}
rowNum = 11
rowNum = 11+1
val row11: Row = sheet.getRow(rowNum)
val cell7 = row11.createCell(2)
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(
// " 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"
@@ -2191,21 +2214,46 @@ open class ReportService(
// + " left join team t2 on t2.id = s.teamId"
// + " ),"
" 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"
+ " left join project p on p.code = i.projectCode"
+ " where i.deleted = false "
+ " and p.deleted = false "
+ " and i.receiptDate >= :startMonth and i.receiptDate <= :endMonth "
+ " group by p.code"
+ " ),"
+ " cte_expense as ( "
+ " select IFNULL(sum(pe.amount),0) as amount, pe.projectId "
+ " from project_expense pe "
+ " where pe.deleted = false "
+ " and pe.issueDate >= :startMonth and pe.issueDate <= :endMonth "
+ " 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 "
+ " from project p"
// + " 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 tsmsdb.team t on t.teamLead = p.teamLead"
+ " 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_fee cte_f on cte_f.projectId = p.id "
+ " where p.status = \'On-going\'"
+ " and p.deleted = false "
+ " and coalesce(p.actualStart, p.planStart) <= :endMonth"
)
if (teamLeadId!! > 0) {
sql.append(" and p.teamLead = :teamLeadId ")
}
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)
}
@@ -3437,7 +3488,9 @@ open class ReportService(
"clientId" to clientId,
"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 updatedTimesheetData = updateTimesheetDataWithEffectiveSalary(manhoursSpent, salaryEffectiveMap)
val projectsExpenditure = calculateProjectExpenditures(updatedTimesheetData)
@@ -5223,7 +5276,16 @@ open class ReportService(
}
// 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(
"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
@@ -5236,7 +5298,8 @@ open class ReportService(
+ " left join project p on t.projectId = p.id"
+ " left join staff s on t.staffId = s.id"
+ " 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"
+ " where p.status = 'On-going'"
@@ -5248,7 +5311,7 @@ open class ReportService(
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 ->
TimesheetData(
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