Browse Source

Merge branch 'master' of https://git.2fi-solutions.com/davidhui/TSMS-backend

tags/Baseline_30082024_BACKEND_UAT
MSI\2Fi 1 year ago
parent
commit
f86e90f5fe
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

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 org.hibernate.proxy.HibernateProxy
import java.time.LocalDate

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

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

@OneToMany(mappedBy = "milestone", orphanRemoval = true)
@OneToMany(mappedBy = "milestone", cascade = [CascadeType.ALL], orphanRemoval = true)
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")
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")
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
@ManyToOne
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

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

@Service
open class ProjectsService(
private val projectRepository: ProjectRepository,
private val customerService: CustomerService,
private val tasksService: TasksService,
private val customerContactService: CustomerContactService,
private val projectCategoryRepository: ProjectCategoryRepository,
private val staffRepository: StaffRepository,
@@ -24,7 +27,10 @@ open class ProjectsService(
private val contractTypeRepository: ContractTypeRepository,
private val locationRepository: LocationRepository,
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> {
return projectRepository.findProjectSearchInfoBy()
@@ -61,15 +67,16 @@ open class ProjectsService(
val customer = customerService.findCustomer(request.clientId)
val clientContact = customerContactService.findByContactId(request.clientContactId)

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


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

this.projectCategory = projectCategory
this.fundingType = fundingType
this.serviceType = serviceType
@@ -85,8 +92,51 @@ open class ProjectsService(
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)
milestoneRepository.saveAll(milestones)
projectTaskRepository.saveAll(tasksToSave)

// Staff allocation
val allocatedStaff = staffRepository.findAllById(request.allocatedStaffIds)
val staffAllocations = allocatedStaff.map { staff -> StaffAllocation().apply {
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

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

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

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

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

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

// Miscellaneous
val expectedProjectFee: Double
)

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

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