diff --git a/build.gradle b/build.gradle index b6b333e..14de75a 100644 --- a/build.gradle +++ b/build.gradle @@ -35,11 +35,16 @@ dependencies { implementation group: 'jakarta.validation', name: 'jakarta.validation-api', version: '3.0.2' implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.15.2' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.15.2' + implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.15.2' + implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5' implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5' implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + implementation "org.jetbrains.kotlin:kotlin-reflect" + compileOnly group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.0.0' runtimeOnly 'com.mysql:mysql-connector-j' @@ -47,7 +52,6 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" } configurations { diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/Task.kt b/src/main/java/com/ffii/tsms/modules/project/entity/Task.kt index 3d8d3cd..d05fd5e 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/Task.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/Task.kt @@ -1,20 +1,24 @@ package com.ffii.tsms.modules.project.entity import com.ffii.core.entity.BaseEntity -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.Table +import jakarta.persistence.* +import jakarta.validation.constraints.NotNull import org.hibernate.proxy.HibernateProxy @Entity @Table(name = "task") open class Task : BaseEntity() { + @NotNull @Column(name = "name") open var name: String? = null @Column(name = "description") open var description: String? = null + @ManyToOne + @JoinColumn(name = "taskGroupId") + open var taskGroup: TaskGroup? = null + final override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null) return false diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/TaskGroup.kt b/src/main/java/com/ffii/tsms/modules/project/entity/TaskGroup.kt new file mode 100644 index 0000000..495006d --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/entity/TaskGroup.kt @@ -0,0 +1,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.Table + +@Entity +@Table(name = "task_group") +open class TaskGroup : IdEntity() { + @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/TaskTemplate.kt b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplate.kt index 06dfcf8..16d8d9a 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplate.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/TaskTemplate.kt @@ -19,5 +19,6 @@ open class TaskTemplate : IdEntity() { @JoinTable(name = "task_template_tasks", joinColumns = [JoinColumn(name = "taskTemplateId")], inverseJoinColumns = [JoinColumn(name = "tasksId")]) - open var tasks: MutableSet = mutableSetOf() + @OrderBy + open var tasks: MutableList = mutableListOf() } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/service/TasksService.kt b/src/main/java/com/ffii/tsms/modules/project/service/TasksService.kt new file mode 100644 index 0000000..4e4d987 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/service/TasksService.kt @@ -0,0 +1,31 @@ +package com.ffii.tsms.modules.project.service + +import com.ffii.tsms.modules.project.entity.Task +import com.ffii.tsms.modules.project.entity.TaskRepository +import com.ffii.tsms.modules.project.entity.TaskTemplate +import com.ffii.tsms.modules.project.entity.TaskTemplateRepository +import org.springframework.stereotype.Service + +@Service +class TasksService( + private val taskTemplateRepository: TaskTemplateRepository, + private val taskRepository: TaskRepository +) { + fun allTasks(): List { + return taskRepository.findAll() + } + + fun allTaskTemplates(): List { + return taskTemplateRepository.findAll() + } + + fun saveTaskTemplate(code: String, name: String, taskIds: List): TaskTemplate { + return taskTemplateRepository.save( + TaskTemplate().apply { + this.name = name + this.code = code + this.tasks = taskRepository.findAllById(taskIds) + } + ) + } +} \ 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 new file mode 100644 index 0000000..680a7bd --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/web/ProjectsController.kt @@ -0,0 +1,14 @@ +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 + +@RestController +@RequestMapping("/projects") +class ProjectsController { + @GetMapping + fun allProjects() { + + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/web/TasksController.kt b/src/main/java/com/ffii/tsms/modules/project/web/TasksController.kt new file mode 100644 index 0000000..8de3826 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/web/TasksController.kt @@ -0,0 +1,35 @@ +package com.ffii.tsms.modules.project.web + +import com.ffii.tsms.modules.project.entity.Task +import com.ffii.tsms.modules.project.entity.TaskTemplate +import com.ffii.tsms.modules.project.service.TasksService +import com.ffii.tsms.modules.project.web.models.NewTaskTemplateRequest +import jakarta.validation.Valid +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/tasks") +class TasksController(private val tasksService: TasksService) { + @GetMapping + fun allTasks(): List { + return tasksService.allTasks() + } + + @GetMapping("/templates") + fun allTaskTemplates(): List { + return tasksService.allTaskTemplates() + } + + @PostMapping("/templates/new") + fun saveTaskTemplate(@Valid @RequestBody newTaskTemplate: NewTaskTemplateRequest): TaskTemplate { + return tasksService.saveTaskTemplate( + newTaskTemplate.code, + newTaskTemplate.name, + newTaskTemplate.taskIds + ) + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/web/models/NewTaskTemplateRequest.kt b/src/main/java/com/ffii/tsms/modules/project/web/models/NewTaskTemplateRequest.kt new file mode 100644 index 0000000..f6fd3af --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/web/models/NewTaskTemplateRequest.kt @@ -0,0 +1,11 @@ +package com.ffii.tsms.modules.project.web.models + +import jakarta.validation.constraints.NotBlank + +data class NewTaskTemplateRequest( + @field:NotBlank(message = "code cannot be empty") + val code: String, + @field:NotBlank(message = "name cannot be empty") + val name: String, + val taskIds: List = emptyList() +) diff --git a/src/main/resources/db/changelog/changes/20240128_01_wayne/02_task.sql b/src/main/resources/db/changelog/changes/20240128_01_wayne/02_task.sql index d53374c..7fda846 100644 --- a/src/main/resources/db/changelog/changes/20240128_01_wayne/02_task.sql +++ b/src/main/resources/db/changelog/changes/20240128_01_wayne/02_task.sql @@ -1,6 +1,12 @@ -- liquibase formatted sql -- changeset wayne:task +CREATE TABLE task_group ( + id INT NOT NULL AUTO_INCREMENT, + name VARCHAR(255) NULL, + CONSTRAINT pk_task_group PRIMARY KEY (id) +); + CREATE TABLE task ( id INT NOT NULL AUTO_INCREMENT, version INT NOT NULL DEFAULT '0', @@ -9,11 +15,14 @@ CREATE TABLE task ( modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, modifiedBy VARCHAR(30) NULL, deleted TINYINT(1) NOT NULL DEFAULT '0', - name VARCHAR(255) NULL, + name VARCHAR(255) NOT NULL, `description` VARCHAR(255) NULL, + taskGroupId INT NULL, CONSTRAINT pk_task PRIMARY KEY (id) ); +ALTER TABLE task ADD CONSTRAINT FK_TASK_ON_TASKGROUPID FOREIGN KEY (taskGroupId) REFERENCES task_group (id); + CREATE TABLE task_template ( id INT NOT NULL AUTO_INCREMENT, code VARCHAR(255) NOT NULL, diff --git a/src/main/resources/db/changelog/changes/20240128_01_wayne/06_task_data.sql b/src/main/resources/db/changelog/changes/20240128_01_wayne/06_task_data.sql new file mode 100644 index 0000000..dc84885 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240128_01_wayne/06_task_data.sql @@ -0,0 +1,63 @@ +-- liquibase formatted sql + +-- changeset wayne:task_data +INSERT +INTO + task_group + (name) +VALUES + ('1. Design & Cost Planning / Estimating'), + ('2. Tender Documentation'), + ('3. Tender Analysis & Report & Contract Documentation'), + ('4. Construction / Post Construction'), + ('5. Miscellaneous'); + +INSERT +INTO + task + (name, taskGroupId) +VALUES + ('1.1 Preparation of preliminary Cost Estimate / Cost Plan including Revised & Refined', 1), + ('1.2 Cash flow forecast', 1), + ('1.3 Cost studies for alternative design solutions', 1), + ('1.4 Attend design co-ordination / project review meetings', 1), + ('1.5 Prepare / Review RIC', 1), + + ('2.1 Advise on tendering & contractual arrangement', 2), + ('2.2 Drafting / Vetting front-parts (incl. Main Contract, Sub-contracts & Direct Contracts)', 2), + ('2.3 Carry out pre-qualification exercise / EOI', 2), + ('2.4 Measurement (incl. billing of items) for Works Packages', 2), + ('2.5 Measurement (incl. billing of items) for tender addendum for Works Packages', 2), + ('2.6 Bulk Checking of Bills of Quantities', 2), + ('2.7 Line through drawings & specifications to check against Bills of Quantities / SOR', 2), + ('2.8 Update cash flow forecast', 2), + ('2.9 Edit tender documents (Incl. Bills of Quantities / SOR)', 2), + ('2.10 Preparation of pre-tender estimates', 2), + ('2.11 Attend design co-ordination / project review meetings / project meetings', 2), + + ('3.1 Evaluation of tenders (incl. arithmetical checking, submission checking, etc)', 3), + ('3.2 Preparation of 3-rates bills', 3), + ('3.3 Preparation of Report on Tenderers (incl. three-rates bills)', 3), + ('3.4 Preparation of tender queries', 3), + ('3.5 Attend tender interviews', 3), + ('3.6 Draft Letter of Acceptance / Award', 3), + ('3.7 Preparation of Contract Documents for Works Packages', 3), + + ('4.1 Check insurance policies, surety bond, guarantee, etc.', 4), + ('4.2 Valuation of works completed for progress payment (incl. site visits)', 4), + ('4.3 Preparation of financial statements (incl. cash flow forecasts)', 4), + ('4.4 Cost check / advice on a alternative design solutions', 4), + ('4.5 Cost estimate for draft AIs/EIs/SIs', 4), + ('4.6 Advise on contractual issues & evaluate monetary contractual claim', 4), + ('4.7 Attend site meetings / project co-ordination meetings / project meetings', 4), + ('4.8 Measurement & valuation of variations / prime cost & provisional sums', 4), + ('4.9 Negotiation and settlement of final accounts (incl. meetings)', 4), + ('4.10 Preparation of Statement of Final Account', 4), + ('4.11 Preparation of Cost Analysis for the Completed project', 4), + ('4.12 Check / Review draft final bills', 4), + ('4.13 Carry out site check for draft final bills', 4), + + ('5.1 Preparation of Fee Proposal / Expression of Interest', 5), + ('5.2 Attend Management Meeting / Management Workshop', 5), + ('5.3 Preparation of project budget i.e. manhours vs fee receivables', 5), + ('5.4 Attend Local / International Conference / Seminar / Webinar', 5); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20240201_01_wayne/01_mock_task_templates.sql b/src/main/resources/db/changelog/changes/20240201_01_wayne/01_mock_task_templates.sql new file mode 100644 index 0000000..80aaed0 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240201_01_wayne/01_mock_task_templates.sql @@ -0,0 +1,57 @@ +-- liquibase formatted sql + +-- changeset wayne:mock_task_templates + +INSERT INTO task_template (code,name) VALUES + ('Pre-001','Pre-contract Template'), + ('Post-001','Post-contract Template'), + ('Full-001','Full Project Template'); + +INSERT INTO task_template_tasks (taskTemplateId,tasksId) VALUES + (1,1), + (2,1), + (3,1), + (1,2), + (3,2), + (1,3), + (2,3), + (3,3), + (3,4), + (3,5), + (1,6), + (3,6), + (1,7), + (3,7), + (3,8), + (3,9), + (3,10), + (3,11), + (3,12), + (3,13), + (3,14), + (3,15), + (3,16), + (3,17), + (3,18), + (3,19), + (3,20), + (3,21), + (3,22), + (3,23), + (3,24), + (3,25), + (3,26), + (3,27), + (3,28), + (3,29), + (3,30), + (3,31), + (3,32), + (3,33), + (3,34), + (3,35), + (3,36), + (3,37), + (3,38), + (3,39), + (3,40);