From 85359415dea612398567014a644c1cdeaa0d561b Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Mon, 21 Oct 2024 12:25:35 +0800 Subject: [PATCH] update financial year --- .../modules/data/service/DashboardService.kt | 233 +++++++++++++++++- .../modules/data/web/DashboardController.kt | 26 ++ 2 files changed, 258 insertions(+), 1 deletion(-) 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 6621d6a..f1d7ef2 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 @@ -36,6 +36,7 @@ import java.math.BigDecimal import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.Optional +import kotlin.time.times @Service open class DashboardService( @@ -3223,6 +3224,142 @@ open class DashboardService( return outputStream.toByteArray() } + open fun testing3( + projectId: Long, + startDate: LocalDate?, + endDate: LocalDate?, + ) { + val project = projectRepository.findById(projectId).orElseThrow() + val timesheet = timesheetRepository.findAll() + val pe = projectExpenseRepository.findAllByProjectIdAndDeletedFalse(projectId) + val invoice = invoiceRepository.findAll() + } + open fun testing2 ( + projectId: Long, + startDate: LocalDate?, + endDate: LocalDate?, + ): DashboardData { + var manhourExpense = 0.0 + var projectExpense = 0.0 + var invoicedAmount = 0.0 + var receivedAmount = 0.0 + +// val salaryEffective = + val project = projectRepository.findById(projectId).orElseThrow() + val timesheet = timesheetRepository.findAll() + val pe = projectExpenseRepository.findAllByProjectIdAndDeletedFalse(projectId) + val invoice = invoiceRepository.findAll() + val maxSize = maxOf(timesheet.size, pe.size, invoice.size) + var lIdx = 0 + var rIdx = maxSize - 1 + while (lIdx<=rIdx) { + // timesheet data + val currTimesheetL = timesheet.getOrNull(lIdx) + val currTimesheetR = timesheet.getOrNull(rIdx) + val otMultiplier = 1.0 + val crossTeamMultiplier = 1.0 + if (currTimesheetL == currTimesheetR && currTimesheetL != null) { + val se = salaryEffectiveService.getStaffSalaryEffective(currTimesheetL.staff!!.id!!, currTimesheetL.recordDate!!) + if (currTimesheetL.deleted == false + && currTimesheetL.project?.id != null + && CheckingUtils.checkTimePeriod(currTimesheetL.recordDate!!, startDate, endDate)) { + val normalCost = (currTimesheetL.normalConsumed ?: 0.0) + val otCost = (currTimesheetL.otConsumed ?: 0.0).times(otMultiplier) + manhourExpense += if (currTimesheetL.project!!.teamLead?.team!!.id != currTimesheetL.staff!!.team.id) + (normalCost+otCost).times(crossTeamMultiplier) + else normalCost+otCost + } + } else { + if (currTimesheetL != null && currTimesheetL.deleted == false + && currTimesheetL.project?.id != null + && CheckingUtils.checkTimePeriod(currTimesheetL.recordDate!!, startDate, endDate)) { + val se = salaryEffectiveService.getStaffSalaryEffective(currTimesheetL.staff!!.id!!, currTimesheetL.recordDate!!) + val normalCost = (currTimesheetL.normalConsumed ?: 0.0).times(se?.salary!!.hourlyRate.toDouble() ?: 0.0) + val otCost = (currTimesheetL.otConsumed ?: 0.0).times(otMultiplier) + manhourExpense += if (currTimesheetL.project!!.teamLead?.team!!.id != currTimesheetL.staff!!.team.id) + (normalCost+otCost).times(crossTeamMultiplier) + else normalCost+otCost + } + if (currTimesheetR != null && currTimesheetR.deleted == false + && currTimesheetR.project?.id != null + && CheckingUtils.checkTimePeriod(currTimesheetR.recordDate!!, startDate, endDate)) { + val se = salaryEffectiveService.getStaffSalaryEffective(currTimesheetR.staff!!.id!!, currTimesheetR.recordDate!!) + val normalCost = (currTimesheetR.normalConsumed ?: 0.0).times(se?.salary!!.hourlyRate.toDouble() ?: 0.0) + val otCost = (currTimesheetR.otConsumed ?: 0.0).times(otMultiplier).times(se?.salary!!.hourlyRate.toDouble() ?: 0.0) + manhourExpense += if (currTimesheetR.project!!.teamLead?.team!!.id != currTimesheetR.staff!!.team.id) + (normalCost+otCost).times(crossTeamMultiplier) + else normalCost+otCost + } + } + // project expense + val currProjectExpenseL = pe.getOrNull(lIdx) + val currProjectExpenseR = pe.getOrNull(rIdx) + if (currProjectExpenseL == currProjectExpenseR && currProjectExpenseL != null) { + if (currProjectExpenseL.deleted == false + && currProjectExpenseL.project!!.id == projectId + && CheckingUtils.checkTimePeriod(currProjectExpenseL.issueDate!!, startDate, endDate)) { + projectExpense += currProjectExpenseL.amount!! + } + } else { + if (currProjectExpenseL != null && currProjectExpenseL.deleted == false + && currProjectExpenseL.project!!.id == projectId + && CheckingUtils.checkTimePeriod(currProjectExpenseL.issueDate!!, startDate, endDate)) { + projectExpense += currProjectExpenseL.amount!! + } + if (currProjectExpenseR != null && currProjectExpenseR.deleted == false + && currProjectExpenseR.project!!.id == projectId + && CheckingUtils.checkTimePeriod(currProjectExpenseR.issueDate!!, startDate, endDate)) { + projectExpense += currProjectExpenseR.amount!! + } + } + // invoice data + val currInvoiceL = invoice.getOrNull(lIdx) + val currInvoiceR = invoice.getOrNull(rIdx) + if (currInvoiceL == currInvoiceR && currInvoiceL != null) { + if (currInvoiceL.deleted == false + && currInvoiceL.projectCode == project.code + && CheckingUtils.checkTimePeriod(currInvoiceL.invoiceDate!!, startDate, endDate)) { + invoicedAmount += currInvoiceL.issueAmount?.toDouble() ?: 0.0 + receivedAmount += currInvoiceL.paidAmount?.toDouble() ?: 0.0 + } + } else { + if (currInvoiceL != null + && currInvoiceL.deleted == false + && currInvoiceL.projectCode == project.code + && CheckingUtils.checkTimePeriod(currInvoiceL.invoiceDate!!, startDate, endDate)) { + invoicedAmount += currInvoiceL.issueAmount?.toDouble() ?: 0.0 + receivedAmount += currInvoiceL.paidAmount?.toDouble() ?: 0.0 + } + if (currInvoiceR != null + && currInvoiceR.deleted == false + && currInvoiceR.projectCode == project.code + && CheckingUtils.checkTimePeriod(currInvoiceR.invoiceDate!!, startDate, endDate)) { + invoicedAmount += currInvoiceR.issueAmount?.toDouble() ?: 0.0 + receivedAmount += currInvoiceR.paidAmount?.toDouble() ?: 0.0 + } + } + + lIdx++ + rIdx-- + } + val nonInvoicedAmount = (project.expectedTotalFee?: 0.0) - invoicedAmount + val cumulativeExpenditure = manhourExpense + projectExpense + val output = DashboardData( + cumulativeExpenditure, + manhourExpense, + projectExpense, + invoicedAmount, + nonInvoicedAmount, + receivedAmount, +// if (invoicedAmount >= manhourExpense+projectExpense) "Positive" else "Negative", +// if (project.expectedTotalFee!! >= cumulativeExpenditure) "Positive" else "Negative", + if (cumulativeExpenditure > 0.0) invoicedAmount/cumulativeExpenditure else 0.0, + if (cumulativeExpenditure > 0.0) project.expectedTotalFee!!/cumulativeExpenditure else 0.0 + ) + return output +// println("invoicedAmount: $invoicedAmount") +// println("receivedAmount: $receivedAmount") + } open fun testing ( projectId: Long, @@ -3297,6 +3434,100 @@ open class DashboardService( ) return output } + open fun getFinancialSummaryByProjectSQL(args: Map): List> { + // timesheet data + val sql = StringBuilder("with manhourExpense as (" + + " with p_cte as ( " + + " select " + + " p.*, " + + " s.teamId " + + " from project p " + + " left join staff s on s.id = p.teamLead " + + " where p.deleted = false " + + " ) " + + " select " + + " projectId, " + + " CASE WHEN tl.teamId = p.teamId " + + " THEN (sum(coalesce(t.normalConsumed, 0)) + sum(coalesce(t.otConsumed, 0)))*max(sal.hourlyRate) " + + " ELSE ((sum(coalesce(t.normalConsumed, 0)) + sum(coalesce(t.otConsumed, 0)))*max(sal.hourlyRate)) * 1 " // cross team multiplier + + " END AS manhourExpense " + + " from ( " + + " SELECT * " + + " FROM timesheet t " + + " where t.deleted = false " + + (if (args.containsKey("startDate") && args.containsKey("endDate")) " and t.recordDate between :startDate AND :endDate " + else if (args.containsKey("endDate")) " and t.recordDate <= :endDate " + else "") + + " and t.projectId is not null " + + " ) t " + + " left join p_cte p on p.id = t.projectId " + + " left join team_log tl on tl.staffId = t.staffId and t.recordDate between tl.`from` AND tl.`to` " + + " inner JOIN salary_effective se ON se.staffId = t.staffId and t.recordDate between se.startDate AND se.endDate " + + " left join salary sal on sal.salaryPoint = se.salaryId " + + " GROUP BY t.projectId, tl.teamId, p.teamId " + + " ) " + // invoice data + + " , invoice_data as ( " + + " select " + + " p.id as projectId, " + + " sum(coalesce(i.issueAmount, 0)) as invoicedAmount, " + + " sum(coalesce(i.paidAmount, 0)) as paidAmount " + + " from invoice i " + + " left join project p on p.code = i.projectCode " + + " left join staff s on s.id = p.teamlead " + + " where i.deleted = false " + + (if (args.containsKey("startDate") && args.containsKey("endDate")) " and i.receiptDate between :startDate AND :endDate " + else if (args.containsKey("endDate")) " and i.receiptDate <= :endDate " + else "") + + " group by p.id " + + " ) " + // project_expense + + " , project_expense as ( " + + " select " + + " pe.projectId, " + + " sum(amount) as projectExpense " + + " from project_expense pe " + + " left join project p on p.id = pe.projectId " + + " left join staff s on s.id = p.teamlead " + + " where pe.deleted = false " + + (if (args.containsKey("startDate") && args.containsKey("endDate")) " and pe.issueDate between :startDate AND :endDate " + else if (args.containsKey("endDate")) " and pe.issueDate <= :endDate " + else "") + + " group by pe.projectId " + + " ) " + + " select " + + " * " + + " from ( " + + " select " + + " p.id, " + + " p.name as projectName, " + + " p.code as projectCode, " + + " s.teamId, " + + " t.name as team, " + + " c.id as custId, " + + " c.name as customerName, " + + " c.code as customerCode, " + + " su.name as subsidiary, " + + " p.expectedTotalFee as totalFee, " + + " (p.expectedTotalFee - ifnull(p.subContractFee, 0)) * 0.8 as totalBudget, " + + " coalesce(me.manhourExpense, 0) as manhourExpense, " + + " coalesce(id.invoicedAmount, 0) as invoicedAmount, " + + " coalesce(id.paidAmount, 0) as paidAmount, " + + " coalesce(pe.projectExpense, 0) as projectExpense " + + " from project p " + + " inner join staff s on s.id = p.teamlead " + + " left join team t on s.teamId = t.id " + + " left join customer c on c.id = p.customerId " + + " left join subsidiary su on su.id = p.customerSubsidiaryId " + + " left join manhourExpense me on me.projectId = p.id " + + " left join invoice_data id on id.projectId = p.id " + + " left join project_expense pe on pe.projectId = p.id " + + " where p.status = 'On-going' " + + (if (args.containsKey("teamId")) "where s.teamId = :teamId" else "") + + " order by p.id " + + " ) result ") + return jdbcDao.queryForList(sql.toString(), args) + } open fun getProjectDashboardDataByProjectId( projectId: Long, @@ -3333,7 +3564,7 @@ open class DashboardService( val projects = projectRepository.findAll() for (curr in projects) { if (curr.deleted == false && curr.teamLead?.team?.id == teamId && curr.status == "On-going") { - val data = testing(curr.id!!, startDate, endDate) + val data = testing2(curr.id!!, startDate, endDate) val item = mapOf( "id" to curr.id!!, "custId" to if (curr.customer != null ) curr.customer!!.id else -1, 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 9a47963..c53a627 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 @@ -482,9 +482,34 @@ class DashboardController( println("end...: ${LocalDateTime.now()}") return output } + @GetMapping("/getFinancialSummary-final") + fun getFinancialSummaryBySql(@Valid request: HttpServletRequest): List> { + println("") + println("start: ${LocalDateTime.now().minute}:${LocalDateTime.now().second}") + val startDate = if (request.getParameter("startDate") != null) LocalDate.parse(request.getParameter("startDate")) else null + val endDate = if (request.getParameter("endDate") != null) LocalDate.parse(request.getParameter("endDate")) else null + val teamId = if (request.getParameter("teamId") != null) request.getParameter("teamId") else null + val args = mutableMapOf() + if (startDate != null) args["startDate"] = startDate + if (endDate != null) args["endDate"] = endDate + if (teamId != null) args["teamId"] = teamId + val output = dashboardService.getFinancialSummaryByProjectSQL(args) + println("end: ${LocalDateTime.now().minute}:${LocalDateTime.now().second}") + return output + } +// @GetMapping("/fromScratch") +// fun fromScratch(@Valid request: HttpServletRequest): List> { +// val startDate = if (request.getParameter("startDate") != null) LocalDate.parse(request.getParameter("startDate")) else null +// val endDate = LocalDate.parse(request.getParameter("endDate")) +// val targetTeam = request.getParameter("teamId") ?: null +// // loop all +// +// } @GetMapping("/getFinancialSummary") fun getFinancialSummary(@Valid request: HttpServletRequest): List> { + println("") + println("start: ${LocalDateTime.now().minute}:${LocalDateTime.now().second}") val output = mutableListOf>() val startDate = if (request.getParameter("startDate") != null) LocalDate.parse(request.getParameter("startDate")) else null val endDate = LocalDate.parse(request.getParameter("endDate")) @@ -500,6 +525,7 @@ class DashboardController( for (id in teamIds) { output.add(dashboardService.fetchFinancialSummary(startDate, endDate, id)) } + println("start: ${LocalDateTime.now().minute}:${LocalDateTime.now().second}") return output }