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()) | ||||