瀏覽代碼

Update

1. CashReport - filter deleted Invoice
2. Invoice - add delete and filter deleted Invoice
tags/Baseline_30082024_BACKEND_UAT
MSI\2Fi 1 年之前
父節點
當前提交
656dec663b
共有 5 個檔案被更改,包括 42 行新增19 行删除
  1. +1
    -1
      src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt
  2. +14
    -7
      src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt
  3. +8
    -7
      src/main/java/com/ffii/tsms/modules/project/web/InvoiceController.kt
  4. +18
    -3
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  5. +1
    -1
      src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt

+ 1
- 1
src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt 查看文件

@@ -16,5 +16,5 @@ interface InvoiceRepository : AbstractRepository<Invoice, Long> {


fun findByInvoiceNo(invoiceNo: String): Invoice fun findByInvoiceNo(invoiceNo: String): Invoice


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

+ 14
- 7
src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt 查看文件

@@ -334,14 +334,15 @@ open class InvoiceService(


open fun allInvoiceV3(): List<Map<String, Any>>{ open fun allInvoiceV3(): List<Map<String, Any>>{
val sql = StringBuilder( val sql = StringBuilder(
"select i.id, i.invoiceNo, i.projectCode, " +
"p.name as projectName, t.code as team, i.invoiceDate, " +
" select i.id, i.invoiceNo, i.projectCode, " +
" p.name as projectName, t.code as team, i.invoiceDate, " +
" concat(t.code, ' - ', t.name) as teamCodeName, " + " concat(t.code, ' - ', t.name) as teamCodeName, " +
"i.receiptDate, i.issueAmount , i.paidAmount " +
"from invoice i " +
"left join project p on i.projectCode = p.code " +
"left join team t on t.id = p.teamLead " +
"order by i.invoiceDate "
" i.receiptDate, i.issueAmount , i.paidAmount " +
" from invoice i " +
" left join project p on i.projectCode = p.code " +
" left join team t on t.id = p.teamLead " +
" where i.deleted = false " +
" order by i.invoiceDate "
) )
return jdbcDao.queryForList(sql.toString()); return jdbcDao.queryForList(sql.toString());
} }
@@ -721,4 +722,10 @@ open class InvoiceService(
} }
} }


open fun markDeleted(id: Long) {
invoiceRepository.save(invoiceRepository.findById(id).orElseThrow().apply {
deleted = true
})
}

} }

+ 8
- 7
src/main/java/com/ffii/tsms/modules/project/web/InvoiceController.kt 查看文件

@@ -15,14 +15,9 @@ import net.sf.jasperreports.engine.JasperExportManager
import net.sf.jasperreports.engine.JasperPrint import net.sf.jasperreports.engine.JasperPrint
import org.apache.poi.ss.usermodel.Workbook import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartHttpServletRequest import org.springframework.web.multipart.MultipartHttpServletRequest
import java.io.OutputStream import java.io.OutputStream


@@ -145,4 +140,10 @@ class InvoiceController(
fun updateInvoiceDetail(@RequestBody req: EditInvoiceRequest): EditInvoiceResponse { fun updateInvoiceDetail(@RequestBody req: EditInvoiceRequest): EditInvoiceResponse {
return invoiceService.updateInvoiceDetail(req) return invoiceService.updateInvoiceDetail(req)
} }

@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
fun deleteProject(@PathVariable id: Long) {
invoiceService.markDeleted(id)
}
} }

+ 18
- 3
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt 查看文件

@@ -3903,6 +3903,7 @@ open class ReportService(
return workbook return workbook
} }
// Use to Calculate cummunlative expenditure // Use to Calculate cummunlative expenditure
// TO DO: Add isCrossTeam
data class TimesheetData( data class TimesheetData(
val normalConsumed: Double, val normalConsumed: Double,
val otConsumed: Double, val otConsumed: Double,
@@ -3913,6 +3914,7 @@ open class ReportService(
val projectCode: String, val projectCode: String,
val planStart: LocalDate, val planStart: LocalDate,
val planEnd: LocalDate val planEnd: LocalDate
// val isCrossTeam: Boolean
) )


data class SalaryEffectiveInfo( data class SalaryEffectiveInfo(
@@ -3947,6 +3949,12 @@ open class ReportService(
fun getManHoursSpentByTeam(teamLeadId: Long?): List<TimesheetData>{ fun getManHoursSpentByTeam(teamLeadId: Long?): List<TimesheetData>{
val sql = StringBuilder( val sql = StringBuilder(
"select coalesce(t.normalConsumed, 0) as normalConsumed, coalesce(t.otConsumed, 0) as otConsumed, t.recordDate, t.staffId, s2.hourlyRate, s2.salaryPoint, p.code, p.planStart, p.planEnd" "select coalesce(t.normalConsumed, 0) as normalConsumed, coalesce(t.otConsumed, 0) as otConsumed, t.recordDate, t.staffId, s2.hourlyRate, s2.salaryPoint, p.code, p.planStart, p.planEnd"
// For later calculating cross team charge
// + ",CASE"
// + " when s.teamId is NUll then null"
// + " when s.teamId = p.teamLead then 1"
// + " else 0"
// + " END as IsCrossTeam"
+ " from timesheet t" + " from timesheet t"
+ " left join project p on t.projectId = p.id" + " left join project p on t.projectId = p.id"
+ " left join staff s on t.staffId = s.id" + " left join staff s on t.staffId = s.id"
@@ -4070,6 +4078,9 @@ open class ReportService(
// } // }
fun calculateProjectExpenditures(timesheetDataList: List<TimesheetData>): Map<String, BigDecimal> { fun calculateProjectExpenditures(timesheetDataList: List<TimesheetData>): Map<String, BigDecimal> {
val otFactor = BigDecimal(1.0) val otFactor = BigDecimal(1.0)
// For cross Team Calculation
// val crossTeamCharge = BigDecimal(1.15)
// If isCrossTeam is true, normal an ot expenditure will times the cross team charge
return timesheetDataList return timesheetDataList
.groupBy { it.projectCode } .groupBy { it.projectCode }
.mapValues { (_, projectTimesheets) -> .mapValues { (_, projectTimesheets) ->
@@ -4084,6 +4095,7 @@ open class ReportService(




// Update timesheet data with salary effective data, then group by project code, group by staff Id and group by Year Month // Update timesheet data with salary effective data, then group by project code, group by staff Id and group by Year Month
// Used for checking data
// Data foramt: // Data foramt:
// "M-0976": { // "M-0976": {
// "184": { // "184": {
@@ -4108,13 +4120,16 @@ open class ReportService(
fun sumTimesheetDataByMonth(timesheetDataList: List<TimesheetData>): Map<String, ProjectSummary> { fun sumTimesheetDataByMonth(timesheetDataList: List<TimesheetData>): Map<String, ProjectSummary> {


return timesheetDataList return timesheetDataList
.groupBy { it.projectCode }
.groupBy { it.projectCode } // Group timesheet data by project code
.mapValues { (_, projectTimesheets) -> .mapValues { (_, projectTimesheets) ->
val staffData = projectTimesheets.groupBy { it.staffId }
// Process each project's timesheet data
val staffData = projectTimesheets.groupBy { it.staffId } // Group by staff ID
.mapValues { (_, staffTimesheets) -> .mapValues { (_, staffTimesheets) ->
// Process each staff member's timesheet data
val monthlyData = staffTimesheets.groupBy { timesheet -> val monthlyData = staffTimesheets.groupBy { timesheet ->
YearMonth.from(timesheet.recordDate)
YearMonth.from(timesheet.recordDate) // Group by month
}.mapValues { (_, monthTimesheets) -> }.mapValues { (_, monthTimesheets) ->
// Calculate monthly summary for each staff member
MonthSummary( MonthSummary(
hourlyRate = monthTimesheets.maxByOrNull { it.recordDate }?.hourlyRate ?: BigDecimal.ZERO, hourlyRate = monthTimesheets.maxByOrNull { it.recordDate }?.hourlyRate ?: BigDecimal.ZERO,
salaryPoint = monthTimesheets.maxByOrNull { it.recordDate }?.salaryPoint ?: 0, salaryPoint = monthTimesheets.maxByOrNull { it.recordDate }?.salaryPoint ?: 0,


+ 1
- 1
src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt 查看文件

@@ -86,7 +86,7 @@ class ReportController(
val project = projectRepository.findById(request.projectId).orElseThrow() val project = projectRepository.findById(request.projectId).orElseThrow()
val projectTasks = projectTaskRepository.findAllByProject(project) val projectTasks = projectTaskRepository.findAllByProject(project)
// val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project) // val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project)
val invoices = invoiceRepository.findAllByProjectCodeAndPaidAmountIsNotNull(project.code!!)
val invoices = invoiceRepository.findAllByProjectCodeAndPaidAmountIsNotNullAndDeletedFalse(project.code!!)
val timesheets = timesheetRepository.findAllByProjectTaskIn(projectTasks) val timesheets = timesheetRepository.findAllByProjectTaskIn(projectTasks)
val monthlyStaffSalaryEffective = salaryEffectiveService.getMonthlyStaffSalaryData(timesheets.minByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.parse("2012-01-01"), timesheets.maxByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.now()) val monthlyStaffSalaryEffective = salaryEffectiveService.getMonthlyStaffSalaryData(timesheets.minByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.parse("2012-01-01"), timesheets.maxByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.now())




Loading…
取消
儲存