|
|
@@ -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<String, Any>): List<Map<String, Any>> { |
|
|
|
// 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<String, Any>( |
|
|
|
"id" to curr.id!!, |
|
|
|
"custId" to if (curr.customer != null ) curr.customer!!.id else -1, |
|
|
|