diff --git a/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt b/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt index 23f90c6..16cb115 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt @@ -223,6 +223,252 @@ open class DashboardService( } return tempList } + fun TeamProjectNo(args: Map): List> { + val sql = StringBuilder("select" + + " ROW_NUMBER() OVER (ORDER BY t.id,t.teamLead,t.code,t.name) AS id," + + " t.id as teamId," + + " t.teamLead as teamLeadId," + + " t.code as teamCode," + + " t.name as teamName," + + " count(p.id) as projectNo" + + " from team t" + + " left join staff s on t.teamLead = s.id" + + " left join project p on s.id = p.teamLead" + + " where t.deleted = 0" + + " and p.status not in (\"Pending to Start\",\"Completed\",\"Deleted\")" + + " group by t.id,t.teamLead,t.code,t.name" + ) + + return jdbcDao.queryForList(sql.toString(), args) + } + + fun searchTeamProject(args: Map): List> { + val sql = StringBuilder( + "select" + + " ROW_NUMBER() OVER (ORDER BY p.id, p.code, p.name, te.code, s.name, tg.name, p.totalManhour, milestonePayment.comingPaymentMilestone) AS id," + + " p.id as id," + + " p.id as projectId," + + " p.code as projectCode," + + " p.name as projectName," + + " te.code as team," + + " s.name as teamLead," + + " tg.name as expectedStage," + + " p.totalManhour as budgetedManhour," + + " sum(t.normalConsumed) + sum(t.otConsumed) as spentManhour," + + " p.totalManhour - sum(t.normalConsumed) - sum(t.otConsumed) as remainedManhour," + + " coalesce (round(((sum(t.normalConsumed) - sum(t.otConsumed))/p.totalManhour)*100,2),0) as manhourConsumptionPercentage," + + " DATE_FORMAT(milestonePayment.comingPaymentMilestone, '%Y-%m-%d') as comingPaymentMilestone" + + " from project p" + + " left join project_task pt on p.id = pt.project_id" + + " left join timesheet t on pt.id = t.projectTaskId" + + " left join team te on p.teamLead = te.teamLead" + + " left join staff s on te.teamLead = s.id" + + " left join milestone m on p.id = m.projectId and curdate() >= m.startDate and curdate() <= m.endDate" + + " left join task_group tg on m.taskGroupId = tg.id" + + " left join (" + + " select" + + " mp.date as comingPaymentMilestone" + + " from project p" + + " left join milestone m on p.id = m.projectId" + + " left join milestone_payment mp on m.id = mp.milestoneId" + + " where p.teamLead = :teamLeadId" + + " and mp.date >= curdate()" + + " order by date asc" + + " limit 1" + + " ) milestonePayment on 1=1" + + " where p.teamLead = :teamLeadId" + + " and p.status not in (\"Pending to Start\",\"Completed\",\"Deleted\")" + + " group by p.id, p.code, p.name, te.code, s.name, tg.name, p.totalManhour, milestonePayment.comingPaymentMilestone" + ) + + return jdbcDao.queryForList(sql.toString(), args) + } + fun searchFinancialSummaryCard(args: Map): List> { + val sql = StringBuilder( + "select" + + " t.id as teamId," + + " t.name as teamName," + + " count(p.name) as projectNo," + + " coalesce(sum(p.expectedTotalFee),0) as totalFee," + + " coalesce(sum(round(p.expectedTotalFee * 0.8,2)),0) as totalBudget," + + " coalesce(sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0) as cumulativeExpenditure," + + " coalesce(sum(i.issueAmount),0) as totalInvoiced," + + " coalesce(sum(i.paidAmount),0) as totalReceived," + + " case" + + " when coalesce(round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2),0) >= 1 then 'Positive'" + + " when coalesce(round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2),0) < 1 then 'Negative'" + + " end as cashFlowStatus," + + " coalesce(round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2),0) as cpi" + + " from team t" + + " left join project p on t.teamLead = p.teamLead" + + " left join invoice i on p.code = i.projectCode" + + " left join (" + + " select" + + " s2.hourlyRate as hourlyRate," + + " sum(t2.normalConsumed) as normalConsumed," + + " sum(t2.otConsumed) as otConsumed" + + " from team t1" + + " left join project p2 on t1.teamLead = p2.teamLead" + + " left join project_task pt ON p2.id = pt.project_id" + + " left join timesheet t2 on pt.id = t2.projectTaskId" + + " left join staff s on t2.staffId = s.id" + + " left join salary s2 on s.salaryId = s2.salaryPoint" + + " where p2.status = 'On-going'" + + " and t2.id is not null" + + " group by s2.hourlyRate" + + " ) as expenditure on 1=1" + + " where t.deleted = 0" + + " and p.status = 'On-going'" + ) + + if (args != null) { + if (args.containsKey("teamId")) + sql.append(" AND t.id = :teamId"); + } + sql.append(" group by t.id, t.name") + + return jdbcDao.queryForList(sql.toString(), args) + } + fun searchFinancialSummaryAllTeamCard(args: Map): List> { + val sql = StringBuilder( "select" + + " 'All Team' as teamName," + + " count(p.code) as projectNo," + + " sum(p.expectedTotalFee) as totalFee," + + " round(sum(p.expectedTotalFee) * 0.8,2) as totalBudget," + + " sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)) as cumulativeExpenditure," + + " sum(i.issueAmount) as totalInvoiced," + + " sum(i.paidAmount) as totalReceived," + + " case" + + " when round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2) >= 1 then 'Positive'" + + " when round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2) < 1 then 'Negative'" + + " end as cashFlowStatus," + + " round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2) as cpi" + + " from project p" + + " left join invoice i on p.code = i.projectCode" + + " left join (" + + " select" + + " s2.hourlyRate as hourlyRate," + + " sum(t2.normalConsumed) as normalConsumed," + + " sum(t2.otConsumed) as otConsumed" + + " from project p2" + + " left join project_task pt ON p2.id = pt.project_id" + + " left join timesheet t2 on pt.id = t2.projectTaskId" + + " left join staff s on t2.staffId = s.id" + + " left join salary s2 on s.salaryId = s2.salaryPoint" + + " where p2.status = 'On-going'" + + " and t2.id is not null" + + " group by s2.hourlyRate" + + " ) as expenditure on 1=1" + + " where p.status = 'On-going'" + ) + + return jdbcDao.queryForList(sql.toString(), args) + } + + fun searchFinancialSummaryByClient(args: Map): List> { + val sql = StringBuilder( "select" + + " t.id as teamId," + + " c.id as id," + + " c.code as customerCode," + + " c.name as customerName," + + " count(p.name) as projectNo," + + " sum(p.expectedTotalFee) as totalFee," + + " round(sum(p.expectedTotalFee) * 0.8,2) as totalBudget," + + " sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)) as cumulativeExpenditure," + + " coalesce(sum(i.issueAmount),0) as totalInvoiced," + + " coalesce(sum(i.paidAmount),0) as totalReceived," + + " case" + + " when coalesce(round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2),0) >= 1 then 'Positive'" + + " when coalesce(round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2),0) < 1 then 'Negative'" + + " end as cashFlowStatus," + + " coalesce(round(sum(i.issueAmount) / (sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0))),2),0) as cpi," + + " case" + + " when coalesce(round(sum(p.expectedTotalFee) * 0.8,2),0) <= coalesce(sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0) then coalesce(round(sum(p.expectedTotalFee) * 0.8,2),0) - coalesce(sum(i.issueAmount),0)" + + " when coalesce(round(sum(p.expectedTotalFee) * 0.8,2),0) > coalesce(sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0) and coalesce(sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0) < coalesce(sum(i.issueAmount),0) then 0" + + " when coalesce(round(sum(p.expectedTotalFee) * 0.8,2),0) > coalesce(sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0) and coalesce(sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0) >= coalesce(sum(i.issueAmount),0) then coalesce(sum((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0) - coalesce(sum(i.issueAmount),0)" + + " end as totalUninvoiced" + + " from team t" + + " left join project p on t.teamLead = p.teamLead" + + " left join customer c on p.customerId = c.id" + + " left join invoice i on p.code = i.projectCode" + + " left join (" + + " select" + + " s2.hourlyRate as hourlyRate," + + " sum(t2.normalConsumed) as normalConsumed," + + " sum(t2.otConsumed) as otConsumed" + + " from team t1" + + " left join project p2 on t1.teamLead = p2.teamLead" + + " left join project_task pt ON p2.id = pt.project_id" + + " left join timesheet t2 on pt.id = t2.projectTaskId" + + " left join staff s on t2.staffId = s.id" + + " left join salary s2 on s.salaryId = s2.salaryPoint" + + " where p2.status = 'On-going'" + + " and t2.id is not null" + + " group by s2.hourlyRate" + + " ) as expenditure on 1=1" + + " where t.deleted = 0" + + " and p.status = 'On-going'" + ) + if (args != null) { + if (args.containsKey("teamId")) + sql.append(" AND t.id = :teamId"); + } + sql.append(" group by t.id, c.id, c.code, c.name") + + return jdbcDao.queryForList(sql.toString(), args) + } + fun searchFinancialSummaryByProject(args: Map): List> { + val sql = StringBuilder( "select" + + " t.id as teamId," + + " p.id as id," + + " p.code as projectCode," + + " p.name as projectName," + + " c.name as customerName," + + " p.expectedTotalFee as totalFee," + + " round(p.expectedTotalFee * 0.8,2) as totalBudget," + + " coalesce((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0),0) as cumulativeExpenditure," + + " coalesce(sum(i.issueAmount),0) as totalInvoiced," + + " coalesce(sum(i.paidAmount),0) as totalReceived," + + " case" + + " when round(coalesce(sum(i.issueAmount),0) / coalesce(((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0),2) >= 1 then 'Positive'" + + " when round(coalesce(sum(i.issueAmount),0) / coalesce(((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0),2) < 1 then 'Negative'" + + " end as cashFlowStatus," + + " round(coalesce(sum(i.issueAmount),0) / coalesce(((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0)),0),2) as cpi," + + " case" + + " when round(p.expectedTotalFee * 0.8,2) <= coalesce((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0),0) then round(p.expectedTotalFee * 0.8,2) - coalesce(sum(i.issueAmount),0)" + + " when round(p.expectedTotalFee * 0.8,2) > coalesce((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0),0) and coalesce((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0),0) < coalesce(sum(i.issueAmount),0) then 0" + + " when round(p.expectedTotalFee * 0.8,2) > coalesce((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0),0) and coalesce((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0),0) >= coalesce(sum(i.issueAmount),0) then coalesce((expenditure.normalConsumed * expenditure.hourlyRate) + (expenditure.otConsumed * expenditure.hourlyRate * 1.0),0) - coalesce(sum(i.issueAmount),0)" + + " end as totalUninvoiced" + + " from team t" + + " left join project p on t.teamLead = p.teamLead" + + " left join customer c on p.customerId = c.id" + + " left join invoice i on p.code = i.projectCode" + + " left join (" + + " select" + + " s2.hourlyRate as hourlyRate," + + " sum(t2.normalConsumed) as normalConsumed," + + " sum(t2.otConsumed) as otConsumed" + + " from team t1" + + " left join project p2 on t1.teamLead = p2.teamLead" + + " left join project_task pt ON p2.id = pt.project_id" + + " left join timesheet t2 on pt.id = t2.projectTaskId" + + " left join staff s on t2.staffId = s.id" + + " left join salary s2 on s.salaryId = s2.salaryPoint" + + " where p2.status = 'On-going'" + + " and t2.id is not null" + + " group by s2.hourlyRate" + + " ) as expenditure on 1=1" + + " where t.deleted = 0" + + " and p.status = 'On-going'" + ) + if (args != null) { + if (args.containsKey("teamId")) + sql.append(" AND t.id = :teamId"); + } + sql.append(" group by t.id, p.id, p.code, p.name, c.name, p.expectedTotalFee,expenditure.normalConsumed, expenditure.hourlyRate, expenditure.otConsumed,i.issueAmount") + + return jdbcDao.queryForList(sql.toString(), args) + } } diff --git a/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt b/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt index 06d9f5f..44f13eb 100644 --- a/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt +++ b/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt @@ -74,4 +74,52 @@ class DashboardController( fun searchFinancialSummary(): List>{ return dashboardService.searchFinancialSummary() } + @GetMapping("/searchTeamProjectNo") + fun searchTeamProjectNo(request: HttpServletRequest?): List> { + val args = mutableMapOf() + return dashboardService.TeamProjectNo(args) + } + @GetMapping("/searchTeamProject") + fun searchTeamProject(request: HttpServletRequest?): List> { + val teamLeadId = request?.getParameter("teamLeadId") + val args = mutableMapOf() + var result: List> = emptyList() + if (teamLeadId != null) { + args["teamLeadId"] = teamLeadId + } + + result = dashboardService.searchTeamProject(args) + + return result + } + @GetMapping("/searchFinancialSummaryCard") + fun searchFinancialSummaryCard(request: HttpServletRequest?): List> { + val args = mutableMapOf() + val allTeamCardData = dashboardService.searchFinancialSummaryAllTeamCard(args) + val cardData = dashboardService.searchFinancialSummaryCard(args) + + val result = mutableListOf>() + result.addAll(allTeamCardData) + result.addAll(cardData) + + return result + } + @GetMapping("/searchFinancialSummaryByClient") + fun searchFinancialSummaryByClient(request: HttpServletRequest?): List> { + val teamId = request?.getParameter("teamId") + val args = mutableMapOf() + if (teamId != null) { + args["teamId"] = teamId + } + return dashboardService.searchFinancialSummaryByClient(args) + } + @GetMapping("/searchFinancialSummaryByProject") + fun searchFinancialSummaryByProject(request: HttpServletRequest?): List> { + val teamId = request?.getParameter("teamId") + val args = mutableMapOf() + if (teamId != null) { + args["teamId"] = teamId + } + return dashboardService.searchFinancialSummaryByProject(args) + } } \ No newline at end of file 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 56d7976..20f497a 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 @@ -1118,7 +1118,7 @@ open class ReportService( fillOrange.setFillPattern(PatternFormatting.SOLID_FOREGROUND) var fillRed = rule2.createPatternFormatting() - fillRed.setFillBackgroundColor(IndexedColors.ROSE.index); + fillRed.setFillBackgroundColor(IndexedColors.PINK.index); fillRed.setFillPattern(PatternFormatting.SOLID_FOREGROUND) val cfRules = arrayOf(rule1, rule2)