diff --git a/src/main/java/com/ffii/tsms/modules/data/entity/TeamRepository.java b/src/main/java/com/ffii/tsms/modules/data/entity/TeamRepository.java index 39038c0..3a3cf41 100644 --- a/src/main/java/com/ffii/tsms/modules/data/entity/TeamRepository.java +++ b/src/main/java/com/ffii/tsms/modules/data/entity/TeamRepository.java @@ -7,4 +7,6 @@ import java.util.List; public interface TeamRepository extends AbstractRepository { List findByDeletedFalse(); + + Team findByStaff(Staff staff); } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/data/service/TeamService.kt b/src/main/java/com/ffii/tsms/modules/data/service/TeamService.kt index b75dc8c..b1893aa 100644 --- a/src/main/java/com/ffii/tsms/modules/data/service/TeamService.kt +++ b/src/main/java/com/ffii/tsms/modules/data/service/TeamService.kt @@ -172,4 +172,8 @@ open class TeamService( ) return jdbcDao.queryForList(sql.toString()) } + + open fun getMyTeamForStaff(staff: Staff): Team? { + return teamRepository.findByStaff(staff) + } } \ No newline at end of file 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 04903af..48d7621 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 @@ -2,16 +2,19 @@ package com.ffii.tsms.modules.timesheet.service import com.ffii.core.exception.BadRequestException import com.ffii.tsms.modules.data.service.StaffsService +import com.ffii.tsms.modules.data.service.TeamService import com.ffii.tsms.modules.project.entity.ProjectRepository import com.ffii.tsms.modules.project.entity.ProjectTaskRepository import com.ffii.tsms.modules.project.entity.TaskRepository import com.ffii.tsms.modules.timesheet.entity.Timesheet import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository +import com.ffii.tsms.modules.timesheet.web.models.TeamMemberTimeEntries import com.ffii.tsms.modules.timesheet.web.models.TimeEntry import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.time.LocalDate import java.time.format.DateTimeFormatter +import kotlin.jvm.optionals.getOrDefault import kotlin.jvm.optionals.getOrNull @Service @@ -20,7 +23,8 @@ open class TimesheetsService( private val projectTaskRepository: ProjectTaskRepository, private val projectRepository: ProjectRepository, private val taskRepository: TaskRepository, - private val staffsService: StaffsService + private val staffsService: StaffsService, + private val teamService: TeamService ) { @Transactional open fun saveTimesheet(recordTimeEntry: Map>): Map> { @@ -52,12 +56,61 @@ open class TimesheetsService( return transformToTimeEntryMap(savedTimesheets) } + @Transactional + open fun saveMemberTimeEntry(staffId: Long, entry: TimeEntry): TimeEntry { + val currentStaff = staffsService.currentStaff() ?: throw BadRequestException() + // Make sure current staff is a team lead + teamService.getMyTeamForStaff(currentStaff) ?: throw BadRequestException() + + val timesheet = timesheetRepository.findById(entry.id).getOrDefault(Timesheet()).apply { + val task = entry.taskId?.let { taskRepository.findById(it).getOrNull() } + val project = entry.projectId?.let { projectRepository.findById(it).getOrNull() } + val projectTask = project?.let { p -> task?.let { t -> projectTaskRepository.findByProjectAndTask(p, t) } } + + this.normalConsumed = entry.inputHours + this.otConsumed = entry.otHours + this.projectTask = projectTask + this.remark = entry.remark + } + + timesheetRepository.save(timesheet) + + return TimeEntry( + id = timesheet.id!!, + projectId = timesheet.projectTask?.project?.id, + taskId = timesheet.projectTask?.task?.id, + taskGroupId = timesheet.projectTask?.task?.taskGroup?.id, + inputHours = timesheet.normalConsumed ?: 0.0, + otHours = timesheet.otConsumed ?: 0.0, + remark = timesheet.remark + ) + } + open fun getTimesheet(): Map> { // Need to be associated with a staff val currentStaff = staffsService.currentStaff() ?: return emptyMap() return transformToTimeEntryMap(timesheetRepository.findAllByStaff(currentStaff)) } + open fun getTimeMemberTimesheet(): Map { + val currentStaff = staffsService.currentStaff() ?: return emptyMap() + // Get team where current staff is team lead + val myTeam = teamService.getMyTeamForStaff(currentStaff) ?: return emptyMap() + + val teamMembers = staffsService.findAllByTeamId(myTeam.id!!).getOrDefault(emptyList()) + + return teamMembers.associate { member -> + Pair( + member.id!!, + TeamMemberTimeEntries( + staffId = member.staffId, + name = member.name, + timeEntries = transformToTimeEntryMap(timesheetRepository.findAllByStaff(member)) + ) + ) + } + } + private fun transformToTimeEntryMap(timesheets: List): Map> { return timesheets .groupBy { timesheet -> timesheet.recordDate!!.format(DateTimeFormatter.ISO_LOCAL_DATE) } diff --git a/src/main/java/com/ffii/tsms/modules/timesheet/web/TimesheetsController.kt b/src/main/java/com/ffii/tsms/modules/timesheet/web/TimesheetsController.kt index 02f8f31..a24a4db 100644 --- a/src/main/java/com/ffii/tsms/modules/timesheet/web/TimesheetsController.kt +++ b/src/main/java/com/ffii/tsms/modules/timesheet/web/TimesheetsController.kt @@ -5,6 +5,8 @@ import com.ffii.tsms.modules.timesheet.entity.LeaveType import com.ffii.tsms.modules.timesheet.service.LeaveService import com.ffii.tsms.modules.timesheet.service.TimesheetsService import com.ffii.tsms.modules.timesheet.web.models.LeaveEntry +import com.ffii.tsms.modules.timesheet.web.models.TeamMemberTimeEntries +import com.ffii.tsms.modules.timesheet.web.models.TeamTimeEntry import com.ffii.tsms.modules.timesheet.web.models.TimeEntry import jakarta.validation.Valid import org.springframework.web.bind.annotation.GetMapping @@ -43,6 +45,16 @@ class TimesheetsController(private val timesheetsService: TimesheetsService, pri return timesheetsService.getTimesheet() } + @GetMapping("/teamTimesheets") + fun getTeamMemberTimesheetEntries(): Map { + return timesheetsService.getTimeMemberTimesheet() + } + + @PostMapping("/saveMemberEntry") + fun saveMemberEntry(@Valid @RequestBody request: TeamTimeEntry): TimeEntry { + return timesheetsService.saveMemberTimeEntry(request.staffId, request.entry) + } + @GetMapping("/leaves") fun getLeaveEntry(): Map> { return leaveService.getLeaves() diff --git a/src/main/java/com/ffii/tsms/modules/timesheet/web/models/TeamMemberTimeEntries.kt b/src/main/java/com/ffii/tsms/modules/timesheet/web/models/TeamMemberTimeEntries.kt new file mode 100644 index 0000000..084440d --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/timesheet/web/models/TeamMemberTimeEntries.kt @@ -0,0 +1,7 @@ +package com.ffii.tsms.modules.timesheet.web.models + +data class TeamMemberTimeEntries( + val timeEntries: Map>, + val staffId: String?, + val name: String?, +) diff --git a/src/main/java/com/ffii/tsms/modules/timesheet/web/models/TeamTimeEntry.kt b/src/main/java/com/ffii/tsms/modules/timesheet/web/models/TeamTimeEntry.kt new file mode 100644 index 0000000..75bab5a --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/timesheet/web/models/TeamTimeEntry.kt @@ -0,0 +1,6 @@ +package com.ffii.tsms.modules.timesheet.web.models + +data class TeamTimeEntry( + val staffId: Long, + val entry: TimeEntry +)