From de4435fcee264ee8e9c9826fbc6923013f72cf22 Mon Sep 17 00:00:00 2001 From: Wayne Date: Mon, 18 Mar 2024 23:25:40 +0900 Subject: [PATCH] Add project creation --- README.md | 2 +- .../modules/data/service/CustomerService.kt | 20 +++++++++ .../modules/data/service/StaffsService.kt | 13 ++++++ .../tsms/modules/data/web/StaffsController.kt | 16 +++++++ .../{PaymentMilestone.kt => Milestone.kt} | 6 ++- .../project/entity/MilestonePayment.kt | 26 +++++++++++ ...neRepository.kt => MilestoneRepository.kt} | 2 +- .../tsms/modules/project/entity/Project.kt | 8 ++++ .../modules/project/entity/ProjectCategory.kt | 15 +++++++ .../entity/ProjectCategoryRepository.kt | 6 +++ .../modules/project/entity/ProjectTask.kt | 2 +- .../project/service/ProjectsService.kt | 43 ++++++++++++++++++ .../modules/project/web/ProjectsController.kt | 23 +++++++--- .../project/web/models/NewProjectRequest.kt | 44 +++++++++++++++++++ .../20240318_01_wayne/01_salary_data.sql | 41 +++++++++++++++++ .../20240318_01_wayne/02_mock_team_leads.sql | 35 +++++++++++++++ .../03_project_categories.sql | 12 +++++ .../20240318_01_wayne/04_update_project.sql | 7 +++ 18 files changed, 312 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt create mode 100644 src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt create mode 100644 src/main/java/com/ffii/tsms/modules/data/web/StaffsController.kt rename src/main/java/com/ffii/tsms/modules/project/entity/{PaymentMilestone.kt => Milestone.kt} (65%) create mode 100644 src/main/java/com/ffii/tsms/modules/project/entity/MilestonePayment.kt rename src/main/java/com/ffii/tsms/modules/project/entity/{PaymentMilestoneRepository.kt => MilestoneRepository.kt} (53%) create mode 100644 src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategory.kt create mode 100644 src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategoryRepository.kt create mode 100644 src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt create mode 100644 src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt create mode 100644 src/main/resources/db/changelog/changes/20240318_01_wayne/01_salary_data.sql create mode 100644 src/main/resources/db/changelog/changes/20240318_01_wayne/02_mock_team_leads.sql create mode 100644 src/main/resources/db/changelog/changes/20240318_01_wayne/03_project_categories.sql create mode 100644 src/main/resources/db/changelog/changes/20240318_01_wayne/04_update_project.sql diff --git a/README.md b/README.md index 7369438..ad7936d 100644 --- a/README.md +++ b/README.md @@ -45,5 +45,5 @@ This project can also be run using gradle. ### Running the application After creating the table in MySQL, run ```shell -SPRING_PROFILES_ACTIVE=db-local,ldap-local ./gradlew bootRun +./gradlew bootRun --args='--spring.profiles.active=db-local' ``` diff --git a/src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt b/src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt new file mode 100644 index 0000000..7f6faad --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt @@ -0,0 +1,20 @@ +package com.ffii.tsms.modules.data.service + +import com.ffii.tsms.modules.data.entity.Customer +import com.ffii.tsms.modules.data.entity.CustomerRepository +import org.springframework.stereotype.Service + +@Service +class CustomerService(private val customerRepository: CustomerRepository) { + fun saveCustomer(name: String, code: String, email: String, phone: String, contactName: String): Customer { + return customerRepository.save( + Customer().apply { + this.name = name + this.email = email + this.phone = phone + this.code = code + this.contactName = contactName + } + ) + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt new file mode 100644 index 0000000..9736e98 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/data/service/StaffsService.kt @@ -0,0 +1,13 @@ +package com.ffii.tsms.modules.data.service + +import com.ffii.tsms.modules.data.entity.Staff +import com.ffii.tsms.modules.data.entity.StaffRepository +import org.springframework.stereotype.Service + +@Service +class StaffsService(private val staffRepository: StaffRepository) { + fun getTeamLeads(): List { + // TODO: Replace with actual logic and make a projection instead of returning all fields + return staffRepository.findAll() + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/data/web/StaffsController.kt b/src/main/java/com/ffii/tsms/modules/data/web/StaffsController.kt new file mode 100644 index 0000000..ea5d4f1 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/data/web/StaffsController.kt @@ -0,0 +1,16 @@ +package com.ffii.tsms.modules.data.web + +import com.ffii.tsms.modules.data.entity.Staff +import com.ffii.tsms.modules.data.service.StaffsService +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/staffs") +class StaffsController(private val staffsService: StaffsService) { + @GetMapping("/teamLeads") + fun teamLeads(): List { + return staffsService.getTeamLeads() + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/PaymentMilestone.kt b/src/main/java/com/ffii/tsms/modules/project/entity/Milestone.kt similarity index 65% rename from src/main/java/com/ffii/tsms/modules/project/entity/PaymentMilestone.kt rename to src/main/java/com/ffii/tsms/modules/project/entity/Milestone.kt index 474bdd3..3e68bca 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/PaymentMilestone.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/Milestone.kt @@ -3,12 +3,13 @@ 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.validation.constraints.NotNull @Entity @Table(name = "milestone") -open class PaymentMilestone : IdEntity() { +open class Milestone : IdEntity() { @NotNull @Column(name = "name") open var name: String? = null @@ -16,4 +17,7 @@ open class PaymentMilestone : IdEntity() { @NotNull @Column(name = "description") open var description: String? = null + + @OneToMany(mappedBy = "milestone", orphanRemoval = true) + open var milestonePayments: MutableList = mutableListOf() } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/MilestonePayment.kt b/src/main/java/com/ffii/tsms/modules/project/entity/MilestonePayment.kt new file mode 100644 index 0000000..f6c4533 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/MilestonePayment.kt @@ -0,0 +1,26 @@ +package com.ffii.tsms.modules.project.entity + +import com.ffii.core.entity.IdEntity +import jakarta.persistence.* +import jakarta.validation.constraints.NotNull +import java.time.LocalDate + +@Entity +@Table(name = "milestone_payment") +open class MilestonePayment : IdEntity() { + @NotNull + @Column(name = "date") + open var date: LocalDate? = null + + @NotNull + @Column(name = "amount") + open var amount: Double? = null + + @NotNull + @Column(name = "description") + open var description: String? = null + + @ManyToOne + @JoinColumn(name = "milestone_id") + open var milestone: Milestone? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/PaymentMilestoneRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/MilestoneRepository.kt similarity index 53% rename from src/main/java/com/ffii/tsms/modules/project/entity/PaymentMilestoneRepository.kt rename to src/main/java/com/ffii/tsms/modules/project/entity/MilestoneRepository.kt index 4af39cf..4b22c09 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/PaymentMilestoneRepository.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/MilestoneRepository.kt @@ -2,5 +2,5 @@ package com.ffii.tsms.modules.project.entity; import com.ffii.core.support.AbstractRepository -interface PaymentMilestoneRepository : AbstractRepository { +interface MilestoneRepository : AbstractRepository { } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/Project.kt b/src/main/java/com/ffii/tsms/modules/project/entity/Project.kt index daa4a96..0933a63 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/Project.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/Project.kt @@ -18,6 +18,14 @@ open class Project : BaseEntity() { @Column(name = "description") open var description: String? = null + @NotNull + @Column(name = "code", length = 30) + open var code: String? = null + + @ManyToOne + @JoinColumn(name = "projectCategoryId") + open var projectCategory: ProjectCategory? = null + @Column(name = "planStart") open var planStart: LocalDate? = null diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategory.kt b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategory.kt new file mode 100644 index 0000000..3f99c49 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategory.kt @@ -0,0 +1,15 @@ +package com.ffii.tsms.modules.project.entity + +import com.ffii.core.entity.IdEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Table +import jakarta.validation.constraints.NotNull + +@Entity +@Table(name = "project_category") +open class ProjectCategory : IdEntity() { + @NotNull + @Column(name = "name") + open var name: String? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategoryRepository.kt b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategoryRepository.kt new file mode 100644 index 0000000..1df277d --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectCategoryRepository.kt @@ -0,0 +1,6 @@ +package com.ffii.tsms.modules.project.entity; + +import com.ffii.core.support.AbstractRepository + +interface ProjectCategoryRepository : AbstractRepository { +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTask.kt b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTask.kt index 000a4d1..ac924ee 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTask.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/ProjectTask.kt @@ -13,7 +13,7 @@ open class ProjectTask : IdEntity() { @ManyToOne @JoinColumn(name = "milestoneId") - open var paymentMilestone: PaymentMilestone? = null + open var milestone: Milestone? = null @NotNull @ManyToOne 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 new file mode 100644 index 0000000..65e70cc --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt @@ -0,0 +1,43 @@ +package com.ffii.tsms.modules.project.service + +import com.ffii.tsms.modules.data.entity.StaffRepository +import com.ffii.tsms.modules.data.service.CustomerService +import com.ffii.tsms.modules.project.entity.Project +import com.ffii.tsms.modules.project.entity.ProjectCategory +import com.ffii.tsms.modules.project.entity.ProjectCategoryRepository +import com.ffii.tsms.modules.project.entity.ProjectRepository +import com.ffii.tsms.modules.project.web.models.NewProjectRequest +import org.springframework.stereotype.Service + +@Service +class ProjectsService( + private val projectRepository: ProjectRepository, + private val customerService: CustomerService, private val projectCategoryRepository: ProjectCategoryRepository, + private val staffRepository: StaffRepository +) { + fun allProjects(): List { + return projectRepository.findAll() + } + + fun allProjectCategories(): List { + return projectCategoryRepository.findAll() + } + + fun saveProject(request: NewProjectRequest): Project { + val projectCategory = projectCategoryRepository.findById(request.projectCategoryId).orElseThrow() + val teamLead = staffRepository.findById(request.projectLeadId).orElseThrow() + val customer = customerService.saveCustomer(request.clientName, request.clientCode, request.clientEmail, request.clientPhone, request.clientContactName) + + // TODO: Add tasks, milestones, allocated + val project = Project().apply { + name = request.projectName + description = request.projectDescription + code = request.projectCode + this.projectCategory = projectCategory + this.teamLead = teamLead + this.customer = customer + } + + return projectRepository.save(project) + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/web/ProjectsController.kt b/src/main/java/com/ffii/tsms/modules/project/web/ProjectsController.kt index 680a7bd..e89c3a8 100644 --- a/src/main/java/com/ffii/tsms/modules/project/web/ProjectsController.kt +++ b/src/main/java/com/ffii/tsms/modules/project/web/ProjectsController.kt @@ -1,14 +1,27 @@ package com.ffii.tsms.modules.project.web -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import com.ffii.tsms.modules.project.entity.Project +import com.ffii.tsms.modules.project.entity.ProjectCategory +import com.ffii.tsms.modules.project.service.ProjectsService +import com.ffii.tsms.modules.project.web.models.NewProjectRequest +import jakarta.validation.Valid +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/projects") -class ProjectsController { +class ProjectsController(private val projectsService: ProjectsService) { @GetMapping - fun allProjects() { + fun allProjects(): List { + return projectsService.allProjects() + } + + @GetMapping("/categories") + fun projectCategories(): List { + return projectsService.allProjectCategories() + } + @PostMapping("/new") + fun saveProject(@Valid @RequestBody newProject: NewProjectRequest): Project { + return projectsService.saveProject(newProject) } } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt b/src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt new file mode 100644 index 0000000..5d46281 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt @@ -0,0 +1,44 @@ +package com.ffii.tsms.modules.project.web.models + +import jakarta.validation.constraints.NotBlank + +data class NewProjectRequest( + @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, + + val clientCode: String, + val clientName: String, + val clientContactName: String, + val clientPhone: String, + val clientEmail: String, + val clientSubsidiary: String, + + val tasks: Map, + + val allocatedStaffIds: List, + + val milestones: Map +) + +data class TaskAllocation( + val manhourAllocation: Map +) + +data class Milestone( + val startDate: String?, + val endDate: String?, + val payments: List +) + +data class PaymentInputs( + val id: Long, + val description: String, + val date: String, + val amount: Double +) \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20240318_01_wayne/01_salary_data.sql b/src/main/resources/db/changelog/changes/20240318_01_wayne/01_salary_data.sql new file mode 100644 index 0000000..368e051 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240318_01_wayne/01_salary_data.sql @@ -0,0 +1,41 @@ +-- liquibase formatted sql + +-- changeset wayne:salary_data + +INSERT INTO salary (salaryPoint, lowerLimit, upperLimit, increment) VALUES +(36, 170001, 180000, 10000), +(35, 160001, 170000, 10000), +(34, 150001, 160000, 10000), +(33, 140001, 150000, 10000), +(32, 130001, 140000, 10000), +(31, 120001, 130000, 10000), +(30, 110001, 120000, 10000), +(29, 100001, 110000, 10000), +(28, 90001, 100000, 10000), +(27, 80001, 90000, 10000), +(26, 70001, 80000, 10000), +(25, 68001, 70000, 2000), +(24, 66001, 68000, 2000), +(23, 64001, 66000, 2000), +(22, 62001, 64000, 2000), +(21, 60001, 62000, 2000), +(20, 58001, 60000, 2000), +(19, 56001, 58000, 2000), +(18, 54001, 56000, 2000), +(17, 52001, 54000, 2000), +(16, 50001, 52000, 2000), +(15, 47001, 50000, 3000), +(14, 44001, 47000, 3000), +(13, 41001, 44000, 3000), +(12, 38001, 41000, 3000), +(11, 35001, 38000, 3000), +(10, 33001, 35000, 2000), +(9, 31001, 33000, 2000), +(8, 29001, 31000, 2000), +(7, 27001, 29000, 2000), +(6, 25001, 27000, 2000), +(5, 23001, 25000, 2000), +(4, 21001, 23000, 2000), +(3, 19001, 21000, 2000), +(2, 17001, 19000, 2000), +(1, 15001, 17000, 2000); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20240318_01_wayne/02_mock_team_leads.sql b/src/main/resources/db/changelog/changes/20240318_01_wayne/02_mock_team_leads.sql new file mode 100644 index 0000000..ce29748 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240318_01_wayne/02_mock_team_leads.sql @@ -0,0 +1,35 @@ +-- liquibase formatted sql + +-- changeset wayne:mock_team_leads + +INSERT INTO `user` (name, username, password) VALUES + ('Wayne Lee','wlee','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'), + ('Ming Chan','mchan','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'); + +INSERT INTO company (companyCode, name) VALUES + ('ABC', 'Company ABC'); + +INSERT INTO team (name, code) VALUES + ('Team Wayne Lee', 'WL'), + ('Team Ming Chan', 'MC'); + +INSERT INTO salary_effective (date, salaryId) VALUES + (current_date, 1); + +INSERT INTO staff (userId, name, staffId, companyId, teamId, salaryEffId) VALUES + ( + (SELECT id from `user` where username = 'wlee'), + 'Wayne Lee', + '001', + (SELECT id from company where companyCode = 'ABC'), + (SELECT id from team where code = 'WL'), + (SELECT id from salary_effective where salaryId = 1) + ), + ( + (SELECT id from `user` where username = 'mchan'), + 'Ming Chan', + '002', + (SELECT id from company where companyCode = 'ABC'), + (SELECT id from team where code = 'MC'), + (SELECT id from salary_effective where salaryId = 1) + ); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20240318_01_wayne/03_project_categories.sql b/src/main/resources/db/changelog/changes/20240318_01_wayne/03_project_categories.sql new file mode 100644 index 0000000..3be9821 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240318_01_wayne/03_project_categories.sql @@ -0,0 +1,12 @@ +-- liquibase formatted sql +-- changeset wayne:project_category + +CREATE TABLE project_category ( + id INT NOT NULL AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + CONSTRAINT pk_project_category PRIMARY KEY (id) +); + +INSERT INTO project_category (name) VALUES + ('Project to be bidded'), + ('Confirmed Project'); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20240318_01_wayne/04_update_project.sql b/src/main/resources/db/changelog/changes/20240318_01_wayne/04_update_project.sql new file mode 100644 index 0000000..cf2e192 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240318_01_wayne/04_update_project.sql @@ -0,0 +1,7 @@ +-- liquibase formatted sql +-- changeset wayne:update_project + +ALTER TABLE project ADD code VARCHAR(30) NOT NULL; +ALTER TABLE project ADD projectCategoryId INT NULL; +ALTER TABLE project ADD CONSTRAINT FK_PROJECT_ON_PROJECTCATEGORYID FOREIGN KEY (projectCategoryId) REFERENCES project_category (id); +