diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt index cdedfc4..940f2d2 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt @@ -12,4 +12,6 @@ interface InvoiceRepository : AbstractRepository { fun findInvoiceInfoByPaidAmountIsNotNull(): List fun findByInvoiceNo(invoiceNo: String): Invoice + + fun findAllByProjectCodeAndPaidAmountIsNotNull(projectCode: String): List } \ No newline at end of file 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 82cf016..406c52e 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 @@ -435,7 +435,8 @@ open class ReportService( val uninvoiceCell = row.createCell(12) uninvoiceCell.apply { cellFormula = - " IF(I${rowNum}<=J${rowNum}, I${rowNum}-L${rowNum}, IF(AND(I${rowNum}>J${rowNum}, J${rowNum}J${rowNum}, J${rowNum}>=L${rowNum}), J${rowNum}-L${rowNum}, 0))) " + " IF(I${rowNum}-L${rowNum}<0, 0, I${rowNum}-L${rowNum})" +// " IF(I${rowNum}<=J${rowNum}, I${rowNum}-L${rowNum}, IF(AND(I${rowNum}>J${rowNum}, J${rowNum}J${rowNum}, J${rowNum}>=L${rowNum}), J${rowNum}-L${rowNum}, 0))) " cellStyle.dataFormat = accountingStyle } @@ -1080,6 +1081,13 @@ open class ReportService( val boldFont = workbook.createFont() boldFont.bold = true boldStyle.setFont(boldFont) + + val projectsStyle = workbook.createCellStyle() + val projectsFont = workbook.createFont() + projectsFont.bold = true + projectsFont.fontName = "Times New Roman" + projectsStyle.setFont(projectsFont) + val daysOfMonth = (1..month.lengthOfMonth()).map { day -> val date = month.withDayOfMonth(day) val formattedDate = date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) @@ -1228,7 +1236,7 @@ open class ReportService( projectList.forEachIndexed { index, title -> tempCell = sheet.getRow(7).createCell(columnIndex + index) tempCell.setCellValue(title) - tempCell.cellStyle = boldStyle + tempCell.cellStyle = projectsStyle CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) CellUtil.setVerticalAlignment(tempCell, VerticalAlignment.CENTER) CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) @@ -1271,7 +1279,7 @@ open class ReportService( ///////////////////////////////////////////////////////// Leave Hours title //////////////////////////////////////////////////////////////////// tempCell = sheet.getRow(rowIndex).createCell(columnIndex) tempCell.setCellValue("Leave Hours") - tempCell.cellStyle = boldStyle + tempCell.cellStyle = projectsStyle CellUtil.setVerticalAlignment(tempCell, VerticalAlignment.CENTER) CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) @@ -1279,8 +1287,10 @@ open class ReportService( columnIndex += 1 tempCell = sheet.getRow(rowIndex).createCell(columnIndex) tempCell.setCellValue("Daily Manhour Spent\n(Excluding Leave Hours)") - tempCell.cellStyle = boldStyle - CellUtil.setAlignment(tempCell, HorizontalAlignment.LEFT) + tempCell.cellStyle = projectsStyle +// CellUtil.setAlignment(tempCell, HorizontalAlignment.LEFT) + CellUtil.setVerticalAlignment(tempCell, VerticalAlignment.CENTER) + CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER) CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom) sheet.addMergedRegion(CellRangeAddress(6, 6, 2, columnIndex)) @@ -1375,7 +1385,7 @@ open class ReportService( rowIndex = 5 columnIndex = 0 - generalCreateReportIndexed(sheet, result, rowIndex, columnIndex) + generalCreateReportIndexed(sheet, result.distinct(), rowIndex, columnIndex) return workbook } @@ -1825,12 +1835,12 @@ open class ReportService( + " (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) as budgetConsumptionRate, " + " (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) as manhourConsumptionRate, " + " CASE " - + " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit and (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) <= 1 " - + " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit and (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) <= 1 " - + " then 'Potential Overconsumption' " + " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= 1 " + " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= 1 " + " then 'Overconsumption' " + + " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit and (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) <= 1 " + + " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit and (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) <= 1 " + + " then 'Potential Overconsumption' " + " else 'Within Budget' " + " END as status " + " FROM project p " @@ -1884,6 +1894,15 @@ open class ReportService( + " left join salary s2 on s.salaryId = s2.salaryPoint" + " left join team t2 on t2.id = s.teamId" + " )," + + " cte_timesheet_sum as (" + + " Select p.code, sum((IFNULL(t.normalConsumed, 0) + IFNULL(t.otConsumed , 0)) * s2.hourlyRate) as sumManhourExpenditure" + + " from timesheet t" + + " left join project_task pt on pt.id = t.projectTaskId" + + " left join project p ON p.id = pt.project_id" + + " left join staff s on s.id = t.staffId" + + " left join salary s2 on s.salaryId = s2.salaryPoint" + + " group by p.code" + + " )," + " cte_invoice as (" + " select p.code, sum(i.issueAmount) as sumIssuedAmount , sum(i.paidAmount) as sumPaidAmount" + " from invoice i" @@ -1893,10 +1912,11 @@ open class ReportService( + " select p.code, p.description, c.name as client, IFNULL(s2.name, \"N/A\") as subsidiary, concat(t.code, \" - \", t.name) as teamLead," + " IFNULL(cte_ts.normalConsumed, 0) as normalConsumed, IFNULL(cte_ts.otConsumed, 0) as otConsumed, DATE_FORMAT(cte_ts.recordDate, '%Y-%m') as recordDate, " + " IFNULL(cte_ts.salaryPoint, 0) as salaryPoint, " - + " IFNULL(cte_ts.hourlyRate, 0) as hourlyRate, IFNULL(cte_i.sumIssuedAmount, 0) as sumIssuedAmount, IFNULL(cte_i.sumPaidAmount, 0) as sumPaidAmount," + + " IFNULL(cte_ts.hourlyRate, 0) as hourlyRate, IFNULL(cte_i.sumIssuedAmount, 0) as sumIssuedAmount, IFNULL(cte_i.sumPaidAmount, 0) as sumPaidAmount, IFNULL(cte_tss.sumManhourExpenditure, 0) as sumManhourExpenditure," + " s.name, s.staffId, g.code as gradeCode, g.name as gradeName, t2.code as teamCode, t2.name as teamName" + " from project p" + " left join cte_timesheet cte_ts on p.code = cte_ts.code" + + " left join cte_timesheet_sum cte_tss on p.code = cte_tss.code" + " left join customer c on c.id = p.customerId" + " left join tsmsdb.team t on t.teamLead = p.teamLead" + " left join cte_invoice cte_i on cte_i.code = p.code" @@ -1959,6 +1979,9 @@ open class ReportService( if (info["code"] == item["code"] && "subsidiary" !in info) { info["subsidiary"] = item.getValue("subsidiary") } + if (info["manhourExpenditure"] != item.getValue("sumManhourExpenditure")) { + info["manhourExpenditure"] = item.getValue("sumManhourExpenditure") + } if (info["description"] != item.getValue("description")) { info["description"] = item.getValue("description") } @@ -2319,7 +2342,8 @@ open class ReportService( } val totalManhourECell = totalManhourERow.getCell(1) ?: totalManhourERow.createCell(1) totalManhourECell.apply { - cellFormula = "SUM(${lastColumnIndex}${startRow}:${lastColumnIndex}${startRow + staffInfoList.size})" +// cellFormula = "SUM(${lastColumnIndex}${startRow}:${lastColumnIndex}${startRow + staffInfoList.size})" + setCellValue(info.getValue("manhourExpenditure") as Double) cellStyle.dataFormat = accountingStyle } CellUtil.setCellStyleProperty(totalManhourETitleCell, "borderBottom", BorderStyle.THIN) 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 f84307e..1c312f0 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 @@ -34,6 +34,8 @@ import java.time.format.DateTimeFormatter import com.ffii.tsms.modules.project.entity.Project import com.ffii.tsms.modules.project.service.SubsidiaryService import com.ffii.tsms.modules.report.web.model.* +import org.apache.commons.logging.Log +import org.apache.commons.logging.LogFactory import org.springframework.data.domain.Example import org.springframework.data.domain.ExampleMatcher @@ -58,6 +60,7 @@ class ReportController( private val subsidiaryRepository: SubsidiaryRepository ) { + private val logger: Log = LogFactory.getLog(javaClass) @PostMapping("/fetchProjectsFinancialStatusReport") @Throws(ServletRequestBindingException::class, IOException::class) fun getFinancialStatusReport(@RequestBody @Valid request: FinancialStatusReportRequest): ResponseEntity { @@ -76,7 +79,8 @@ class ReportController( val project = projectRepository.findById(request.projectId).orElseThrow() val projectTasks = projectTaskRepository.findAllByProject(project) - val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project) +// val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project) + val invoices = invoiceRepository.findAllByProjectCodeAndPaidAmountIsNotNull(project.code!!) val timesheets = timesheetRepository.findAllByProjectTaskIn(projectTasks) val reportResult: ByteArray = excelReportService.generateProjectCashFlowReport(project, invoices, timesheets, request.dateType) diff --git a/src/main/resources/templates/report/AR04_Cost and Expense Report v02.xlsx b/src/main/resources/templates/report/AR04_Cost and Expense Report v02.xlsx index 8f971d5..6dea4f8 100644 Binary files a/src/main/resources/templates/report/AR04_Cost and Expense Report v02.xlsx and b/src/main/resources/templates/report/AR04_Cost and Expense Report v02.xlsx differ diff --git a/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx b/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx index c471a6a..29dbffd 100644 Binary files a/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx and b/src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx differ