| @@ -2100,47 +2100,95 @@ open class ReportService( | |||||
| return jdbcDao.queryForList(sql.toString(), args) | return jdbcDao.queryForList(sql.toString(), args) | ||||
| } | } | ||||
| open fun getProjectResourceOverconsumptionReport_projectInfo(args: Map<String, Any>): List<Map<String, Any>> { | |||||
| val sql = StringBuilder("SELECT" | |||||
| + " t.projectId as id, " | |||||
| + " p.code as projectCode, " | |||||
| + " p.name as projectName, " | |||||
| + " te.code as team, " | |||||
| + " CONCAT( c.code, ' - ' ,c.name ) as client, " | |||||
| + " COALESCE(concat(sub.code, ' - ', sub.name), 'N/A') as subsidaiary, " | |||||
| + " (p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8 as plannedBudget " | |||||
| + " from timesheet t " | |||||
| + " left join project p on p.id = t.projectId " | |||||
| + " left join team te on te.teamLead = p.teamLead " | |||||
| + " left join customer c ON p.customerId = c.id " | |||||
| + " left join subsidiary sub on sub.id = p.customerSubsidiaryId " | |||||
| + " where t.projectid is not NULL " | |||||
| + " and p.deleted = false " | |||||
| + " and p.status = 'On-going' " | |||||
| ) | |||||
| if (args != null) { | |||||
| if (args.containsKey("teamId")) | |||||
| sql.append(" and tm.id = :teamId") | |||||
| if (args.containsKey("custId")) | |||||
| sql.append(" and c.id = :custId") | |||||
| if (args.containsKey("subsidiaryId")) | |||||
| sql.append(" and ss.id = :subsidiaryId") | |||||
| } | |||||
| sql.append(" group by t.projectId; ") | |||||
| return jdbcDao.queryForList(sql.toString(), args) | |||||
| } | |||||
| open fun getProjectResourceOverconsumptionReport_timesheetInfo(): List<Map<String, Any>> { | |||||
| val sql = StringBuilder("SELECT" | |||||
| + " t.*, " | |||||
| + " sal.hourlyRate " | |||||
| + " from timesheet t " | |||||
| + " left join staff s on s.id = t.staffId " | |||||
| + " left join salary sal on sal.salaryPoint = s.salaryId " | |||||
| + " where t.deleted = false " | |||||
| ) | |||||
| return jdbcDao.queryForList(sql.toString()) | |||||
| } | |||||
| open fun getProjectResourceOverconsumptionReport(args: Map<String, Any>): List<Map<String, Any>> { | open fun getProjectResourceOverconsumptionReport(args: Map<String, Any>): List<Map<String, Any>> { | ||||
| val sql = StringBuilder( | 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 - ifnull(p.subContractFee, 0)) * 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 - ifnull(p.subContractFee, 0)) * 0.8) as budgetConsumptionRate, " | |||||
| + " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0) as manhourConsumptionRate, " | |||||
| + " case " | |||||
| + " when sum(t.consumedBudget) / ((p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8) >= 1 " | |||||
| + " or (sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0)) >= 1 " | |||||
| + " then 'Overconsumption' " | |||||
| + " when sum(t.consumedBudget) / ((p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8) >= :lowerLimit and sum(t.consumedBudget) / ((p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8) <= 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' " | |||||
| + " 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' " | |||||
| "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 - ifnull(p.subContractFee, 0)) * 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 - ifnull(p.subContractFee, 0)) * 0.8) as budgetConsumptionRate, " | |||||
| + " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0) as manhourConsumptionRate, " | |||||
| + " case " | |||||
| + " when sum(t.consumedBudget) / ((p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8) >= 1 " | |||||
| + " or (sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) / COALESCE(p.totalManhour, 0)) >= 1 " | |||||
| + " then 'Overconsumption' " | |||||
| + " when sum(t.consumedBudget) / ((p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8) >= :lowerLimit and sum(t.consumedBudget) / ((p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8) <= 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' " | |||||
| + " else 'Within Budget' " | |||||
| + " END as status " | |||||
| + " from " | |||||
| + " (SELECT t.*, (t.normalConsumed + COALESCE(t.otConsumed, 0)) * sal.hourlyRate as consumedBudget " | |||||
| + " FROM " | |||||
| + " ( " | |||||
| + " SELECT t.id AS tid, max(se.date) AS max_date " | |||||
| + " FROM timesheet t " | |||||
| + " INNER JOIN salary_effective se ON se.staffId = t.staffId AND se.date <= t.recordDate " | |||||
| + " GROUP BY t.id " | |||||
| + " ) max_se " | |||||
| + " LEFT JOIN timesheet t ON t.id = max_se.tid " | |||||
| + " LEFT JOIN staff s on s.id = t.staffId " | |||||
| + " inner join salary_effective se on se.date = max_se.max_date " | |||||
| + " left join salary sal on se.salaryId = sal.salaryPoint) 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' " | |||||
| ) | ) | ||||
| var statusFilter: String = "" | var statusFilter: String = "" | ||||
| if (args != null) { | if (args != null) { | ||||
| if (args.containsKey("teamId")) | if (args.containsKey("teamId")) | ||||
| sql.append(" and t.id = :teamId") | |||||
| sql.append(" and tm.id = :teamId") | |||||
| if (args.containsKey("custId")) | if (args.containsKey("custId")) | ||||
| sql.append(" and c.id = :custId") | sql.append(" and c.id = :custId") | ||||
| if (args.containsKey("subsidiaryId")) | if (args.containsKey("subsidiaryId")) | ||||