From e69bf306531f5a16e55df82f433999010c3d3344 Mon Sep 17 00:00:00 2001 From: "DESKTOP\\derek" Date: Mon, 17 Feb 2025 17:03:15 +0800 Subject: [PATCH 1/7] update filter for mail --- .../modules/common/mail/service/MailReminderService.kt | 8 ++++---- .../ffii/tsms/modules/data/entity/StaffRepository.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt b/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt index 83749d9..5cce160 100644 --- a/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt +++ b/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt @@ -128,7 +128,7 @@ open class MailReminderService( hours = it["hours"].toString().toDouble() ) } - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} val teams = teamRepository.findAll().filter { team -> team.deleted == false // && ( team.code == "WY" || team.code == "TW" || team.code == "CH" || team.code == "MN" || team.code == "MC" ) } @@ -202,7 +202,7 @@ open class MailReminderService( hours = it["hours"].toString().toDouble() ) } - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} val teams = teamRepository.findAll().filter { team -> team.deleted == false // && ( team.code == "WY" || team.code == "TW" || team.code == "CH" || team.code == "MN" || team.code == "MC" ) } @@ -307,7 +307,7 @@ open class MailReminderService( ) } // val timesheet = timesheetRepository.findByDeletedFalseAndRecordDateBetweenOrderByRecordDate(sevenDaysBefore, fourDaysBefore) - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} val staffIds: List = staffs.map { it.id as Long } val timesheetByIdAndRecord = timesheet.groupBy { it.staffId to it.recordDate @@ -382,7 +382,7 @@ open class MailReminderService( val timesheet = timesheetRepository.findByDeletedFalseAndRecordDateBetweenOrderByRecordDate(sevenDaysBefore,fourDaysBefore) // just getting my own staff record // change it back later - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME) + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME) val staffIds: List = staffs.map { it.id as Long } val timesheetByIdAndRecord = timesheet.groupBy { it.staff?.id to it.recordDate } diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java index 2750a7f..fed8675 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java @@ -24,7 +24,7 @@ public interface StaffRepository extends AbstractRepository { Optional findByUserId(@Param("userId") Long userId); Optional> findAllByTeamIdAndDeletedFalse(Long id); - List findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(@Param("employType") String employType); + List findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(@Param("employType") String employType); Optional> findAllByDeletedFalse(); From a08ddab2abd725ceae9ec6c472479dd9d1cae7c8 Mon Sep 17 00:00:00 2001 From: "DESKTOP\\derek" Date: Mon, 17 Feb 2025 17:09:21 +0800 Subject: [PATCH 2/7] update email filter list --- .../modules/common/mail/service/MailReminderService.kt | 8 ++++---- .../ffii/tsms/modules/data/entity/StaffRepository.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt b/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt index 5cce160..e33f836 100644 --- a/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt +++ b/src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt @@ -128,7 +128,7 @@ open class MailReminderService( hours = it["hours"].toString().toDouble() ) } - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team?.code != "HO"} val teams = teamRepository.findAll().filter { team -> team.deleted == false // && ( team.code == "WY" || team.code == "TW" || team.code == "CH" || team.code == "MN" || team.code == "MC" ) } @@ -202,7 +202,7 @@ open class MailReminderService( hours = it["hours"].toString().toDouble() ) } - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team?.code != "HO"} val teams = teamRepository.findAll().filter { team -> team.deleted == false // && ( team.code == "WY" || team.code == "TW" || team.code == "CH" || team.code == "MN" || team.code == "MC" ) } @@ -307,7 +307,7 @@ open class MailReminderService( ) } // val timesheet = timesheetRepository.findByDeletedFalseAndRecordDateBetweenOrderByRecordDate(sevenDaysBefore, fourDaysBefore) - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team.code != "HO"} + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME).filter { it.staffId != "A003" && it.staffId != "A004" && it.staffId != "B011" }.filter{ it.team?.code != "HO"} val staffIds: List = staffs.map { it.id as Long } val timesheetByIdAndRecord = timesheet.groupBy { it.staffId to it.recordDate @@ -382,7 +382,7 @@ open class MailReminderService( val timesheet = timesheetRepository.findByDeletedFalseAndRecordDateBetweenOrderByRecordDate(sevenDaysBefore,fourDaysBefore) // just getting my own staff record // change it back later - val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(FULLTIME) + val staffs = staffRepository.findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(FULLTIME) val staffIds: List = staffs.map { it.id as Long } val timesheetByIdAndRecord = timesheet.groupBy { it.staff?.id to it.recordDate } diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java index fed8675..2750a7f 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java @@ -24,7 +24,7 @@ public interface StaffRepository extends AbstractRepository { Optional findByUserId(@Param("userId") Long userId); Optional> findAllByTeamIdAndDeletedFalse(Long id); - List findAllByEmployTypeAndDeletedFalseAndDepartDateIsNullAndTeamIdIsNotNull(@Param("employType") String employType); + List findAllByEmployTypeAndDeletedFalseAndDepartDateIsNull(@Param("employType") String employType); Optional> findAllByDeletedFalse(); From 4f23570a7b835f66c1f0119f6850ad57692a5538 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Mon, 17 Feb 2025 18:59:34 +0800 Subject: [PATCH 3/7] 1. client & subsidiary (master, project) will be ordered by name 2. timesheet amendment - staff selection - sort by staffId 3. if the staff is not a teamlead but have authority to edit timesheet amendment, the staff will be not able to view/edit others. 4. update the checking of depart date --- .../data/entity/CustomerRepository.java | 2 +- .../modules/data/entity/StaffRepository.java | 2 + .../data/entity/SubsidiaryRepository.java | 2 +- .../modules/data/service/CustomerService.kt | 2 +- .../modules/data/service/StaffsService.kt | 7 ++- .../modules/data/service/SubsidiaryService.kt | 2 +- .../timesheet/service/TimesheetsService.kt | 44 +++++++++++-------- 7 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/CustomerRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/CustomerRepository.java index 58355b6..c1cb9a8 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/CustomerRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/CustomerRepository.java @@ -9,7 +9,7 @@ import org.springframework.data.repository.query.Param; import com.ffii.core.support.AbstractRepository; public interface CustomerRepository extends AbstractRepository { - List findAllByDeletedFalse(); + List findAllByDeletedFalseOrderByNameAsc(); Optional findByCode(@Param("code") String code); Optional findByName(@Param("name") String name); diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java index 2750a7f..8593e12 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java @@ -28,6 +28,8 @@ public interface StaffRepository extends AbstractRepository { Optional> findAllByDeletedFalse(); + Optional> findAllByIdInAndDeletedFalse(List id); + Optional findIdAndNameByUserIdAndDeletedFalse(Long id); } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/SubsidiaryRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/SubsidiaryRepository.java index 9edc95c..fe9e2ba 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/SubsidiaryRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/SubsidiaryRepository.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.Optional; public interface SubsidiaryRepository extends AbstractRepository { - List findAllByDeletedFalse(); + List findAllByDeletedFalseOrderByNameAsc(); List findAllByDeletedFalseAndIdIn(List id); diff --git a/src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt b/src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt index e0fee79..a0df3dc 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt @@ -23,7 +23,7 @@ open class CustomerService( ) : AbstractBaseEntityService(jdbcDao, customerRepository){ open fun allCustomers(): List { - return customerRepository.findAllByDeletedFalse() + return customerRepository.findAllByDeletedFalseOrderByNameAsc() } open fun allCustomerTypes(): List { diff --git a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt index 7132867..ba51d7d 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt @@ -97,8 +97,13 @@ open class StaffsService( } open fun findAll(): Optional> { - return staffRepository.findAllByDeletedFalse() + return staffRepository.findAllByDeletedFalse(); } + + open fun findAllByIdIn(ids: List): Optional> { + return staffRepository.findAllByIdInAndDeletedFalse(ids); + } + open fun getStaff(args: Map): Optional>? { val sql = StringBuilder("select" + " s.id as id," diff --git a/src/main/java/com/ffii/tsms/modules/data/service/SubsidiaryService.kt b/src/main/java/com/ffii/tsms/modules/data/service/SubsidiaryService.kt index 23f53c6..1b9d0d0 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/SubsidiaryService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/SubsidiaryService.kt @@ -23,7 +23,7 @@ open class SubsidiaryService( private val subsidiaryContactService: SubsidiaryContactService, ) : AbstractBaseEntityService(jdbcDao, subsidiaryRepository) { open fun allSubsidiaries(): List { - return subsidiaryRepository.findAllByDeletedFalse() + return subsidiaryRepository.findAllByDeletedFalseOrderByNameAsc() } open fun allSubsidiaryTypes(): List { diff --git a/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt b/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt index 5573028..8735d33 100644 --- a/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt +++ b/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt @@ -129,29 +129,37 @@ open class TimesheetsService( open fun getTeamMemberTimesheet(): Map { val authorities = staffsService.currentAuthorities() ?: return emptyMap() + if (authorities.stream().anyMatch { it.authority.equals("MAINTAIN_TIMESHEET") }) { val currentStaff = staffsService.currentStaff() - // Get team where current staff is team lead - - val myTeam = if (currentStaff != null) teamService.getMyTeamForStaff(currentStaff) else null - val teamMembers = if (myTeam != null) { - staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) - } else { - staffsService.findAll().getOrDefault(emptyList()) - } + if (currentStaff != null) { + val isTeamLead = currentStaff.team.staff.id?.equals(currentStaff.id) + // Get team where current staff is team lead + + val myTeam = teamService.getMyTeamForStaff(currentStaff) + val teamMembers = if (myTeam != null && isTeamLead == true) { + staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) + } else if (isTeamLead != true) { + staffsService.findAllByIdIn(listOf(currentStaff.id!!)).getOrDefault(emptyList()) + } else { + staffsService.findAll().getOrDefault(emptyList()) + } - return teamMembers.filter { it.departDate == null }.associate { member -> - Pair( - member.id!!, - TeamMemberTimeEntries( - staffId = member.staffId, - name = member.name, - timeEntries = transformToTimeEntryMap(timesheetRepository.findAllByStaff(member)), - employType = member.employType + return teamMembers.filter { it.departDate == null || it.departDate > LocalDate.now() }.sortedBy { it.staffId }.associate { member -> + Pair( + member.id!!, + TeamMemberTimeEntries( + staffId = member.staffId, + name = member.name, + timeEntries = transformToTimeEntryMap(timesheetRepository.findAllByStaff(member)), + employType = member.employType + ) ) - ) + } } - } else return emptyMap() + } + + return emptyMap() } private fun transformToTimeEntryMap(timesheets: List): Map> { From c8ad56f707fe55390e206c89e2b5314eaf31974f Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Tue, 18 Feb 2025 16:24:40 +0800 Subject: [PATCH 4/7] 1. add authority for normal staff to view/edit timesheet amendment --- .../modules/timesheet/service/LeaveService.kt | 12 +++-- .../timesheet/service/TimesheetsService.kt | 47 +++++++++---------- .../20250218_01_cyril/01_add_authority.sql | 5 ++ 3 files changed, 37 insertions(+), 27 deletions(-) create mode 100644 src/main/resources/db/changelog/changes/20250218_01_cyril/01_add_authority.sql diff --git a/src/main/java/com/ffii/tsms/modules/timesheet/service/LeaveService.kt b/src/main/java/com/ffii/tsms/modules/timesheet/service/LeaveService.kt index 0d3232d..d0b9430 100644 --- a/src/main/java/com/ffii/tsms/modules/timesheet/service/LeaveService.kt +++ b/src/main/java/com/ffii/tsms/modules/timesheet/service/LeaveService.kt @@ -101,18 +101,24 @@ open class LeaveService( open fun getTeamMemberLeave(): Map { val authorities = staffsService.currentAuthorities() ?: return emptyMap() - if (authorities.stream().anyMatch { it.authority.equals("MAINTAIN_TIMESHEET") }) { + val authMaintainTimesheet = authorities.any { it.authority.equals("MAINTAIN_TIMESHEET") } + val authMaintainTimesheetSelf = authorities.any { it.authority.equals("MAINTAIN_TIMESHEET_SELF") } + +// if (authorities.stream().anyMatch { it.authority.equals("MAINTAIN_TIMESHEET") }) { + if (authMaintainTimesheet || authMaintainTimesheetSelf) { val currentStaff = staffsService.currentStaff() // Get team where current staff is team lead val myTeam = if (currentStaff != null) teamService.getMyTeamForStaff(currentStaff) else null - val teamMembers = if (myTeam != null) { + val teamMembers = if (myTeam != null && authMaintainTimesheet) { staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) + } else if (authMaintainTimesheetSelf) { + staffsService.findAllByIdIn(listOf(currentStaff?.id!!)).getOrDefault(emptyList()) } else { staffsService.findAll().getOrDefault(emptyList()) } - return teamMembers.filter { it.departDate == null }.associate { member -> + return teamMembers.filter { it.departDate == null || it.departDate > LocalDate.now() }.sortedBy { it.staffId }.associate { member -> Pair( member.id!!, TeamMemberLeaveEntries( diff --git a/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt b/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt index 8735d33..f8c4949 100644 --- a/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt +++ b/src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt @@ -129,33 +129,32 @@ open class TimesheetsService( open fun getTeamMemberTimesheet(): Map { val authorities = staffsService.currentAuthorities() ?: return emptyMap() - - if (authorities.stream().anyMatch { it.authority.equals("MAINTAIN_TIMESHEET") }) { + val authMaintainTimesheet = authorities.any { it.authority.equals("MAINTAIN_TIMESHEET") } + val authMaintainTimesheetSelf = authorities.any { it.authority.equals("MAINTAIN_TIMESHEET_SELF") } +// if (authorities.stream().anyMatch { it.authority.equals("MAINTAIN_TIMESHEET") }) { + if (authMaintainTimesheet || authMaintainTimesheetSelf) { val currentStaff = staffsService.currentStaff() - if (currentStaff != null) { - val isTeamLead = currentStaff.team.staff.id?.equals(currentStaff.id) - // Get team where current staff is team lead - - val myTeam = teamService.getMyTeamForStaff(currentStaff) - val teamMembers = if (myTeam != null && isTeamLead == true) { - staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) - } else if (isTeamLead != true) { - staffsService.findAllByIdIn(listOf(currentStaff.id!!)).getOrDefault(emptyList()) - } else { - staffsService.findAll().getOrDefault(emptyList()) - } - return teamMembers.filter { it.departDate == null || it.departDate > LocalDate.now() }.sortedBy { it.staffId }.associate { member -> - Pair( - member.id!!, - TeamMemberTimeEntries( - staffId = member.staffId, - name = member.name, - timeEntries = transformToTimeEntryMap(timesheetRepository.findAllByStaff(member)), - employType = member.employType - ) + // Get team where current staff is team lead + val myTeam = if (currentStaff != null) teamService.getMyTeamForStaff(currentStaff) else null + val teamMembers = if (myTeam != null && authMaintainTimesheet) { + staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) + } else if (authMaintainTimesheetSelf) { + staffsService.findAllByIdIn(listOf(currentStaff?.id!!)).getOrDefault(emptyList()) + } else { + staffsService.findAll().getOrDefault(emptyList()) + } + + return teamMembers.filter { it.departDate == null || it.departDate > LocalDate.now() }.sortedBy { it.staffId }.associate { member -> + Pair( + member.id!!, + TeamMemberTimeEntries( + staffId = member.staffId, + name = member.name, + timeEntries = transformToTimeEntryMap(timesheetRepository.findAllByStaff(member)), + employType = member.employType ) - } + ) } } diff --git a/src/main/resources/db/changelog/changes/20250218_01_cyril/01_add_authority.sql b/src/main/resources/db/changelog/changes/20250218_01_cyril/01_add_authority.sql new file mode 100644 index 0000000..c7b8dfa --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250218_01_cyril/01_add_authority.sql @@ -0,0 +1,5 @@ +-- liquibase formatted sql +-- changeset cyril:add_authority + +INSERT INTO `authority` (`authority`, `name`) VALUES + ('MAINTAIN_TIMESHEET_SELF', 'Maintain Self Timesheet'); \ No newline at end of file From 2abe8260521fda76d238ccaec89cb40fad9bcccd Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Wed, 19 Feb 2025 15:47:47 +0800 Subject: [PATCH 5/7] update project status (copy function) --- .../com/ffii/tsms/modules/project/service/ProjectsService.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt b/src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt index 09bb101..39edddc 100644 --- a/src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt +++ b/src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt @@ -246,7 +246,8 @@ open class ProjectsService( if (this.status == "Completed") "On-going" else "Completed" ) else if (this.actualStart != null) "On-going" - else request.projectStatus ?: "Pending To Start" + else if (request.projectStatus.isNullOrBlank()) "Pending To Start" + else request.projectStatus isClpProject = request.isClpProject this.mainProject = mainProject From 62d066503bbc409963cd2a0ee9c7991091be8b43 Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Tue, 25 Feb 2025 16:21:46 +0800 Subject: [PATCH 6/7] remove subContractFee for finanicial summary --- .../java/com/ffii/tsms/modules/data/service/DashboardService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt b/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt index e8bfd48..c9af7f8 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt @@ -3989,7 +3989,7 @@ open class DashboardService( + " c.code as customerCode, " + " su.name as subsidiary, " + " coalesce(pf.projectFee, 0) as totalFee, " - + " (coalesce(pf.projectFee, 0) - ifnull(p.subContractFee, 0)) * 0.8 as totalBudget, " + + " coalesce(pf.projectFee, 0) * 0.8 as totalBudget, " + " coalesce(me.manhourExpense, 0) as manhourExpense, " + " coalesce(id.invoicedAmount, 0) as invoicedAmount, " // + " coalesce(id.uninvoicedAmount, 0) as uninvoicedAmount, " From f6e4f10f8783ed3d2b3b0156b6d332d0a606d12b Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Thu, 27 Feb 2025 17:24:49 +0800 Subject: [PATCH 7/7] update item row147 --- .../data/entity/GradeLogRepository.java | 1 + .../data/entity/PositionLogRepository.java | 2 +- .../data/entity/TeamLogRepository.java | 3 + .../modules/data/service/GradeLogService.kt | 36 ++++- .../data/service/PositionLogService.kt | 33 ++++- .../modules/data/service/StaffsService.kt | 123 +++++++----------- .../modules/data/service/TeamLogService.kt | 35 ++++- .../data/web/models/NewStaffRequest.kt | 9 +- 8 files changed, 146 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/GradeLogRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/GradeLogRepository.java index 4ae08ac..d3e9457 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/GradeLogRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/GradeLogRepository.java @@ -10,6 +10,7 @@ public interface GradeLogRepository extends AbstractRepository { List findGradeLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); GradeLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); + void deleteAllByStaff(Staff staff); List findByDeletedFalseAndFromBeforeAndToIsNullOrToAfter(LocalDate before, LocalDate after); // fun findByDeletedFalseAndRecordDateBetweenOrderByRecordDate(start: LocalDate, end: LocalDate): List } diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/PositionLogRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/PositionLogRepository.java index 4909889..c244527 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/PositionLogRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/PositionLogRepository.java @@ -8,7 +8,7 @@ import java.util.List; public interface PositionLogRepository extends AbstractRepository { List findPositionLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); - + void deleteAllByStaff(Staff staff); PositionLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); } diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/TeamLogRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/TeamLogRepository.java index 7e151b7..f8ee964 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/TeamLogRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/TeamLogRepository.java @@ -8,4 +8,7 @@ import java.util.List; public interface TeamLogRepository extends AbstractRepository { List findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); TeamLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); + + void deleteAllByStaff(Staff staff); + } diff --git a/src/main/java/com/ffii/tsms/modules/data/service/GradeLogService.kt b/src/main/java/com/ffii/tsms/modules/data/service/GradeLogService.kt index 9ec034d..3a9a556 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/GradeLogService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/GradeLogService.kt @@ -2,14 +2,11 @@ package com.ffii.tsms.modules.data.service import com.ffii.core.support.AbstractBaseEntityService import com.ffii.core.support.JdbcDao -import com.ffii.tsms.modules.data.entity.Department -import com.ffii.tsms.modules.data.entity.DepartmentRepository -import com.ffii.tsms.modules.data.entity.GradeLog -import com.ffii.tsms.modules.data.entity.GradeLogRepository -import com.ffii.tsms.modules.data.entity.GradeRepository +import com.ffii.tsms.modules.data.entity.* import com.ffii.tsms.modules.data.entity.projections.GradeLogInfo import com.ffii.tsms.modules.data.web.models.GradeHistory import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service open class GradeLogService( @@ -18,8 +15,35 @@ open class GradeLogService( private val jdbcDao: JdbcDao, ) : AbstractBaseEntityService(jdbcDao, gradeLogRepository) { open fun allGradeLog(staffId: Long): List { - return gradeLogRepository.findGradeLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId).drop(1) + return gradeLogRepository.findGradeLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId) } + + @Transactional + open fun saveGradeLogs(staff: Staff, entries: List) { + try { + // replace grade log data by delete all and add + gradeLogRepository.deleteAllByStaff(staff) + + val sortedEntries = entries.sortedBy { it.from } + val gradeEntries = mutableListOf() + sortedEntries.forEachIndexed { index, it -> + val grade = gradeRepository.findById(it.grade).orElseThrow() + val gradeLog = GradeLog().apply { + this.staff = staff + this.grade = grade + this.from = it.from + } + if (index > 0) { + gradeEntries[index - 1].to = it.from + } + gradeEntries.add(gradeLog) + } + gradeLogRepository.saveAll(gradeEntries) + } catch (e: Exception) { + throw Exception("Error saving grade logs", e) + } + } + open fun editGradeLog(gradeHistory: List, delGradeHistory: List) { if (delGradeHistory.isNotEmpty()) { delGradeHistory.forEach { diff --git a/src/main/java/com/ffii/tsms/modules/data/service/PositionLogService.kt b/src/main/java/com/ffii/tsms/modules/data/service/PositionLogService.kt index ff1c1bc..8a41e32 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/PositionLogService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/PositionLogService.kt @@ -2,12 +2,11 @@ package com.ffii.tsms.modules.data.service import com.ffii.core.support.AbstractBaseEntityService import com.ffii.core.support.JdbcDao -import com.ffii.tsms.modules.data.entity.PositionLog -import com.ffii.tsms.modules.data.entity.PositionLogRepository -import com.ffii.tsms.modules.data.entity.PositionRepository +import com.ffii.tsms.modules.data.entity.* import com.ffii.tsms.modules.data.entity.projections.PositionLogInfo import com.ffii.tsms.modules.data.web.models.PositionHistory import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service @@ -17,7 +16,33 @@ open class PositionLogService ( private val jdbcDao: JdbcDao, ) : AbstractBaseEntityService(jdbcDao, positionLogRepository) { open fun allPositionLog(staffId: Long): List { - return positionLogRepository.findPositionLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId).drop(1) + return positionLogRepository.findPositionLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId) + } + + @Transactional + open fun savePositionLogs(staff: Staff, entries: List) { + try { + // replace team log data by delete all and add + positionLogRepository.deleteAllByStaff(staff) + + val sortedEntries = entries.sortedBy { it.from } + val positionEntries = mutableListOf() + sortedEntries.forEachIndexed { index, it -> + val position = positionRepository.findById(it.position).orElseThrow() + val positionLog = PositionLog().apply { + this.staff = staff + this.position = position + this.from = it.from + } + if (index > 0) { + positionEntries[index - 1].to = it.from + } + positionEntries.add(positionLog) + } + positionLogRepository.saveAll(positionEntries) + } catch (e: Exception) { + throw Exception("Error saving position logs", e) + } } open fun editPositionLog(positionHistory: List, delPositionHistory: List) { diff --git a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt index ba51d7d..a9e0e35 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt @@ -4,15 +4,12 @@ import com.ffii.core.exception.UnprocessableEntityException import com.ffii.core.support.AbstractBaseEntityService import com.ffii.core.support.JdbcDao import com.ffii.tsms.modules.common.SecurityUtils -import com.ffii.tsms.modules.common.SettingNames -import com.ffii.tsms.modules.common.mail.pojo.MailRequest import com.ffii.tsms.modules.data.entity.* import com.ffii.tsms.modules.data.entity.projections.StaffSearchInfo import com.ffii.tsms.modules.data.web.models.NewStaffRequest import com.ffii.tsms.modules.data.web.models.SalaryEffectiveInfo import com.ffii.tsms.modules.user.entity.User import com.ffii.tsms.modules.user.entity.UserRepository -import jakarta.mail.internet.InternetAddress import org.springframework.scheduling.annotation.Scheduled import org.springframework.security.core.GrantedAuthority import org.springframework.security.crypto.password.PasswordEncoder @@ -140,14 +137,18 @@ open class StaffsService( throw UnprocessableEntityException("Duplicated StaffId Found") } } - val currentPosition = positionRepository.findById(req.currentPositionId).orElseThrow() +// val currentPosition = positionRepository.findById(req.currentPositionId).orElseThrow() val joinPosition = if (req.joinPositionId != null && req.joinPositionId > 0L) positionRepository.findById(req.joinPositionId).orElseThrow() else null val company = companyRepository.findById(req.companyId).orElseThrow() - val grade = gradeRepository.findById(req.gradeId).orElseThrow() - val team = if (req.teamId != null && req.teamId > 0L) teamRepository.findById(req.teamId).orElseThrow() else null - val salary = salaryRepository.findBySalaryPoint(req.salaryId).orElseThrow() +// val grade = gradeRepository.findById(req.gradeId).orElseThrow() +// val team = if (req.teamId != null && req.teamId > 0L) teamRepository.findById(req.teamId).orElseThrow() else null +// val salary = salaryRepository.findBySalaryPoint(req.salaryId).orElseThrow() val department = if (req.departmentId != null && req.departmentId > 0L) departmentRepository.findById(req.departmentId).orElseThrow() else null + val salary = if (!req.salaryEffectiveInfo.isNullOrEmpty()) salaryRepository.findBySalaryPoint(req.salaryEffectiveInfo.last().salaryPoint).orElseThrow() else null + val team = if (!req.teamHistory.isNullOrEmpty()) teamRepository.findById(req.teamHistory.last().team).orElseThrow() else null + val grade = if (!req.gradeHistory.isNullOrEmpty()) gradeRepository.findById(req.gradeHistory.last().grade).orElseThrow() else null + val currentPosition = if (!req.positionHistory.isNullOrEmpty()) positionRepository.findById(req.positionHistory.last().position).orElseThrow() else null val user = userRepository.saveAndFlush( User().apply { username = req.staffId @@ -198,29 +199,19 @@ open class StaffsService( staffSkillsetRepository.save(ss) } } - salaryEffectiveService.saveSalaryEffective(staff.id!!, req.joinDate ?: LocalDate.now(), salary.salaryPoint.toLong()) - if (team != null) { - val teamLog = TeamLog().apply { - this.staff = staff - this.team = team - from = req.joinDate ?: LocalDate.now() - } - teamLogRepository.save(teamLog) +// if (salary != null) salaryEffectiveService.saveSalaryEffective(staff.id!!, req.joinDate ?: LocalDate.now(), salary.salaryPoint.toLong()) + if (!req.salaryEffectiveInfo.isNullOrEmpty()) { + salaryEffectiveService.updateSalaryEffective(staff.id!!, req.salaryEffectiveInfo.sortedBy { it.date }, listOf()) } - - val gradeLog = GradeLog().apply { - this.staff = staff - this.grade = grade - from = req.joinDate ?: LocalDate.now() + if (!req.teamHistory.isNullOrEmpty()) { + teamLogService.saveTeamLogs(staff, req.teamHistory) } - gradeLogRepository.save(gradeLog) - - val positionLog = PositionLog().apply { - this.staff = staff - this.position = currentPosition - from = req.joinDate ?: LocalDate.now() + if (!req.gradeHistory.isNullOrEmpty()) { + gradeLogService.saveGradeLogs(staff, req.gradeHistory) + } + if (!req.positionHistory.isNullOrEmpty()) { + positionLogService.savePositionLogs(staff, req.positionHistory) } - positionLogRepository.save(positionLog) return staff } @@ -240,54 +231,35 @@ open class StaffsService( staffSkillsetRepository.save(ss) } } - val currentPosition = positionRepository.findById(req.currentPositionId).orElseThrow() + val gradeHistory = req.gradeHistory + val positionHistory = req.positionHistory + val teamHistory = req.teamHistory + + var currentPosition: Position? = null + var grade: Grade? = null + var team: Team? = null + if (!positionHistory.isNullOrEmpty()) { + currentPosition = positionRepository.findById(req.positionHistory.last().position).orElseThrow() + positionLogService.savePositionLogs(staff, positionHistory) + } + if (!gradeHistory.isNullOrEmpty()) { + grade = gradeRepository.findById(req.gradeHistory.last().grade).orElseThrow() + gradeLogService.saveGradeLogs(staff, gradeHistory) + } + if (!teamHistory.isNullOrEmpty()) { + team = teamRepository.findById(req.teamHistory.last().team).orElseThrow() + teamLogService.saveTeamLogs(staff, teamHistory) + } +// val currentPosition = if (!positionHistory.isNullOrEmpty()) positionRepository.findById(req.positionHistory.last().position).orElseThrow() else null +// val grade = if (!gradeHistory.isNullOrEmpty()) gradeRepository.findById(req.gradeHistory.last().grade).orElseThrow() else null +// val team = if (!teamHistory.isNullOrEmpty()) teamRepository.findById(req.teamHistory.last().team).orElseThrow() else null + val joinPosition = if (req.joinPositionId != null && req.joinPositionId > 0L) positionRepository.findById(req.joinPositionId).orElseThrow() else null val company = companyRepository.findById(req.companyId).orElseThrow() - val grade = gradeRepository.findById(req.gradeId).orElseThrow() - val team = if (req.teamId != null && req.teamId > 0L) teamRepository.findById(req.teamId).orElseThrow() else null val salaryPoint = checkLatestSalaryPoint(req?.salaryEffectiveInfo) ?: 0 val salary = salaryRepository.findBySalaryPoint(salaryPoint).orElseThrow() val department = if (req.departmentId != null && req.departmentId > 0L) departmentRepository.findById(req.departmentId).orElseThrow() else null - val latestTeam = teamLogRepository.findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(staff.id) - val latestGrade = gradeLogRepository.findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(staff.id) - val latestPosition = positionLogRepository.findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(staff.id) - if (latestTeam != null && latestTeam.team.id != req.teamId) { - val teamLog = TeamLog().apply { - this.staff = staff - this.team = team - from = LocalDate.now() - } - val lastRecordTeam = latestTeam.apply { - to = LocalDate.now() - } - teamLogRepository.save(teamLog) - teamLogRepository.save(lastRecordTeam) - } - if (latestGrade != null && latestGrade.grade.id != req.gradeId) { - val gradeLog = GradeLog().apply { - this.staff = staff - this.grade = grade - from = LocalDate.now() - } - val lastRecordGrade = latestGrade.apply { - to = LocalDate.now() - } - gradeLogRepository.save(gradeLog) - gradeLogRepository.save(lastRecordGrade) - } - if (latestPosition != null && latestPosition.position.id != req.currentPositionId) { - val positionLog = PositionLog().apply { - this.staff = staff - this.position = currentPosition - from = LocalDate.now() - } - val lastRecordPosition = latestPosition.apply { - to = LocalDate.now() - } - positionLogRepository.save(positionLog) - positionLogRepository.save(lastRecordPosition) - } staff.apply { joinDate = req.joinDate name = req.name @@ -325,13 +297,14 @@ open class StaffsService( // salaryEffectiveService.saveSalaryEffective(staff.id!!, salary.salaryPoint.toLong()) if (req.salaryEffectiveInfo != null && req.delSalaryEffectiveInfo != null) { salaryEffectiveService.updateSalaryEffective(staff.id!!, req.salaryEffectiveInfo.sortedBy { it.date }, req.delSalaryEffectiveInfo) - } else if (req.teamHistory != null && req.delTeamHistory != null) { - teamLogService.editTeamLog(req.teamHistory, req.delTeamHistory) - } else if (req.gradeHistory != null && req.delGradeHistory != null) { - gradeLogService.editGradeLog(req.gradeHistory, req.delGradeHistory) - } else if (req.positionHistory != null && req.delPositionHistory != null) { - positionLogService.editPositionLog(req.positionHistory, req.delPositionHistory) } +// else if (req.teamHistory != null && req.delTeamHistory != null) { +// teamLogService.editTeamLog(req.teamHistory, req.delTeamHistory) +// } else if (req.gradeHistory != null && req.delGradeHistory != null) { +// gradeLogService.editGradeLog(req.gradeHistory, req.delGradeHistory) +// } else if (req.positionHistory != null && req.delPositionHistory != null) { +// positionLogService.editPositionLog(req.positionHistory, req.delPositionHistory) +// } return staffRepository.save(staff) } diff --git a/src/main/java/com/ffii/tsms/modules/data/service/TeamLogService.kt b/src/main/java/com/ffii/tsms/modules/data/service/TeamLogService.kt index 9f456b6..baec6ba 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/TeamLogService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/TeamLogService.kt @@ -2,12 +2,11 @@ package com.ffii.tsms.modules.data.service import com.ffii.core.support.AbstractBaseEntityService import com.ffii.core.support.JdbcDao -import com.ffii.tsms.modules.data.entity.TeamLog -import com.ffii.tsms.modules.data.entity.TeamLogRepository -import com.ffii.tsms.modules.data.entity.TeamRepository +import com.ffii.tsms.modules.data.entity.* import com.ffii.tsms.modules.data.entity.projections.TeamLogInfo import com.ffii.tsms.modules.data.web.models.TeamHistory import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional import java.time.LocalDate @Service @@ -17,7 +16,7 @@ open class TeamLogService ( private val jdbcDao: JdbcDao, ) : AbstractBaseEntityService(jdbcDao, teamLogRepository) { open fun allTeamLog(staffId: Long): List { - return teamLogRepository.findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId).drop(1) + return teamLogRepository.findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId) } open fun getStaffTeamLog(staffId:Long, recordDate: LocalDate): TeamLog? { @@ -30,6 +29,34 @@ open class TeamLogService ( return team } + @Transactional + open fun saveTeamLogs(staff: Staff, entries: List) { + try { + val testList = mutableListOf() + // replace team log data by delete all and add + teamLogRepository.deleteAllByStaff(staff) + + val sortedEntries = entries.sortedBy { it.from } + val teamEntries = mutableListOf() + sortedEntries.forEachIndexed { index, it -> + val team = teamRepository.findById(it.team).orElseThrow() + val teamLog = TeamLog().apply { + this.staff = staff + this.team = team + this.from = it.from + } + if (index > 0) { + teamEntries[index - 1].to = it.from + } + testList.add(index) + teamEntries.add(teamLog) + } + teamLogRepository.saveAll(teamEntries) + } catch (e: Exception) { + throw Exception("Error saving team logs", e) + } + } + open fun editTeamLog(teamHistory: List, delTeamHistory: List) { if (delTeamHistory.isNotEmpty()) { delTeamHistory.forEach { diff --git a/src/main/java/com/ffii/tsms/modules/data/web/models/NewStaffRequest.kt b/src/main/java/com/ffii/tsms/modules/data/web/models/NewStaffRequest.kt index e923a38..0f05f63 100644 --- a/src/main/java/com/ffii/tsms/modules/data/web/models/NewStaffRequest.kt +++ b/src/main/java/com/ffii/tsms/modules/data/web/models/NewStaffRequest.kt @@ -12,18 +12,15 @@ data class NewStaffRequest( val staffId: String, @field:NotNull(message = "Staff companyId cannot be empty") val companyId: Long, - @field:NotNull(message = "Staff salaryId cannot be empty") - val salaryId: Long, - @field:NotNull(message = "Staff currentPositionId cannot be empty") - val currentPositionId: Long, @field:NotBlank(message = "Staff phone1 cannot be empty") val phone1: String, @field:NotBlank(message = "Staff email cannot be empty") val email: String, @field:NotBlank(message = "Staff employType cannot be empty") val employType: String, - @field:NotNull(message = "Staff grade cannot be empty") - val gradeId: Long, + + val currentPositionId: Long?, + val gradeId: Long?, val joinDate: LocalDate?, val joinPositionId: Long?,