diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocationRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocationRepository.kt index 46dc040..afa3d89 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocationRepository.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocationRepository.kt @@ -1,7 +1,10 @@ package com.ffii.tsms.modules.project.entity; import com.ffii.core.support.AbstractRepository +import com.ffii.tsms.modules.data.entity.Grade interface GradeAllocationRepository : AbstractRepository { fun findByProject(project: Project): List + + fun findByProjectAndGrade(project: Project, grade: Grade): GradeAllocation? } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/MilestoneRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/MilestoneRepository.kt index 8cbddb1..e463f60 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/MilestoneRepository.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/MilestoneRepository.kt @@ -8,4 +8,6 @@ interface MilestoneRepository : AbstractRepository { fun findInvoiceSearchInfoBy(): List fun findAllByProject(project: Project): List + + fun findByProjectAndTaskGroup(project: Project, taskGroup: TaskGroup): Milestone? } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTaskRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTaskRepository.kt index b909b93..b1b57e0 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTaskRepository.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTaskRepository.kt @@ -5,5 +5,5 @@ import com.ffii.core.support.AbstractRepository interface ProjectTaskRepository : AbstractRepository { fun findAllByProject(project: Project): List - fun findByProjectAndTask(project: Project, task: Task): ProjectTask + fun findByProjectAndTask(project: Project, task: Task): ProjectTask? } \ No newline at end of file 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 2c32f2c..fc10e84 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 @@ -15,29 +15,31 @@ import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.time.LocalDate import java.time.format.DateTimeFormatter +import java.util.Optional import kotlin.jvm.optionals.getOrElse import kotlin.jvm.optionals.getOrNull @Service open class ProjectsService( - private val projectRepository: ProjectRepository, - private val customerService: CustomerService, - private val tasksService: TasksService, - private val customerContactService: CustomerContactService, - private val subsidiaryService: SubsidiaryService, - private val gradeService: GradeService, - private val projectCategoryRepository: ProjectCategoryRepository, - private val staffRepository: StaffRepository, - private val staffAllocationRepository: StaffAllocationRepository, - private val fundingTypeRepository: FundingTypeRepository, - private val serviceTypeRepository: ServiceTypeRepository, - private val contractTypeRepository: ContractTypeRepository, - private val locationRepository: LocationRepository, - private val buildingTypeRepository: BuildingTypeRepository, - private val workNatureRepository: WorkNatureRepository, - private val milestoneRepository: MilestoneRepository, - private val gradeAllocationRepository: GradeAllocationRepository, - private val projectTaskRepository: ProjectTaskRepository + private val projectRepository: ProjectRepository, + private val customerService: CustomerService, + private val tasksService: TasksService, + private val customerContactService: CustomerContactService, + private val subsidiaryService: SubsidiaryService, + private val gradeService: GradeService, + private val projectCategoryRepository: ProjectCategoryRepository, + private val staffRepository: StaffRepository, + private val staffAllocationRepository: StaffAllocationRepository, + private val fundingTypeRepository: FundingTypeRepository, + private val serviceTypeRepository: ServiceTypeRepository, + private val contractTypeRepository: ContractTypeRepository, + private val locationRepository: LocationRepository, + private val buildingTypeRepository: BuildingTypeRepository, + private val workNatureRepository: WorkNatureRepository, + private val milestoneRepository: MilestoneRepository, + private val gradeAllocationRepository: GradeAllocationRepository, + private val projectTaskRepository: ProjectTaskRepository, + private val milestonePaymentRepository: MilestonePaymentRepository, private val taskGroupRepository: TaskGroupRepository ) { open fun allProjects(): List { return projectRepository.findProjectSearchInfoByOrderByCreatedDesc() @@ -93,7 +95,7 @@ open class ProjectsService( @Transactional open fun saveProject(request: NewProjectRequest): NewProjectResponse { val projectCategory = - projectCategoryRepository.findById(request.projectCategoryId).orElseThrow() + projectCategoryRepository.findById(request.projectCategoryId).orElseThrow() val fundingType = fundingTypeRepository.findById(request.fundingTypeId).orElseThrow() val serviceType = serviceTypeRepository.findById(request.serviceTypeId).orElseThrow() val contractType = contractTypeRepository.findById(request.contractTypeId).orElseThrow() @@ -112,65 +114,76 @@ open class ProjectsService( val project = if (request.projectId != null && request.projectId > 0) projectRepository.findById(request.projectId).orElseThrow() else Project() project.apply { - name = request.projectName - description = request.projectDescription - code = request.projectCode - expectedTotalFee = request.expectedProjectFee - totalManhour = request.totalManhour - actualStart = request.projectActualStart - actualEnd = request.projectActualEnd - - this.projectCategory = projectCategory - this.fundingType = fundingType - this.serviceType = serviceType - this.contractType = contractType - this.location = location - this.buildingTypes = buildingTypes - this.workNatures = workNatures - - this.teamLead = teamLead - this.customer = customer - custLeadName = clientContact.name - custLeadEmail = clientContact.email - custLeadPhone = clientContact.phone - this.customerSubsidiary = customerSubsidiary - } + name = request.projectName + description = request.projectDescription + code = request.projectCode + expectedTotalFee = request.expectedProjectFee + totalManhour = request.totalManhour + actualStart = request.projectActualStart + actualEnd = request.projectActualEnd + + this.projectCategory = projectCategory + this.fundingType = fundingType + this.serviceType = serviceType + this.contractType = contractType + this.location = location + this.buildingTypes = buildingTypes + this.workNatures = workNatures + + this.teamLead = teamLead + this.customer = customer + custLeadName = clientContact.name + custLeadEmail = clientContact.email + custLeadPhone = clientContact.phone + this.customerSubsidiary = customerSubsidiary + } // Milestones and tasks val tasksToSave = mutableListOf() val milestones = request.taskGroups.entries.map { (taskStageId, taskGroupAllocation) -> - Milestone().apply { + val taskGroup = taskGroupRepository.findById(taskStageId).orElse(TaskGroup()) + val milestone = milestoneRepository.findByProjectAndTaskGroup(project, taskGroup) ?: Milestone() + milestone.apply { val newMilestone = this val requestMilestone = request.milestones[taskStageId] this.project = project this.taskGroup = taskGroupMap[taskStageId] this.startDate = requestMilestone?.startDate?.let { LocalDate.parse(it) } this.endDate = requestMilestone?.endDate?.let { LocalDate.parse(it) } - this.milestonePayments = requestMilestone?.payments?.map { - MilestonePayment().apply { + requestMilestone?.payments?.map { + val milestonePayment = if (it.id > 0) milestonePaymentRepository.findById(it.id).orElse(MilestonePayment()) else MilestonePayment() + + this.milestonePayments.add(milestonePayment.apply { + this.milestone = newMilestone this.description = it.description this.amount = it.amount this.date = LocalDate.parse(it.date) - this.milestone = newMilestone - } - }?.toMutableList() ?: mutableListOf() + }) + } // Tasks this.stagePercentAllocation = taskGroupAllocation.percentAllocation - taskGroupAllocation.taskIds.map { taskId -> ProjectTask().apply { - this.project = project - this.milestone = newMilestone - this.task = allTasksMap[taskId] - } }.let { tasksToSave.addAll(it) } + taskGroupAllocation.taskIds.map { taskId -> + val projectTask = projectTaskRepository.findByProjectAndTask(project, allTasksMap[taskId]!!) ?:ProjectTask() + projectTask.apply { + this.project = project + this.milestone = newMilestone + this.task = allTasksMap[taskId] + } + }.let { + tasksToSave.addAll(it) + } } } // Grade allocation (from manhourPercentageByGrade) val gradeAllocations = request.manhourPercentageByGrade.entries.map { - GradeAllocation().apply { + val gradeAllocation = gradeAllocationRepository.findByProjectAndGrade(project, gradeMap[it.key]!!) ?: GradeAllocation() + + gradeAllocation.apply { this.project = project this.manhour = it.value this.grade = gradeMap[it.key] @@ -185,6 +198,14 @@ 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()) + milestoneRepository.deleteAll(milestonesToDelete) + projectTaskRepository.deleteAll(tasksToDelete) + gradeAllocationRepository.deleteAll(gradeAllocationsToDelete) + milestoneRepository.saveAll(milestones) projectTaskRepository.saveAll(tasksToSave) gradeAllocationRepository.saveAll(gradeAllocations) @@ -195,6 +216,8 @@ open class ProjectsService( this.project = savedProject this.staff = staff } } + val staffAllocationsToDelete = staffAllocationRepository.findByProject(savedProject).subtract(staffAllocations.toSet()) + staffAllocationRepository.deleteAll(staffAllocationsToDelete) staffAllocationRepository.saveAll(staffAllocations) return savedProject.let { @@ -251,15 +274,15 @@ open class ProjectsService( ) }, allocatedStaffIds = staffAllocationRepository.findByProject(it).mapNotNull { allocation -> allocation.staff?.id }, milestones = milestoneMap.mapValues { (_, milestone) -> com.ffii.tsms.modules.project.web.models.Milestone( - startDate = milestone.startDate?.format(DateTimeFormatter.ISO_LOCAL_DATE), - endDate = milestone.endDate?.format(DateTimeFormatter.ISO_LOCAL_DATE), - payments = milestone.milestonePayments.map { payment -> PaymentInputs( - id = payment.id!!, - amount = payment.amount!!, - description = payment.description!!, - date = payment.date!!.format(DateTimeFormatter.ISO_LOCAL_DATE) - )} - )}, + startDate = milestone.startDate?.format(DateTimeFormatter.ISO_LOCAL_DATE), + endDate = milestone.endDate?.format(DateTimeFormatter.ISO_LOCAL_DATE), + payments = milestone.milestonePayments.map { payment -> PaymentInputs( + id = payment.id!!, + amount = payment.amount!!, + description = payment.description!!, + date = payment.date!!.format(DateTimeFormatter.ISO_LOCAL_DATE) + )} + )}, expectedProjectFee = it.expectedTotalFee ) }