private val DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd")
private val FORMATTED_TODAY = LocalDate.now().format(DATE_FORMATTER)
private val PandL_REPORT = "templates/report/AR07_Project P&L Report v02.xlsx"
private val FINANCIAL_STATUS_REPORT = "templates/report/EX01_Financial Status Report.xlsx"
private val PROJECT_CASH_FLOW_REPORT = "templates/report/EX02_Project Cash Flow Report.xlsx"
private val MONTHLY_WORK_HOURS_ANALYSIS_REPORT = "templates/report/AR08_Monthly Work Hours Analysis Report.xlsx"
@@ -1177,4 +1173,456 @@ open class ReportService(
return jdbcDao.queryForList(sql.toString(), args)
}
open fun getManhoursSpent(projectId: Long, startMonth: String, endMonth: String): List<Map<String, Any>>{
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.salaryPoint, s2.hourlyRate, t.staffId,"
+ " t.recordDate"
+ " from timesheet t"
+ " left join project_task pt on pt.id = t.projectTaskId"
+ " left join project p ON p.id = pt.project_id"
+ " left join staff s on s.id = t.staffId"
+ " left join salary s2 on s.salaryId = s2.salaryPoint"
+ " left join team t2 on t2.id = s.teamId"
+ " ),"
+ " cte_invoice as ("
+ " select p.code, sum(i.issueAmount) as sumIssuedAmount , sum(i.paidAmount) as sumPaidAmount"
+ " from invoice i"
+ " left join project p on p.code = i.projectCode"
+ " group by p.code"
+ " )"
+ " select p.code, p.description, c.name as client, concat(t.code, \" - \", t.name) as teamLead,"
+ " IFNULL(cte_ts.normalConsumed, 0) as normalConsumed, IFNULL(cte_ts.otConsumed, 0) as otConsumed, DATE_FORMAT(cte_ts.recordDate, '%Y-%m') as recordDate, "
+ " IFNULL(cte_ts.salaryPoint, 0) as salaryPoint, "
+ " IFNULL(cte_ts.hourlyRate, 0) as hourlyRate, IFNULL(cte_i.sumIssuedAmount, 0) as sumIssuedAmount, IFNULL(cte_i.sumPaidAmount, 0) as sumPaidAmount,"
+ " s.name, s.staffId, g.code as gradeCode, g.name as gradeName, t2.code as teamCode, t2.name as teamName"
+ " from project p"
+ " left join cte_timesheet cte_ts on p.code = cte_ts.code"
+ " left join customer c on c.id = p.customerId"
+ " left join tsmsdb.team t on t.teamLead = p.teamLead"
+ " left join cte_invoice cte_i on cte_i.code = p.code"
+ " left join staff s on s.id = cte_ts.staffId"
+ " left join grade g on g.id = s.gradeId"
+ " left join team t2 on t2.id = s.teamId"
+ " where p.deleted = false"
+ " and (DATE_FORMAT(cte_ts.recordDate, \'%Y-%m\') >= :startMonth and DATE_FORMAT(cte_ts.recordDate, \'%Y-%m\') <= :endMonth)"
+ " and p.id = :projectId"
+ " order by g.code, s.name, cte_ts.recordDate"
)
val args = mapOf(
"projectId" to projectId,
"startMonth" to startMonth,
"endMonth" to endMonth,
)
val manHoursSpent = jdbcDao.queryForList(sql.toString(), args)
val projectCodeSql = StringBuilder(
"select p.code, p.description from project p where p.deleted = false and p.id = :projectId"
)
val args2 = mapOf(
"projectId" to projectId,
)
val projectsCode = jdbcDao.queryForMap(projectCodeSql.toString(), args).get()
val otFactor = BigDecimal(1).toDouble()
var tempList = mutableListOf<Map<String, Any>>()
val info: MutableMap<String, Any?> = mutableMapOf(
"reportGenerationDate" to LocalDate.now().toString(),
"startMonth" to startMonth,
"endMonth" to endMonth,
"code" to projectsCode["code"],
"description" to projectsCode["description"],
)
val staffInfoList = mutableListOf<Map<String, Any>>()
"team" to "${item.getValue("teamCode")} - ${item.getValue("teamName")}",
"grade" to item.getValue("gradeCode"),
"salaryPoint" to item.getValue("salaryPoint"),
"hourlyRate" to hourlyRate,
"hourlySpent" to mutableListOf(
mapOf(
"recordDate" to item.getValue("recordDate"),
"normalConsumed" to item.getValue("normalConsumed"),
"otConsumed" to item.getValue("otConsumed"),
"totalManHours" to item.getValue("normalConsumed") as Double + item.getValue("otConsumed") as Double,
"manhourExpenditure" to (hourlyRate * item.getValue("normalConsumed") as Double )
+ (hourlyRate * item.getValue("otConsumed") as Double * otFactor)
)
)
)
)
}else{
val existingMap = staffInfoList.find { it.containsValue(item.getValue("staffId")) }!!
val updatedMap = existingMap.toMutableMap()
val hourlySpentList = updatedMap["hourlySpent"] as MutableList<Map<String, Any>>
val existingRecord = hourlySpentList.find { it["recordDate"] == item.getValue("recordDate") }
if (existingRecord != null) {
val existingIndex = hourlySpentList.indexOf(existingRecord)
val updatedRecord = existingRecord.toMutableMap()
updatedRecord["normalConsumed"] = (updatedRecord["normalConsumed"] as Double) + item.getValue("normalConsumed") as Double
updatedRecord["otConsumed"] = (updatedRecord["otConsumed"] as Double) + item.getValue("otConsumed") as Double
updatedRecord["totalManHours"] = (updatedRecord["totalManHours"] as Double) + item.getValue("normalConsumed") as Double + item.getValue("otConsumed") as Double
updatedRecord["manhourExpenditure"] = (updatedRecord["manhourExpenditure"] as Double) + (hourlyRate * item.getValue("normalConsumed") as Double) + (hourlyRate * item.getValue("otConsumed") as Double * otFactor)
hourlySpentList[existingIndex] = updatedRecord
} else {
hourlySpentList.add(
mapOf(
"recordDate" to item.getValue("recordDate"),
"normalConsumed" to item.getValue("normalConsumed"),
"otConsumed" to item.getValue("otConsumed"),
"totalManHours" to item.getValue("normalConsumed") as Double + item.getValue("otConsumed") as Double,
"manhourExpenditure" to (hourlyRate * item.getValue("normalConsumed") as Double)
+ (hourlyRate * item.getValue("otConsumed") as Double * otFactor)
)
)
}
updatedMap["hourlySpent"] = hourlySpentList
val updatedIndex = staffInfoList.indexOf(existingMap)