|
|
@@ -0,0 +1,82 @@ |
|
|
|
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.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.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 |
|
|
|
|
|
|
|
open class TimesheetsService( |
|
|
|
private val timesheetRepository: TimesheetRepository, |
|
|
|
private val projectTaskRepository: ProjectTaskRepository, |
|
|
|
private val projectRepository: ProjectRepository, |
|
|
|
private val taskRepository: TaskRepository, |
|
|
|
private val staffsService: StaffsService |
|
|
|
) { |
|
|
|
@Transactional |
|
|
|
open fun saveTimesheet(recordTimeEntry: Map<LocalDate, List<TimeEntry>>): Map<String, List<TimeEntry>> { |
|
|
|
// Need to be associated with a staff |
|
|
|
val currentStaff = staffsService.currentStaff() ?: throw BadRequestException() |
|
|
|
|
|
|
|
val timesheetEntries = recordTimeEntry.entries.flatMap { (entryDate, timeEntries) -> |
|
|
|
// Replace db timesheet entries by deleting and then adding back |
|
|
|
timesheetRepository.deleteAllByStaffAndRecordDate(currentStaff, entryDate) |
|
|
|
|
|
|
|
mergeTimeEntriesByProjectAndTask(timeEntries).map { timeEntry -> |
|
|
|
val task = timeEntry.taskId?.let { taskRepository.findById(it).getOrNull() } |
|
|
|
val project = timeEntry.projectId?.let { projectRepository.findById(it).getOrNull() } |
|
|
|
val projectTask = project?.let { p -> task?.let { t -> projectTaskRepository.findByProjectAndTask(p, t) } } |
|
|
|
|
|
|
|
Timesheet().apply { |
|
|
|
this.staff = currentStaff |
|
|
|
this.recordDate = entryDate |
|
|
|
this.normalConsumed = timeEntry.inputHours |
|
|
|
this.projectTask = projectTask |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
val savedTimesheets = timesheetRepository.saveAll(timesheetEntries) |
|
|
|
|
|
|
|
return transformToTimeEntryMap(savedTimesheets) |
|
|
|
} |
|
|
|
|
|
|
|
open fun getTimesheet(): Map<String, List<TimeEntry>> { |
|
|
|
// Need to be associated with a staff |
|
|
|
val currentStaff = staffsService.currentStaff() ?: throw BadRequestException() |
|
|
|
return transformToTimeEntryMap(timesheetRepository.findAllByStaff(currentStaff)) |
|
|
|
} |
|
|
|
|
|
|
|
private fun transformToTimeEntryMap(timesheets: List<Timesheet>): Map<String, List<TimeEntry>> { |
|
|
|
return timesheets |
|
|
|
.groupBy { timesheet -> timesheet.recordDate!!.format(DateTimeFormatter.ISO_LOCAL_DATE) } |
|
|
|
.mapValues { (_, timesheets) -> timesheets.map { timesheet -> |
|
|
|
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 |
|
|
|
) |
|
|
|
} } |
|
|
|
} |
|
|
|
|
|
|
|
private fun mergeTimeEntriesByProjectAndTask(entries: List<TimeEntry>): List<TimeEntry> { |
|
|
|
return entries |
|
|
|
.groupBy { timeEntry -> Pair(timeEntry.projectId, timeEntry.taskId) } |
|
|
|
.values.map { timeEntries -> |
|
|
|
timeEntries.reduce { acc, timeEntry -> acc.copy(inputHours = acc.inputHours + timeEntry.inputHours) } |
|
|
|
} |
|
|
|
} |
|
|
|
} |