@@ -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<Long>() { | |||
inverseJoinColumns = [JoinColumn(name = "tasksId")]) | |||
@OrderBy | |||
open var tasks: MutableList<Task> = mutableListOf() | |||
@JsonManagedReference | |||
@OneToMany(mappedBy = "taskTemplate", cascade = [CascadeType.ALL], orphanRemoval = true) | |||
open var gradeAllocations: MutableSet<TaskTemplateGradeAllocation> = mutableSetOf() | |||
@JsonManagedReference | |||
@OneToMany(mappedBy = "taskTemplate", cascade = [CascadeType.ALL], orphanRemoval = true) | |||
open var groupAllocations: MutableSet<TaskTemplateGroupAllocation> = mutableSetOf() | |||
} |
@@ -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<Long>() { | |||
@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 | |||
} |
@@ -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<TaskTemplateGradeAllocation, Long> { | |||
fun findByTaskTemplateAndGrade(taskTemplate: TaskTemplate, grade: Grade): TaskTemplateGradeAllocation? | |||
fun findAllByTaskTemplate(taskTemplate: TaskTemplate): List<TaskTemplateGradeAllocation> | |||
} |
@@ -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<Long>() { | |||
@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 | |||
} |
@@ -0,0 +1,9 @@ | |||
package com.ffii.tsms.modules.project.entity | |||
import com.ffii.core.support.AbstractRepository | |||
interface TaskTemplateGroupAllocationRepository : AbstractRepository<TaskTemplateGroupAllocation, Long> { | |||
fun findByTaskTemplateAndTaskGroup(taskTemplate: TaskTemplate, taskGroup: TaskGroup): TaskTemplateGroupAllocation? | |||
fun findAllByTaskTemplate(taskTemplate: TaskTemplate): List<TaskTemplateGroupAllocation> | |||
} |
@@ -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) | |||
@@ -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<Task> { | |||
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<Long>, 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>( | |||
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>(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<TaskTemplateGradeAllocation>(gradeAllocations) | |||
taskTemplateGroupAllocationRepository.saveAll<TaskTemplateGroupAllocation>(groupAllocations) | |||
return savedTaskTemplate | |||
} | |||
fun allTaskGroups(): List<TaskGroup> { | |||
@@ -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) | |||
} | |||
} |
@@ -5,5 +5,7 @@ data class EditTaskTemplateDetails ( | |||
val code: String?, | |||
val name: String?, | |||
val taskIds: List<Long>? | |||
val manhourPercentageByGrade: Map<Long, Double>, | |||
val taskGroups: Map<Long, TaskGroupAllocation>?, | |||
) |
@@ -7,7 +7,9 @@ data class NewTaskTemplateRequest( | |||
val code: String, | |||
@field:NotBlank(message = "name cannot be empty") | |||
val name: String, | |||
val taskIds: List<Long> = emptyList(), | |||
// val taskIds: List<Long> = emptyList(), | |||
val manhourPercentageByGrade: Map<Long, Double>, | |||
val taskGroups: Map<Long, TaskGroupAllocation>, | |||
val id: Long? | |||
) |
@@ -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); | |||