Bläddra i källkod

report add subsidiary

tags/Baseline_30082024_BACKEND_UAT
leoho2fi 1 år sedan
förälder
incheckning
b1207ceeac
3 ändrade filer med 85 tillägg och 111 borttagningar
  1. +67
    -70
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  2. +17
    -41
      src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt
  3. +1
    -0
      src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt

+ 67
- 70
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt Visa fil

@@ -5,35 +5,23 @@ import com.ffii.tsms.modules.data.entity.Customer
import com.ffii.tsms.modules.data.entity.Salary import com.ffii.tsms.modules.data.entity.Salary
import com.ffii.tsms.modules.data.entity.Staff import com.ffii.tsms.modules.data.entity.Staff
import com.ffii.tsms.modules.data.entity.Team import com.ffii.tsms.modules.data.entity.Team
import com.ffii.tsms.modules.project.entity.GradeAllocation
import com.ffii.tsms.modules.project.entity.Invoice import com.ffii.tsms.modules.project.entity.Invoice
import com.ffii.tsms.modules.project.entity.Milestone import com.ffii.tsms.modules.project.entity.Milestone
import com.ffii.tsms.modules.project.entity.Project import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.report.web.model.costAndExpenseRequest import com.ffii.tsms.modules.report.web.model.costAndExpenseRequest
import com.ffii.tsms.modules.timesheet.entity.Leave
import com.ffii.tsms.modules.timesheet.entity.Timesheet import com.ffii.tsms.modules.timesheet.entity.Timesheet
import com.ffii.tsms.modules.timesheet.entity.projections.MonthlyLeave
import com.ffii.tsms.modules.timesheet.entity.projections.ProjectMonthlyHoursWithDate
import com.ffii.tsms.modules.timesheet.entity.projections.TimesheetHours
import com.ffii.tsms.modules.timesheet.web.models.LeaveEntry
import org.apache.commons.logging.Log import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory import org.apache.commons.logging.LogFactory
import org.apache.poi.ss.usermodel.* import org.apache.poi.ss.usermodel.*
import org.apache.poi.ss.util.CellAddress
import org.apache.poi.ss.util.CellRangeAddress 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.xssf.usermodel.XSSFWorkbook import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.apache.poi.ss.usermodel.FormulaEvaluator import org.apache.poi.ss.usermodel.FormulaEvaluator
import org.apache.poi.ss.usermodel.CellStyle
import org.apache.poi.ss.usermodel.DateUtil
import org.apache.poi.ss.usermodel.CellType
import org.hibernate.jdbc.Work
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
import java.io.IOException import java.io.IOException
import java.math.BigDecimal import java.math.BigDecimal
import java.sql.Time
import java.time.LocalDate import java.time.LocalDate
import java.time.YearMonth import java.time.YearMonth
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -41,7 +29,6 @@ import java.time.ZoneId
import java.time.format.DateTimeParseException import java.time.format.DateTimeParseException
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
import java.util.* import java.util.*
import kotlin.jvm.optionals.getOrElse




data class DayInfo(val date: String?, val weekday: String?) data class DayInfo(val date: String?, val weekday: String?)
@@ -287,26 +274,22 @@ open class ReportService(
fun generateLateStartReport( fun generateLateStartReport(
teamId: Long, teamId: Long,
clientId: Long, clientId: Long,
remainedDate:LocalDate,
remainedDateTo:LocalDate,
remainedDate: LocalDate,
remainedDateTo: LocalDate,
teams: List<Team>, teams: List<Team>,
customers: List<Customer>, customers: List<Customer>,
searchedClient: String,
type: String,
): ByteArray { ): ByteArray {
val projectDetails = getLateStartDetails(teamId, clientId, remainedDate, remainedDateTo)

// Find team and customer names based on teamId and clientId for the Excel report headers
// val team = teamRepository.findById(teamId).orElse(null)
// val teams = if (team == null) listOf() else listOf(team)
// val customer = customerRepository.findById(clientId).orElse(null)
// val customers = if (customer == null) listOf() else listOf(customer)

val projectDetails = getLateStartDetails(teamId, clientId, remainedDate, remainedDateTo, type)
val workbook: Workbook = createLateStartReport( val workbook: Workbook = createLateStartReport(
teams, teams,
customers, customers,
LATE_START_REPORT, // Ensure you provide the correct path to your template LATE_START_REPORT, // Ensure you provide the correct path to your template
teamId, teamId,
clientId, clientId,
projectDetails
projectDetails,
searchedClient
) )
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
workbook.write(outputStream) workbook.write(outputStream)
@@ -1448,7 +1431,8 @@ open class ReportService(
templatePath: String, templatePath: String,
teamId: Long, teamId: Long,
clientId: Long, clientId: Long,
lateStartData: List<Map<String, Any>>
lateStartData: List<Map<String, Any>>,
searchedClient: String
): Workbook { ): Workbook {
val resource = ClassPathResource(templatePath) val resource = ClassPathResource(templatePath)
val templateInputStream = resource.inputStream val templateInputStream = resource.inputStream
@@ -1463,7 +1447,7 @@ open class ReportService(
setDateInCellC2(workbook, sheet) setDateInCellC2(workbook, sheet)


// Populate team and client information based on IDs // Populate team and client information based on IDs
setTeamAndClientIds(sheet, team, teamId, customer, clientId)
setTeamAndClientIds(sheet, team, teamId, searchedClient)


// Process late start data, and apply data and conditional formatting to the sheet // Process late start data, and apply data and conditional formatting to the sheet
setDataAndConditionalFormatting(workbook, sheet, lateStartData, evaluator) setDataAndConditionalFormatting(workbook, sheet, lateStartData, evaluator)
@@ -1505,16 +1489,16 @@ open class ReportService(
cell.cellStyle = boldCellStyle cell.cellStyle = boldCellStyle
} }


// Apply a bold, bottom-bordered, center-aligned style to header cells from A6 to J6
val styleA6ToJ6 = workbook.createCellStyle().apply {
// Apply a bold, bottom-bordered, center-aligned style to header cells from A6 to K6
val styleA6ToK6 = workbook.createCellStyle().apply {
setFont(timesNewRoman) // Use the standard bold font for consistency setFont(timesNewRoman) // Use the standard bold font for consistency
alignment = HorizontalAlignment.CENTER alignment = HorizontalAlignment.CENTER
borderBottom = BorderStyle.THIN borderBottom = BorderStyle.THIN
} }
val rowA6 = sheet.getRow(5) ?: sheet.createRow(5) val rowA6 = sheet.getRow(5) ?: sheet.createRow(5)
(0..9).forEach { colIndex ->
(0..10).forEach { colIndex ->
val cell = rowA6.getCell(colIndex) ?: rowA6.createCell(colIndex) val cell = rowA6.getCell(colIndex) ?: rowA6.createCell(colIndex)
cell.cellStyle = styleA6ToJ6
cell.cellStyle = styleA6ToK6
} }
} }


@@ -1545,32 +1529,32 @@ open class ReportService(
// Only apply conditional formatting if there is data // Only apply conditional formatting if there is data
if (lateStartData.isNotEmpty()) { if (lateStartData.isNotEmpty()) {
val sheetCF = sheet.sheetConditionalFormatting val sheetCF = sheet.sheetConditionalFormatting
val rule1 = sheetCF.createConditionalFormattingRule("J7 < 60")
val rule1 = sheetCF.createConditionalFormattingRule("K7 < 60")
val pattern1 = rule1.createPatternFormatting().apply { val pattern1 = rule1.createPatternFormatting().apply {
fillBackgroundColor = IndexedColors.RED.index fillBackgroundColor = IndexedColors.RED.index
fillPattern = PatternFormatting.SOLID_FOREGROUND fillPattern = PatternFormatting.SOLID_FOREGROUND
} }
val rule2 = sheetCF.createConditionalFormattingRule("J7 >= 60")
val rule2 = sheetCF.createConditionalFormattingRule("K7 >= 60")
val pattern2 = rule2.createPatternFormatting().apply { val pattern2 = rule2.createPatternFormatting().apply {
fillBackgroundColor = IndexedColors.YELLOW.index fillBackgroundColor = IndexedColors.YELLOW.index
fillPattern = PatternFormatting.SOLID_FOREGROUND fillPattern = PatternFormatting.SOLID_FOREGROUND
} }
val region = CellRangeAddress(6, dataRowIndex - 1, 9, 9) // Column J
val region = CellRangeAddress(6, dataRowIndex - 1, 10, 10) // Column K
sheetCF.addConditionalFormatting(arrayOf(region), arrayOf(rule1, rule2)) sheetCF.addConditionalFormatting(arrayOf(region), arrayOf(rule1, rule2))
} }
} }


// Sets team and client IDs in the sheet to manage data visibility based on the selected team and client // Sets team and client IDs in the sheet to manage data visibility based on the selected team and client
private fun setTeamAndClientIds(sheet: Sheet, team: List<Team>, teamId: Long, customer: List<Customer>, clientId: Long) {
private fun setTeamAndClientIds(sheet: Sheet, team: List<Team>, teamId: Long, searchedClient: String) {
// Insert the team name or "All" if no specific team is selected in cell C3 // Insert the team name or "All" if no specific team is selected in cell C3
val teamIdRow = sheet.getRow(2) ?: sheet.createRow(2) val teamIdRow = sheet.getRow(2) ?: sheet.createRow(2)
val teamIdCell = teamIdRow.getCell(2) ?: teamIdRow.createCell(2) val teamIdCell = teamIdRow.getCell(2) ?: teamIdRow.createCell(2)
teamIdCell.setCellValue(if (teamId == 0L) "All" else team.getOrNull(0)?.name ?: "Unknown") teamIdCell.setCellValue(if (teamId == 0L) "All" else team.getOrNull(0)?.name ?: "Unknown")


// Insert the client name or "All" if no specific client is selecred in cell C4
// Insert the client name or "All" directly in cell C4
val clientIdRow = sheet.getRow(3) ?: sheet.createRow(3) val clientIdRow = sheet.getRow(3) ?: sheet.createRow(3)
val clientIdCell = clientIdRow.getCell(2) ?: clientIdRow.createCell(2) val clientIdCell = clientIdRow.getCell(2) ?: clientIdRow.createCell(2)
clientIdCell.setCellValue(if (clientId == 0L) "All" else customer.getOrNull(0)?.name ?: "Unknown")
clientIdCell.setCellValue(searchedClient)
} }


// Populates a single row with data from a map and applies formatting and formulas // Populates a single row with data from a map and applies formatting and formulas
@@ -1612,9 +1596,12 @@ open class ReportService(
val customerNameCell = row.createCell(4) val customerNameCell = row.createCell(4)
customerNameCell.setCellValue(data["customer_name"] as String) customerNameCell.setCellValue(data["customer_name"] as String)


// // Column F: Project Plan Start Date
// Parse the project start date and apply the date format
val projectPlanStartCell = row.createCell(5)
// NEW Column F: Subsidiary Name
val subsidiaryNameCell = row.createCell(5)
subsidiaryNameCell.setCellValue(data["subsidiary_name"] as String)

// Column G: Project Plan Start Date
val projectPlanStartCell = row.createCell(6)
try { try {
val date = LocalDate.parse(data["project_plan_start"].toString(), DateTimeFormatter.ISO_LOCAL_DATE) val date = LocalDate.parse(data["project_plan_start"].toString(), DateTimeFormatter.ISO_LOCAL_DATE)
projectPlanStartCell.setCellValue(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant())) projectPlanStartCell.setCellValue(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()))
@@ -1623,17 +1610,17 @@ open class ReportService(
} }
projectPlanStartCell.cellStyle = dateCellStyle projectPlanStartCell.cellStyle = dateCellStyle


// Column G: Calculated Date Difference (days since project start from today)
val daysDifferenceCell = row.createCell(6)
daysDifferenceCell.setCellFormula("C$2-F${row.rowNum + 1}")
// Column H: Calculated Date Difference (days since project start from today)
val daysDifferenceCell = row.createCell(7)
daysDifferenceCell.setCellFormula("C$2-G${row.rowNum + 1}")
daysDifferenceCell.cellStyle = centerAlignedStyle daysDifferenceCell.cellStyle = centerAlignedStyle


// Column H: Task Group Name
val taskGroupNameCell = row.createCell(7)
// Column I: Task Group Name
val taskGroupNameCell = row.createCell(8)
taskGroupNameCell.setCellValue(data["task_group_name"] as String) taskGroupNameCell.setCellValue(data["task_group_name"] as String)


// Column I: Milestone End Date
val dateCell = row.createCell(8) // Milestone end date in column I
// Column J: Milestone End Date
val dateCell = row.createCell(9) // Milestone end date in column I
try { try {
val date = LocalDate.parse(data["milestone_end_date"].toString()) val date = LocalDate.parse(data["milestone_end_date"].toString())
dateCell.setCellValue(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant())) dateCell.setCellValue(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()))
@@ -1646,15 +1633,16 @@ open class ReportService(
val today = LocalDate.now() val today = LocalDate.now()
val endDate = LocalDate.parse(data["milestone_end_date"].toString(), DateTimeFormatter.ISO_LOCAL_DATE) val endDate = LocalDate.parse(data["milestone_end_date"].toString(), DateTimeFormatter.ISO_LOCAL_DATE)
val daysBetween = ChronoUnit.DAYS.between(today, endDate).toInt() // Calculate the difference in days val daysBetween = ChronoUnit.DAYS.between(today, endDate).toInt() // Calculate the difference in days

val daysDifferenceCellJ = row.createCell(9)
daysDifferenceCellJ.setCellValue(daysBetween.toDouble()) // Set as double for consistency
// Ensure days difference is not negative
val adjustedDaysBetween = if (daysBetween < 0) 0 else daysBetween
val daysDifferenceCellJ = row.createCell(10)
daysDifferenceCellJ.setCellValue(adjustedDaysBetween.toDouble()) // Set as double for consistency
daysDifferenceCellJ.cellStyle = centerAlignedStyle daysDifferenceCellJ.cellStyle = centerAlignedStyle
} }


// Automatically adjusts the width if all columns in the sheet to fit their content optimally. // Automatically adjusts the width if all columns in the sheet to fit their content optimally.
private fun autoSizeColumns(sheet: Sheet) { private fun autoSizeColumns(sheet: Sheet) {
for (colIndex in 0..9) { // Iterate through columns A to J
for (colIndex in 0..10) { // Iterate through columns A to K
sheet.autoSizeColumn(colIndex) // Auto-size each column based on its content sheet.autoSizeColumn(colIndex) // Auto-size each column based on its content
} }
} }
@@ -2542,33 +2530,42 @@ open class ReportService(


return outputStream.toByteArray() return outputStream.toByteArray()
} }
open fun getLateStartDetails(teamId: Long?, clientId: Long?, remainedDate: LocalDate, remainedDateTo: LocalDate): List<Map<String, Any>> {
open fun getLateStartDetails(teamId: Long?, clientId: Long?, remainedDate: LocalDate, remainedDateTo: LocalDate, type: String?): List<Map<String, Any>> {
val sql = StringBuilder(""" val sql = StringBuilder("""
SELECT
p.code AS project_code,
p.name AS project_name,
t.name AS team_name,
c.name AS customer_name,
p.planStart AS project_plan_start,
tg.name AS task_group_name,
m.endDate AS milestone_end_date
FROM
project p
LEFT JOIN team t ON p.teamLead = t.teamLead
LEFT JOIN customer c ON p.customerId = c.id
LEFT JOIN task_group tg ON tg.id = (SELECT taskGroupId FROM milestone WHERE projectId = p.id LIMIT 1)
LEFT JOIN milestone m ON m.taskGroupId = tg.id AND m.projectId = p.id
WHERE
p.status = 'Pending to Start'
AND p.planStart < CURRENT_DATE
AND m.endDate BETWEEN :remainedDate AND :remainedDateTo
SELECT
p.code AS project_code,
p.name AS project_name,
t.name AS team_name,
c.name AS customer_name,
s.name AS subsidiary_name,
p.planStart AS project_plan_start,
tg.name AS task_group_name,
m.endDate AS milestone_end_date
FROM
project p
LEFT JOIN team t ON p.teamLead = t.teamLead
LEFT JOIN customer c ON p.customerId = c.id
LEFT JOIN subsidiary s ON p.customerSubsidiaryId = s.id
LEFT JOIN task_group tg ON tg.id = (SELECT taskGroupId FROM milestone WHERE projectId = p.id LIMIT 1)
LEFT JOIN milestone m ON m.taskGroupId = tg.id AND m.projectId = p.id
WHERE
p.status = 'Pending to Start'
AND p.planStart < CURRENT_DATE
AND m.endDate BETWEEN :remainedDate AND :remainedDateTo
""".trimIndent()) """.trimIndent())


if (teamId != null && teamId > 0) { if (teamId != null && teamId > 0) {
sql.append(" AND t.id = :teamId") sql.append(" AND t.id = :teamId")
} }
// if (clientId != null && clientId > 0) {
// sql.append(" AND c.id = :clientId")
// }
if (clientId != null && clientId > 0) { if (clientId != null && clientId > 0) {
sql.append(" AND c.id = :clientId")
when (type) {
"subsidiary" -> sql.append(" AND s.id = :clientId")
"client" -> sql.append(" AND c.id = :clientId")
"All" -> {} // No action needed if type is "All"
}
} }


val args = mutableMapOf( val args = mutableMapOf(


+ 17
- 41
src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt Visa fil

@@ -4,11 +4,9 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.ffii.tsms.modules.data.entity.* import com.ffii.tsms.modules.data.entity.*
//import com.ffii.tsms.modules.data.entity.projections.FinancialStatusReportInfo //import com.ffii.tsms.modules.data.entity.projections.FinancialStatusReportInfo
import com.ffii.tsms.modules.data.entity.projections.StaffSearchInfo
import com.ffii.tsms.modules.data.service.CustomerService import com.ffii.tsms.modules.data.service.CustomerService
import com.ffii.tsms.modules.data.service.TeamService import com.ffii.tsms.modules.data.service.TeamService
import com.ffii.tsms.modules.project.entity.* import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.project.entity.projections.ProjectResourceReport
import com.ffii.tsms.modules.project.service.InvoiceService import com.ffii.tsms.modules.project.service.InvoiceService
import com.ffii.tsms.modules.report.service.ReportService import com.ffii.tsms.modules.report.service.ReportService
import com.ffii.tsms.modules.report.web.model.FinancialStatusReportRequest import com.ffii.tsms.modules.report.web.model.FinancialStatusReportRequest
@@ -19,7 +17,6 @@ import com.ffii.tsms.modules.report.web.model.LateStartReportRequest
import com.ffii.tsms.modules.project.entity.ProjectRepository import com.ffii.tsms.modules.project.entity.ProjectRepository
import com.ffii.tsms.modules.timesheet.entity.LeaveRepository import com.ffii.tsms.modules.timesheet.entity.LeaveRepository
import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository
import com.ffii.tsms.modules.timesheet.entity.projections.ProjectMonthlyHoursWithDate
import jakarta.validation.Valid import jakarta.validation.Valid
import org.springframework.core.io.ByteArrayResource import org.springframework.core.io.ByteArrayResource
import org.springframework.core.io.Resource import org.springframework.core.io.Resource
@@ -32,15 +29,11 @@ import java.io.IOException
import java.time.LocalDate import java.time.LocalDate
import java.net.URLEncoder import java.net.URLEncoder
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import org.springframework.stereotype.Controller
import org.springframework.data.jpa.repository.JpaRepository
import com.ffii.tsms.modules.project.entity.Project import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.project.service.SubsidiaryService import com.ffii.tsms.modules.project.service.SubsidiaryService
import com.ffii.tsms.modules.report.web.model.* import com.ffii.tsms.modules.report.web.model.*
import com.ffii.tsms.modules.timesheet.entity.Timesheet
import org.springframework.data.domain.Example import org.springframework.data.domain.Example
import org.springframework.data.domain.ExampleMatcher import org.springframework.data.domain.ExampleMatcher
import java.time.temporal.ChronoUnit


@RestController @RestController
@RequestMapping("/reports") @RequestMapping("/reports")
@@ -160,6 +153,7 @@ class ReportController(
val args: MutableMap<String, Any> = mutableMapOf( val args: MutableMap<String, Any> = mutableMapOf(
"status" to request.status, "status" to request.status,
"lowerLimit" to lowerLimit "lowerLimit" to lowerLimit

) )
if (request.teamId != null) { if (request.teamId != null) {
args["teamId"] = request.teamId args["teamId"] = request.teamId
@@ -222,9 +216,24 @@ class ReportController(
val customers = if (customer == null) customerRepository.findAll() else listOf(customer) val customers = if (customer == null) customerRepository.findAll() else listOf(customer)
val projects = projectRepository.findAllByPlanStartLessThanEqualAndPlanEndGreaterThanEqual(request.remainedDate, request.remainedDateTo) val projects = projectRepository.findAllByPlanStartLessThanEqualAndPlanEndGreaterThanEqual(request.remainedDate, request.remainedDateTo)


println(request.clientId)
println(request.type)

val client = if (request.clientId.equals(0) || request.type != "client") null else customerRepository.findById(request.clientId.toLong()).orElse(null)
val subsidiary = if (request.clientId.equals(0) || request.type != "subsidiary") null else subsidiaryRepository.findById(request.clientId.toLong()).orElse(null)
val searchedClient = if (client != null) { // For display use
client.code + " - " + client.name
} else if (subsidiary != null) {
subsidiary.code + " - " + subsidiary.name
} else {
"All"
}
println(searchedClient)

val reportResult: ByteArray = try { val reportResult: ByteArray = try {
excelReportService.generateLateStartReport(request.teamId, request.clientId, excelReportService.generateLateStartReport(request.teamId, request.clientId,
request.remainedDate, request.remainedDateTo,teams,customers)
request.remainedDate, request.remainedDateTo,teams,customers, searchedClient,request.type
)
} catch (e: Exception) { } catch (e: Exception) {
throw Exception("Error generating report", e) throw Exception("Error generating report", e)
} }
@@ -245,39 +254,6 @@ class ReportController(
.body(ByteArrayResource(reportResult)) .body(ByteArrayResource(reportResult))
} }


//fun downloadLateStartReport(@RequestBody @Valid request: LateStartReportRequest): ResponseEntity<ByteArrayResource> {
// val team = teamRepository.findById(request.teamId).orElseThrow {
// Exception("Team not found with ID: ${request.teamId}")
// }
//
// val customer = customerRepository.findByName(request.customer).orElseThrow()
// // ?: throw Exception("Customer not found with name: ${request.customer}")
//
// val projects = projectRepository.findAllByPlanStartLessThanEqualAndPlanEndGreaterThanEqual(request.remainedDateFrom, request.remainedDateTo)
// if (projects.isEmpty()) {
// throw Exception("No projects found for the given date: ${request.reportDate}")
// }
//
// val reportResult: ByteArray = try {
// excelReportService.generateLateStartReport(team, customer, projects)
// } catch (e: Exception) {
// throw Exception("Error generating report", e)
// }
//
// val headers = HttpHeaders()
// val formattedDate = request.reportDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"))
// val filename = "Late_Start_Report_$formattedDate.xlsx"
// headers.add("Content-Disposition", "attachment; filename=${URLEncoder.encode(filename, "UTF-8")}")
//
// println("Generated filename for download: $filename")
//
// return ResponseEntity.ok()
// .headers(headers)
// .contentLength(reportResult.size.toLong())
// .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
// .body(ByteArrayResource(reportResult))
// }

// For API TESTING // For API TESTING
@GetMapping("/financialReport/{id}") @GetMapping("/financialReport/{id}")
fun getFinancialReport(@PathVariable id: Long): List<Map<String, Any>> { fun getFinancialReport(@PathVariable id: Long): List<Map<String, Any>> {


+ 1
- 0
src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt Visa fil

@@ -42,6 +42,7 @@ data class LateStartReportRequest (
val clientId: Long, val clientId: Long,
val remainedDate: LocalDate, val remainedDate: LocalDate,
val remainedDateTo: LocalDate, val remainedDateTo: LocalDate,
val type: String,
) )
data class ProjectResourceOverconsumptionReport ( data class ProjectResourceOverconsumptionReport (
val teamId: Long?, val teamId: Long?,


Laddar…
Avbryt
Spara