1. CashReport - filter deleted Invoice 2. Invoice - add delete and filter deleted Invoicetags/Baseline_30082024_BACKEND_UAT
| @@ -16,5 +16,5 @@ interface InvoiceRepository : AbstractRepository<Invoice, Long> { | |||||
| fun findByInvoiceNo(invoiceNo: String): Invoice | fun findByInvoiceNo(invoiceNo: String): Invoice | ||||
| fun findAllByProjectCodeAndPaidAmountIsNotNull(projectCode: String): List<Invoice> | |||||
| fun findAllByProjectCodeAndPaidAmountIsNotNullAndDeletedFalse(projectCode: String): List<Invoice> | |||||
| } | } | ||||
| @@ -334,14 +334,15 @@ open class InvoiceService( | |||||
| open fun allInvoiceV3(): List<Map<String, Any>>{ | open fun allInvoiceV3(): List<Map<String, Any>>{ | ||||
| val sql = StringBuilder( | val sql = StringBuilder( | ||||
| "select i.id, i.invoiceNo, i.projectCode, " + | |||||
| "p.name as projectName, t.code as team, i.invoiceDate, " + | |||||
| " select i.id, i.invoiceNo, i.projectCode, " + | |||||
| " p.name as projectName, t.code as team, i.invoiceDate, " + | |||||
| " concat(t.code, ' - ', t.name) as teamCodeName, " + | " concat(t.code, ' - ', t.name) as teamCodeName, " + | ||||
| "i.receiptDate, i.issueAmount , i.paidAmount " + | |||||
| "from invoice i " + | |||||
| "left join project p on i.projectCode = p.code " + | |||||
| "left join team t on t.id = p.teamLead " + | |||||
| "order by i.invoiceDate " | |||||
| " i.receiptDate, i.issueAmount , i.paidAmount " + | |||||
| " from invoice i " + | |||||
| " left join project p on i.projectCode = p.code " + | |||||
| " left join team t on t.id = p.teamLead " + | |||||
| " where i.deleted = false " + | |||||
| " order by i.invoiceDate " | |||||
| ) | ) | ||||
| return jdbcDao.queryForList(sql.toString()); | return jdbcDao.queryForList(sql.toString()); | ||||
| } | } | ||||
| @@ -721,4 +722,10 @@ open class InvoiceService( | |||||
| } | } | ||||
| } | } | ||||
| open fun markDeleted(id: Long) { | |||||
| invoiceRepository.save(invoiceRepository.findById(id).orElseThrow().apply { | |||||
| deleted = true | |||||
| }) | |||||
| } | |||||
| } | } | ||||
| @@ -15,14 +15,9 @@ import net.sf.jasperreports.engine.JasperExportManager | |||||
| import net.sf.jasperreports.engine.JasperPrint | import net.sf.jasperreports.engine.JasperPrint | ||||
| import org.apache.poi.ss.usermodel.Workbook | import org.apache.poi.ss.usermodel.Workbook | ||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook | import org.apache.poi.xssf.usermodel.XSSFWorkbook | ||||
| import org.springframework.http.HttpStatus | |||||
| import org.springframework.http.ResponseEntity | import org.springframework.http.ResponseEntity | ||||
| import org.springframework.web.bind.annotation.GetMapping | |||||
| import org.springframework.web.bind.annotation.PathVariable | |||||
| import org.springframework.web.bind.annotation.PostMapping | |||||
| import org.springframework.web.bind.annotation.RequestBody | |||||
| import org.springframework.web.bind.annotation.RequestMapping | |||||
| import org.springframework.web.bind.annotation.RequestParam | |||||
| import org.springframework.web.bind.annotation.RestController | |||||
| import org.springframework.web.bind.annotation.* | |||||
| import org.springframework.web.multipart.MultipartHttpServletRequest | import org.springframework.web.multipart.MultipartHttpServletRequest | ||||
| import java.io.OutputStream | import java.io.OutputStream | ||||
| @@ -145,4 +140,10 @@ class InvoiceController( | |||||
| fun updateInvoiceDetail(@RequestBody req: EditInvoiceRequest): EditInvoiceResponse { | fun updateInvoiceDetail(@RequestBody req: EditInvoiceRequest): EditInvoiceResponse { | ||||
| return invoiceService.updateInvoiceDetail(req) | return invoiceService.updateInvoiceDetail(req) | ||||
| } | } | ||||
| @DeleteMapping("/{id}") | |||||
| @ResponseStatus(HttpStatus.NO_CONTENT) | |||||
| fun deleteProject(@PathVariable id: Long) { | |||||
| invoiceService.markDeleted(id) | |||||
| } | |||||
| } | } | ||||
| @@ -3903,6 +3903,7 @@ open class ReportService( | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| // Use to Calculate cummunlative expenditure | // Use to Calculate cummunlative expenditure | ||||
| // TO DO: Add isCrossTeam | |||||
| data class TimesheetData( | data class TimesheetData( | ||||
| val normalConsumed: Double, | val normalConsumed: Double, | ||||
| val otConsumed: Double, | val otConsumed: Double, | ||||
| @@ -3913,6 +3914,7 @@ open class ReportService( | |||||
| val projectCode: String, | val projectCode: String, | ||||
| val planStart: LocalDate, | val planStart: LocalDate, | ||||
| val planEnd: LocalDate | val planEnd: LocalDate | ||||
| // val isCrossTeam: Boolean | |||||
| ) | ) | ||||
| data class SalaryEffectiveInfo( | data class SalaryEffectiveInfo( | ||||
| @@ -3947,6 +3949,12 @@ open class ReportService( | |||||
| fun getManHoursSpentByTeam(teamLeadId: Long?): List<TimesheetData>{ | fun getManHoursSpentByTeam(teamLeadId: Long?): List<TimesheetData>{ | ||||
| val sql = StringBuilder( | val sql = StringBuilder( | ||||
| "select coalesce(t.normalConsumed, 0) as normalConsumed, coalesce(t.otConsumed, 0) as otConsumed, t.recordDate, t.staffId, s2.hourlyRate, s2.salaryPoint, p.code, p.planStart, p.planEnd" | "select coalesce(t.normalConsumed, 0) as normalConsumed, coalesce(t.otConsumed, 0) as otConsumed, t.recordDate, t.staffId, s2.hourlyRate, s2.salaryPoint, p.code, p.planStart, p.planEnd" | ||||
| // For later calculating cross team charge | |||||
| // + ",CASE" | |||||
| // + " when s.teamId is NUll then null" | |||||
| // + " when s.teamId = p.teamLead then 1" | |||||
| // + " else 0" | |||||
| // + " END as IsCrossTeam" | |||||
| + " from timesheet t" | + " from timesheet t" | ||||
| + " left join project p on t.projectId = p.id" | + " left join project p on t.projectId = p.id" | ||||
| + " left join staff s on t.staffId = s.id" | + " left join staff s on t.staffId = s.id" | ||||
| @@ -4070,6 +4078,9 @@ open class ReportService( | |||||
| // } | // } | ||||
| fun calculateProjectExpenditures(timesheetDataList: List<TimesheetData>): Map<String, BigDecimal> { | fun calculateProjectExpenditures(timesheetDataList: List<TimesheetData>): Map<String, BigDecimal> { | ||||
| val otFactor = BigDecimal(1.0) | val otFactor = BigDecimal(1.0) | ||||
| // For cross Team Calculation | |||||
| // val crossTeamCharge = BigDecimal(1.15) | |||||
| // If isCrossTeam is true, normal an ot expenditure will times the cross team charge | |||||
| return timesheetDataList | return timesheetDataList | ||||
| .groupBy { it.projectCode } | .groupBy { it.projectCode } | ||||
| .mapValues { (_, projectTimesheets) -> | .mapValues { (_, projectTimesheets) -> | ||||
| @@ -4084,6 +4095,7 @@ open class ReportService( | |||||
| // Update timesheet data with salary effective data, then group by project code, group by staff Id and group by Year Month | // Update timesheet data with salary effective data, then group by project code, group by staff Id and group by Year Month | ||||
| // Used for checking data | |||||
| // Data foramt: | // Data foramt: | ||||
| // "M-0976": { | // "M-0976": { | ||||
| // "184": { | // "184": { | ||||
| @@ -4108,13 +4120,16 @@ open class ReportService( | |||||
| fun sumTimesheetDataByMonth(timesheetDataList: List<TimesheetData>): Map<String, ProjectSummary> { | fun sumTimesheetDataByMonth(timesheetDataList: List<TimesheetData>): Map<String, ProjectSummary> { | ||||
| return timesheetDataList | return timesheetDataList | ||||
| .groupBy { it.projectCode } | |||||
| .groupBy { it.projectCode } // Group timesheet data by project code | |||||
| .mapValues { (_, projectTimesheets) -> | .mapValues { (_, projectTimesheets) -> | ||||
| val staffData = projectTimesheets.groupBy { it.staffId } | |||||
| // Process each project's timesheet data | |||||
| val staffData = projectTimesheets.groupBy { it.staffId } // Group by staff ID | |||||
| .mapValues { (_, staffTimesheets) -> | .mapValues { (_, staffTimesheets) -> | ||||
| // Process each staff member's timesheet data | |||||
| val monthlyData = staffTimesheets.groupBy { timesheet -> | val monthlyData = staffTimesheets.groupBy { timesheet -> | ||||
| YearMonth.from(timesheet.recordDate) | |||||
| YearMonth.from(timesheet.recordDate) // Group by month | |||||
| }.mapValues { (_, monthTimesheets) -> | }.mapValues { (_, monthTimesheets) -> | ||||
| // Calculate monthly summary for each staff member | |||||
| MonthSummary( | MonthSummary( | ||||
| hourlyRate = monthTimesheets.maxByOrNull { it.recordDate }?.hourlyRate ?: BigDecimal.ZERO, | hourlyRate = monthTimesheets.maxByOrNull { it.recordDate }?.hourlyRate ?: BigDecimal.ZERO, | ||||
| salaryPoint = monthTimesheets.maxByOrNull { it.recordDate }?.salaryPoint ?: 0, | salaryPoint = monthTimesheets.maxByOrNull { it.recordDate }?.salaryPoint ?: 0, | ||||
| @@ -86,7 +86,7 @@ class ReportController( | |||||
| val project = projectRepository.findById(request.projectId).orElseThrow() | val project = projectRepository.findById(request.projectId).orElseThrow() | ||||
| val projectTasks = projectTaskRepository.findAllByProject(project) | val projectTasks = projectTaskRepository.findAllByProject(project) | ||||
| // val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project) | // val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project) | ||||
| val invoices = invoiceRepository.findAllByProjectCodeAndPaidAmountIsNotNull(project.code!!) | |||||
| val invoices = invoiceRepository.findAllByProjectCodeAndPaidAmountIsNotNullAndDeletedFalse(project.code!!) | |||||
| val timesheets = timesheetRepository.findAllByProjectTaskIn(projectTasks) | val timesheets = timesheetRepository.findAllByProjectTaskIn(projectTasks) | ||||
| val monthlyStaffSalaryEffective = salaryEffectiveService.getMonthlyStaffSalaryData(timesheets.minByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.parse("2012-01-01"), timesheets.maxByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.now()) | val monthlyStaffSalaryEffective = salaryEffectiveService.getMonthlyStaffSalaryData(timesheets.minByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.parse("2012-01-01"), timesheets.maxByOrNull { it.recordDate!! }?.recordDate ?: LocalDate.now()) | ||||