diff --git a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt index ffb9409..a013c05 100644 --- a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt +++ b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt @@ -2027,55 +2027,43 @@ open class ReportService( } open fun getProjectResourceOverconsumptionReport(args: Map): List> { - val sql = StringBuilder( - "with teamNormalConsumed as (" - + " SELECT" - + " t.projectId," - + " p.teamLead," - + " sum(t.normalConsumed) as normalConsumed," - + " sum(t.otConsumed) as otConsumed," - + " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) as totalConsumed," - + " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) * sal.hourlyRate as totalBudget" - + " from timesheet t" - + " left join project p on p.id = t.projectId" - + " left join staff s on s.id = p.teamLead" - + " left join salary sal on sal.salaryPoint = s.salaryId" - + " group by p.teamLead, t.projectId, sal.hourlyRate" - + " )" - + " SELECT" - + " p.id," - + " p.code," - + " p.name," - + " t.code," - + " concat(c.code, ' - ',c.name) as client," - + " COALESCE(concat(ss.code, ' - ', ss.name), 'N/A') as subsidiary," - + " p.expectedTotalFee * 0.8 as plannedBudget," - + " COALESCE(tns.totalBudget, 0) as actualConsumedBudget," - + " COALESCE(p.totalManhour, 0) as plannedManhour," - + " COALESCE(tns.totalConsumed, 0) as actualConsumedManhour," - + " (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) as budgetConsumptionRate," - + " (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) as manhourConsumptionRate," - + " CASE" - + " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit and (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) <= 1" - + " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit and (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) <= 1" - + " then 'Potential Overconsumption'" - + " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= 1" - + " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= 1" - + " then 'Overconsumption'" - + " else 'Within Budget'" - + " END as status" - + " from project p" - + " left join staff s on s.id = p.teamLead" - + " left join team t on t.id = s.teamId" - + " left join customer c on c.id = p.customerId" - + " LEFT JOIN subsidiary ss on p.customerSubsidiaryId = ss.id" - + " LEFT JOIN salary sa ON s.salaryId = sa.salaryPoint" - + " left join teamNormalConsumed tns on tns.projectId = p.id" - + " WHERE p.deleted = false " - + " and p.status = 'On-going' " + val sql = StringBuilder("SELECT" + + " p.code, " + + " p.name, " + + " tm.code as team, " + + " concat(c.code, ' - ',c.name) as client, " + + " COALESCE(concat(ss.code, ' - ', ss.name), 'N/A') as subsidiary, " + + " p.expectedTotalFee * 0.8 as plannedBudget, " + + " sum(t.consumedBudget) as actualConsumedBudget, " + + " COALESCE(p.totalManhour, 0) as plannedManhour, " + + " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) as actualConsumedManhour, " + + " sum(t.consumedBudget) / p.expectedTotalFee as budgetConsumptionRate, " + + " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0) as manhourConsumptionRate, " + + " case " + + " when (sum(t.consumedBudget) / p.expectedTotalFee) >= :lowerLimit and (sum(t.consumedBudget) / p.expectedTotalFee) <= 1 " + + " or (sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0)) >= :lowerLimit and (sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0)) <= 1 " + + " then 'Potential Overconsumption' " + + " when (sum(t.consumedBudget) / p.expectedTotalFee) >= 1 " + + " or (sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0)) >= 1 " + + " then 'Overconsumption' " + + " else 'Within Budget' " + + " END as status " + + " from " + + " (SELECT " + + " t.*, " + + " (t.normalConsumed + COALESCE(t.otConsumed, 0)) * sal.hourlyRate as consumedBudget " + + " from timesheet t " + + " left join staff s on s.id = t.staffId " + + " left join salary sal on sal.salaryPoint = s.salaryId ) t " + + " left join project p on p.id = t.projectId " + + " left join team tm on p.teamLead = tm.teamLead " + + " left join customer c on c.id = p.customerId " + + " LEFT JOIN subsidiary ss on p.customerSubsidiaryId = ss.id " + + " WHERE p.deleted = false " + + " and p.status = 'On-going' " ) - if (args != null) { var statusFilter: String = "" + if (args != null) { if (args.containsKey("teamId")) sql.append(" and t.id = :teamId") if (args.containsKey("custId")) @@ -2084,23 +2072,19 @@ open class ReportService( sql.append(" and ss.id = :subsidiaryId") if (args.containsKey("status")) statusFilter = when (args.get("status")) { - "Potential Overconsumption" -> " and " + - " (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit " + - " and (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) <= 1 " + - " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit " + - " and (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) <= 1 " - - "All" -> " and " + - " (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit " + - " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit " -// "Overconsumption" -> " and " + -// " ((COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= 1 " + -// " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= 1) " - + "Potential Overconsumption" -> " having " + + " (sum(t.consumedBudget) / p.expectedTotalFee) >= :lowerLimit " + + " and (sum(t.consumedBudget) / p.expectedTotalFee) <= 1 " + + " or (sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0)) >= :lowerLimit " + + " and (sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0)) <= 1 " + "All" -> " having " + + " (sum(t.consumedBudget) / p.expectedTotalFee) >= :lowerLimit " + + " or (sum(t.consumedBudget) / p.expectedTotalFee) >= :lowerLimit " else -> "" } + } + sql.append(" group by p.code, p.name, tm.code, c.code, c.name, ss.code, ss.name,p.expectedTotalFee, p.totalManhour, p.expectedTotalFee ") sql.append(statusFilter) - } return jdbcDao.queryForList(sql.toString(), args) } diff --git a/src/main/resources/templates/report/AR03_Resource Overconsumption.xlsx b/src/main/resources/templates/report/AR03_Resource Overconsumption.xlsx index 2050300..4700608 100644 Binary files a/src/main/resources/templates/report/AR03_Resource Overconsumption.xlsx and b/src/main/resources/templates/report/AR03_Resource Overconsumption.xlsx differ