浏览代码

update report

tags/Baseline_30082024_BACKEND_UAT
cyril.tsui 1年前
父节点
当前提交
ea09340e3b
共有 3 个文件被更改,包括 80 次插入30 次删除
  1. +69
    -28
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  2. +8
    -2
      src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt
  3. +3
    -0
      src/main/java/com/ffii/tsms/modules/timesheet/entity/TimesheetRepository.kt

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

@@ -1,12 +1,11 @@
package com.ffii.tsms.modules.report.service

import com.ffii.tsms.modules.data.entity.Salary
import com.ffii.tsms.modules.data.entity.projections.SalarySearchInfo
import com.ffii.tsms.modules.project.entity.Invoice
import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.timesheet.entity.Timesheet
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.xssf.usermodel.XSSFDataFormat
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.core.io.ClassPathResource
import org.springframework.stereotype.Service
@@ -25,9 +24,9 @@ open class ReportService {

// ==============================|| GENERATE REPORT ||============================== //
@Throws(IOException::class)
fun generateProjectCashFlowReport(project: Project, invoices: List<Invoice>): ByteArray {
fun generateProjectCashFlowReport(project: Project, invoices: List<Invoice>, timesheets: List<Timesheet>): ByteArray {
// Generate the Excel report with query results
val workbook: Workbook = createProjectCashFlowReport(project, invoices, PROJECT_CASH_FLOW_REPORT)
val workbook: Workbook = createProjectCashFlowReport(project, invoices, timesheets, PROJECT_CASH_FLOW_REPORT)

// Write the workbook to a ByteArrayOutputStream
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
@@ -55,6 +54,7 @@ open class ReportService {
private fun createProjectCashFlowReport(
project: Project,
invoices: List<Invoice>,
timesheets: List<Timesheet>,
templatePath: String,
): Workbook {
// please create a new function for each report template
@@ -108,10 +108,11 @@ open class ReportService {

rowIndex = 10
val actualIncome = invoices.sumOf { invoice -> invoice.paidAmount!! }
val actualExpenditure = timesheets.sumOf { timesheet -> timesheet.staff!!.salary.hourlyRate.toDouble() * ((timesheet.normalConsumed ?: 0.0) + (timesheet.otConsumed ?: 0.0)) }
sheet.getRow(rowIndex).apply {
getCell(1).apply {
// TODO: Replace by actual expenditure
setCellValue(actualIncome * 0.8)
setCellValue(actualExpenditure)
cellStyle.dataFormat = accountingStyle
}

@@ -136,37 +137,77 @@ open class ReportService {
}

// TODO: Add expenditure
// formula =IF(B17>0,D16-B17,D16+C17)
rowIndex = 15
val combinedResults = (invoices.map { it.receiptDate } + timesheets.map { it.recordDate }).filterNotNull().sortedBy { it }

val dateFormatter = DateTimeFormatter.ofPattern("MMM YYYY")
invoices.forEach { invoice: Invoice ->
sheet.getRow(rowIndex++).apply {
getCell(0).apply {
setCellValue(invoice.receiptDate!!.format(dateFormatter))
}
combinedResults.forEach { result: LocalDate ->
val invoice = invoices.find { invoice: Invoice -> invoice.receiptDate == result }
val timesheet = timesheets.find { timesheet: Timesheet -> timesheet.recordDate == result}

getCell(1).apply {
setCellValue(0.0)
cellStyle.dataFormat = accountingStyle
}
if (invoice != null) {
sheet.getRow(rowIndex++).apply {

getCell(2).apply {
setCellValue(invoice.paidAmount!!)
cellStyle.dataFormat = accountingStyle
}
getCell(0).apply {
setCellValue(result.format(dateFormatter))
}

getCell(1).apply {
setCellValue(0.0)
cellStyle.dataFormat = accountingStyle
}

getCell(2).apply {
setCellValue(invoice.paidAmount!!)
cellStyle.dataFormat = accountingStyle
}

getCell(3).apply {
val lastRow = rowIndex - 1
if (lastRow == 15) {
cellFormula = "C{currentRow}-B{currentRow}".replace("{currentRow}", rowIndex.toString())
} else {
cellFormula = "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace("{currentRow}", rowIndex.toString()).replace("{lastRow}", lastRow.toString())
}
cellStyle.dataFormat = accountingStyle
}

getCell(3).apply {
val lastRow = rowIndex - 1
if (lastRow == 15) {
cellFormula = "C{currentRow}".replace("{currentRow}", rowIndex.toString())
} else {
cellFormula = "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace("{currentRow}", rowIndex.toString()).replace("{lastRow}", lastRow.toString())
getCell(4).apply {
setCellValue(invoice.milestonePayment!!.description!!)
}
cellStyle.dataFormat = accountingStyle
}
}

if (timesheet != null) {
sheet.getRow(rowIndex++).apply {

getCell(0).apply {
setCellValue(result.format(dateFormatter))
}

getCell(1).apply {
setCellValue(timesheet.staff!!.salary.hourlyRate.toDouble() * ((timesheet.normalConsumed ?: 0.0) + (timesheet.otConsumed ?: 0.0)))
cellStyle.dataFormat = accountingStyle
}

getCell(4).apply {
setCellValue(invoice.milestonePayment!!.description!!)
getCell(2).apply {
setCellValue(0.0)
cellStyle.dataFormat = accountingStyle
}

getCell(3).apply {
val lastRow = rowIndex - 1
if (lastRow == 15) {
cellFormula = "C{currentRow}-B{currentRow}".replace("{currentRow}", rowIndex.toString())
} else {
cellFormula = "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace("{currentRow}", rowIndex.toString()).replace("{lastRow}", lastRow.toString())
}
cellStyle.dataFormat = accountingStyle
}

getCell(4).apply {
setCellValue("Monthly Manpower Expenditure")
}
}
}
}


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

@@ -4,6 +4,7 @@ import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.report.service.ReportService
import com.ffii.tsms.modules.project.service.InvoiceService
import com.ffii.tsms.modules.report.web.model.ProjectCashFlowReportRequest
import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository
import jakarta.validation.Valid
import org.springframework.core.io.ByteArrayResource
import org.springframework.core.io.Resource
@@ -21,16 +22,21 @@ import java.time.LocalDate

@RestController
@RequestMapping("/reports")
class ReportController(private val invoiceRepository: InvoiceRepository, private val milestonePaymentRepository: MilestonePaymentRepository, private val excelReportService: ReportService, private val projectRepository: ProjectRepository, private val invoiceService: InvoiceService) {
class ReportController(private val invoiceRepository: InvoiceRepository, private val milestonePaymentRepository: MilestonePaymentRepository, private val excelReportService: ReportService, private val projectRepository: ProjectRepository, private val invoiceService: InvoiceService,
private val timesheetRepository: TimesheetRepository,
private val projectTaskRepository: ProjectTaskRepository
) {

@PostMapping("/ProjectCashFlowReport")
@Throws(ServletRequestBindingException::class, IOException::class)
fun getProjectCashFlowReport(@RequestBody @Valid request: ProjectCashFlowReportRequest): ResponseEntity<Resource> {

val project = projectRepository.findById(request.projectId).orElseThrow()
val projectTasks = projectTaskRepository.findAllByProject(project)
val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project)
val timesheets = timesheetRepository.findAllByProjectTaskIn(projectTasks)

val reportResult: ByteArray = excelReportService.generateProjectCashFlowReport(project, invoices)
val reportResult: ByteArray = excelReportService.generateProjectCashFlowReport(project, invoices, timesheets)
// val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
return ResponseEntity.ok()
// .contentType(mediaType)


+ 3
- 0
src/main/java/com/ffii/tsms/modules/timesheet/entity/TimesheetRepository.kt 查看文件

@@ -4,6 +4,7 @@ import com.ffii.core.support.AbstractRepository
import com.ffii.tsms.modules.data.entity.Staff
import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.timesheet.entity.projections.TimesheetHours
import com.ffii.tsms.modules.project.entity.ProjectTask
import org.springframework.data.jpa.repository.Query
import java.time.LocalDate

@@ -11,6 +12,8 @@ interface TimesheetRepository : AbstractRepository<Timesheet, Long> {

fun findAllByStaff(staff: Staff): List<Timesheet>

fun findAllByProjectTaskIn(projectTasks: List<ProjectTask>): List<Timesheet>

fun deleteAllByStaffAndRecordDate(staff: Staff, recordDate: LocalDate)

@Query("SELECT new com.ffii.tsms.modules.timesheet.entity.projections.TimesheetHours(IFNULL(SUM(normalConsumed), 0), IFNULL(SUM(otConsumed), 0)) FROM Timesheet t JOIN ProjectTask pt on t.projectTask = pt WHERE pt.project = ?1")


正在加载...
取消
保存