Kaynağa Gözat

update financial year with year filter

add_swagger
MSI\derek 10 ay önce
ebeveyn
işleme
9d89079ad3
13 değiştirilmiş dosya ile 505 ekleme ve 5 silme
  1. +17
    -0
      src/main/java/com/ffii/core/utils/CheckingUtils.kt
  2. +272
    -2
      src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt
  3. +9
    -0
      src/main/java/com/ffii/tsms/modules/data/service/SalaryEffectiveService.kt
  4. +11
    -0
      src/main/java/com/ffii/tsms/modules/data/service/TeamLogService.kt
  5. +37
    -0
      src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt
  6. +1
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt
  7. +2
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/ProjectExpenseRepository.kt
  8. +17
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/projections/DashboardData.kt
  9. +8
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/projections/InvoiceData.kt
  10. +22
    -0
      src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt
  11. +17
    -0
      src/main/java/com/ffii/tsms/modules/project/service/ProjectExpenseService.kt
  12. +49
    -3
      src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt
  13. +43
    -0
      src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt

+ 17
- 0
src/main/java/com/ffii/core/utils/CheckingUtils.kt Dosyayı Görüntüle

@@ -0,0 +1,17 @@
package com.ffii.core.utils

import java.time.LocalDate

open class CheckingUtils {
companion object {
fun checkTimePeriod(checkDate: LocalDate, startDate: LocalDate?, endDate: LocalDate?): Boolean {
return if (startDate == null && endDate == null) {
true
} else if (startDate == null) {
checkDate.isBefore(endDate)
} else {
checkDate.isAfter(startDate) && checkDate.isBefore(endDate)
}
}
}
}

+ 272
- 2
src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt Dosyayı Görüntüle

@@ -2,20 +2,30 @@ package com.ffii.tsms.modules.data.service

import com.ffii.core.support.AbstractBaseEntityService
import com.ffii.core.support.JdbcDao
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.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.web.models.FinancialSummaryByClient
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.Invoice
import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.project.entity.projections.DashboardData
import com.ffii.tsms.modules.project.service.InvoiceService
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.service.TimesheetsService
import org.apache.poi.ss.usermodel.*
import org.apache.poi.ss.util.CellRangeAddress
import org.apache.poi.ss.util.CellUtil
import org.apache.poi.util.ArrayUtil
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.beans.BeanUtils
import org.springframework.core.io.ClassPathResource
@@ -33,7 +43,17 @@ open class DashboardService(
private val customerTypeRepository: CustomerTypeRepository,
private val customerSubsidiaryService: CustomerSubsidiaryService,
private val customerContactService: CustomerContactService,
private val projectRepository: ProjectRepository,
private val timesheetsService: TimesheetsService,
private val invoiceService: InvoiceService,
private val projectExpenseService: ProjectExpenseService,
private val timesheetRepository: TimesheetRepository,
private val invoiceRepository: InvoiceRepository,
private val staffsService: StaffsService,
private val teamLogService: TeamLogService,
private val salaryEffectiveService: SalaryEffectiveService,
private val projectExpenseRepository: ProjectExpenseRepository,
private val teamRepository: TeamRepository,
private val jdbcDao: JdbcDao
) {
private val DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd")
@@ -3204,6 +3224,256 @@ open class DashboardService(
return outputStream.toByteArray()
}

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 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 = testing(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)
private fun createFinancialSummaryByProjectExcel(
financialSummaryByProjects: List<FinancialSummaryByProject>,


+ 9
- 0
src/main/java/com/ffii/tsms/modules/data/service/SalaryEffectiveService.kt Dosyayı Görüntüle

@@ -133,6 +133,15 @@ open class SalaryEffectiveService(
}
}

open fun getStaffSalaryEffective(staffId: Long, recordDate: LocalDate): SalaryEffective? {
val salaryEffective = salaryEffectiveRepository.findAll()
val thisSE = salaryEffective.find {
it.staff.id == staffId
&& it.startDate.isBefore(recordDate) && (it.endDate.isAfter(recordDate) || it.endDate == null)
}
return thisSE
}


data class SalaryData(val idInStaff: Long, val staffId: String, val financialYear: LocalDate, val hourlyRate: BigDecimal, val salaryPoint: Int)
data class StaffSalaryData(val staffId: String, val salaryData: List<SalaryData>)


+ 11
- 0
src/main/java/com/ffii/tsms/modules/data/service/TeamLogService.kt Dosyayı Görüntüle

@@ -8,6 +8,7 @@ import com.ffii.tsms.modules.data.entity.TeamRepository
import com.ffii.tsms.modules.data.entity.projections.TeamLogInfo
import com.ffii.tsms.modules.data.web.models.TeamHistory
import org.springframework.stereotype.Service
import java.time.LocalDate

@Service
open class TeamLogService (
@@ -19,6 +20,16 @@ open class TeamLogService (
return teamLogRepository.findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId).drop(1)
}

open fun getStaffTeamLog(staffId:Long, recordDate: LocalDate): TeamLog? {
val teamLog = teamLogRepository.findAll()
val team = teamLog.find{
it.deleted == false
&& it.staff.id == staffId
&& it.from.isBefore(recordDate) && (it.to == null || it.to.isAfter(recordDate))
}
return team
}

open fun editTeamLog(teamHistory: List<TeamHistory>, delTeamHistory: List<Long>) {
if (delTeamHistory.isNotEmpty()) {
delTeamHistory.forEach {


+ 37
- 0
src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt Dosyayı Görüntüle

@@ -15,13 +15,18 @@ import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.ResponseStatus
import com.ffii.core.response.RecordsRes
import com.ffii.core.utils.CriteriaArgsBuilder
import com.ffii.tsms.modules.data.entity.TeamRepository
import com.ffii.tsms.modules.data.service.*
import com.ffii.tsms.modules.data.web.models.ExportFinancialSummaryByClientExcelRequest
import com.ffii.tsms.modules.data.web.models.ExportFinancialSummaryByProjectExcelRequest
import com.ffii.tsms.modules.data.web.models.FinancialSummaryRequest
import com.ffii.tsms.modules.project.entity.projections.DashboardData
import org.springframework.core.io.ByteArrayResource
import org.springframework.core.io.Resource
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestParam
import java.time.LocalDate
import java.time.LocalDateTime

@RestController
@RequestMapping("/dashboard")
@@ -30,6 +35,7 @@ class DashboardController(
private val customerSubsidiaryService: CustomerSubsidiaryService,
private val customerContactService: CustomerContactService,
private val dashboardService: DashboardService,
private val teamRepository: TeamRepository,
private val staffsService: StaffsService,
) {
@GetMapping("/searchCustomerSubsidiary")
@@ -465,6 +471,37 @@ class DashboardController(
val args = mutableMapOf<String, Any>()
return dashboardService.staffCombo(args)
}
@GetMapping("/getFinancialSummaryByProject")
fun getFinancialSummaryByProject(@Valid request: HttpServletRequest): List<Map<String, Any>> {
println("")
println("start...: ${LocalDateTime.now()}")
val startDate = if (request.getParameter("startDate") != null) LocalDate.parse(request.getParameter("startDate")) else null
val endDate = LocalDate.parse(request.getParameter("endDate"))
val teamId = request.getParameter("teamId").toLong()
val output = dashboardService.fetchFinancialSummaryByProject(teamId, startDate, endDate)
println("end...: ${LocalDateTime.now()}")
return output
}

@GetMapping("/getFinancialSummary")
fun getFinancialSummary(@Valid request: HttpServletRequest): List<Map<String, Any>> {
val output = mutableListOf<Map<String, Any>>()
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
val teams = teamRepository.findAll()
val teamIds: List<Long> = if (targetTeam != null) {
listOf(targetTeam.toLong())
} else {
teams.mapNotNull {
if (it.deleted == false) it.id else null
}
}
for (id in teamIds) {
output.add(dashboardService.fetchFinancialSummary(startDate, endDate, id))
}
return output
}

@PostMapping("/exportFinancialSummaryByClientExcel")
fun exportFinancialSummaryByClientExcel(@Valid @RequestBody request: ExportFinancialSummaryByClientExcelRequest): ResponseEntity<Resource> {


+ 1
- 0
src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt Dosyayı Görüntüle

@@ -15,6 +15,7 @@ interface InvoiceRepository : AbstractRepository<Invoice, Long> {
fun findInvoiceInfoByPaidAmountIsNotNull(): List<InvoiceInfo>

fun findByInvoiceNo(invoiceNo: String): Invoice
fun findAllByProjectCodeIn(projectCode: List<String>): List<Invoice>

fun findAllByProjectCodeAndPaidAmountIsNotNullAndDeletedFalse(projectCode: String): List<Invoice>
}

+ 2
- 0
src/main/java/com/ffii/tsms/modules/project/entity/ProjectExpenseRepository.kt Dosyayı Görüntüle

@@ -7,4 +7,6 @@ interface ProjectExpenseRepository : AbstractRepository<ProjectExpense, Long> {
fun findExpenseSearchInfoByDeletedFalseOrderByProjectCode(): List<ProjectExpenseSearchInfo>

fun findAllByProjectIdAndDeletedFalse(projectId: Long): List<ProjectExpense>

fun findAllByProjectIdInAndDeletedFalse(projectIds: List<Long>): List<ProjectExpense>
}

+ 17
- 0
src/main/java/com/ffii/tsms/modules/project/entity/projections/DashboardData.kt Dosyayı Görüntüle

@@ -0,0 +1,17 @@
package com.ffii.tsms.modules.project.entity.projections

data class DashboardData(
// timesheet data
val cumulativeExpenditure: Double,
val manhourExpense: Double,
val projectExpense: Double,
// invoice data
val invoicedAmount: Double,
val nonInvoicedAmount: Double,
val receivedAmount: Double,
// calculation
// val cashFlowStatus: String,
// val projectedCashFlowStatus: String,
val cpi: Double,
val projectedCpi: Double,
)

+ 8
- 0
src/main/java/com/ffii/tsms/modules/project/entity/projections/InvoiceData.kt Dosyayı Görüntüle

@@ -0,0 +1,8 @@
package com.ffii.tsms.modules.project.entity.projections

data class InvoiceData(
// invoice data
val invoicedAmount: Double,
val nonInvoicedAmount: Double,
val receivedAmount: Double,
)

+ 22
- 0
src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt Dosyayı Görüntüle

@@ -4,7 +4,9 @@ import com.ffii.core.support.AbstractIdEntityService
import com.ffii.core.support.JdbcDao
import com.ffii.core.utils.ExcelUtils
import com.ffii.core.utils.PdfUtils
import com.ffii.core.utils.CheckingUtils
import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.project.entity.projections.InvoiceData
import com.ffii.tsms.modules.project.entity.projections.InvoiceInfo

import com.ffii.tsms.modules.project.entity.projections.InvoicePDFReq
@@ -33,12 +35,32 @@ import kotlin.math.min
@Service
open class InvoiceService(
private val invoiceRepository: InvoiceRepository,
private val projectRepository: ProjectRepository,
private val milestoneRepository: MilestoneRepository,
private val milestonePaymentRepository: MilestonePaymentRepository,
private val projectService: ProjectsService,
private val jdbcDao: JdbcDao,
) : AbstractIdEntityService<Invoice, Long, InvoiceRepository>(jdbcDao, invoiceRepository){

open fun getInvoiceDataByProjectId(projectId: Long, startDate: LocalDate?, endDate: LocalDate?): InvoiceData {
val project = projectRepository.findById(projectId).orElseThrow()
val code = project.code
val invoice = invoiceRepository.findAll()
var invoicedAmount = 0.0
var receivedAmount = 0.0
for (curr in invoice) {
if (curr.deleted == false
&& curr.projectCode == code
&& CheckingUtils.checkTimePeriod(curr.invoiceDate!!, startDate, endDate)
) {
invoicedAmount += curr.issueAmount!!.toDouble()
receivedAmount += curr.paidAmount?.toDouble() ?: 0.0
}
}
val nonInvoicedAmount = (project.expectedTotalFee?: 0.0) - invoicedAmount
return InvoiceData(invoicedAmount, nonInvoicedAmount, receivedAmount)
}

open fun findAllByProjectAndPaidAmountIsNotNull(project: Project): List<Invoice> {
val milestones = milestoneRepository.findAllByProject(project)
val milestonePayments = milestonePaymentRepository.findAllByMilestoneIn(milestones)


+ 17
- 0
src/main/java/com/ffii/tsms/modules/project/service/ProjectExpenseService.kt Dosyayı Görüntüle

@@ -2,12 +2,14 @@ package com.ffii.tsms.modules.project.service

import com.ffii.core.support.AbstractIdEntityService
import com.ffii.core.support.JdbcDao
import com.ffii.core.utils.CheckingUtils
import com.ffii.tsms.modules.project.entity.ProjectExpense
import com.ffii.tsms.modules.project.entity.ProjectExpenseRepository
import com.ffii.tsms.modules.project.entity.ProjectRepository
import com.ffii.tsms.modules.project.entity.projections.ProjectExpenseSearchInfo
import com.ffii.tsms.modules.project.web.models.EditProjectExpenseRequest
import com.ffii.tsms.modules.project.web.models.ProjectExpenseRequest
import org.springframework.cglib.core.Local
import org.springframework.stereotype.Service
import java.time.LocalDate
import java.time.format.DateTimeFormatter
@@ -22,6 +24,21 @@ open class ProjectExpenseService(
return projectExpenseRepository.findExpenseSearchInfoByDeletedFalseOrderByProjectCode()
}

open fun getProjectExpenseByProjectId(projectId: Long, startDate: LocalDate?, endDate: LocalDate?): Double {
val projectExpense = projectExpenseRepository.findAllByProjectIdAndDeletedFalse(projectId)
var sum = 0.0
for (curr in projectExpense) {
if (curr!!.deleted == false
&& curr.project!!.id == projectId
// issueDate might be an issue
&& CheckingUtils.checkTimePeriod(curr.issueDate!!, startDate, endDate)
) {
sum += curr.amount ?: 0.0
}
}
return sum
}

open fun createProjectExpense(projectExpenseList: List<ProjectExpenseRequest>): Boolean {
try {
for (projectExpense in projectExpenseList) {


+ 49
- 3
src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt Dosyayı Görüntüle

@@ -1,5 +1,6 @@
package com.ffii.tsms.modules.project.service

import com.ffii.core.utils.CheckingUtils
import com.ffii.core.utils.ExcelUtils
import com.ffii.tsms.modules.common.SecurityUtils
import com.ffii.tsms.modules.data.entity.*
@@ -7,11 +8,10 @@ import com.ffii.tsms.modules.data.service.*
import com.ffii.tsms.modules.data.web.models.SaveCustomerResponse
import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.project.entity.Milestone
import com.ffii.tsms.modules.project.entity.projections.InvoiceInfoSearchInfo
import com.ffii.tsms.modules.project.entity.projections.InvoiceSearchInfo
import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo
import com.ffii.tsms.modules.project.entity.projections.*
import com.ffii.tsms.modules.project.web.models.*
import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository
import com.ffii.tsms.modules.timesheet.service.TimesheetsService
import org.apache.commons.logging.LogFactory
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.DataFormatter
@@ -31,6 +31,9 @@ import kotlin.jvm.optionals.getOrNull
@Service
open class ProjectsService(
private val projectRepository: ProjectRepository,
// private val invoiceService: InvoiceService,
private val invoiceRepository: InvoiceRepository,
private val projectExpenseService: ProjectExpenseService,
private val customerService: CustomerService,
private val tasksService: TasksService,
private val customerContactService: CustomerContactService,
@@ -51,6 +54,7 @@ open class ProjectsService(
private val milestonePaymentRepository: MilestonePaymentRepository,
private val taskGroupRepository: TaskGroupRepository,
private val timesheetRepository: TimesheetRepository,
private val timesheetsService: TimesheetsService,
private val taskTemplateRepository: TaskTemplateRepository,
private val subsidiaryContactService: SubsidiaryContactService,
private val subsidiaryContactRepository: SubsidiaryContactRepository,
@@ -376,6 +380,48 @@ open class ProjectsService(
)
}
}
open fun getInvoiceDataByProjectId(projectId: Long, startDate: LocalDate?, endDate: LocalDate?): InvoiceData {
val project = projectRepository.findById(projectId).orElseThrow()
val code = project.code
val invoice = invoiceRepository.findAll()
var invoicedAmount = 0.0
var receivedAmount = 0.0
for (curr in invoice) {
if (curr.deleted == false
&& curr.projectCode == code
&& CheckingUtils.checkTimePeriod(curr.invoiceDate!!, startDate, endDate)
) {
invoicedAmount += curr.issueAmount!!.toDouble()
receivedAmount += curr.paidAmount?.toDouble() ?: 0.0
}
}
val nonInvoicedAmount = (project.expectedTotalFee?: 0.0) - invoicedAmount
return InvoiceData(invoicedAmount, nonInvoicedAmount, receivedAmount)
}
// 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 = getInvoiceDataByProjectId(projectId,startDate,endDate)
// 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 getProjectDetails(projectId: Long): EditProjectDetails? {
val project = projectRepository.findById(projectId)


+ 43
- 0
src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt Dosyayı Görüntüle

@@ -3,9 +3,12 @@ package com.ffii.tsms.modules.timesheet.service
import com.ffii.core.exception.BadRequestException
import com.ffii.core.support.AbstractBaseEntityService
import com.ffii.core.support.JdbcDao
import com.ffii.core.utils.CheckingUtils
import com.ffii.tsms.modules.data.entity.Staff
import com.ffii.tsms.modules.data.entity.StaffRepository
import com.ffii.tsms.modules.data.service.SalaryEffectiveService
import com.ffii.tsms.modules.data.service.StaffsService
import com.ffii.tsms.modules.data.service.TeamLogService
import com.ffii.tsms.modules.data.service.TeamService
import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.timesheet.entity.Leave
@@ -23,6 +26,7 @@ import java.time.LocalDate
import java.time.format.DateTimeFormatter
import kotlin.jvm.optionals.getOrDefault
import kotlin.jvm.optionals.getOrNull
import kotlin.time.times

@Service
open class TimesheetsService(
@@ -32,6 +36,8 @@ open class TimesheetsService(
private val taskRepository: TaskRepository,
private val staffsService: StaffsService,
private val teamService: TeamService,
private val teamLogService: TeamLogService,
private val salaryEffectiveService: SalaryEffectiveService,
private val staffRepository: StaffRepository, private val leaveRepository: LeaveRepository,
private val jdbcDao: JdbcDao,
) : AbstractBaseEntityService<Timesheet, Long, TimesheetRepository>(jdbcDao, timesheetRepository) {
@@ -322,6 +328,43 @@ open class TimesheetsService(

return if (sheet.lastRowNum > 0) "Import Excel success btw staffId:" + notExistStaffIdList.distinct().joinToString(", ") else "Import Excel failure"
}
open fun getManpowerExpenseByProjectId(
projectId: Long,
startDate: LocalDate?,
endDate: LocalDate?,
): Double {
val timesheet = timesheetRepository.findAll()
var manpowerExpense = 0.0
for (curr in timesheet) {
val project = curr.project
val otMultiplier = 1.0
val crossTeamMultipier = 1.0
val recordDate = curr.recordDate!!
if (curr.deleted == false
&& project != null
&& project.id == projectId
&& CheckingUtils.checkTimePeriod(recordDate, startDate, endDate)) {
val staffId = curr.staff!!.id!!
val staffTeam = teamLogService.getStaffTeamLog(staffId, recordDate)
if (staffTeam == null) {
println(staffId)
}
val thisSE = salaryEffectiveService.getStaffSalaryEffective(staffId, recordDate)
val hourlyRate = thisSE!!.salary.hourlyRate
// will the staff be no team during that period of time?????
val normalHour = curr.normalConsumed ?: 0.0
val otHour = curr.otConsumed ?: 0.0
val normalCost = normalHour.times(hourlyRate.toDouble())
val otCost = otHour.times(hourlyRate.toDouble()).times(otMultiplier)
if (project.teamLead?.id != staffTeam!!.team.id) { // cross team
manpowerExpense += (normalCost + otCost).times(crossTeamMultipier)
} else {
manpowerExpense += (normalCost + otCost)
}
}
}
return manpowerExpense
}

@Transactional(rollbackFor = [Exception::class])
open fun rearrangeTimesheets(): String {


Yükleniyor…
İptal
Kaydet