diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplate.kt b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplate.kt index 16d8d9a..41c1a02 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplate.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplate.kt @@ -1,5 +1,6 @@ package com.ffii.tsms.modules.project.entity +import com.fasterxml.jackson.annotation.JsonManagedReference import com.ffii.core.entity.IdEntity import jakarta.persistence.* import jakarta.validation.constraints.NotNull @@ -21,4 +22,12 @@ open class TaskTemplate : IdEntity() { inverseJoinColumns = [JoinColumn(name = "tasksId")]) @OrderBy open var tasks: MutableList = mutableListOf() + + @JsonManagedReference + @OneToMany(mappedBy = "taskTemplate", cascade = [CascadeType.ALL], orphanRemoval = true) + open var gradeAllocations: MutableSet = mutableSetOf() + + @JsonManagedReference + @OneToMany(mappedBy = "taskTemplate", cascade = [CascadeType.ALL], orphanRemoval = true) + open var groupAllocations: MutableSet = mutableSetOf() } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGradeAllocation.kt b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGradeAllocation.kt new file mode 100644 index 0000000..2108a78 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGradeAllocation.kt @@ -0,0 +1,27 @@ +package com.ffii.tsms.modules.project.entity + +import com.fasterxml.jackson.annotation.JsonBackReference +import com.ffii.core.entity.IdEntity +import com.ffii.tsms.modules.data.entity.Grade +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table + +@Entity +@Table(name = "task_template_grade_allocation") +open class TaskTemplateGradeAllocation: IdEntity() { + @ManyToOne + @JsonBackReference + @JoinColumn(name = "taskTemplateId") + open var taskTemplate: TaskTemplate? = null + + @ManyToOne +// @JsonBackReference + @JoinColumn(name = "gradeId") + open var grade: Grade? = null + + @Column(name = "percentage") + open var percentage: Double? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGradeAllocationRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGradeAllocationRepository.kt new file mode 100644 index 0000000..fc9a07e --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGradeAllocationRepository.kt @@ -0,0 +1,10 @@ +package com.ffii.tsms.modules.project.entity + +import com.ffii.core.support.AbstractRepository +import com.ffii.tsms.modules.data.entity.Grade + +interface TaskTemplateGradeAllocationRepository : AbstractRepository { + fun findByTaskTemplateAndGrade(taskTemplate: TaskTemplate, grade: Grade): TaskTemplateGradeAllocation? + + fun findAllByTaskTemplate(taskTemplate: TaskTemplate): List +} diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGroupAllocation.kt b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGroupAllocation.kt new file mode 100644 index 0000000..dd75fb8 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGroupAllocation.kt @@ -0,0 +1,23 @@ +package com.ffii.tsms.modules.project.entity + +import com.fasterxml.jackson.annotation.JsonBackReference +import com.ffii.core.entity.IdEntity +import com.ffii.tsms.modules.data.entity.Grade +import jakarta.persistence.* + +@Entity +@Table(name = "task_template_group_allocation") +open class TaskTemplateGroupAllocation: IdEntity() { + @ManyToOne + @JsonBackReference + @JoinColumn(name = "taskTemplateId") + open var taskTemplate: TaskTemplate? = null + + @ManyToOne +// @JsonBackReference + @JoinColumn(name = "taskGroupId") + open var taskGroup: TaskGroup? = null + + @Column(name = "percentage") + open var percentage: Double? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGroupAllocationRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGroupAllocationRepository.kt new file mode 100644 index 0000000..17a70f8 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplateGroupAllocationRepository.kt @@ -0,0 +1,9 @@ +package com.ffii.tsms.modules.project.entity + +import com.ffii.core.support.AbstractRepository + +interface TaskTemplateGroupAllocationRepository : AbstractRepository { + fun findByTaskTemplateAndTaskGroup(taskTemplate: TaskTemplate, taskGroup: TaskGroup): TaskTemplateGroupAllocation? + + fun findAllByTaskTemplate(taskTemplate: TaskTemplate): List +} 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 2a6a509..2aeebb5 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 @@ -223,9 +223,9 @@ open class ProjectsService( val savedProject = projectRepository.save(project) - val milestonesToDelete = milestoneRepository.findAllByProject(savedProject).subtract(milestones.toSet()) - val tasksToDelete = projectTaskRepository.findAllByProject(savedProject).subtract(tasksToSave.toSet()) - val gradeAllocationsToDelete = gradeAllocationRepository.findByProject(savedProject).subtract(gradeAllocations.toSet()) + val milestonesToDelete = milestoneRepository.findAllByProject(project).subtract(milestones.toSet()) + val tasksToDelete = projectTaskRepository.findAllByProject(project).subtract(tasksToSave.toSet()) + val gradeAllocationsToDelete = gradeAllocationRepository.findByProject(project).subtract(gradeAllocations.toSet()) milestoneRepository.deleteAll(milestonesToDelete) projectTaskRepository.deleteAll(tasksToDelete) gradeAllocationRepository.deleteAll(gradeAllocationsToDelete) diff --git a/src/main/java/com/ffii/tsms/modules/project/service/TasksService.kt b/src/main/java/com/ffii/tsms/modules/project/service/TasksService.kt index 4ac534b..98d6247 100644 --- a/src/main/java/com/ffii/tsms/modules/project/service/TasksService.kt +++ b/src/main/java/com/ffii/tsms/modules/project/service/TasksService.kt @@ -1,8 +1,12 @@ package com.ffii.tsms.modules.project.service import com.ffii.core.support.JdbcDao +import com.ffii.tsms.modules.data.entity.GradeRepository import com.ffii.tsms.modules.project.entity.* import com.ffii.tsms.modules.project.web.models.EditTaskTemplateDetails +import com.ffii.tsms.modules.project.web.models.NewProjectRequest +import com.ffii.tsms.modules.project.web.models.NewTaskTemplateRequest +import com.ffii.tsms.modules.project.web.models.TaskGroupAllocation import org.springframework.stereotype.Service import kotlin.jvm.optionals.getOrNull @@ -12,6 +16,9 @@ class TasksService( private val taskRepository: TaskRepository, private val taskGroupRepository: TaskGroupRepository, private val jdbcDao: JdbcDao, + private val taskTemplateGroupAllocationRepository: TaskTemplateGroupAllocationRepository, + private val gradeRepository: GradeRepository, + private val taskTemplateGradeAllocationRepository: TaskTemplateGradeAllocationRepository, ) { fun allTasks(): List { return taskRepository.findAll() @@ -33,26 +40,73 @@ class TasksService( val taskTemplate = taskTemplateRepository.findById(id) return taskTemplate.getOrNull()?.let { + val gradeAllocations = it.gradeAllocations + .filter { gradeAllocation -> gradeAllocation.grade?.id != null } + .associate { gradeAllocation -> Pair(gradeAllocation.grade!!.id!!, gradeAllocation.percentage ?: 0.0) } + val groupAllocations = it.groupAllocations + .filter { groupAllocation -> groupAllocation.taskGroup?.id != null } + .associateBy { groupAllocation -> groupAllocation.taskGroup!!.id!! } + EditTaskTemplateDetails( id = it.id, code = it.code, name = it.name, - taskIds = it.tasks.map { task: Task -> task.id!! } + manhourPercentageByGrade = gradeAllocations, + + taskGroups = it.tasks.groupBy { task: Task -> task.taskGroup!!.id!! } + .mapValues { (taskGroupId, tasks) -> TaskGroupAllocation( + taskIds = tasks.mapNotNull { task -> task.id }, + percentAllocation = if(groupAllocations.containsKey(taskGroupId)) groupAllocations[taskGroupId]?.percentage!! else 0.0 + ) } ) } } - fun saveTaskTemplate(code: String, name: String, taskIds: List, id: Long?): TaskTemplate { + fun saveTaskTemplate(request: NewTaskTemplateRequest): TaskTemplate { + val id = request.id val taskTemplate = if (id != null && id > 0) findTaskTemplate(id) else TaskTemplate() + taskTemplate.apply { + this.name = request.name + this.code = request.code + this.tasks = taskRepository.findAllById(request.taskGroups.values.flatMap { taskGroup -> taskGroup.taskIds }) + } + + val gradeAllocations = request.manhourPercentageByGrade.entries.map { + val grade = gradeRepository.findById(it.key).orElseThrow() + val gradeAllocation = if (taskTemplate.id != null && taskTemplate.id!! > 0) taskTemplateGradeAllocationRepository.findByTaskTemplateAndGrade(taskTemplate, grade) ?:TaskTemplateGradeAllocation() else TaskTemplateGradeAllocation() + + gradeAllocation.apply { + this.taskTemplate = taskTemplate + this.grade = grade + percentage = it.value + } + } - return taskTemplateRepository.save( - taskTemplate.apply { - this.name = name - this.code = code - this.tasks = taskRepository.findAllById(taskIds) + val groupAllocations = request.taskGroups.entries.map { + val taskGroup = taskGroupRepository.findById(it.key).orElseThrow() + val groupAllocation = if (taskTemplate.id != null && taskTemplate.id!! > 0) taskTemplateGroupAllocationRepository.findByTaskTemplateAndTaskGroup(taskTemplate, taskGroup) ?:TaskTemplateGroupAllocation() else TaskTemplateGroupAllocation() + + groupAllocation.apply { + this.taskTemplate = taskTemplate + this.taskGroup = taskGroup + percentage = it.value.percentAllocation } - ) + } + + val savedTaskTemplate = taskTemplateRepository.save(taskTemplate) + + + println(taskTemplateGroupAllocationRepository.findAllByTaskTemplate(taskTemplate).size) + println(groupAllocations.size) + println(taskTemplateGroupAllocationRepository.findAllByTaskTemplate(taskTemplate).subtract(gradeAllocations.toSet()).size) + taskTemplateGradeAllocationRepository.deleteAll(taskTemplateGradeAllocationRepository.findAllByTaskTemplate(taskTemplate).subtract(gradeAllocations.toSet())) + taskTemplateGroupAllocationRepository.deleteAll(taskTemplateGroupAllocationRepository.findAllByTaskTemplate(taskTemplate).subtract(groupAllocations.toSet())) + + taskTemplateGradeAllocationRepository.saveAll(gradeAllocations) + taskTemplateGroupAllocationRepository.saveAll(groupAllocations) + + return savedTaskTemplate } fun allTaskGroups(): List { diff --git a/src/main/java/com/ffii/tsms/modules/project/web/TasksController.kt b/src/main/java/com/ffii/tsms/modules/project/web/TasksController.kt index 5621950..a454bbc 100644 --- a/src/main/java/com/ffii/tsms/modules/project/web/TasksController.kt +++ b/src/main/java/com/ffii/tsms/modules/project/web/TasksController.kt @@ -41,11 +41,6 @@ class TasksController(private val tasksService: TasksService) { @PostMapping("/templates/save") fun saveTaskTemplate(@Valid @RequestBody newTaskTemplate: NewTaskTemplateRequest): TaskTemplate { - return tasksService.saveTaskTemplate( - newTaskTemplate.code, - newTaskTemplate.name, - newTaskTemplate.taskIds, - newTaskTemplate.id - ) + return tasksService.saveTaskTemplate(newTaskTemplate) } } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/web/models/EditTaskTemplateDetails.kt b/src/main/java/com/ffii/tsms/modules/project/web/models/EditTaskTemplateDetails.kt index c0b497e..f98ceeb 100644 --- a/src/main/java/com/ffii/tsms/modules/project/web/models/EditTaskTemplateDetails.kt +++ b/src/main/java/com/ffii/tsms/modules/project/web/models/EditTaskTemplateDetails.kt @@ -5,5 +5,7 @@ data class EditTaskTemplateDetails ( val code: String?, val name: String?, - val taskIds: List? + val manhourPercentageByGrade: Map, + + val taskGroups: Map?, ) diff --git a/src/main/java/com/ffii/tsms/modules/project/web/models/NewTaskTemplateRequest.kt b/src/main/java/com/ffii/tsms/modules/project/web/models/NewTaskTemplateRequest.kt index f15e73b..67cae9d 100644 --- a/src/main/java/com/ffii/tsms/modules/project/web/models/NewTaskTemplateRequest.kt +++ b/src/main/java/com/ffii/tsms/modules/project/web/models/NewTaskTemplateRequest.kt @@ -7,7 +7,9 @@ data class NewTaskTemplateRequest( val code: String, @field:NotBlank(message = "name cannot be empty") val name: String, - val taskIds: List = emptyList(), +// val taskIds: List = emptyList(), + val manhourPercentageByGrade: Map, + val taskGroups: Map, val id: Long? ) diff --git a/src/main/resources/db/changelog/changes/20240510_01_cyril/01_create_task_template_allocation.sql b/src/main/resources/db/changelog/changes/20240510_01_cyril/01_create_task_template_allocation.sql new file mode 100644 index 0000000..15d49e1 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240510_01_cyril/01_create_task_template_allocation.sql @@ -0,0 +1,41 @@ +-- liquibase formatted sql +-- changeset cyril:task_template_grade_allocation, task_template_stage_allocation + +CREATE TABLE `task_template_grade_allocation` ( + `id` INT NOT NULL AUTO_INCREMENT, + `taskTemplateId` INT NULL DEFAULT NULL, + `gradeId` INT NULL DEFAULT NULL, + `percentage` DOUBLE NULL DEFAULT NULL, + PRIMARY KEY (`id`), + INDEX `FK_TASK_TEMPLATE_GRADE_ALLOCATION_ON_GRADEID` (`gradeId` ASC) VISIBLE, + INDEX `FK_TASK_TEMPLATE_GRADE_ALLOCATION_ON_TASKTEMPLATEID` (`taskTemplateId` ASC) VISIBLE, + CONSTRAINT `FK_TASK_TEMPLATE_GRADE_ALLOCATION_ON_GRADEID` + FOREIGN KEY (`gradeId`) + REFERENCES `grade` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + CONSTRAINT `FK_TASK_TEMPLATE_GRADE_ALLOCATION_ON_TASKTEMPLATEID` + FOREIGN KEY (`taskTemplateId`) + REFERENCES `task_template` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION); + +CREATE TABLE `task_template_group_allocation` ( + `id` INT NOT NULL AUTO_INCREMENT, + `taskTemplateId` INT NULL, + `taskGroupId` INT NULL, + `percentage` DOUBLE NULL, + PRIMARY KEY (`id`), + INDEX `FK_TASK_TEMPLATE_GRADE_ALLOCATION_ON_TASKGROUPID` (`taskGroupId` ASC) VISIBLE, + INDEX `FK_TASK_TEMPLATE_GRADE_ALLOCATION_ON_TASKTEMPLATEID` (`taskTemplateId` ASC) VISIBLE, + CONSTRAINT `FK_TASK_TEMPLATE_GROUP_ALLOCATION_ON_TASKGROUPID` + FOREIGN KEY (`taskGroupId`) + REFERENCES `task_group` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + CONSTRAINT `FK_TASK_TEMPLATE_GROUP_ALLOCATION_ON_TASKTEMPLATEID` + FOREIGN KEY (`taskTemplateId`) + REFERENCES `task_template` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION); +