|
@@ -1,33 +1,21 @@ |
|
|
package com.ffii.tsms.modules.data.service |
|
|
package com.ffii.tsms.modules.data.service |
|
|
|
|
|
|
|
|
import com.ffii.core.support.AbstractBaseEntityService |
|
|
|
|
|
import com.ffii.core.support.JdbcDao |
|
|
import com.ffii.core.support.JdbcDao |
|
|
import com.ffii.core.utils.CheckingUtils |
|
|
import com.ffii.core.utils.CheckingUtils |
|
|
import com.ffii.tsms.modules.data.entity.Customer |
|
|
|
|
|
import com.ffii.tsms.modules.data.entity.CustomerType |
|
|
|
|
|
import com.ffii.tsms.modules.data.entity.CustomerRepository |
|
|
import com.ffii.tsms.modules.data.entity.CustomerRepository |
|
|
import com.ffii.tsms.modules.data.entity.CustomerTypeRepository |
|
|
import com.ffii.tsms.modules.data.entity.CustomerTypeRepository |
|
|
import com.ffii.tsms.modules.data.entity.SalaryEffectiveRepository |
|
|
|
|
|
import com.ffii.tsms.modules.data.entity.TeamLogRepository |
|
|
|
|
|
import com.ffii.tsms.modules.data.entity.TeamRepository |
|
|
import com.ffii.tsms.modules.data.entity.TeamRepository |
|
|
import com.ffii.tsms.modules.data.web.models.FinancialSummaryByClient |
|
|
import com.ffii.tsms.modules.data.web.models.FinancialSummaryByClient |
|
|
import com.ffii.tsms.modules.data.web.models.FinancialSummaryByProject |
|
|
import com.ffii.tsms.modules.data.web.models.FinancialSummaryByProject |
|
|
import com.ffii.tsms.modules.data.web.models.SaveCustomerResponse |
|
|
|
|
|
import com.ffii.tsms.modules.project.entity.* |
|
|
import com.ffii.tsms.modules.project.entity.* |
|
|
import com.ffii.tsms.modules.project.entity.projections.DashboardData |
|
|
import com.ffii.tsms.modules.project.entity.projections.DashboardData |
|
|
import com.ffii.tsms.modules.project.service.InvoiceService |
|
|
import com.ffii.tsms.modules.project.service.InvoiceService |
|
|
import com.ffii.tsms.modules.project.service.ProjectExpenseService |
|
|
import com.ffii.tsms.modules.project.service.ProjectExpenseService |
|
|
import com.ffii.tsms.modules.project.service.ProjectsService |
|
|
|
|
|
import com.ffii.tsms.modules.project.web.models.SaveCustomerRequest |
|
|
|
|
|
import com.ffii.tsms.modules.timesheet.entity.Timesheet |
|
|
|
|
|
import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository |
|
|
import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository |
|
|
import com.ffii.tsms.modules.timesheet.service.TimesheetsService |
|
|
import com.ffii.tsms.modules.timesheet.service.TimesheetsService |
|
|
import org.apache.poi.ss.usermodel.* |
|
|
import org.apache.poi.ss.usermodel.* |
|
|
import org.apache.poi.ss.util.CellRangeAddress |
|
|
|
|
|
import org.apache.poi.ss.util.CellUtil |
|
|
import org.apache.poi.ss.util.CellUtil |
|
|
import org.apache.poi.util.ArrayUtil |
|
|
|
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook |
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook |
|
|
import org.springframework.beans.BeanUtils |
|
|
|
|
|
import org.springframework.core.io.ClassPathResource |
|
|
import org.springframework.core.io.ClassPathResource |
|
|
import org.springframework.stereotype.Service |
|
|
import org.springframework.stereotype.Service |
|
|
import java.io.ByteArrayOutputStream |
|
|
import java.io.ByteArrayOutputStream |
|
@@ -35,8 +23,6 @@ import java.io.IOException |
|
|
import java.math.BigDecimal |
|
|
import java.math.BigDecimal |
|
|
import java.time.LocalDate |
|
|
import java.time.LocalDate |
|
|
import java.time.format.DateTimeFormatter |
|
|
import java.time.format.DateTimeFormatter |
|
|
import java.util.Optional |
|
|
|
|
|
import kotlin.time.times |
|
|
|
|
|
|
|
|
|
|
|
@Service |
|
|
@Service |
|
|
open class DashboardService( |
|
|
open class DashboardService( |
|
@@ -3337,7 +3323,7 @@ open class DashboardService( |
|
|
projectId: Long, |
|
|
projectId: Long, |
|
|
startDate: LocalDate?, |
|
|
startDate: LocalDate?, |
|
|
endDate: LocalDate?, |
|
|
endDate: LocalDate?, |
|
|
): DashboardData { |
|
|
|
|
|
|
|
|
): Double { |
|
|
var manhourExpense = 0.0 |
|
|
var manhourExpense = 0.0 |
|
|
var projectExpense = 0.0 |
|
|
var projectExpense = 0.0 |
|
|
var invoicedAmount = 0.0 |
|
|
var invoicedAmount = 0.0 |
|
@@ -3351,43 +3337,58 @@ open class DashboardService( |
|
|
val maxSize = maxOf(timesheet.size, pe.size, invoice.size) |
|
|
val maxSize = maxOf(timesheet.size, pe.size, invoice.size) |
|
|
var lIdx = 0 |
|
|
var lIdx = 0 |
|
|
var rIdx = maxSize - 1 |
|
|
var rIdx = maxSize - 1 |
|
|
while (lIdx<=rIdx) { |
|
|
|
|
|
|
|
|
while (lIdx <= rIdx) { |
|
|
// timesheet data |
|
|
// timesheet data |
|
|
val currTimesheetL = timesheet.getOrNull(lIdx) |
|
|
val currTimesheetL = timesheet.getOrNull(lIdx) |
|
|
val currTimesheetR = timesheet.getOrNull(rIdx) |
|
|
val currTimesheetR = timesheet.getOrNull(rIdx) |
|
|
val otMultiplier = 1.0 |
|
|
val otMultiplier = 1.0 |
|
|
val crossTeamMultiplier = 1.0 |
|
|
val crossTeamMultiplier = 1.0 |
|
|
if (currTimesheetL == currTimesheetR && currTimesheetL != null) { |
|
|
if (currTimesheetL == currTimesheetR && currTimesheetL != null) { |
|
|
val se = salaryEffectiveService.getStaffSalaryEffective(currTimesheetL.staff!!.id!!, currTimesheetL.recordDate!!) |
|
|
|
|
|
|
|
|
val se = salaryEffectiveService.getStaffSalaryEffective( |
|
|
|
|
|
currTimesheetL.staff!!.id!!, |
|
|
|
|
|
currTimesheetL.recordDate!! |
|
|
|
|
|
) |
|
|
if (currTimesheetL.deleted == false |
|
|
if (currTimesheetL.deleted == false |
|
|
&& currTimesheetL.project?.id != null |
|
|
&& currTimesheetL.project?.id != null |
|
|
&& CheckingUtils.checkTimePeriod(currTimesheetL.recordDate!!, startDate, endDate)) { |
|
|
|
|
|
|
|
|
// && CheckingUtils.checkTimePeriod(currTimesheetL.recordDate!!, startDate, endDate) |
|
|
|
|
|
) { |
|
|
val normalCost = (currTimesheetL.normalConsumed ?: 0.0) |
|
|
val normalCost = (currTimesheetL.normalConsumed ?: 0.0) |
|
|
val otCost = (currTimesheetL.otConsumed ?: 0.0).times(otMultiplier) |
|
|
val otCost = (currTimesheetL.otConsumed ?: 0.0).times(otMultiplier) |
|
|
manhourExpense += if (currTimesheetL.project!!.teamLead?.team!!.id != currTimesheetL.staff!!.team.id) |
|
|
manhourExpense += if (currTimesheetL.project!!.teamLead?.team!!.id != currTimesheetL.staff!!.team.id) |
|
|
(normalCost+otCost).times(crossTeamMultiplier) |
|
|
|
|
|
else normalCost+otCost |
|
|
|
|
|
|
|
|
(normalCost + otCost).times(crossTeamMultiplier) |
|
|
|
|
|
else normalCost + otCost |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
if (currTimesheetL != null && currTimesheetL.deleted == false |
|
|
if (currTimesheetL != null && currTimesheetL.deleted == false |
|
|
&& currTimesheetL.project?.id != null |
|
|
&& 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) |
|
|
|
|
|
|
|
|
// && 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) |
|
|
val otCost = (currTimesheetL.otConsumed ?: 0.0).times(otMultiplier) |
|
|
manhourExpense += if (currTimesheetL.project!!.teamLead?.team!!.id != currTimesheetL.staff!!.team.id) |
|
|
manhourExpense += if (currTimesheetL.project!!.teamLead?.team!!.id != currTimesheetL.staff!!.team.id) |
|
|
(normalCost+otCost).times(crossTeamMultiplier) |
|
|
|
|
|
else normalCost+otCost |
|
|
|
|
|
|
|
|
(normalCost + otCost).times(crossTeamMultiplier) |
|
|
|
|
|
else normalCost + otCost |
|
|
} |
|
|
} |
|
|
if (currTimesheetR != null && currTimesheetR.deleted == false |
|
|
if (currTimesheetR != null && currTimesheetR.deleted == false |
|
|
&& currTimesheetR.project?.id != null |
|
|
&& 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) |
|
|
|
|
|
|
|
|
// && 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) |
|
|
manhourExpense += if (currTimesheetR.project!!.teamLead?.team!!.id != currTimesheetR.staff!!.team.id) |
|
|
(normalCost+otCost).times(crossTeamMultiplier) |
|
|
|
|
|
else normalCost+otCost |
|
|
|
|
|
|
|
|
(normalCost + otCost).times(crossTeamMultiplier) |
|
|
|
|
|
else normalCost + otCost |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// project expense |
|
|
// project expense |
|
@@ -3396,18 +3397,21 @@ open class DashboardService( |
|
|
if (currProjectExpenseL == currProjectExpenseR && currProjectExpenseL != null) { |
|
|
if (currProjectExpenseL == currProjectExpenseR && currProjectExpenseL != null) { |
|
|
if (currProjectExpenseL.deleted == false |
|
|
if (currProjectExpenseL.deleted == false |
|
|
&& currProjectExpenseL.project!!.id == projectId |
|
|
&& currProjectExpenseL.project!!.id == projectId |
|
|
&& CheckingUtils.checkTimePeriod(currProjectExpenseL.issueDate!!, startDate, endDate)) { |
|
|
|
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currProjectExpenseL.issueDate!!, startDate, endDate) |
|
|
|
|
|
) { |
|
|
projectExpense += currProjectExpenseL.amount!! |
|
|
projectExpense += currProjectExpenseL.amount!! |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
if (currProjectExpenseL != null && currProjectExpenseL.deleted == false |
|
|
if (currProjectExpenseL != null && currProjectExpenseL.deleted == false |
|
|
&& currProjectExpenseL.project!!.id == projectId |
|
|
&& currProjectExpenseL.project!!.id == projectId |
|
|
&& CheckingUtils.checkTimePeriod(currProjectExpenseL.issueDate!!, startDate, endDate)) { |
|
|
|
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currProjectExpenseL.issueDate!!, startDate, endDate) |
|
|
|
|
|
) { |
|
|
projectExpense += currProjectExpenseL.amount!! |
|
|
projectExpense += currProjectExpenseL.amount!! |
|
|
} |
|
|
} |
|
|
if (currProjectExpenseR != null && currProjectExpenseR.deleted == false |
|
|
if (currProjectExpenseR != null && currProjectExpenseR.deleted == false |
|
|
&& currProjectExpenseR.project!!.id == projectId |
|
|
&& currProjectExpenseR.project!!.id == projectId |
|
|
&& CheckingUtils.checkTimePeriod(currProjectExpenseR.issueDate!!, startDate, endDate)) { |
|
|
|
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currProjectExpenseR.issueDate!!, startDate, endDate) |
|
|
|
|
|
) { |
|
|
projectExpense += currProjectExpenseR.amount!! |
|
|
projectExpense += currProjectExpenseR.amount!! |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@@ -3417,7 +3421,8 @@ open class DashboardService( |
|
|
if (currInvoiceL == currInvoiceR && currInvoiceL != null) { |
|
|
if (currInvoiceL == currInvoiceR && currInvoiceL != null) { |
|
|
if (currInvoiceL.deleted == false |
|
|
if (currInvoiceL.deleted == false |
|
|
&& currInvoiceL.projectCode == project.code |
|
|
&& currInvoiceL.projectCode == project.code |
|
|
&& CheckingUtils.checkTimePeriod(currInvoiceL.invoiceDate!!, startDate, endDate)) { |
|
|
|
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currInvoiceL.invoiceDate!!, startDate, endDate) |
|
|
|
|
|
) { |
|
|
invoicedAmount += currInvoiceL.issueAmount?.toDouble() ?: 0.0 |
|
|
invoicedAmount += currInvoiceL.issueAmount?.toDouble() ?: 0.0 |
|
|
receivedAmount += currInvoiceL.paidAmount?.toDouble() ?: 0.0 |
|
|
receivedAmount += currInvoiceL.paidAmount?.toDouble() ?: 0.0 |
|
|
} |
|
|
} |
|
@@ -3425,114 +3430,24 @@ open class DashboardService( |
|
|
if (currInvoiceL != null |
|
|
if (currInvoiceL != null |
|
|
&& currInvoiceL.deleted == false |
|
|
&& currInvoiceL.deleted == false |
|
|
&& currInvoiceL.projectCode == project.code |
|
|
&& currInvoiceL.projectCode == project.code |
|
|
&& CheckingUtils.checkTimePeriod(currInvoiceL.invoiceDate!!, startDate, endDate)) { |
|
|
|
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currInvoiceL.invoiceDate!!, startDate, endDate) |
|
|
|
|
|
) { |
|
|
invoicedAmount += currInvoiceL.issueAmount?.toDouble() ?: 0.0 |
|
|
invoicedAmount += currInvoiceL.issueAmount?.toDouble() ?: 0.0 |
|
|
receivedAmount += currInvoiceL.paidAmount?.toDouble() ?: 0.0 |
|
|
receivedAmount += currInvoiceL.paidAmount?.toDouble() ?: 0.0 |
|
|
} |
|
|
} |
|
|
if (currInvoiceR != null |
|
|
if (currInvoiceR != null |
|
|
&& currInvoiceR.deleted == false |
|
|
&& currInvoiceR.deleted == false |
|
|
&& currInvoiceR.projectCode == project.code |
|
|
&& currInvoiceR.projectCode == project.code |
|
|
&& CheckingUtils.checkTimePeriod(currInvoiceR.invoiceDate!!, startDate, endDate)) { |
|
|
|
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currInvoiceR.invoiceDate!!, startDate, endDate) |
|
|
|
|
|
) { |
|
|
invoicedAmount += currInvoiceR.issueAmount?.toDouble() ?: 0.0 |
|
|
invoicedAmount += currInvoiceR.issueAmount?.toDouble() ?: 0.0 |
|
|
receivedAmount += currInvoiceR.paidAmount?.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") |
|
|
|
|
|
|
|
|
return manhourExpense |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
open fun testing ( |
|
|
|
|
|
projectId: Long, |
|
|
|
|
|
startDate: LocalDate?, |
|
|
|
|
|
endDate: LocalDate?, |
|
|
|
|
|
): DashboardData { |
|
|
|
|
|
var i = 0 |
|
|
|
|
|
// data to add |
|
|
|
|
|
var manhourExpense = 0.0 |
|
|
|
|
|
var projectExpense = 0.0 |
|
|
|
|
|
var invoicedAmount = 0.0 |
|
|
|
|
|
var receivedAmount = 0.0 |
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
for (i in 0 until maxSize) { |
|
|
|
|
|
val currTs = if (i < timesheet.size) timesheet[i] else null |
|
|
|
|
|
val currPe = if (i < pe.size) pe[i] else null |
|
|
|
|
|
val currInvoice = if (i < invoice.size) invoice[i] else null |
|
|
|
|
|
if (currTs != null |
|
|
|
|
|
&& currTs.deleted == false |
|
|
|
|
|
&& currTs.project != null |
|
|
|
|
|
&& currTs.project!!.id == projectId |
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currTs.recordDate!!, startDate, endDate)) { |
|
|
|
|
|
val otMultiplier = 1.0 |
|
|
|
|
|
val crossTeamMultipier = 1.0 |
|
|
|
|
|
val staffId = currTs.staff!!.id!! |
|
|
|
|
|
val staffTeam = teamLogService.getStaffTeamLog(staffId, currTs.recordDate!!) |
|
|
|
|
|
val thisSE = salaryEffectiveService.getStaffSalaryEffective(staffId, currTs.recordDate!!) |
|
|
|
|
|
val hourlyRate = thisSE!!.salary.hourlyRate |
|
|
|
|
|
val normalHour = currTs.normalConsumed ?: 0.0 |
|
|
|
|
|
val otHour = currTs.otConsumed ?: 0.0 |
|
|
|
|
|
val normalCost = normalHour.times(hourlyRate.toDouble()) |
|
|
|
|
|
val otCost = otHour.times(hourlyRate.toDouble()).times(otMultiplier) |
|
|
|
|
|
if (currTs.project!!.teamLead?.id != staffTeam!!.team.id) { // cross team |
|
|
|
|
|
manhourExpense += (normalCost + otCost).times(crossTeamMultipier) |
|
|
|
|
|
} else { |
|
|
|
|
|
manhourExpense += (normalCost + otCost) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (currPe != null |
|
|
|
|
|
&& currPe.deleted == false |
|
|
|
|
|
&& currPe.project!!.id == projectId |
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currPe.issueDate!!, startDate, endDate)) { |
|
|
|
|
|
projectExpense += currPe.amount!! |
|
|
|
|
|
} |
|
|
|
|
|
if (currInvoice != null |
|
|
|
|
|
&& currInvoice.deleted == false |
|
|
|
|
|
&& currInvoice.projectCode == project.code |
|
|
|
|
|
&& CheckingUtils.checkTimePeriod(currInvoice.invoiceDate!!, startDate, endDate)) { |
|
|
|
|
|
invoicedAmount += currInvoice.issueAmount!!.toDouble() |
|
|
|
|
|
receivedAmount += currInvoice.paidAmount?.toDouble() ?: 0.0 |
|
|
|
|
|
} |
|
|
|
|
|
// i++ |
|
|
|
|
|
} |
|
|
|
|
|
val cumulativeExpenditure = manhourExpense + projectExpense |
|
|
|
|
|
val nonInvoicedAmount = (project.expectedTotalFee?: 0.0) - invoicedAmount |
|
|
|
|
|
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 |
|
|
|
|
|
} |
|
|
|
|
|
open fun getFinancialSummaryByProjectSQL(args: Map<String, Any>): List<Map<String, Any>> { |
|
|
open fun getFinancialSummaryByProjectSQL(args: Map<String, Any>): List<Map<String, Any>> { |
|
|
// timesheet data |
|
|
// timesheet data |
|
|
val sql = StringBuilder("with manhourExpense as (" |
|
|
val sql = StringBuilder("with manhourExpense as (" |
|
@@ -3635,182 +3550,6 @@ open class DashboardService( |
|
|
return jdbcDao.queryForList(sql.toString(), args) |
|
|
return jdbcDao.queryForList(sql.toString(), args) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
open fun getProjectDashboardDataByProjectId( |
|
|
|
|
|
projectId: Long, |
|
|
|
|
|
startDate: LocalDate?, |
|
|
|
|
|
endDate: LocalDate?, |
|
|
|
|
|
): DashboardData { |
|
|
|
|
|
val project = projectRepository.findById(projectId).orElseThrow() |
|
|
|
|
|
val manhourExpense = timesheetsService.getManpowerExpenseByProjectId(projectId,startDate,endDate) |
|
|
|
|
|
val projectExpense = projectExpenseService.getProjectExpenseByProjectId(projectId,startDate,endDate) |
|
|
|
|
|
val invoiceData = invoiceService.getInvoiceDataByProjectId(projectId,startDate,endDate) |
|
|
|
|
|
// var index = 0 |
|
|
|
|
|
// while () |
|
|
|
|
|
val cumulativeExpenditure = manhourExpense + projectExpense |
|
|
|
|
|
val output = DashboardData( |
|
|
|
|
|
cumulativeExpenditure, |
|
|
|
|
|
manhourExpense, |
|
|
|
|
|
projectExpense, |
|
|
|
|
|
invoiceData.invoicedAmount, |
|
|
|
|
|
invoiceData.nonInvoicedAmount, |
|
|
|
|
|
invoiceData.receivedAmount, |
|
|
|
|
|
// if (invoiceData.invoicedAmount >= manhourExpense+projectExpense) "Positive" else "Negative", |
|
|
|
|
|
// if (project.expectedTotalFee!! >= cumulativeExpenditure) "Positive" else "Negative", |
|
|
|
|
|
if (cumulativeExpenditure > 0.0) invoiceData.invoicedAmount/cumulativeExpenditure else 0.0, |
|
|
|
|
|
if (cumulativeExpenditure > 0.0) project.expectedTotalFee!!/cumulativeExpenditure else 0.0 |
|
|
|
|
|
) |
|
|
|
|
|
return output |
|
|
|
|
|
} |
|
|
|
|
|
open fun fetchFinancialSummaryByProject( |
|
|
|
|
|
teamId: Long, |
|
|
|
|
|
startDate: LocalDate?, |
|
|
|
|
|
endDate: LocalDate, |
|
|
|
|
|
): List<Map<String, Any>> { |
|
|
|
|
|
val output = mutableListOf<Map<String, Any>>() |
|
|
|
|
|
val projects = projectRepository.findAll() |
|
|
|
|
|
for (curr in projects) { |
|
|
|
|
|
if (curr.deleted == false && curr.teamLead?.team?.id == teamId && curr.status == "On-going") { |
|
|
|
|
|
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, |
|
|
|
|
|
"projectCode" to curr.code!!, |
|
|
|
|
|
"projectName" to curr.name!!, |
|
|
|
|
|
"customerName" to if (curr.customer != null) curr.customer!!.name else "", |
|
|
|
|
|
"customerName" to if (curr.customer != null) curr.customer!!.code else "", |
|
|
|
|
|
"subsidiaryName" to if (curr.customerSubsidiary != null) curr.customerSubsidiary!!.name else "", |
|
|
|
|
|
"totalFee" to curr.expectedTotalFee!!, |
|
|
|
|
|
"totalBudget" to curr.expectedTotalFee!! * 0.8, |
|
|
|
|
|
"cumulativeExpenditure" to data.cumulativeExpenditure, |
|
|
|
|
|
"manhourExpense" to data.manhourExpense, |
|
|
|
|
|
"projectExpense" to data.projectExpense, |
|
|
|
|
|
"invoicedAmount" to data.invoicedAmount, |
|
|
|
|
|
"nonInvoicedAmount" to data.nonInvoicedAmount, |
|
|
|
|
|
"receivedAmount" to data.receivedAmount, |
|
|
|
|
|
// "cashFlowStatus" to data.cashFlowStatus, |
|
|
|
|
|
// "projectedCashFlowStatus" to data.projectedCashFlowStatus, |
|
|
|
|
|
"cpi" to data.cpi, |
|
|
|
|
|
"projectedCpi" to data.projectedCpi, |
|
|
|
|
|
) |
|
|
|
|
|
output.add(item) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
println(output) |
|
|
|
|
|
return output |
|
|
|
|
|
} |
|
|
|
|
|
open fun fetchFinancialSummary( |
|
|
|
|
|
startDate: LocalDate?, |
|
|
|
|
|
endDate: LocalDate, |
|
|
|
|
|
teamId: Long |
|
|
|
|
|
): Map<String, Any> { |
|
|
|
|
|
fun checkTimePeriod(checkDate: LocalDate): Boolean { |
|
|
|
|
|
return if (startDate == null) { |
|
|
|
|
|
checkDate.isBefore(endDate) |
|
|
|
|
|
} else { |
|
|
|
|
|
checkDate.isAfter(startDate) && checkDate.isBefore(endDate) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
val projects = projectRepository.findAll() |
|
|
|
|
|
// active project |
|
|
|
|
|
val activeProject = projects |
|
|
|
|
|
.filter { |
|
|
|
|
|
it.deleted == false |
|
|
|
|
|
&& it.teamLead!!.id == teamId |
|
|
|
|
|
&& it.status == "On-going" |
|
|
|
|
|
}.size |
|
|
|
|
|
|
|
|
|
|
|
var totalFee = 0.0 |
|
|
|
|
|
val projectCodes = mutableListOf<String>() |
|
|
|
|
|
val projectIds = mutableListOf<Long>() |
|
|
|
|
|
for (curr in projects) { |
|
|
|
|
|
val isTargetTeam = curr.teamLead!!.id == teamId |
|
|
|
|
|
val isOnGoing = curr.status == "On-going" |
|
|
|
|
|
if (curr.deleted == false && isTargetTeam && isOnGoing) { |
|
|
|
|
|
totalFee += curr.expectedTotalFee ?: 0.0 |
|
|
|
|
|
projectCodes.add(curr.code!!) |
|
|
|
|
|
projectIds.add(curr.id!!) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// manpower Expense |
|
|
|
|
|
var manpowerExpense = 0.0 |
|
|
|
|
|
val timesheet = timesheetRepository.findAll() |
|
|
|
|
|
for (curr in timesheet) { |
|
|
|
|
|
val projectTeam = curr.project?.teamLead?.team |
|
|
|
|
|
val recordDate = curr.recordDate!! |
|
|
|
|
|
val staffId = curr.staff!!.id!! |
|
|
|
|
|
if (checkTimePeriod(recordDate) && curr.deleted == false && projectTeam?.id == teamId) { |
|
|
|
|
|
val crossTeamMultiplier = 1.0 |
|
|
|
|
|
val otMultiplier = 1.0 |
|
|
|
|
|
val staffTeam = teamLogService.getStaffTeamLog(staffId, recordDate)?.team?.code |
|
|
|
|
|
val salaryEffective = salaryEffectiveService.getStaffSalaryEffective(staffId, recordDate)!! |
|
|
|
|
|
val normalHour = curr.normalConsumed ?: 0.0 |
|
|
|
|
|
val otHour = curr.otConsumed ?: 0.0 |
|
|
|
|
|
val normalCost = normalHour.times(salaryEffective.salary.hourlyRate.toDouble()) |
|
|
|
|
|
val otCost = otHour.times(salaryEffective.salary.hourlyRate.toDouble()).times(otMultiplier) |
|
|
|
|
|
val totalCost = normalCost + otCost; |
|
|
|
|
|
// crossed team |
|
|
|
|
|
if (staffTeam != projectTeam.code) { |
|
|
|
|
|
manpowerExpense += totalCost.times(crossTeamMultiplier); |
|
|
|
|
|
} else { |
|
|
|
|
|
manpowerExpense += totalCost; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// project expense |
|
|
|
|
|
var projectExpense = 0.0 |
|
|
|
|
|
val projectExpenseList = projectExpenseRepository.findAll() |
|
|
|
|
|
for (curr in projectExpenseList) { |
|
|
|
|
|
val issueDate = curr.issueDate!! |
|
|
|
|
|
if (checkTimePeriod(issueDate) && curr.project?.teamLead?.team?.id == teamId && curr.deleted == false) { |
|
|
|
|
|
projectExpense += curr.amount ?: 0.0 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
var invoicedAmount = 0.0 |
|
|
|
|
|
var paidAmount = 0.0 |
|
|
|
|
|
val invoice = invoiceRepository.findAllByProjectCodeIn(projectCodes) |
|
|
|
|
|
for (curr in invoice) { |
|
|
|
|
|
val invoiceDate = curr.invoiceDate!! |
|
|
|
|
|
if (curr.deleted == false && checkTimePeriod(invoiceDate)) { |
|
|
|
|
|
invoicedAmount += curr.issueAmount?.toDouble() ?: 0.0 |
|
|
|
|
|
paidAmount += curr.paidAmount?.toDouble() ?: 0.0 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
val cumulativeExpenditure = manpowerExpense + projectExpense |
|
|
|
|
|
// cashFlowStatus |
|
|
|
|
|
val cashFlowStatus = if (invoicedAmount >= cumulativeExpenditure) { |
|
|
|
|
|
"Positive" |
|
|
|
|
|
} else { |
|
|
|
|
|
"Negative" |
|
|
|
|
|
} |
|
|
|
|
|
// projectedCashFlowStatus |
|
|
|
|
|
val projectedCashFlowStatus = if (totalFee >= cumulativeExpenditure) { |
|
|
|
|
|
"Positive" |
|
|
|
|
|
} else { |
|
|
|
|
|
"Negative" |
|
|
|
|
|
} |
|
|
|
|
|
val dataMap = mapOf( |
|
|
|
|
|
// team project basic info |
|
|
|
|
|
"team" to teamRepository.findById(teamId), |
|
|
|
|
|
"activeProject" to activeProject, |
|
|
|
|
|
"totalFees" to totalFee, |
|
|
|
|
|
"totalBudget" to totalFee * 0.8, |
|
|
|
|
|
// timesheet data |
|
|
|
|
|
"cumulativeExpenditure" to cumulativeExpenditure, |
|
|
|
|
|
"manpowerExpense" to manpowerExpense, |
|
|
|
|
|
"projectExpense" to projectExpense, |
|
|
|
|
|
// invoice data |
|
|
|
|
|
"invoicedAmount" to invoicedAmount, |
|
|
|
|
|
"nonInvoicedAmount" to totalFee - invoicedAmount, |
|
|
|
|
|
"receivedAmount" to paidAmount, |
|
|
|
|
|
// calculation |
|
|
|
|
|
"cashFlowStatus" to cashFlowStatus, |
|
|
|
|
|
"costPerformanceIndex" to if (cumulativeExpenditure > 0.0) invoicedAmount / cumulativeExpenditure else 0.0, |
|
|
|
|
|
"projectedCashFlowStatus" to projectedCashFlowStatus, |
|
|
|
|
|
"projectedCostPerformanceIndex" to if (cumulativeExpenditure > 0.0) totalFee / cumulativeExpenditure else 0.0 |
|
|
|
|
|
) |
|
|
|
|
|
return dataMap |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Throws(IOException::class) |
|
|
@Throws(IOException::class) |
|
|
private fun createFinancialSummaryByProjectExcel( |
|
|
private fun createFinancialSummaryByProjectExcel( |
|
|
financialSummaryByProjects: List<FinancialSummaryByProject>, |
|
|
financialSummaryByProjects: List<FinancialSummaryByProject>, |
|
|