diff --git a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt index 20f497a..42c9754 100644 --- a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt +++ b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt @@ -20,6 +20,7 @@ import org.apache.poi.ss.util.CellAddress import org.apache.poi.ss.util.CellRangeAddress import org.apache.poi.ss.util.CellUtil import org.apache.poi.xssf.usermodel.XSSFWorkbook +import org.hibernate.jdbc.Work import org.springframework.core.io.ClassPathResource import org.springframework.stereotype.Service import java.io.ByteArrayOutputStream @@ -50,6 +51,8 @@ open class ReportService( private val SALART_LIST_TEMPLATE = "templates/report/Salary Template.xlsx" private val LATE_START_REPORT = "templates/report/AR01_Late Start Report v01.xlsx" private val RESOURCE_OVERCONSUMPTION_REPORT = "templates/report/AR03_Resource Overconsumption.xlsx" + private val COMPLETE_PROJECT_OUTSTANDING_RECEIVABLE = "templates/report/AR06_Project Completion Report with Outstanding Accounts Receivable v02.xlsx" + private val COMPLETION_PROJECT = "templates/report/AR05_Project Completion Report.xlsx" // ==============================|| GENERATE REPORT ||============================== // @@ -174,6 +177,28 @@ open class ReportService( return outputStream.toByteArray() } + @Throws(IOException::class) + fun generateProjectCompletionReport( + args: MutableMap, + result: List> + ): ByteArray { + var REPORT_PATH: String = COMPLETE_PROJECT_OUTSTANDING_RECEIVABLE + if (args.get("outstanding") as Boolean == false) { + REPORT_PATH = COMPLETION_PROJECT + } + // Generate the Excel report with query results + val workbook: Workbook = createProjectCompletionReport( + args, + result, + REPORT_PATH + ) + // Write the workbook to a ByteArrayOutputStream + val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() + workbook.write(outputStream) + workbook.close() + + return outputStream.toByteArray() + } @Throws(IOException::class) fun exportSalaryList(salarys: List): ByteArray { @@ -1061,6 +1086,49 @@ open class ReportService( return workbook } + private fun createProjectCompletionReport( + args: MutableMap, + result: List>, + templatePath: String + ): Workbook { + val resource = ClassPathResource(templatePath) + val templateInputStream = resource.inputStream + val workbook: Workbook = XSSFWorkbook(templateInputStream) + + val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") + val monthStyle = workbook.createDataFormat().getFormat("MMM YYYY") + val dateStyle = workbook.createDataFormat().getFormat("dd/mm/yyyy") + + val sheet: Sheet = workbook.getSheetAt(0) + + var rowIndex = 1 // Assuming the location is in (1,2), which is the report date field + var columnIndex = 2 + var tempRow = sheet.getRow(rowIndex) + var tempCell = tempRow.getCell(columnIndex) + tempCell.setCellValue(FORMATTED_TODAY) + + rowIndex = 2 + tempCell = sheet.getRow(rowIndex).getCell(columnIndex) + tempCell.setCellValue("${args.get("startDate").toString()} to ${args.get("endDate").toString()}") + + rowIndex = 5 + columnIndex = 0 + result.forEachIndexed { index, obj -> + tempCell = sheet.getRow(rowIndex).createCell(columnIndex) + tempCell.setCellValue((index + 1).toDouble()) + val keys = obj.keys.toList() + keys.forEachIndexed { keyIndex, key -> + tempCell = sheet.getRow(rowIndex).getCell(columnIndex + keyIndex + 1) ?: sheet.getRow(rowIndex).createCell(columnIndex + keyIndex + 1) + when (obj[key]) { + is Double -> tempCell.setCellValue(obj[key] as Double) + else -> tempCell.setCellValue(obj[key] as String ) + } + } + rowIndex++ + } + return workbook + } + private fun createProjectResourceOverconsumptionReport( team: String, @@ -1273,6 +1341,54 @@ open class ReportService( ) return jdbcDao.queryForList(sql.toString(), args) } + open fun getProjectCompletionReport(args: Map): List> { + val sql = StringBuilder("select" + + " result.code, " + + " result.name, " + + " result.teamCode, " + + " result.custCode, " ) + if (args.get("outstanding") as Boolean) { + sql.append(" result.totalBudget - COALESCE(i.issueAmount , 0) + COALESCE(i.issueAmount, 0) - COALESCE(i.paidAmount, 0) as `Receivable Remained`, ") + } + sql.append( + " DATE_FORMAT(result.actualEnd, '%d/%m/%Y') as actualEnd " + + " from ( " + + " SELECT " + + " pt.project_id, " + + " min(p.code) as code, " + + " min(p.name) as name, " + + " min(t.code) as teamCode, " + + " min(c.code) as custCode, " + + " min(p.actualEnd) as actualEnd, " + + " sum(COALESCE(tns.totalConsumed*sal.hourlyRate, 0)) as totalBudget " + + " FROM ( " + + " SELECT " + + " t.staffId, " + + " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) as totalConsumed, " + + " t.projectTaskId AS taskId " + + " FROM timesheet t " + + " LEFT JOIN staff s ON t.staffId = s.id " + + " LEFT JOIN team te on s.teamId = te.id " + + " GROUP BY t.staffId, t.projectTaskId " + + " order by t.staffId " + + " ) AS tns " + + " inner join project_task pt ON tns.taskId = pt.id " + + " left JOIN staff s ON tns.staffId = s.id " + + " left join salary sal on s.salaryId = sal.salaryPoint " + + " left JOIN team t ON s.teamId = t.id " + + " left join project p on p.id = pt.project_id " + + " left join customer c on c.id = p.customerId " + + " where p.deleted = false " + + " and p.status = 'Completed' " + + " and p.actualEnd BETWEEN :startDate and :endDate " + + " group by pt.project_id " + + " ) as result " + + " left join invoice i on result.code = i.projectCode " + + " order by result.actualEnd " + ) + + return jdbcDao.queryForList(sql.toString(), args) + } open fun getProjectResourceOverconsumptionReport(args: Map): List> { val sql = StringBuilder("WITH teamNormalConsumed AS (" diff --git a/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt b/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt index 8c8e045..b6be334 100644 --- a/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt +++ b/src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt @@ -141,6 +141,30 @@ class ReportController( .body(ByteArrayResource(reportResult)) } + @PostMapping("/ProjectCompletionReportwithOutstandingAccountsReceivable") + @Throws(ServletRequestBindingException::class, IOException::class) + fun ProjectCompletionReport(@RequestBody @Valid request: ProjectCompletionReport): ResponseEntity { + val args: MutableMap = mutableMapOf( + "startDate" to request.startDate, + "endDate" to request.endDate, + "outstanding" to request.outstanding + ) + val result = excelReportService.getProjectCompletionReport(args); + val reportResult: ByteArray = excelReportService.generateProjectCompletionReport(args, result) + // val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + if (request.outstanding) { + return ResponseEntity.ok() + // .contentType(mediaType) + .header("filename", "Project Completion Report with Outstanding Accounts Receivable - " + " - " + LocalDate.now() + ".xlsx") + .body(ByteArrayResource(reportResult)) + } + return ResponseEntity.ok() +// .contentType(mediaType) + .header("filename", "Project Completion Report - " + " - " + LocalDate.now() + ".xlsx") + .body(ByteArrayResource(reportResult)) + + } + @GetMapping("/test/{id}") fun test(@PathVariable id: Long): List { val project = projectRepository.findById(id).orElseThrow() diff --git a/src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt b/src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt index b5797e3..70671a7 100644 --- a/src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt +++ b/src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt @@ -36,4 +36,9 @@ data class ProjectResourceOverconsumptionReport ( val custId: Long?, val status: String, val lowerLimit: Double +) +data class ProjectCompletionReport ( + val startDate: LocalDate, + val endDate: LocalDate, + val outstanding: Boolean ) \ No newline at end of file diff --git a/src/main/resources/templates/report/AR05_Project Completion Report.xlsx b/src/main/resources/templates/report/AR05_Project Completion Report.xlsx index d5bd3cc..126f10c 100644 Binary files a/src/main/resources/templates/report/AR05_Project Completion Report.xlsx and b/src/main/resources/templates/report/AR05_Project Completion Report.xlsx differ diff --git a/src/main/resources/templates/report/AR06_Project Completion Report with Outstanding Accounts Receivable v02.xlsx b/src/main/resources/templates/report/AR06_Project Completion Report with Outstanding Accounts Receivable v02.xlsx index 25a4a74..db5ea39 100644 Binary files a/src/main/resources/templates/report/AR06_Project Completion Report with Outstanding Accounts Receivable v02.xlsx and b/src/main/resources/templates/report/AR06_Project Completion Report with Outstanding Accounts Receivable v02.xlsx differ