Sfoglia il codice sorgente

update

tags/Baseline_30082024_BACKEND_UAT
MSI\derek 1 anno fa
parent
commit
59ef02e1d0
6 ha cambiato i file con 166 aggiunte e 149 eliminazioni
  1. +4
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/SalaryRepository.java
  2. +1
    -1
      src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt
  3. +3
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/StaffAllocationRepository.kt
  4. +133
    -146
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  5. +2
    -1
      src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt
  6. +23
    -1
      src/main/java/com/ffii/tsms/modules/user/web/UserController.java

+ 4
- 0
src/main/java/com/ffii/tsms/modules/data/entity/SalaryRepository.java Vedi File

@@ -2,9 +2,13 @@ package com.ffii.tsms.modules.data.entity;

import com.ffii.core.support.AbstractRepository;
import com.ffii.tsms.modules.data.entity.projections.SalarySearchInfo;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;

public interface SalaryRepository extends AbstractRepository<Salary, Long> {
List<SalarySearchInfo> findSalarySearchInfoByOrderBySalaryPoint();

Optional<Salary> findBySalaryPoint(@Param("salaryPoint") Long salaryPoint);
}

+ 1
- 1
src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt Vedi File

@@ -107,7 +107,7 @@ open class StaffsService(
val company = companyRepository.findById(req.companyId).orElseThrow()
val grade = if (req.gradeId != null && req.gradeId > 0L) gradeRepository.findById(req.gradeId).orElseThrow() else null
val team = if (req.teamId != null && req.teamId > 0L) teamRepository.findById(req.teamId).orElseThrow() else null
val salary = salaryRepository.findById(req.salaryId).orElseThrow()
val salary = salaryRepository.findBySalaryPoint(req.salaryId).orElseThrow()
// val salaryEffective = salaryEffectiveRepository.findById(req.salaryEffId).orElseThrow()
val department = departmentRepository.findById(req.departmentId).orElseThrow()



+ 3
- 0
src/main/java/com/ffii/tsms/modules/project/entity/StaffAllocationRepository.kt Vedi File

@@ -2,8 +2,11 @@ package com.ffii.tsms.modules.project.entity;

import com.ffii.core.support.AbstractRepository
import com.ffii.tsms.modules.data.entity.Staff
import com.ffii.tsms.modules.data.entity.projections.StaffSearchInfo
import java.time.LocalDate

interface StaffAllocationRepository : AbstractRepository<StaffAllocation, Long> {
fun findAssignedProjectsByStaff(staff: Staff): List<StaffAllocation>

fun findByProject(project: Project): List<StaffAllocation>
}

+ 133
- 146
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt Vedi File

@@ -21,10 +21,10 @@ import java.io.IOException
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.*
import org.apache.poi.ss.util.CellUtil
import kotlin.time.times

data class DayInfo(val date: String?, val weekday: String?)

@Service
open class ReportService(
private val jdbcDao: JdbcDao,
@@ -108,8 +108,8 @@ open class ReportService(
}

@Throws(IOException::class)
fun generateLateStartReport(project: Project): ByteArray {
val workbook: Workbook = createLateStartReport(project, LATE_START_REPORT)
fun generateLateStartReport(project: Project?): ByteArray {
val workbook: Workbook = createLateStartReport(project,LATE_START_REPORT)
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
workbook.write(outputStream)
workbook.close()
@@ -370,6 +370,9 @@ open class ReportService(
templatePath: String,
): Workbook {
// val yearMonth = YearMonth.of(2022, 5) // May 2022
println("t $timesheets")
println("l $leaves")
println("p $projectList")
val resource = ClassPathResource(templatePath)
val templateInputStream = resource.inputStream
val workbook: Workbook = XSSFWorkbook(templateInputStream)
@@ -398,210 +401,195 @@ open class ReportService(
var columnSize = 0

var dayInt = 0
// tempCell = tempRow.createCell(columnIndex)
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(FORMATTED_TODAY)
}
println(sheet.getRow(1).getCell(2))
var tempCell: Cell

tempCell = sheet.getRow(rowIndex).createCell(columnIndex)
tempCell.setCellValue(FORMATTED_TODAY)

rowIndex = 2
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(month)
cellStyle.dataFormat = monthStyle
}
tempCell = sheet.getRow(rowIndex).createCell(columnIndex)
tempCell.setCellValue(month)
tempCell.cellStyle.dataFormat = monthStyle

rowIndex = 3
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(staff.name)
}
tempCell. sheet.getRow(rowIndex).createCell(columnIndex)
tempCell.setCellValue(staff.name)

rowIndex = 4
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(staff.team.name)
}
tempCell.sheet.getRow(rowIndex).createCell(columnIndex)
tempCell.setCellValue(staff.team.name)

rowIndex = 5
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(staff.grade.code)
}
tempCell = sheet.getRow(rowIndex).createCell(columnIndex)
tempCell.setCellValue(staff.grade.code)

val DoubleBorderBottom: MutableMap<String?, Any?> = mutableMapOf()
DoubleBorderBottom["borderTop"] = BorderStyle.THIN
DoubleBorderBottom["borderBottom"] = BorderStyle.DOUBLE

val ThinBorderBottom: MutableMap<String?, Any?> = mutableMapOf()
ThinBorderBottom["borderBottom"] = BorderStyle.THIN
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
rowIndex = 7
daysOfMonth.forEach { dayInfo ->
rowIndex++
rowSize++
sheet.getRow(rowIndex).getCell(0).apply {
setCellValue(dayInfo.date)
cellStyle.dataFormat = dateStyle
cellStyle.setFont(boldFont)
}
sheet.getRow(rowIndex).getCell(1).apply {
setCellValue(dayInfo.weekday)
cellStyle.setFont(boldFont)
}
tempCell = sheet.createRow(rowIndex).createCell(0)
tempCell.setCellValue(dayInfo.date)
tempCell.cellStyle.dataFormat = dateStyle
tempCell.cellStyle.setFont(boldFont)
// cellStyle.alignment = HorizontalAlignment.LEFT
tempCell = sheet.createRow(rowIndex).createCell(1)
tempCell.setCellValue(dayInfo.weekday)
tempCell.cellStyle.setFont(boldFont)
// cellStyle.alignment = HorizontalAlignment.LEFT
}

rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Sub-total")
cellStyle.setFont(boldFont)
// cellStyle.borderTop = BorderStyle.THIN
// cellStyle.borderBottom = BorderStyle.DOUBLE
cellStyle.alignment = HorizontalAlignment.CENTER
}
sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1))
//
tempCell = sheet.createRow(rowIndex).createCell(0)
sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
tempCell.setCellValue("Sub-total")
tempCell.cellStyle.setFont(boldFont)
CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER)
CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom)
tempCell = sheet.createRow(rowIndex).createCell(1)
CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom)
rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Total Normal Hours [A]")
// cellStyle.setFont(boldFont)
cellStyle.alignment = HorizontalAlignment.CENTER
}
tempCell = sheet.createRow(rowIndex).createCell(0)
tempCell.setCellValue("Total Normal Hours [A]")
CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER)

var normalConsumed = 0.0
var otConsumed = 0.0
var leaveHours = 0.0
if (timesheets.isNotEmpty()) {
timesheets.forEach { t ->
normalConsumed += t.normalConsumed!!
otConsumed += t.otConsumed!!
otConsumed += t.otConsumed ?: 0.0
}
}
sheet.getRow(rowIndex).getCell(2).apply {
setCellValue(normalConsumed)
cellStyle.alignment = HorizontalAlignment.CENTER
cellStyle.dataFormat = accountingStyle
}
sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1))
tempCell = sheet.createRow(rowIndex).createCell(2)
tempCell.setCellValue(normalConsumed)
tempCell.cellStyle.dataFormat = accountingStyle

sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
//
rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Total Other Hours [B]")
cellStyle.setFont(boldFont)
cellStyle.alignment = HorizontalAlignment.CENTER
}
sheet.getRow(rowIndex).getCell(2).apply {
setCellValue(otConsumed)
cellStyle.alignment = HorizontalAlignment.CENTER
cellStyle.dataFormat = accountingStyle
}
tempCell = sheet.createRow(rowIndex).createCell(0)
tempCell.setCellValue("Total Other Hours [B]")
CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER)
tempCell.cellStyle.setFont(boldFont)
tempCell = sheet.createRow(rowIndex).createCell(2)
tempCell.setCellValue(otConsumed)
tempCell.cellStyle.dataFormat = accountingStyle


sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1))

// Total Leave Hours
rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Total Leave Hours")
cellStyle.alignment = HorizontalAlignment.CENTER
}
tempCell = sheet.createRow(rowIndex).createCell(0)
tempCell.setCellValue("Total Leave Hours")
CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER)
sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
if (leaves.isNotEmpty()) {
leaves.forEach { l ->
leaveHours += l.leaveHours!!
}
}
sheet.getRow(rowIndex).getCell(2).apply {
setCellValue(leaveHours)
cellStyle.dataFormat = accountingStyle
}
tempCell = sheet.createRow(rowIndex).createCell(2)
tempCell.setCellValue(leaveHours)
tempCell.cellStyle.dataFormat = accountingStyle

// Total Spent Manhours
rowIndex += 1
sheet.getRow(rowIndex).getCell(0).apply {
setCellValue("Total Spent Manhours [A+B]")
cellStyle.setFont(boldFont)
cellStyle.alignment = HorizontalAlignment.CENTER
// cellStyle.borderTop = BorderStyle.THIN
// cellStyle.borderBottom = BorderStyle.DOUBLE
}
sheet.getRow(rowIndex).getCell(2).apply {
cellFormula = "C${rowIndex - 2}+C${rowIndex - 1}"
cellStyle.dataFormat = accountingStyle
// cellStyle.borderTop = BorderStyle.THIN
// cellStyle.borderBottom = BorderStyle.DOUBLE
}
sheet.addMergedRegion(CellRangeAddress(rowIndex, rowIndex, 0, 1))
tempCell = sheet.createRow(rowIndex).createCell(0)
tempCell.setCellValue("Total Spent Manhours [A+B]")
tempCell.cellStyle.setFont(boldFont)
CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER)
CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom)
tempCell = sheet.createRow(rowIndex).createCell(1)
CellUtil.setAlignment(tempCell, HorizontalAlignment.CENTER)
CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom)

tempCell = sheet.createRow(rowIndex).createCell(2)
tempCell.cellFormula = "C${rowIndex-2}+C${rowIndex-1}"
tempCell.cellStyle.dataFormat = accountingStyle
CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom)

sheet.addMergedRegion(CellRangeAddress(rowIndex,rowIndex , 0, 1))
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
rowIndex = 7
columnIndex = 2
projectList.forEachIndexed { index, title ->
sheet.getRow(7).getCell(columnIndex + index).apply {
setCellValue(title)
}
tempCell = sheet.createRow(7).createCell(columnIndex + index)
tempCell.setCellValue(title)
CellUtil.setAlignment(tempCell, HorizontalAlignment.RIGHT)
CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom)
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (timesheets.isNotEmpty()) {
projectList.forEach { _ ->
for (i in 0 until rowSize) {
tempCell = sheet.createRow(8 + i).createCell(columnIndex)
tempCell.setCellValue(0.0)
tempCell.cellStyle.dataFormat = accountingStyle
}
timesheets.forEach { timesheet ->
dayInt = timesheet.recordDate!!.dayOfMonth
sheet.getRow(dayInt.plus(7)).getCell(columnIndex).apply {
setCellValue(timesheet.normalConsumed!!)
}
tempCell = sheet.createRow(dayInt.plus(7)).createCell(columnIndex)
tempCell.setCellValue(timesheet.normalConsumed!!)
}
columnIndex++
}
}
// dates
if (leaves.isNotEmpty()) {
leaves.forEach { leave ->
dayInt = leave.recordDate!!.dayOfMonth
sheet.getRow(dayInt.plus(7)).getCell(columnIndex).apply {
setCellValue(leave.leaveHours!!)
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
sheet.getRow(rowIndex).apply {
getCell(columnIndex).setCellValue("Leave Hours")
getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER
for (i in 0 until rowSize) {
tempCell = sheet.createRow(8 + i).createCell(columnIndex)
tempCell.setCellValue(0.0)
tempCell.cellStyle.dataFormat = accountingStyle

columnIndex += 1
getCell(columnIndex).setCellValue("Daily Manhour Spent\n" + "(Excluding Leave Hours)")
getCell(columnIndex).cellStyle.alignment = HorizontalAlignment.CENTER
columnSize = columnIndex
}
sheet.addMergedRegion(CellRangeAddress(6, 6, 2, columnIndex))
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
for (i in 2 until columnIndex) {
for (k in 0 until rowSize) {
sheet.getRow(8 + k).getCell(i).apply {
setCellValue(0.0)
cellStyle.dataFormat = accountingStyle
}
dayInt = leave.recordDate!!.dayOfMonth
tempCell = sheet.createRow(dayInt.plus(7)).createCell(columnIndex)
tempCell.setCellValue(leave.leaveHours!!)

}
}
///////////////////////////////////////////////////////// Leave Hours ////////////////////////////////////////////////////////////////////
tempCell = sheet.createRow(rowIndex).createCell(columnIndex)
tempCell.setCellValue("Leave Hours")
CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom)

columnIndex += 1
tempCell = sheet.createRow(rowIndex).createCell(columnIndex)
tempCell.setCellValue("Daily Manhour Spent\n(Excluding Leave Hours)")
CellUtil.setCellStyleProperties(tempCell, ThinBorderBottom)

sheet.addMergedRegion(CellRangeAddress(6,6 , 2, columnIndex))
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
rowIndex = 8
if (sheet.getRow(rowIndex - 1).getCell(2).stringCellValue != "Leave Hours") {
// cal daily spent manhour
for (i in 0 until rowSize) {
val cell =
sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex)
cell?.cellFormula =
"SUM(${getColumnAlphabet(2)}${rowIndex + 1}:${getColumnAlphabet(columnIndex)}${rowIndex + 1})" // should columnIndex - 2
rowIndex++
}
// cal subtotal
for (i in 0 until columnSize) { // minus last col
val cell = sheet.getRow(rowIndex)?.getCell(2) ?: sheet.getRow(rowIndex)?.createCell(2)
cell?.cellFormula =
"SUM(${getColumnAlphabet(2)}${rowIndex}:${getColumnAlphabet(columnIndex + i)}${rowIndex})"
cell?.cellStyle?.dataFormat = accountingStyle
cell?.cellStyle?.setFont(boldFont)
// cell?.cellStyle?.borderTop = BorderStyle.THIN
// cell?.cellStyle?.borderBottom = BorderStyle.DOUBLE
}
} else { // just for preview when no data
// if (sheet.createRow(rowIndex - 1).getCell(2).stringCellValue != "Leave Hours") {
// cal daily spent manhour
for (i in 0 until rowSize) {
val cell =
sheet.getRow(rowIndex)?.getCell(columnIndex) ?: sheet.getRow(rowIndex + i)?.createCell(columnIndex)
cell?.setCellValue("daily spent manhour")
tempCell = sheet.createRow(rowIndex).createCell(columnIndex)
tempCell.cellFormula = "SUM(${getColumnAlphabet(2)}${rowIndex+1}:${getColumnAlphabet(columnIndex - 2)}${rowIndex+1})" // should columnIndex - 2
rowIndex++
}
// cal subtotal
for (i in 0 until columnSize) { // minus last col
val cell = sheet.getRow(rowIndex)?.getCell(2) ?: sheet.getRow(rowIndex)?.createCell(2)
cell?.setCellValue("testing subtotal")
cell?.cellStyle?.dataFormat = accountingStyle
cell?.cellStyle?.setFont(boldFont)
// cell?.cellStyle?.borderTop = BorderStyle.THIN
// cell?.cellStyle?.borderBottom = BorderStyle.DOUBLE
}
println(rowIndex)
for (i in 0 until columnSize - 2) { // minus last col
tempCell = sheet.createRow(rowIndex).createCell(2 + i)
tempCell.cellFormula = "SUM(${getColumnAlphabet(2 + i)}9:${getColumnAlphabet(2 + i)}${rowIndex})"
tempCell.cellStyle.dataFormat = accountingStyle
tempCell.cellStyle.setFont(boldFont)
CellUtil.setCellStyleProperties(tempCell, DoubleBorderBottom)
// }
}
return workbook
}
@@ -647,16 +635,15 @@ open class ReportService(
}

private fun createLateStartReport(
project: Project,
project: Project?,
templatePath: String
):Workbook{

project
val resource = ClassPathResource(templatePath)
val templateInputStream = resource.inputStream
val workbook: Workbook = XSSFWorkbook(templateInputStream)
val sheet = workbook.getSheetAt(0)
// Formatting the current date to "YYYY/MM/DD" and setting it to cell C2
val formattedToday = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"))
val dateCell = sheet.getRow(1)?.getCell(2) ?: sheet.getRow(1).createCell(2)
@@ -674,7 +661,7 @@ open class ReportService(
// projectDataRow.createCell(5).setCellValue(
// project.planStart?.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")) ?: "N/A" // Column F
// )
// Styling for cell A1: Font size 16 and bold
val headerFont = workbook.createFont().apply {
bold = true


+ 2
- 1
src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt Vedi File

@@ -83,6 +83,7 @@ class ReportController(
val projects = timesheetRepository.findDistinctProjectTaskByStaffAndRecordDateBetweenOrderByRecordDate(staff, thisMonth, nextMonth)
val projectList: List<String> = projects.map { p -> "${p.projectTask!!.project!!.code}\n ${p.projectTask!!.project!!.name}" }


val reportResult: ByteArray = excelReportService.generateStaffMonthlyWorkHourAnalysisReport(thisMonth, staff, timesheets, leaves, projectList)
// val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
return ResponseEntity.ok()
@@ -99,7 +100,7 @@ class ReportController(

@PostMapping("/downloadLateStartReport")
fun downloadLateStartReport(): ResponseEntity<ByteArrayResource> {
val reportBytes = excelReportService.generateLateStartReport(Project())
val reportBytes = excelReportService.generateLateStartReport(null)
val headers = HttpHeaders()
headers.add("Content-Disposition", "attachment; filename=Late_Start_Report_${LocalDate.now()}.xlsx")



+ 23
- 1
src/main/java/com/ffii/tsms/modules/user/web/UserController.java Vedi File

@@ -131,7 +131,6 @@ public class UserController{
// })
@PatchMapping("/change-password")
@ResponseStatus(HttpStatus.NO_CONTENT)
// @PreAuthorize("hasAuthority('MAINTAIN_USER')")
public void changePassword(@RequestBody @Valid ChangePwdReq req) {
long id = SecurityUtils.getUser().get().getId();
User instance = userService.find(id).orElseThrow(NotFoundException::new);
@@ -151,6 +150,26 @@ public class UserController{
userService.save(instance);
}

@PatchMapping("/admin-change-password")
@ResponseStatus(HttpStatus.NO_CONTENT)
@PreAuthorize("hasAuthority('MAINTAIN_USER')")
public void adminChangePassword(@RequestBody @Valid ChangePwdReq req) {
long id = req.getId();
User instance = userService.find(id).orElseThrow(NotFoundException::new);

logger.info("TEST req: "+req.getPassword());
logger.info("TEST instance: "+instance.getPassword());
// if (!passwordEncoder.matches(req.getPassword(), instance.getPassword())) {
// throw new BadRequestException();
// }
PasswordRule rule = new PasswordRule(settingsService);
if (!PasswordUtils.checkPwd(req.getNewPassword(), rule)) {
throw new UnprocessableEntityException(ErrorCodes.USER_WRONG_NEW_PWD);
}
instance.setPassword(passwordEncoder.encode(req.getNewPassword()));
userService.save(instance);
}

// @Operation(summary = "reset password", responses = {
// @ApiResponse(responseCode = "204"),
// @ApiResponse(responseCode = "404", content = @Content),
@@ -170,11 +189,14 @@ public class UserController{
}

public static class ChangePwdReq {
private Long id;
@NotBlank
private String password;
@NotBlank
private String newPassword;

public Long getId() { return id; }
public Long setId(Long id) { return this.id = id; }
public String getPassword() {
return password;
}


Caricamento…
Annulla
Salva