Browse Source

Save milestones

tags/Baseline_30082024_BACKEND_UAT
Wayne 1 year ago
parent
commit
47817346a7
12 changed files with 179 additions and 21 deletions
  1. +37
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocation.kt
  2. +6
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocationRepository.kt
  3. +33
    -7
      src/main/java/com/ffii/tsms/modules/project/entity/Milestone.kt
  4. +9
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/Project.kt
  5. +0
    -8
      src/main/java/com/ffii/tsms/modules/project/entity/ProjectTask.kt
  6. +53
    -3
      src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt
  7. +11
    -3
      src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt
  8. +4
    -0
      src/main/resources/db/changelog/changes/20240423_01_wayne/01_update_project_manhour.sql
  9. +4
    -0
      src/main/resources/db/changelog/changes/20240423_01_wayne/02_update_milestone.sql
  10. +14
    -0
      src/main/resources/db/changelog/changes/20240423_01_wayne/03_grade_allocation.sql
  11. +4
    -0
      src/main/resources/db/changelog/changes/20240423_01_wayne/04_remove_milestone_non_null.sql
  12. +4
    -0
      src/main/resources/db/changelog/changes/20240423_01_wayne/05_remove_percentage_project_task.sql

+ 37
- 0
src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocation.kt View File

@@ -0,0 +1,37 @@
package com.ffii.tsms.modules.project.entity

import com.ffii.core.entity.IdEntity
import com.ffii.tsms.modules.data.entity.Grade
import jakarta.persistence.*
import org.hibernate.proxy.HibernateProxy

@Entity
@Table(name = "grade_allocation")
open class GradeAllocation : IdEntity<Long>() {
@ManyToOne
@JoinColumn(name = "gradeId")
open var grade: Grade? = null

@Column(name = "manhour")
open var manhour: Double? = null

@ManyToOne
@JoinColumn(name = "projectId")
open var project: Project? = null

final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null) return false
val oEffectiveClass =
if (other is HibernateProxy) other.hibernateLazyInitializer.persistentClass else other.javaClass
val thisEffectiveClass =
if (this is HibernateProxy) this.hibernateLazyInitializer.persistentClass else this.javaClass
if (thisEffectiveClass != oEffectiveClass) return false
other as GradeAllocation

return id != null && id == other.id
}

final override fun hashCode(): Int =
if (this is HibernateProxy) this.hibernateLazyInitializer.persistentClass.hashCode() else javaClass.hashCode()
}

+ 6
- 0
src/main/java/com/ffii/tsms/modules/project/entity/GradeAllocationRepository.kt View File

@@ -0,0 +1,6 @@
package com.ffii.tsms.modules.project.entity;

import com.ffii.core.support.AbstractRepository

interface GradeAllocationRepository : AbstractRepository<GradeAllocation, Long> {
}

+ 33
- 7
src/main/java/com/ffii/tsms/modules/project/entity/Milestone.kt View File

@@ -1,23 +1,49 @@
package com.ffii.tsms.modules.project.entity package com.ffii.tsms.modules.project.entity


import com.ffii.core.entity.IdEntity import com.ffii.core.entity.IdEntity
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.OneToMany
import jakarta.persistence.Table
import jakarta.persistence.*
import jakarta.validation.constraints.NotNull import jakarta.validation.constraints.NotNull
import org.hibernate.proxy.HibernateProxy
import java.time.LocalDate


@Entity @Entity
@Table(name = "milestone") @Table(name = "milestone")
open class Milestone : IdEntity<Long>() { open class Milestone : IdEntity<Long>() {
@NotNull
@Column(name = "name") @Column(name = "name")
open var name: String? = null open var name: String? = null


@NotNull
@Column(name = "description") @Column(name = "description")
open var description: String? = null open var description: String? = null


@OneToMany(mappedBy = "milestone", orphanRemoval = true)
@OneToMany(mappedBy = "milestone", cascade = [CascadeType.ALL], orphanRemoval = true)
open var milestonePayments: MutableList<MilestonePayment> = mutableListOf() open var milestonePayments: MutableList<MilestonePayment> = mutableListOf()

@Column(name = "startDate")
open var startDate: LocalDate? = null

@Column(name = "endDate")
open var endDate: LocalDate? = null

@Column(name = "stagePercentAllocation")
open var stagePercentAllocation: Double? = null

@ManyToOne
@JoinColumn(name = "projectId")
open var project: Project? = null

final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null) return false
val oEffectiveClass =
if (other is HibernateProxy) other.hibernateLazyInitializer.persistentClass else other.javaClass
val thisEffectiveClass =
if (this is HibernateProxy) this.hibernateLazyInitializer.persistentClass else this.javaClass
if (thisEffectiveClass != oEffectiveClass) return false
other as Milestone

return id != null && id == other.id
}

final override fun hashCode(): Int =
if (this is HibernateProxy) this.hibernateLazyInitializer.persistentClass.hashCode() else javaClass.hashCode()
} }

+ 9
- 0
src/main/java/com/ffii/tsms/modules/project/entity/Project.kt View File

@@ -60,6 +60,15 @@ open class Project : BaseEntity<Long>() {
@Column(name = "billStatus") @Column(name = "billStatus")
open var billStatus: Boolean? = null open var billStatus: Boolean? = null


@Column(name = "totalManhour")
open var totalManhour: Double? = null

@OneToMany(mappedBy = "project", cascade = [CascadeType.ALL], orphanRemoval = true)
open var gradeAllocations: MutableSet<GradeAllocation> = mutableSetOf()

@OneToMany(mappedBy = "project", cascade = [CascadeType.ALL], orphanRemoval = true)
open var milestones: MutableSet<Milestone> = mutableSetOf()

@Column(name = "expectedTotalFee") @Column(name = "expectedTotalFee")
open var expectedTotalFee: Double? = null open var expectedTotalFee: Double? = null




+ 0
- 8
src/main/java/com/ffii/tsms/modules/project/entity/ProjectTask.kt View File

@@ -18,12 +18,4 @@ open class ProjectTask : IdEntity<Long>() {
@NotNull @NotNull
@ManyToOne @ManyToOne
open var task: Task? = null open var task: Task? = null

@NotNull
@Column(name = "paymentPercentage")
open var paymentPercentage: Double? = null

@NotNull
@Column(name = "reminderPercentage")
open var reminderPercentage: Double? = null
} }

+ 53
- 3
src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt View File

@@ -8,11 +8,14 @@ import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.project.web.models.NewProjectRequest import com.ffii.tsms.modules.project.web.models.NewProjectRequest
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate
import java.time.format.DateTimeFormatter


@Service @Service
open class ProjectsService( open class ProjectsService(
private val projectRepository: ProjectRepository, private val projectRepository: ProjectRepository,
private val customerService: CustomerService, private val customerService: CustomerService,
private val tasksService: TasksService,
private val customerContactService: CustomerContactService, private val customerContactService: CustomerContactService,
private val projectCategoryRepository: ProjectCategoryRepository, private val projectCategoryRepository: ProjectCategoryRepository,
private val staffRepository: StaffRepository, private val staffRepository: StaffRepository,
@@ -22,7 +25,10 @@ open class ProjectsService(
private val contractTypeRepository: ContractTypeRepository, private val contractTypeRepository: ContractTypeRepository,
private val locationRepository: LocationRepository, private val locationRepository: LocationRepository,
private val buildingTypeRepository: BuildingTypeRepository, private val buildingTypeRepository: BuildingTypeRepository,
private val workNatureRepository: WorkNatureRepository
private val workNatureRepository: WorkNatureRepository,
private val milestoneRepository: MilestoneRepository,
private val gradeAllocationRepository: GradeAllocationRepository,
private val projectTaskRepository: ProjectTaskRepository
) { ) {
open fun allProjects(): List<ProjectSearchInfo> { open fun allProjects(): List<ProjectSearchInfo> {
return projectRepository.findProjectSearchInfoBy() return projectRepository.findProjectSearchInfoBy()
@@ -47,15 +53,16 @@ open class ProjectsService(
val customer = customerService.findCustomer(request.clientId) val customer = customerService.findCustomer(request.clientId)
val clientContact = customerContactService.findByContactId(request.clientContactId) val clientContact = customerContactService.findByContactId(request.clientContactId)


val allTasksMap = tasksService.allTasks().associateBy { it.id }



// TODO: Add tasks, milestones
val project = val project =
Project().apply { Project().apply {
name = request.projectName name = request.projectName
description = request.projectDescription description = request.projectDescription
code = request.projectCode code = request.projectCode
expectedTotalFee = request.expectedProjectFee expectedTotalFee = request.expectedProjectFee
totalManhour = request.totalManhour

this.projectCategory = projectCategory this.projectCategory = projectCategory
this.fundingType = fundingType this.fundingType = fundingType
this.serviceType = serviceType this.serviceType = serviceType
@@ -71,8 +78,51 @@ open class ProjectsService(
custLeadPhone = clientContact.phone custLeadPhone = clientContact.phone
} }




// Milestones and tasks
val tasksToSave = mutableListOf<ProjectTask>()
val milestones = request.milestones.entries.map { (taskStageId, requestMilestone) ->
Milestone().apply {
val newMilestone = this
this.project = project
this.startDate = LocalDate.parse(requestMilestone.startDate)
this.endDate = LocalDate.parse(requestMilestone.endDate)
this.milestonePayments = requestMilestone.payments.map {
MilestonePayment().apply {
this.description = it.description
this.amount = it.amount
this.date = LocalDate.parse(it.date)
this.milestone = newMilestone
}
}.toMutableList()

// Tasks
val taskGroupAllocation = request.taskGroups[taskStageId]
this.stagePercentAllocation = taskGroupAllocation?.percentAllocation

taskGroupAllocation?.taskIds?.map { taskId -> ProjectTask().apply {
this.project = project
this.milestone = newMilestone
this.task = allTasksMap[taskId]
} }?.let { tasksToSave.addAll(it) }
}
}

// TODO: Get Grades from db
// Grade allocation (from manhourPercentageByGrade)
// request.manhourPercentageByGrade.entries.map {
// GradeAllocation().apply {
// this.project = project
// this.manhour = it.value
// }
// }

val savedProject = projectRepository.save(project) val savedProject = projectRepository.save(project)
milestoneRepository.saveAll(milestones)
projectTaskRepository.saveAll(tasksToSave)


// Staff allocation
val allocatedStaff = staffRepository.findAllById(request.allocatedStaffIds) val allocatedStaff = staffRepository.findAllById(request.allocatedStaffIds)
val staffAllocations = allocatedStaff.map { staff -> StaffAllocation().apply { val staffAllocations = allocatedStaff.map { staff -> StaffAllocation().apply {
this.project = savedProject this.project = savedProject


+ 11
- 3
src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt View File

@@ -3,11 +3,11 @@ package com.ffii.tsms.modules.project.web.models
import jakarta.validation.constraints.NotBlank import jakarta.validation.constraints.NotBlank


data class NewProjectRequest( data class NewProjectRequest(
// Project details
@field:NotBlank(message = "project code cannot be empty") @field:NotBlank(message = "project code cannot be empty")
val projectCode: String, val projectCode: String,
@field:NotBlank(message = "project name cannot be empty") @field:NotBlank(message = "project name cannot be empty")
val projectName: String, val projectName: String,

val projectCategoryId: Long, val projectCategoryId: Long,
val projectDescription: String, val projectDescription: String,
val projectLeadId: Long, val projectLeadId: Long,
@@ -19,19 +19,27 @@ data class NewProjectRequest(
val buildingTypeIds: List<Long>, val buildingTypeIds: List<Long>,
val workNatureIds: List<Long>, val workNatureIds: List<Long>,


// Client details
val clientId: Long, val clientId: Long,
val clientContactId: Long, val clientContactId: Long,
val clientSubsidiaryId: Long?, val clientSubsidiaryId: Long?,


// Allocation
val totalManhour: Double,
val manhourPercentageByGrade: Map<Long, Double>,
val taskGroups: Map<Long, TaskGroupAllocation>,
val allocatedStaffIds: List<Long>, val allocatedStaffIds: List<Long>,


// Milestones
val milestones: Map<Long, Milestone>, val milestones: Map<Long, Milestone>,


// Miscellaneous
val expectedProjectFee: Double val expectedProjectFee: Double
) )


data class TaskAllocation(
val manhourAllocation: Map<Long, Double>
data class TaskGroupAllocation(
val taskIds: List<Long>,
val percentAllocation: Double
) )


data class Milestone( data class Milestone(


+ 4
- 0
src/main/resources/db/changelog/changes/20240423_01_wayne/01_update_project_manhour.sql View File

@@ -0,0 +1,4 @@
-- liquibase formatted sql
-- changeset wayne:update_project_manhour

ALTER TABLE project ADD totalManhour DOUBLE NULL;

+ 4
- 0
src/main/resources/db/changelog/changes/20240423_01_wayne/02_update_milestone.sql View File

@@ -0,0 +1,4 @@
-- liquibase formatted sql
-- changeset wayne:update_milestone

ALTER TABLE milestone ADD startDate date NULL, ADD endDate date NULL, ADD stagePercentAllocation DOUBLE NULL, ADD projectId INT NULL;

+ 14
- 0
src/main/resources/db/changelog/changes/20240423_01_wayne/03_grade_allocation.sql View File

@@ -0,0 +1,14 @@
-- liquibase formatted sql
-- changeset wayne:grade_allocation

CREATE TABLE grade_allocation (
id INT NOT NULL AUTO_INCREMENT,
gradeId INT NULL,
manhour DOUBLE NULL,
projectId INT NULL,
CONSTRAINT pk_grade_allocation PRIMARY KEY (id)
);

ALTER TABLE grade_allocation ADD CONSTRAINT FK_GRADE_ALLOCATION_ON_GRADEID FOREIGN KEY (gradeId) REFERENCES grade (id);

ALTER TABLE grade_allocation ADD CONSTRAINT FK_GRADE_ALLOCATION_ON_PROJECTID FOREIGN KEY (projectId) REFERENCES project (id);

+ 4
- 0
src/main/resources/db/changelog/changes/20240423_01_wayne/04_remove_milestone_non_null.sql View File

@@ -0,0 +1,4 @@
-- liquibase formatted sql
-- changeset wayne:remove_milestone_non_null

ALTER TABLE milestone MODIFY name VARCHAR(255) NULL, MODIFY `description` VARCHAR(255) NULL;

+ 4
- 0
src/main/resources/db/changelog/changes/20240423_01_wayne/05_remove_percentage_project_task.sql View File

@@ -0,0 +1,4 @@
-- liquibase formatted sql
-- changeset wayne:remove_percentage_project_task

ALTER TABLE project_task DROP COLUMN paymentPercentage, DROP COLUMN reminderPercentage;

Loading…
Cancel
Save