# Conflicts: # src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.ktdevelop
| @@ -9,7 +9,7 @@ import org.springframework.data.repository.query.Param; | |||||
| import com.ffii.core.support.AbstractRepository; | import com.ffii.core.support.AbstractRepository; | ||||
| public interface CustomerRepository extends AbstractRepository<Customer, Long> { | public interface CustomerRepository extends AbstractRepository<Customer, Long> { | ||||
| List<Customer> findAllByDeletedFalse(); | |||||
| List<Customer> findAllByDeletedFalseOrderByNameAsc(); | |||||
| Optional<Customer> findByCode(@Param("code") String code); | Optional<Customer> findByCode(@Param("code") String code); | ||||
| Optional<Customer> findByName(@Param("name") String name); | Optional<Customer> findByName(@Param("name") String name); | ||||
| @@ -10,6 +10,7 @@ public interface GradeLogRepository extends AbstractRepository<GradeLog, Long> { | |||||
| List<GradeLogInfo> findGradeLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | List<GradeLogInfo> findGradeLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | ||||
| GradeLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | GradeLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | ||||
| void deleteAllByStaff(Staff staff); | |||||
| List<GradeLog> findByDeletedFalseAndFromBeforeAndToIsNullOrToAfter(LocalDate before, LocalDate after); | List<GradeLog> findByDeletedFalseAndFromBeforeAndToIsNullOrToAfter(LocalDate before, LocalDate after); | ||||
| // fun findByDeletedFalseAndRecordDateBetweenOrderByRecordDate(start: LocalDate, end: LocalDate): List<Timesheet> | // fun findByDeletedFalseAndRecordDateBetweenOrderByRecordDate(start: LocalDate, end: LocalDate): List<Timesheet> | ||||
| } | } | ||||
| @@ -8,7 +8,7 @@ import java.util.List; | |||||
| public interface PositionLogRepository extends AbstractRepository<PositionLog, Long> { | public interface PositionLogRepository extends AbstractRepository<PositionLog, Long> { | ||||
| List<PositionLogInfo> findPositionLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | List<PositionLogInfo> findPositionLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | ||||
| void deleteAllByStaff(Staff staff); | |||||
| PositionLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | PositionLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | ||||
| } | } | ||||
| @@ -28,6 +28,8 @@ public interface StaffRepository extends AbstractRepository<Staff, Long> { | |||||
| Optional<List<Staff>> findAllByDeletedFalse(); | Optional<List<Staff>> findAllByDeletedFalse(); | ||||
| Optional<List<Staff>> findAllByIdInAndDeletedFalse(List<Long> id); | |||||
| Optional<Staff> findIdAndNameByUserIdAndDeletedFalse(Long id); | Optional<Staff> findIdAndNameByUserIdAndDeletedFalse(Long id); | ||||
| } | } | ||||
| @@ -8,7 +8,7 @@ import java.util.List; | |||||
| import java.util.Optional; | import java.util.Optional; | ||||
| public interface SubsidiaryRepository extends AbstractRepository<Subsidiary, Long> { | public interface SubsidiaryRepository extends AbstractRepository<Subsidiary, Long> { | ||||
| List<Subsidiary> findAllByDeletedFalse(); | |||||
| List<Subsidiary> findAllByDeletedFalseOrderByNameAsc(); | |||||
| List<Subsidiary> findAllByDeletedFalseAndIdIn(List<Long> id); | List<Subsidiary> findAllByDeletedFalseAndIdIn(List<Long> id); | ||||
| @@ -8,4 +8,7 @@ import java.util.List; | |||||
| public interface TeamLogRepository extends AbstractRepository<TeamLog, Long> { | public interface TeamLogRepository extends AbstractRepository<TeamLog, Long> { | ||||
| List<TeamLogInfo> findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | List<TeamLogInfo> findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | ||||
| TeamLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | TeamLog findFirstByStaffIdAndDeletedFalseOrderByCreatedDesc(Long staffId); | ||||
| void deleteAllByStaff(Staff staff); | |||||
| } | } | ||||
| @@ -23,7 +23,7 @@ open class CustomerService( | |||||
| ) : AbstractBaseEntityService<Customer, Long, CustomerRepository>(jdbcDao, customerRepository){ | ) : AbstractBaseEntityService<Customer, Long, CustomerRepository>(jdbcDao, customerRepository){ | ||||
| open fun allCustomers(): List<Customer> { | open fun allCustomers(): List<Customer> { | ||||
| return customerRepository.findAllByDeletedFalse() | |||||
| return customerRepository.findAllByDeletedFalseOrderByNameAsc() | |||||
| } | } | ||||
| open fun allCustomerTypes(): List<CustomerType> { | open fun allCustomerTypes(): List<CustomerType> { | ||||
| @@ -3989,7 +3989,7 @@ open class DashboardService( | |||||
| + " c.code as customerCode, " | + " c.code as customerCode, " | ||||
| + " su.name as subsidiary, " | + " su.name as subsidiary, " | ||||
| + " coalesce(pf.projectFee, 0) as totalFee, " | + " 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(me.manhourExpense, 0) as manhourExpense, " | ||||
| + " coalesce(id.invoicedAmount, 0) as invoicedAmount, " | + " coalesce(id.invoicedAmount, 0) as invoicedAmount, " | ||||
| // + " coalesce(id.uninvoicedAmount, 0) as uninvoicedAmount, " | // + " coalesce(id.uninvoicedAmount, 0) as uninvoicedAmount, " | ||||
| @@ -2,14 +2,11 @@ package com.ffii.tsms.modules.data.service | |||||
| import com.ffii.core.support.AbstractBaseEntityService | import com.ffii.core.support.AbstractBaseEntityService | ||||
| import com.ffii.core.support.JdbcDao | 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.entity.projections.GradeLogInfo | ||||
| import com.ffii.tsms.modules.data.web.models.GradeHistory | import com.ffii.tsms.modules.data.web.models.GradeHistory | ||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Service | @Service | ||||
| open class GradeLogService( | open class GradeLogService( | ||||
| @@ -18,8 +15,35 @@ open class GradeLogService( | |||||
| private val jdbcDao: JdbcDao, | private val jdbcDao: JdbcDao, | ||||
| ) : AbstractBaseEntityService<GradeLog, Long, GradeLogRepository>(jdbcDao, gradeLogRepository) { | ) : AbstractBaseEntityService<GradeLog, Long, GradeLogRepository>(jdbcDao, gradeLogRepository) { | ||||
| open fun allGradeLog(staffId: Long): List<GradeLogInfo> { | open fun allGradeLog(staffId: Long): List<GradeLogInfo> { | ||||
| return gradeLogRepository.findGradeLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId).drop(1) | |||||
| return gradeLogRepository.findGradeLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId) | |||||
| } | } | ||||
| @Transactional | |||||
| open fun saveGradeLogs(staff: Staff, entries: List<GradeHistory>) { | |||||
| try { | |||||
| // replace grade log data by delete all and add | |||||
| gradeLogRepository.deleteAllByStaff(staff) | |||||
| val sortedEntries = entries.sortedBy { it.from } | |||||
| val gradeEntries = mutableListOf<GradeLog>() | |||||
| 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<GradeHistory>, delGradeHistory: List<Long>) { | open fun editGradeLog(gradeHistory: List<GradeHistory>, delGradeHistory: List<Long>) { | ||||
| if (delGradeHistory.isNotEmpty()) { | if (delGradeHistory.isNotEmpty()) { | ||||
| delGradeHistory.forEach { | delGradeHistory.forEach { | ||||
| @@ -2,12 +2,11 @@ package com.ffii.tsms.modules.data.service | |||||
| import com.ffii.core.support.AbstractBaseEntityService | import com.ffii.core.support.AbstractBaseEntityService | ||||
| import com.ffii.core.support.JdbcDao | 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.entity.projections.PositionLogInfo | ||||
| import com.ffii.tsms.modules.data.web.models.PositionHistory | import com.ffii.tsms.modules.data.web.models.PositionHistory | ||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Service | @Service | ||||
| @@ -17,7 +16,33 @@ open class PositionLogService ( | |||||
| private val jdbcDao: JdbcDao, | private val jdbcDao: JdbcDao, | ||||
| ) : AbstractBaseEntityService<PositionLog, Long, PositionLogRepository>(jdbcDao, positionLogRepository) { | ) : AbstractBaseEntityService<PositionLog, Long, PositionLogRepository>(jdbcDao, positionLogRepository) { | ||||
| open fun allPositionLog(staffId: Long): List<PositionLogInfo> { | open fun allPositionLog(staffId: Long): List<PositionLogInfo> { | ||||
| return positionLogRepository.findPositionLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId).drop(1) | |||||
| return positionLogRepository.findPositionLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId) | |||||
| } | |||||
| @Transactional | |||||
| open fun savePositionLogs(staff: Staff, entries: List<PositionHistory>) { | |||||
| try { | |||||
| // replace team log data by delete all and add | |||||
| positionLogRepository.deleteAllByStaff(staff) | |||||
| val sortedEntries = entries.sortedBy { it.from } | |||||
| val positionEntries = mutableListOf<PositionLog>() | |||||
| 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<PositionHistory>, delPositionHistory: List<Long>) { | open fun editPositionLog(positionHistory: List<PositionHistory>, delPositionHistory: List<Long>) { | ||||
| @@ -4,15 +4,12 @@ import com.ffii.core.exception.UnprocessableEntityException | |||||
| import com.ffii.core.support.AbstractBaseEntityService | import com.ffii.core.support.AbstractBaseEntityService | ||||
| import com.ffii.core.support.JdbcDao | import com.ffii.core.support.JdbcDao | ||||
| import com.ffii.tsms.modules.common.SecurityUtils | 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.* | ||||
| import com.ffii.tsms.modules.data.entity.projections.StaffSearchInfo | 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.NewStaffRequest | ||||
| import com.ffii.tsms.modules.data.web.models.SalaryEffectiveInfo | import com.ffii.tsms.modules.data.web.models.SalaryEffectiveInfo | ||||
| import com.ffii.tsms.modules.user.entity.User | import com.ffii.tsms.modules.user.entity.User | ||||
| import com.ffii.tsms.modules.user.entity.UserRepository | import com.ffii.tsms.modules.user.entity.UserRepository | ||||
| import jakarta.mail.internet.InternetAddress | |||||
| import org.springframework.scheduling.annotation.Scheduled | import org.springframework.scheduling.annotation.Scheduled | ||||
| import org.springframework.security.core.GrantedAuthority | import org.springframework.security.core.GrantedAuthority | ||||
| import org.springframework.security.crypto.password.PasswordEncoder | import org.springframework.security.crypto.password.PasswordEncoder | ||||
| @@ -97,8 +94,13 @@ open class StaffsService( | |||||
| } | } | ||||
| open fun findAll(): Optional<List<Staff>> { | open fun findAll(): Optional<List<Staff>> { | ||||
| return staffRepository.findAllByDeletedFalse() | |||||
| return staffRepository.findAllByDeletedFalse(); | |||||
| } | } | ||||
| open fun findAllByIdIn(ids: List<Long>): Optional<List<Staff>> { | |||||
| return staffRepository.findAllByIdInAndDeletedFalse(ids); | |||||
| } | |||||
| open fun getStaff(args: Map<String, Any>): Optional<MutableMap<String, Any>>? { | open fun getStaff(args: Map<String, Any>): Optional<MutableMap<String, Any>>? { | ||||
| val sql = StringBuilder("select" | val sql = StringBuilder("select" | ||||
| + " s.id as id," | + " s.id as id," | ||||
| @@ -135,14 +137,18 @@ open class StaffsService( | |||||
| throw UnprocessableEntityException("Duplicated StaffId Found") | 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 joinPosition = if (req.joinPositionId != null && req.joinPositionId > 0L) positionRepository.findById(req.joinPositionId).orElseThrow() else null | ||||
| val company = companyRepository.findById(req.companyId).orElseThrow() | 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 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( | val user = userRepository.saveAndFlush( | ||||
| User().apply { | User().apply { | ||||
| username = req.staffId | username = req.staffId | ||||
| @@ -193,29 +199,19 @@ open class StaffsService( | |||||
| staffSkillsetRepository.save(ss) | 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 | return staff | ||||
| } | } | ||||
| @@ -235,54 +231,35 @@ open class StaffsService( | |||||
| staffSkillsetRepository.save(ss) | 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 joinPosition = if (req.joinPositionId != null && req.joinPositionId > 0L) positionRepository.findById(req.joinPositionId).orElseThrow() else null | ||||
| val company = companyRepository.findById(req.companyId).orElseThrow() | 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 salaryPoint = checkLatestSalaryPoint(req?.salaryEffectiveInfo) ?: 0 | ||||
| val salary = salaryRepository.findBySalaryPoint(salaryPoint).orElseThrow() | val salary = salaryRepository.findBySalaryPoint(salaryPoint).orElseThrow() | ||||
| val department = if (req.departmentId != null && req.departmentId > 0L) departmentRepository.findById(req.departmentId).orElseThrow() else null | 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 { | staff.apply { | ||||
| joinDate = req.joinDate | joinDate = req.joinDate | ||||
| name = req.name | name = req.name | ||||
| @@ -320,13 +297,14 @@ open class StaffsService( | |||||
| // salaryEffectiveService.saveSalaryEffective(staff.id!!, salary.salaryPoint.toLong()) | // salaryEffectiveService.saveSalaryEffective(staff.id!!, salary.salaryPoint.toLong()) | ||||
| if (req.salaryEffectiveInfo != null && req.delSalaryEffectiveInfo != null) { | if (req.salaryEffectiveInfo != null && req.delSalaryEffectiveInfo != null) { | ||||
| salaryEffectiveService.updateSalaryEffective(staff.id!!, req.salaryEffectiveInfo.sortedBy { it.date }, req.delSalaryEffectiveInfo) | 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) | return staffRepository.save(staff) | ||||
| } | } | ||||
| @@ -23,7 +23,7 @@ open class SubsidiaryService( | |||||
| private val subsidiaryContactService: SubsidiaryContactService, | private val subsidiaryContactService: SubsidiaryContactService, | ||||
| ) : AbstractBaseEntityService<Subsidiary, Long, SubsidiaryRepository>(jdbcDao, subsidiaryRepository) { | ) : AbstractBaseEntityService<Subsidiary, Long, SubsidiaryRepository>(jdbcDao, subsidiaryRepository) { | ||||
| open fun allSubsidiaries(): List<Subsidiary> { | open fun allSubsidiaries(): List<Subsidiary> { | ||||
| return subsidiaryRepository.findAllByDeletedFalse() | |||||
| return subsidiaryRepository.findAllByDeletedFalseOrderByNameAsc() | |||||
| } | } | ||||
| open fun allSubsidiaryTypes(): List<SubsidiaryType> { | open fun allSubsidiaryTypes(): List<SubsidiaryType> { | ||||
| @@ -2,12 +2,11 @@ package com.ffii.tsms.modules.data.service | |||||
| import com.ffii.core.support.AbstractBaseEntityService | import com.ffii.core.support.AbstractBaseEntityService | ||||
| import com.ffii.core.support.JdbcDao | 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.entity.projections.TeamLogInfo | ||||
| import com.ffii.tsms.modules.data.web.models.TeamHistory | import com.ffii.tsms.modules.data.web.models.TeamHistory | ||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | |||||
| import java.time.LocalDate | import java.time.LocalDate | ||||
| @Service | @Service | ||||
| @@ -17,7 +16,7 @@ open class TeamLogService ( | |||||
| private val jdbcDao: JdbcDao, | private val jdbcDao: JdbcDao, | ||||
| ) : AbstractBaseEntityService<TeamLog, Long, TeamLogRepository>(jdbcDao, teamLogRepository) { | ) : AbstractBaseEntityService<TeamLog, Long, TeamLogRepository>(jdbcDao, teamLogRepository) { | ||||
| open fun allTeamLog(staffId: Long): List<TeamLogInfo> { | open fun allTeamLog(staffId: Long): List<TeamLogInfo> { | ||||
| return teamLogRepository.findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId).drop(1) | |||||
| return teamLogRepository.findTeamLogInfoByStaffIdAndDeletedFalseOrderByCreatedDesc(staffId) | |||||
| } | } | ||||
| open fun getStaffTeamLog(staffId:Long, recordDate: LocalDate): TeamLog? { | open fun getStaffTeamLog(staffId:Long, recordDate: LocalDate): TeamLog? { | ||||
| @@ -30,6 +29,34 @@ open class TeamLogService ( | |||||
| return team | return team | ||||
| } | } | ||||
| @Transactional | |||||
| open fun saveTeamLogs(staff: Staff, entries: List<TeamHistory>) { | |||||
| try { | |||||
| val testList = mutableListOf<Int>() | |||||
| // replace team log data by delete all and add | |||||
| teamLogRepository.deleteAllByStaff(staff) | |||||
| val sortedEntries = entries.sortedBy { it.from } | |||||
| val teamEntries = mutableListOf<TeamLog>() | |||||
| 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<TeamHistory>, delTeamHistory: List<Long>) { | open fun editTeamLog(teamHistory: List<TeamHistory>, delTeamHistory: List<Long>) { | ||||
| if (delTeamHistory.isNotEmpty()) { | if (delTeamHistory.isNotEmpty()) { | ||||
| delTeamHistory.forEach { | delTeamHistory.forEach { | ||||
| @@ -12,18 +12,15 @@ data class NewStaffRequest( | |||||
| val staffId: String, | val staffId: String, | ||||
| @field:NotNull(message = "Staff companyId cannot be empty") | @field:NotNull(message = "Staff companyId cannot be empty") | ||||
| val companyId: Long, | 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") | @field:NotBlank(message = "Staff phone1 cannot be empty") | ||||
| val phone1: String, | val phone1: String, | ||||
| @field:NotBlank(message = "Staff email cannot be empty") | @field:NotBlank(message = "Staff email cannot be empty") | ||||
| val email: String, | val email: String, | ||||
| @field:NotBlank(message = "Staff employType cannot be empty") | @field:NotBlank(message = "Staff employType cannot be empty") | ||||
| val employType: String, | val employType: String, | ||||
| @field:NotNull(message = "Staff grade cannot be empty") | |||||
| val gradeId: Long, | |||||
| val currentPositionId: Long?, | |||||
| val gradeId: Long?, | |||||
| val joinDate: LocalDate?, | val joinDate: LocalDate?, | ||||
| val joinPositionId: Long?, | val joinPositionId: Long?, | ||||
| @@ -101,18 +101,24 @@ open class LeaveService( | |||||
| open fun getTeamMemberLeave(): Map<Long, TeamMemberLeaveEntries> { | open fun getTeamMemberLeave(): Map<Long, TeamMemberLeaveEntries> { | ||||
| val authorities = staffsService.currentAuthorities() ?: return emptyMap() | 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() | val currentStaff = staffsService.currentStaff() | ||||
| // Get team where current staff is team lead | // Get team where current staff is team lead | ||||
| val myTeam = if (currentStaff != null) teamService.getMyTeamForStaff(currentStaff) else null | 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()) | staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) | ||||
| } else if (authMaintainTimesheetSelf) { | |||||
| staffsService.findAllByIdIn(listOf(currentStaff?.id!!)).getOrDefault(emptyList()) | |||||
| } else { | } else { | ||||
| staffsService.findAll().getOrDefault(emptyList()) | 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( | Pair( | ||||
| member.id!!, | member.id!!, | ||||
| TeamMemberLeaveEntries( | TeamMemberLeaveEntries( | ||||
| @@ -129,18 +129,23 @@ open class TimesheetsService( | |||||
| open fun getTeamMemberTimesheet(): Map<Long, TeamMemberTimeEntries> { | open fun getTeamMemberTimesheet(): Map<Long, TeamMemberTimeEntries> { | ||||
| val authorities = staffsService.currentAuthorities() ?: return emptyMap() | 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() | val currentStaff = staffsService.currentStaff() | ||||
| // Get team where current staff is team lead | |||||
| // Get team where current staff is team lead | |||||
| val myTeam = if (currentStaff != null) teamService.getMyTeamForStaff(currentStaff) else null | 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()) | staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) | ||||
| } else if (authMaintainTimesheetSelf) { | |||||
| staffsService.findAllByIdIn(listOf(currentStaff?.id!!)).getOrDefault(emptyList()) | |||||
| } else { | } else { | ||||
| staffsService.findAll().getOrDefault(emptyList()) | 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( | Pair( | ||||
| member.id!!, | member.id!!, | ||||
| TeamMemberTimeEntries( | TeamMemberTimeEntries( | ||||
| @@ -151,7 +156,9 @@ open class TimesheetsService( | |||||
| ) | ) | ||||
| ) | ) | ||||
| } | } | ||||
| } else return emptyMap() | |||||
| } | |||||
| return emptyMap() | |||||
| } | } | ||||
| private fun transformToTimeEntryMap(timesheets: List<Timesheet>): Map<String, List<TimeEntry>> { | private fun transformToTimeEntryMap(timesheets: List<Timesheet>): Map<String, List<TimeEntry>> { | ||||
| @@ -0,0 +1,5 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset cyril:add_authority | |||||
| INSERT INTO `authority` (`authority`, `name`) VALUES | |||||
| ('MAINTAIN_TIMESHEET_SELF', 'Maintain Self Timesheet'); | |||||