diff --git a/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt b/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt index 98b916c..f1a2697 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt @@ -5,6 +5,8 @@ import com.ffii.core.utils.CheckingUtils import com.ffii.tsms.modules.data.entity.CustomerRepository import com.ffii.tsms.modules.data.entity.CustomerTypeRepository import com.ffii.tsms.modules.data.entity.TeamRepository +import com.ffii.tsms.modules.data.web.models.ExportFinancialSummaryV2ByClientRequest +import com.ffii.tsms.modules.data.web.models.ExportFinancialSummaryV2ByProjectRequest import com.ffii.tsms.modules.data.web.models.FinancialSummaryByClient import com.ffii.tsms.modules.data.web.models.FinancialSummaryByProject import com.ffii.tsms.modules.project.entity.* @@ -3405,7 +3407,7 @@ open class DashboardService( } createCell(4).apply { - cellFormula = "IFERROR(IF(K${rowIndex}=0, 0, K${rowIndex}/J${rowIndex}),0)" + cellFormula = "IFERROR(IF(M${rowIndex}=0, 0, M${rowIndex}/J${rowIndex}),0)" cellStyle.apply { setFont(normalFont) dataFormat = accountingStyle @@ -3509,6 +3511,195 @@ open class DashboardService( return workbook } + @Throws(IOException::class) + fun exportFinancialSummaryV2ByClientExcel( + financialSummaryByClients: List, + ): ByteArray { + // Generate the Excel report with query results + val workbook: Workbook = + createFinancialSummaryV2ByClientExcel(financialSummaryByClients, FINANCIAL_SUMMARY_FOR_CLIENT) + + // Write the workbook to a ByteArrayOutputStream + val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() + workbook.write(outputStream) + workbook.close() + + return outputStream.toByteArray() + } + + @Throws(IOException::class) + private fun createFinancialSummaryV2ByClientExcel( + financialSummaryByClients: List, + templatePath: String, + ): Workbook { + // please create a new function for each report template + val resource = ClassPathResource(templatePath) + val templateInputStream = resource.inputStream + val workbook: Workbook = XSSFWorkbook(templateInputStream) + + val sheet: Sheet = workbook.getSheetAt(0) + + // accounting style + comma style + val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") + + // normal font + val normalFont = workbook.createFont().apply { + fontName = "Times New Roman" + } + +// val normalFontStyle = workbook.createCellStyle().apply { +// setFont(normalFont) +// } + + var rowIndex = 1 // Assuming the location is in (1,2), which is the report date field + var columnIndex = 1 + sheet.getRow(rowIndex).createCell(columnIndex).apply { + setCellValue(FORMATTED_TODAY) + } + + rowIndex = 4 + financialSummaryByClients.forEach { financialSummaryByClient: ExportFinancialSummaryV2ByClientRequest -> + sheet.createRow(rowIndex++).apply { + createCell(0).apply { + setCellValue(financialSummaryByClient.customerCode) + cellStyle.apply { + setFont(normalFont) + } + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } + + createCell(1).apply { + setCellValue(financialSummaryByClient.customerName) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } + + createCell(2).apply { + setCellValue(financialSummaryByClient.sumOfProjects) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } + + createCell(3).apply { + cellFormula = "IF(E${rowIndex}>=1,\"Positive\",\"Negative\")" + cellStyle.apply { + setFont(normalFont) + } + CellUtil.setAlignment(this, HorizontalAlignment.CENTER) + } + + createCell(4).apply { + cellFormula = "IFERROR(IF(M${rowIndex}=0, 0, M${rowIndex}/J${rowIndex}),0)" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(5).apply { + cellFormula = "IF(G${rowIndex}>=1,\"Positive\",\"Negative\")" + cellStyle.apply { + setFont(normalFont) + } + CellUtil.setAlignment(this, HorizontalAlignment.CENTER) + } + + createCell(6).apply { + cellFormula = "IFERROR(H${rowIndex}/J${rowIndex},0)" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(7).apply { + setCellValue(financialSummaryByClient.totalFee) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(8).apply { +// cellFormula = "H${rowIndex}*80%" + setCellValue(financialSummaryByClient.totalBudget) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(9).apply { +// setCellValue(financialSummaryByClient.cumulativeExpenditure) + cellFormula = "IFERROR(K${rowIndex}+L${rowIndex},0)" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + + createCell(10).apply { + setCellValue(financialSummaryByClient.manhourExpense) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(11).apply { + setCellValue(financialSummaryByClient.projectExpense) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(12).apply { + setCellValue(financialSummaryByClient.invoicedAmount) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(13).apply { + cellFormula = "IF(H${rowIndex}-M${rowIndex}<0,0,H${rowIndex}-M${rowIndex})" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(14).apply { + setCellValue(financialSummaryByClient.paidAmount) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + } + } + + return workbook + } + @Throws(IOException::class) fun exportFinancialSummaryByProjectExcel( financialSummaryByProjects: List, @@ -3524,6 +3715,23 @@ open class DashboardService( return outputStream.toByteArray() } + + @Throws(IOException::class) + fun exportFinancialSummaryV2ByProjectExcel( + financialSummaryByProjects: List, + ): ByteArray { + // Generate the Excel report with query results + val workbook: Workbook = + createFinancialSummaryV2ByProjectExcel(financialSummaryByProjects, FINANCIAL_SUMMARY_FOR_PROJECT) + + // Write the workbook to a ByteArrayOutputStream + val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() + workbook.write(outputStream) + workbook.close() + + return outputStream.toByteArray() + } + open fun testing3( projectId: Long, startDate: LocalDate?, @@ -3842,7 +4050,7 @@ open class DashboardService( } createCell(5).apply { - cellFormula = "IFERROR(IF(L${rowIndex}=0, 0,L${rowIndex}/K${rowIndex}),0)" + cellFormula = "IFERROR(IF(N${rowIndex}=0, 0,N${rowIndex}/K${rowIndex}),0)" cellStyle.apply { setFont(normalFont) dataFormat = accountingStyle @@ -3944,6 +4152,187 @@ open class DashboardService( return workbook } + + @Throws(IOException::class) + private fun createFinancialSummaryV2ByProjectExcel( + financialSummaryByProjects: List, + templatePath: String, + ): Workbook { + // please create a new function for each report template + val resource = ClassPathResource(templatePath) + val templateInputStream = resource.inputStream + val workbook: Workbook = XSSFWorkbook(templateInputStream) + + val sheet: Sheet = workbook.getSheetAt(0) + + // accounting style + comma style + val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)") + + // normal font + val normalFont = workbook.createFont().apply { + fontName = "Times New Roman" + } + +// val normalFontStyle = workbook.createCellStyle().apply { +// setFont(normalFont) +// } + + var rowIndex = 1 // Assuming the location is in (1,2), which is the report date field + var columnIndex = 1 + sheet.getRow(rowIndex).createCell(columnIndex).apply { + setCellValue(FORMATTED_TODAY) + } + + rowIndex = 4 + financialSummaryByProjects.forEach { financialSummaryByProject: ExportFinancialSummaryV2ByProjectRequest -> + sheet.createRow(rowIndex++).apply { + createCell(0).apply { + setCellValue(financialSummaryByProject.projectCode) + cellStyle.apply { + setFont(normalFont) + } + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } + + createCell(1).apply { + setCellValue(financialSummaryByProject.projectName) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } + + createCell(2).apply { + setCellValue(financialSummaryByProject.customerName) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } + + createCell(3).apply { + setCellValue(financialSummaryByProject.subsidiaryName ?: "N/A") + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } + + createCell(4).apply { + cellFormula = "IF(F${rowIndex}>=1,\"Positive\",\"Negative\")" + cellStyle.apply { + setFont(normalFont) + } + CellUtil.setAlignment(this, HorizontalAlignment.CENTER) + } + + createCell(5).apply { + cellFormula = "IFERROR(IF(N${rowIndex}=0, 0,N${rowIndex}/K${rowIndex}),0)" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(6).apply { + cellFormula = "IF(H${rowIndex}>=1,\"Positive\",\"Negative\")" + cellStyle.apply { + setFont(normalFont) + } + CellUtil.setAlignment(this, HorizontalAlignment.CENTER) + } + + createCell(7).apply { + cellFormula = "IFERROR(I${rowIndex}/K${rowIndex},0)" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(8).apply { + setCellValue(financialSummaryByProject.totalFee) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(9).apply { +// cellFormula = "I${rowIndex}*80%" + setCellValue(financialSummaryByProject.totalBudget) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(10).apply { +// setCellValue(financialSummaryByProject.cumulativeExpenditure) + cellFormula = "IFERROR(L${rowIndex}+M${rowIndex},0)" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(11).apply { + setCellValue(financialSummaryByProject.manhourExpense) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(12).apply { + setCellValue(financialSummaryByProject.projectExpense) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(13).apply { + setCellValue(financialSummaryByProject.invoicedAmount) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(14).apply { + cellFormula = "IF(I${rowIndex}-N${rowIndex}<0,0,I${rowIndex}-N${rowIndex})" + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + + createCell(15).apply { + setCellValue(financialSummaryByProject.paidAmount) + cellStyle.apply { + setFont(normalFont) + dataFormat = accountingStyle + } + CellUtil.setAlignment(this, HorizontalAlignment.RIGHT) + } + } + } + + return workbook + } } diff --git a/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt b/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt index 468482c..f1e4840 100644 --- a/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt +++ b/src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt @@ -19,6 +19,8 @@ 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.ExportFinancialSummaryV2ByClientRequest +import com.ffii.tsms.modules.data.web.models.ExportFinancialSummaryV2ByProjectRequest import com.ffii.tsms.modules.project.entity.ProjectRepository import org.springframework.core.io.ByteArrayResource import org.springframework.core.io.Resource @@ -511,6 +513,14 @@ class DashboardController( .body(ByteArrayResource(reportResult)) } + @PostMapping("/exportFinancialSummaryV2ByClientExcel") + fun exportFinancialSummaryV2ByClientExcel(@Valid @RequestBody request: List): ResponseEntity { + val reportResult: ByteArray = dashboardService.exportFinancialSummaryV2ByClientExcel(request) + return ResponseEntity.ok() + .header("filename", "Financial Summary for Client - " + LocalDate.now() + ".xlsx") + .body(ByteArrayResource(reportResult)) + } + @PostMapping("/exportFinancialSummaryByProjectExcel") fun exportFinancialSummaryByProjectExcel(@Valid @RequestBody request: ExportFinancialSummaryByProjectExcelRequest): ResponseEntity { val reportResult: ByteArray = dashboardService.exportFinancialSummaryByProjectExcel(request.financialSummaryByProjects) @@ -518,4 +528,12 @@ class DashboardController( .header("filename", "Financial Summary for Project - " + LocalDate.now() + ".xlsx") .body(ByteArrayResource(reportResult)) } + + @PostMapping("/exportFinancialSummaryV2ByProjectExcel") + fun exportFinancialSummaryV2ByProjectExcel(@Valid @RequestBody request: List): ResponseEntity { + val reportResult: ByteArray = dashboardService.exportFinancialSummaryV2ByProjectExcel(request) + return ResponseEntity.ok() + .header("filename", "Financial Summary for Project - " + LocalDate.now() + ".xlsx") + .body(ByteArrayResource(reportResult)) + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/data/web/models/ExportDashboardExcelRequest.kt b/src/main/java/com/ffii/tsms/modules/data/web/models/ExportDashboardExcelRequest.kt index ba44282..bbb0dc8 100644 --- a/src/main/java/com/ffii/tsms/modules/data/web/models/ExportDashboardExcelRequest.kt +++ b/src/main/java/com/ffii/tsms/modules/data/web/models/ExportDashboardExcelRequest.kt @@ -41,4 +41,31 @@ data class FinancialSummaryByProject ( data class ExportFinancialSummaryByProjectExcelRequest ( val financialSummaryByProjects: List +) + +data class ExportFinancialSummaryV2ByClientRequest ( + val customerCode: String, + val customerName: String, + val sumOfProjects: Double, + val totalFee: Double, + val totalBudget: Double, +// val cumulativeExpenditure: Double, + val manhourExpense: Double, + val projectExpense: Double, + val invoicedAmount: Double, + val paidAmount: Double, +) + +data class ExportFinancialSummaryV2ByProjectRequest ( + val projectCode: String, + val projectName: String, + val customerName: String, + val subsidiaryName: String?, + val totalFee: Double, + val totalBudget: Double, +// val cumulativeExpenditure: Double, + val manhourExpense: Double, + val projectExpense: Double, + val invoicedAmount: Double, + val paidAmount: Double, ) \ No newline at end of file