| @@ -11,8 +11,8 @@ import java.util.Map; | |||||
| import java.util.Optional; | import java.util.Optional; | ||||
| public interface StaffRepository extends AbstractRepository<Staff, Long> { | public interface StaffRepository extends AbstractRepository<Staff, Long> { | ||||
| List<StaffSearchInfo> findStaffSearchInfoByAndDeletedFalse(); | |||||
| List<StaffSearchInfo> findStaffSearchInfoByAndDeletedFalseAndTeamIdIsNull(); | |||||
| List<StaffSearchInfo> findStaffSearchInfoByAndDeletedFalseOrderByStaffIdAsc(); | |||||
| List<StaffSearchInfo> findStaffSearchInfoByAndDeletedFalseAndTeamIdIsNullOrderByStaffIdAsc(); | |||||
| List<StaffSearchInfo> findAllStaffSearchInfoByIdIn(List<Serializable> ids); | List<StaffSearchInfo> findAllStaffSearchInfoByIdIn(List<Serializable> ids); | ||||
| Optional<Staff> findByStaffId(@Param("staffId") String staffId); | Optional<Staff> findByStaffId(@Param("staffId") String staffId); | ||||
| @@ -41,10 +41,10 @@ open class StaffsService( | |||||
| } | } | ||||
| open fun allStaff(): List<StaffSearchInfo> { | open fun allStaff(): List<StaffSearchInfo> { | ||||
| return staffRepository.findStaffSearchInfoByAndDeletedFalse(); | |||||
| return staffRepository.findStaffSearchInfoByAndDeletedFalseOrderByStaffIdAsc(); | |||||
| } | } | ||||
| open fun StaffWithoutTeam(): List<StaffSearchInfo> { | open fun StaffWithoutTeam(): List<StaffSearchInfo> { | ||||
| return staffRepository.findStaffSearchInfoByAndDeletedFalseAndTeamIdIsNull(); | |||||
| return staffRepository.findStaffSearchInfoByAndDeletedFalseAndTeamIdIsNullOrderByStaffIdAsc(); | |||||
| } | } | ||||
| open fun getStaff(id: Long): Staff { | open fun getStaff(id: Long): Staff { | ||||
| @@ -115,7 +115,7 @@ open class StaffsService( | |||||
| @Transactional(rollbackFor = [Exception::class]) | @Transactional(rollbackFor = [Exception::class]) | ||||
| open fun saveStaff(req: NewStaffRequest): Staff { | open fun saveStaff(req: NewStaffRequest): Staff { | ||||
| val checkStaffIdList: List<StaffSearchInfo> = staffRepository.findStaffSearchInfoByAndDeletedFalse() | |||||
| val checkStaffIdList: List<StaffSearchInfo> = staffRepository.findStaffSearchInfoByAndDeletedFalseOrderByStaffIdAsc() | |||||
| checkStaffIdList.forEach{ s -> | checkStaffIdList.forEach{ s -> | ||||
| if (s.staffId == req.staffId) { | if (s.staffId == req.staffId) { | ||||
| throw UnprocessableEntityException("Duplicated StaffId Found") | throw UnprocessableEntityException("Duplicated StaffId Found") | ||||
| @@ -20,6 +20,7 @@ open class Project : BaseEntity<Long>() { | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "code", length = 30) | @Column(name = "code", length = 30) | ||||
| @OrderBy("code asc") | |||||
| open var code: String? = null | open var code: String? = null | ||||
| @ManyToOne | @ManyToOne | ||||
| @@ -12,7 +12,7 @@ import java.io.Serializable | |||||
| import java.time.LocalDate | import java.time.LocalDate | ||||
| interface ProjectRepository : AbstractRepository<Project, Long> { | interface ProjectRepository : AbstractRepository<Project, Long> { | ||||
| fun findProjectSearchInfoByOrderByCreatedDesc(): List<ProjectSearchInfo> | |||||
| fun findProjectSearchInfoByDeletedIsFalseOrderByCodeDesc(): List<ProjectSearchInfo> | |||||
| fun findInvoiceSearchInfoBy(): List<InvoiceSearchInfo> | fun findInvoiceSearchInfoBy(): List<InvoiceSearchInfo> | ||||
| @@ -24,9 +24,9 @@ interface ProjectRepository : AbstractRepository<Project, Long> { | |||||
| fun findAllByPlanStartLessThanEqualAndPlanEndGreaterThanEqual(remainedDateFrom: LocalDate?, remainedDateTo: LocalDate?):List<Project> | fun findAllByPlanStartLessThanEqualAndPlanEndGreaterThanEqual(remainedDateFrom: LocalDate?, remainedDateTo: LocalDate?):List<Project> | ||||
| @Query("SELECT max(cast(substring_index(substring_index(p.code, '-', 2), '-', -1) as long)) FROM Project p WHERE p.isClpProject = ?1 and p.id != ?2" + | |||||
| @Query("SELECT max(cast(substring_index(substring_index(p.code, '-', 2), '-', -1) as long)) FROM Project p WHERE p.id != ?1" + | |||||
| "") | "") | ||||
| fun getLatestCodeNumberByMainProject(isClpProject: Boolean, id: Serializable?): Long? | |||||
| fun getLatestCodeNumberByMainProject(id: Serializable?): Long? | |||||
| @Query("SELECT max(case when length(p.code) - length(replace(p.code, '-', '')) > 1 then cast(substring_index(p.code, '-', -1) as long) end) FROM Project p WHERE p.code like %?1% and p.id != ?2") | @Query("SELECT max(case when length(p.code) - length(replace(p.code, '-', '')) > 1 then cast(substring_index(p.code, '-', -1) as long) end) FROM Project p WHERE p.code like %?1% and p.id != ?2") | ||||
| fun getLatestCodeNumberBySubProject(code: String, id: Serializable?): Long? | fun getLatestCodeNumberBySubProject(code: String, id: Serializable?): Long? | ||||
| @@ -4,6 +4,7 @@ import com.ffii.core.utils.ExcelUtils | |||||
| import com.ffii.tsms.modules.common.SecurityUtils | import com.ffii.tsms.modules.common.SecurityUtils | ||||
| import com.ffii.tsms.modules.data.entity.* | import com.ffii.tsms.modules.data.entity.* | ||||
| import com.ffii.tsms.modules.data.service.* | import com.ffii.tsms.modules.data.service.* | ||||
| import com.ffii.tsms.modules.data.web.models.SaveCustomerResponse | |||||
| import com.ffii.tsms.modules.project.entity.* | import com.ffii.tsms.modules.project.entity.* | ||||
| import com.ffii.tsms.modules.project.entity.Milestone | import com.ffii.tsms.modules.project.entity.Milestone | ||||
| import com.ffii.tsms.modules.project.entity.projections.InvoiceInfoSearchInfo | import com.ffii.tsms.modules.project.entity.projections.InvoiceInfoSearchInfo | ||||
| @@ -12,12 +13,18 @@ import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo | |||||
| import com.ffii.tsms.modules.project.web.models.* | import com.ffii.tsms.modules.project.web.models.* | ||||
| import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository | import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository | ||||
| import org.apache.commons.logging.LogFactory | import org.apache.commons.logging.LogFactory | ||||
| import org.apache.poi.ss.usermodel.CellType | |||||
| import org.apache.poi.ss.usermodel.DataFormatter | |||||
| import org.apache.poi.ss.usermodel.DateUtil | |||||
| import org.apache.poi.ss.usermodel.Sheet | import org.apache.poi.ss.usermodel.Sheet | ||||
| import org.apache.poi.ss.usermodel.Workbook | import org.apache.poi.ss.usermodel.Workbook | ||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | import org.springframework.transaction.annotation.Transactional | ||||
| import java.time.LocalDate | import java.time.LocalDate | ||||
| import java.time.ZoneId | |||||
| import java.time.format.DateTimeFormatter | import java.time.format.DateTimeFormatter | ||||
| import java.time.format.FormatStyle | |||||
| import java.util.Locale | |||||
| import kotlin.jvm.optionals.getOrNull | import kotlin.jvm.optionals.getOrNull | ||||
| @@ -53,8 +60,7 @@ open class ProjectsService( | |||||
| private val customerSubsidiaryService: CustomerSubsidiaryService, | private val customerSubsidiaryService: CustomerSubsidiaryService, | ||||
| ) { | ) { | ||||
| open fun allProjects(): List<ProjectSearchInfo> { | open fun allProjects(): List<ProjectSearchInfo> { | ||||
| return projectRepository.findProjectSearchInfoByOrderByCreatedDesc() | |||||
| .sortedByDescending { it.status?.lowercase() != "deleted" } | |||||
| return projectRepository.findProjectSearchInfoByDeletedIsFalseOrderByCodeDesc() | |||||
| } | } | ||||
| open fun allInvoices(): List<InvoiceSearchInfo> { | open fun allInvoices(): List<InvoiceSearchInfo> { | ||||
| @@ -132,7 +138,7 @@ open class ProjectsService( | |||||
| val checkIsClpProject = isClpProject != null && isClpProject | val checkIsClpProject = isClpProject != null && isClpProject | ||||
| val prefix = if (checkIsClpProject) "C" else "M" | val prefix = if (checkIsClpProject) "C" else "M" | ||||
| val latestProjectCode = projectRepository.getLatestCodeNumberByMainProject(checkIsClpProject, project.id ?: -1) | |||||
| val latestProjectCode = projectRepository.getLatestCodeNumberByMainProject(project.id ?: -1) | |||||
| if (latestProjectCode != null) { | if (latestProjectCode != null) { | ||||
| val lastFix = latestProjectCode | val lastFix = latestProjectCode | ||||
| @@ -186,17 +192,31 @@ open class ProjectsService( | |||||
| val project = | val project = | ||||
| if (request.projectId != null && request.projectId > 0) projectRepository.findById(request.projectId) | if (request.projectId != null && request.projectId > 0) projectRepository.findById(request.projectId) | ||||
| .orElseThrow() else Project() | .orElseThrow() else Project() | ||||
| val duplicateProject = | |||||
| if (request.projectCode != null) projectRepository.findByCode(request.projectCode) else null | |||||
| //check duplicate project | |||||
| if (duplicateProject != null && !duplicateProject.deleted && duplicateProject.id?.equals(request.projectId) == false) { | |||||
| return NewProjectResponse( | |||||
| id = request.projectId, | |||||
| code = request.projectCode, | |||||
| name = request.projectName, | |||||
| client = null, | |||||
| category = null, | |||||
| team = null, | |||||
| message = "The project code has already existed", | |||||
| errorPosition = "projectCode" | |||||
| ); | |||||
| } | |||||
| project.apply { | project.apply { | ||||
| name = request.projectName | name = request.projectName | ||||
| description = request.projectDescription | description = request.projectDescription | ||||
| code = request.projectCode | |||||
| ?: if (this.code.isNullOrEmpty() && request.mainProjectId == null) createProjectCode( | |||||
| request.isClpProject, | |||||
| project | |||||
| ) else if (this.code.isNullOrEmpty() && request.mainProjectId != null && mainProject != null) createSubProjectCode( | |||||
| mainProject, | |||||
| project | |||||
| ) else this.code | |||||
| code = if (request.mainProjectId != null && mainProject != null) createSubProjectCode( | |||||
| mainProject, | |||||
| project | |||||
| ) else request.projectCode | |||||
| expectedTotalFee = request.expectedProjectFee | expectedTotalFee = request.expectedProjectFee | ||||
| subContractFee = request.subContractFee | subContractFee = request.subContractFee | ||||
| totalManhour = request.totalManhour | totalManhour = request.totalManhour | ||||
| @@ -305,7 +325,8 @@ open class ProjectsService( | |||||
| val milestonesToDelete = milestoneRepository.findAllByProject(project).subtract(milestones.toSet()) | val milestonesToDelete = milestoneRepository.findAllByProject(project).subtract(milestones.toSet()) | ||||
| val mapTasksToSave = tasksToSave.map { it.task!!.id } | val mapTasksToSave = tasksToSave.map { it.task!!.id } | ||||
| val tasksToDelete = projectTaskRepository.findAllByProject(project).filter { !mapTasksToSave.contains(it.task!!.id) } | |||||
| val tasksToDelete = | |||||
| projectTaskRepository.findAllByProject(project).filter { !mapTasksToSave.contains(it.task!!.id) } | |||||
| val gradeAllocationsToDelete = | val gradeAllocationsToDelete = | ||||
| gradeAllocationRepository.findByProject(project).subtract(gradeAllocations.toSet()) | gradeAllocationRepository.findByProject(project).subtract(gradeAllocations.toSet()) | ||||
| milestoneRepository.deleteAll(milestonesToDelete) | milestoneRepository.deleteAll(milestonesToDelete) | ||||
| @@ -336,7 +357,9 @@ open class ProjectsService( | |||||
| name = it.name, | name = it.name, | ||||
| client = it.customer?.name, | client = it.customer?.name, | ||||
| category = it.projectCategory?.name, | category = it.projectCategory?.name, | ||||
| team = it.teamLead?.team?.code | |||||
| team = it.teamLead?.team?.code, | |||||
| message = "Success", | |||||
| errorPosition = null, | |||||
| ) | ) | ||||
| } | } | ||||
| } | } | ||||
| @@ -523,14 +546,15 @@ open class ProjectsService( | |||||
| val splitMainProjectCode = splitProjectCode[0].split('-') | val splitMainProjectCode = splitProjectCode[0].split('-') | ||||
| logger.info("splitProjectCode: " + splitProjectCode[1].split(')')[0]) | logger.info("splitProjectCode: " + splitProjectCode[1].split(')')[0]) | ||||
| val mainProjectCode = splitMainProjectCode[0] + '-' + String.format( | |||||
| "%04d", | |||||
| splitMainProjectCode[1].toInt() | |||||
| ) | |||||
| projectCode = | projectCode = | ||||
| splitMainProjectCode[0] + '-' + String.format( | |||||
| "%04d", | |||||
| splitMainProjectCode[1].toInt() | |||||
| ) + '-' + String.format("%03d", splitProjectCode[1].split(')')[0].toInt()) | |||||
| mainProjectCode + '-' + String.format("%03d", splitProjectCode[1].split(')')[0].toInt()) | |||||
| val mainProject = | val mainProject = | ||||
| projectRepository.findByCode(splitProjectCode[0]) ?: projectRepository.saveAndFlush( | |||||
| projectRepository.findByCode(mainProjectCode) ?: projectRepository.saveAndFlush( | |||||
| Project().apply { | Project().apply { | ||||
| name = row.getCell(1).stringCellValue | name = row.getCell(1).stringCellValue | ||||
| description = row.getCell(1).stringCellValue | description = row.getCell(1).stringCellValue | ||||
| @@ -642,7 +666,8 @@ open class ProjectsService( | |||||
| keySelector = { it.taskGroup!!.id!! }, | keySelector = { it.taskGroup!!.id!! }, | ||||
| valueTransform = { it.percentage!! } | valueTransform = { it.percentage!! } | ||||
| ) | ) | ||||
| val projectTasks = if (project != null) projectTaskRepository.findAllByProject(project) else mutableListOf() | |||||
| val projectTasks = | |||||
| if (project != null) projectTaskRepository.findAllByProject(project) else mutableListOf() | |||||
| var groupedProjectTasks = mapOf<Long, List<Long>>() | var groupedProjectTasks = mapOf<Long, List<Long>>() | ||||
| if (projectTasks.isNotEmpty()) { | if (projectTasks.isNotEmpty()) { | ||||
| groupedProjectTasks = projectTasks.groupBy { | groupedProjectTasks = projectTasks.groupBy { | ||||
| @@ -652,7 +677,7 @@ open class ProjectsService( | |||||
| } | } | ||||
| } | } | ||||
| val taskGroups = mutableMapOf<Long, TaskGroupAllocation>() | val taskGroups = mutableMapOf<Long, TaskGroupAllocation>() | ||||
| groups.entries.forEach{ (key, value) -> | |||||
| groups.entries.forEach { (key, value) -> | |||||
| var taskIds = tasks[key]!!.map { it.id!! } | var taskIds = tasks[key]!!.map { it.id!! } | ||||
| if (groupedProjectTasks.isNotEmpty() && !groupedProjectTasks[key].isNullOrEmpty()) { | if (groupedProjectTasks.isNotEmpty() && !groupedProjectTasks[key].isNullOrEmpty()) { | ||||
| taskIds = (taskIds + groupedProjectTasks[key]!!).distinct() | taskIds = (taskIds + groupedProjectTasks[key]!!).distinct() | ||||
| @@ -7,4 +7,6 @@ data class NewProjectResponse( | |||||
| val category: String?, | val category: String?, | ||||
| val team: String?, | val team: String?, | ||||
| val client: String?, | val client: String?, | ||||
| val message: String?, | |||||
| val errorPosition: String?, | |||||
| ) | ) | ||||
| @@ -1,6 +1,7 @@ | |||||
| package com.ffii.tsms.modules.report.service | package com.ffii.tsms.modules.report.service | ||||
| import com.ffii.core.support.JdbcDao | import com.ffii.core.support.JdbcDao | ||||
| import com.ffii.core.utils.ExcelUtils | |||||
| import com.ffii.tsms.modules.data.entity.Customer | import com.ffii.tsms.modules.data.entity.Customer | ||||
| import com.ffii.tsms.modules.data.entity.Grade | import com.ffii.tsms.modules.data.entity.Grade | ||||
| import com.ffii.tsms.modules.data.entity.Salary | import com.ffii.tsms.modules.data.entity.Salary | ||||
| @@ -59,6 +60,20 @@ open class ReportService( | |||||
| private val COMPLETION_PROJECT = "templates/report/AR05_Project Completion Report.xlsx" | private val COMPLETION_PROJECT = "templates/report/AR05_Project Completion Report.xlsx" | ||||
| private val CROSS_TEAM_CHARGE_REPORT = "templates/report/Cross Team Charge Report.xlsx" | private val CROSS_TEAM_CHARGE_REPORT = "templates/report/Cross Team Charge Report.xlsx" | ||||
| private fun conditionalFormattingNegative(sheet: Sheet) { | |||||
| // Create a conditional formatting rule | |||||
| val sheetCF = sheet.sheetConditionalFormatting | |||||
| val ruleNegative = sheetCF.createConditionalFormattingRule(ComparisonOperator.LT, "0").apply { | |||||
| createFontFormatting().apply { | |||||
| fontColorIndex = IndexedColors.RED.index | |||||
| } | |||||
| } | |||||
| val lastCell = sheet.maxOf { it.lastCellNum - 1 } | |||||
| val regions = arrayOf(CellRangeAddress(0, sheet.lastRowNum, 0, lastCell)) | |||||
| sheetCF.addConditionalFormatting(regions, ruleNegative) | |||||
| } | |||||
| // ==============================|| GENERATE REPORT ||============================== // | // ==============================|| GENERATE REPORT ||============================== // | ||||
| fun generalCreateReportIndexed( // just loop through query records one by one, return rowIndex | fun generalCreateReportIndexed( // just loop through query records one by one, return rowIndex | ||||
| sheet: Sheet, | sheet: Sheet, | ||||
| @@ -655,6 +670,8 @@ open class ReportService( | |||||
| cellStyle.dataFormat = accountingStyle | cellStyle.dataFormat = accountingStyle | ||||
| } | } | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -760,6 +777,7 @@ open class ReportService( | |||||
| cellStyle.dataFormat = accountingStyle | cellStyle.dataFormat = accountingStyle | ||||
| } | } | ||||
| } | } | ||||
| var regions = arrayOf(CellRangeAddress(12, 12, 1, 2)) | |||||
| rowIndex = 16 | rowIndex = 16 | ||||
| @@ -814,7 +832,7 @@ open class ReportService( | |||||
| combinedResults.forEach { result: String -> | combinedResults.forEach { result: String -> | ||||
| if (groupedInvoices.containsKey(result)) { | if (groupedInvoices.containsKey(result)) { | ||||
| groupedInvoices[result]!!.forEachIndexed { _, invoice -> | |||||
| // groupedInvoices[result]!!.forEachIndexed { _, invoice -> | |||||
| sheet.createRow(rowIndex++).apply { | sheet.createRow(rowIndex++).apply { | ||||
| createCell(0).apply { | createCell(0).apply { | ||||
| setCellValue(result) | setCellValue(result) | ||||
| @@ -826,7 +844,7 @@ open class ReportService( | |||||
| } | } | ||||
| createCell(2).apply { | createCell(2).apply { | ||||
| setCellValue(invoice["paidAmount"] as Double) | |||||
| setCellValue(groupedInvoices[result]?.sumOf { it["paidAmount"] as Double } ?: 0.0) | |||||
| cellStyle.dataFormat = accountingStyle | cellStyle.dataFormat = accountingStyle | ||||
| } | } | ||||
| @@ -847,9 +865,9 @@ open class ReportService( | |||||
| createCell(4)?.apply { | createCell(4)?.apply { | ||||
| // setCellValue(invoice["description"].toString()) | // setCellValue(invoice["description"].toString()) | ||||
| setCellValue("Invoice Receipt: " + (invoice["invoiceNo"] ?: "N/A").toString()) | |||||
| setCellValue("Invoice Receipt: " + (groupedInvoices[result]?.map { it["invoiceNo"] }?.joinToString() ?: "N/A").toString()) | |||||
| } | } | ||||
| } | |||||
| // } | |||||
| } | } | ||||
| } | } | ||||
| @@ -892,6 +910,8 @@ open class ReportService( | |||||
| } | } | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -1053,6 +1073,8 @@ open class ReportService( | |||||
| } | } | ||||
| } | } | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -1348,6 +1370,9 @@ open class ReportService( | |||||
| CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) | CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom) | ||||
| } | } | ||||
| } | } | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -1403,6 +1428,8 @@ open class ReportService( | |||||
| } | } | ||||
| // println(salarys.size) | // println(salarys.size) | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -1435,6 +1462,9 @@ open class ReportService( | |||||
| columnIndex = 0 | columnIndex = 0 | ||||
| generalCreateReportIndexed(sheet, result.distinct(), rowIndex, columnIndex) | generalCreateReportIndexed(sheet, result.distinct(), rowIndex, columnIndex) | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -1492,6 +1522,8 @@ open class ReportService( | |||||
| val regions = arrayOf(CellRangeAddress.valueOf("\$K7:\$L${rowIndex + 1}")) | val regions = arrayOf(CellRangeAddress.valueOf("\$K7:\$L${rowIndex + 1}")) | ||||
| sheetCF.addConditionalFormatting(regions, cfRules); | sheetCF.addConditionalFormatting(regions, cfRules); | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -1526,6 +1558,8 @@ open class ReportService( | |||||
| // Automatically adjust column widths to fit content | // Automatically adjust column widths to fit content | ||||
| autoSizeColumns(sheet) | autoSizeColumns(sheet) | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -2416,6 +2450,8 @@ open class ReportService( | |||||
| CellUtil.setCellStyleProperty(panlCellTitle, "borderBottom", BorderStyle.DOUBLE) | CellUtil.setCellStyleProperty(panlCellTitle, "borderBottom", BorderStyle.DOUBLE) | ||||
| CellUtil.setCellStyleProperty(panlCell, "borderBottom", BorderStyle.DOUBLE) | CellUtil.setCellStyleProperty(panlCell, "borderBottom", BorderStyle.DOUBLE) | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -2650,6 +2686,8 @@ open class ReportService( | |||||
| sheet.setRowBreak(rowNum++); | sheet.setRowBreak(rowNum++); | ||||
| } | } | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| @@ -2961,6 +2999,8 @@ open class ReportService( | |||||
| } | } | ||||
| // } | // } | ||||
| conditionalFormattingNegative(sheet) | |||||
| return workbook | return workbook | ||||
| } | } | ||||
| } | } | ||||
| @@ -90,7 +90,7 @@ class ReportController( | |||||
| // val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | // val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
| return ResponseEntity.ok() | return ResponseEntity.ok() | ||||
| // .contentType(mediaType) | // .contentType(mediaType) | ||||
| .header("filename", "Project Cash Flow Report - " + LocalDate.now() + ".xlsx") | |||||
| .header("filename", "Project Cash Flow Report (${if(request.dateType == "Date") "by Date" else "by Month"}) - " + LocalDate.now() + ".xlsx") | |||||
| .body(ByteArrayResource(reportResult)) | .body(ByteArrayResource(reportResult)) | ||||
| } | } | ||||
| @@ -182,7 +182,7 @@ public class GroupService extends AbstractBaseEntityService<Group, Long, GroupRe | |||||
| + " where g.deleted = false " | + " where g.deleted = false " | ||||
| + " and u.id = :userId" | + " and u.id = :userId" | ||||
| ); | ); | ||||
| return jdbcDao.queryForString(sql.toString(), args); | |||||
| return jdbcDao.queryForList(sql.toString(), args).stream().map(String::valueOf).collect(Collectors.joining(",")); | |||||
| } | } | ||||
| @@ -0,0 +1,7 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset cyril:authority, user_authority | |||||
| INSERT INTO authority (authority,name) | |||||
| VALUES ('VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING','View Project Resource Consumption Ranking in Dashboard'); | |||||
| INSERT INTO `user_authority` VALUES (1,41); | |||||