瀏覽代碼

add project import function

tags/Baseline_30082024_BACKEND_UAT
cyril.tsui 1 年之前
父節點
當前提交
9ddfcf6aab
共有 16 個文件被更改,包括 355 次插入28 次删除
  1. +1
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/BuildingTypeRepository.kt
  2. +4
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/CustomerRepository.java
  3. +2
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/LocationRepository.kt
  4. +1
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java
  5. +1
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/Subsidiary.java
  6. +6
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/SubsidiaryRepository.java
  7. +2
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/TeamRepository.java
  8. +1
    -0
      src/main/java/com/ffii/tsms/modules/data/entity/WorkNatureRepository.kt
  9. +12
    -0
      src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt
  10. +11
    -0
      src/main/java/com/ffii/tsms/modules/data/service/SubsidiaryService.kt
  11. +2
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/ProjectRepository.kt
  12. +270
    -24
      src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt
  13. +24
    -2
      src/main/java/com/ffii/tsms/modules/project/web/ProjectsController.kt
  14. +4
    -2
      src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt
  15. +9
    -0
      src/main/resources/db/changelog/changes/20240617_01_cyril/01_update_task.sql
  16. +5
    -0
      src/main/resources/db/changelog/changes/20240617_01_cyril/02_update_project.sql

+ 1
- 0
src/main/java/com/ffii/tsms/modules/data/entity/BuildingTypeRepository.kt 查看文件

@@ -3,4 +3,5 @@ package com.ffii.tsms.modules.data.entity;
import com.ffii.core.support.AbstractRepository

interface BuildingTypeRepository : AbstractRepository<BuildingType, Long> {
fun findByName(name: String): BuildingType?
}

+ 4
- 0
src/main/java/com/ffii/tsms/modules/data/entity/CustomerRepository.java 查看文件

@@ -3,6 +3,7 @@ package com.ffii.tsms.modules.data.entity;
import java.util.Optional;
import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.ffii.core.support.AbstractRepository;
@@ -11,4 +12,7 @@ public interface CustomerRepository extends AbstractRepository<Customer, Long> {
List<Customer> findAllByDeletedFalse();
Optional<Customer> findByCode(@Param("code") String code);
Optional<Customer> findByName(@Param("name") String name);

@Query("SELECT max(cast(substring_index(c.code, '-', -1) as long)) FROM Customer c")
Long getLatestCodeNumber();
}

+ 2
- 0
src/main/java/com/ffii/tsms/modules/data/entity/LocationRepository.kt 查看文件

@@ -3,4 +3,6 @@ package com.ffii.tsms.modules.data.entity;
import com.ffii.core.support.AbstractRepository

interface LocationRepository : AbstractRepository<Location, Long> {

fun findByName(name: String): Location
}

+ 1
- 0
src/main/java/com/ffii/tsms/modules/data/entity/StaffRepository.java 查看文件

@@ -25,4 +25,5 @@ public interface StaffRepository extends AbstractRepository<Staff, Long> {
Optional<List<Staff>> findAllByDeletedFalse();

Optional<Staff> findIdAndNameByUserIdAndDeletedFalse(Long id);

}

+ 1
- 0
src/main/java/com/ffii/tsms/modules/data/entity/Subsidiary.java 查看文件

@@ -10,6 +10,7 @@ import java.util.List;

import static jakarta.persistence.CascadeType.ALL;


@Entity
@Table(name = "subsidiary")
public class Subsidiary extends BaseEntity<Long> {


+ 6
- 0
src/main/java/com/ffii/tsms/modules/data/entity/SubsidiaryRepository.java 查看文件

@@ -1,6 +1,7 @@
package com.ffii.tsms.modules.data.entity;

import com.ffii.core.support.AbstractRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
@@ -12,4 +13,9 @@ public interface SubsidiaryRepository extends AbstractRepository<Subsidiary, Lon
List<Subsidiary> findAllByDeletedFalseAndIdIn(List<Long> id);

Optional<Subsidiary> findByCode(@Param("code") String code);

Optional<Subsidiary> findByName(@Param("name") String name);

@Query("SELECT max(cast(substring_index(s.code, '-', -1) as long)) FROM Subsidiary s")
Long getLatestCodeNumber();
}

+ 2
- 0
src/main/java/com/ffii/tsms/modules/data/entity/TeamRepository.java 查看文件

@@ -9,4 +9,6 @@ public interface TeamRepository extends AbstractRepository<Team, Long> {
List<Team> findByDeletedFalse();

Team findByStaff(Staff staff);

Team findByCode(String code);
}

+ 1
- 0
src/main/java/com/ffii/tsms/modules/data/entity/WorkNatureRepository.kt 查看文件

@@ -3,4 +3,5 @@ package com.ffii.tsms.modules.data.entity;
import com.ffii.core.support.AbstractRepository

interface WorkNatureRepository : AbstractRepository<WorkNature, Long> {
fun findByName(name: String): WorkNature?
}

+ 12
- 0
src/main/java/com/ffii/tsms/modules/data/service/CustomerService.kt 查看文件

@@ -37,6 +37,18 @@ open class CustomerService(
return customerRepository.findByCode(code);
}

open fun createClientCode(): String {
val prefix = "CT"

val latestClientCode = customerRepository.getLatestCodeNumber()

if (latestClientCode != null) {
return "$prefix-" + String.format("%03d", latestClientCode + 1L)
} else {
return "$prefix-001"
}
}

open fun saveCustomer(saveCustomer: SaveCustomerRequest): SaveCustomerResponse {

val duplicateCustomer = findCustomerByCode(saveCustomer.code)


+ 11
- 0
src/main/java/com/ffii/tsms/modules/data/service/SubsidiaryService.kt 查看文件

@@ -38,6 +38,17 @@ open class SubsidiaryService(
return subsidiaryRepository.findByCode(code);
}

open fun createSubsidiaryCode(): String {
val prefix = "SY"

val latestSubsidiaryCode = subsidiaryRepository.getLatestCodeNumber()

if (latestSubsidiaryCode != null) {
return "$prefix-" + String.format("%03d", latestSubsidiaryCode + 1L)
} else {
return "$prefix-001"
}
}
open fun saveSubsidiary(saveSubsidiary: SaveSubsidiaryRequest): SaveSubsidiaryResponse {

val duplicateSubsidiary = findSubsidiaryByCode(saveSubsidiary.code)


+ 2
- 0
src/main/java/com/ffii/tsms/modules/project/entity/ProjectRepository.kt 查看文件

@@ -34,4 +34,6 @@ interface ProjectRepository : AbstractRepository<Project, Long> {
fun findAllByStatusIsNotAndMainProjectIsNull(status: String): List<Project>

fun findAllByTeamLeadAndCustomer(teamLead: Staff, customer: Customer): List<Project>

fun findByCode(code: String): Project?
}

+ 270
- 24
src/main/java/com/ffii/tsms/modules/project/service/ProjectsService.kt 查看文件

@@ -1,26 +1,26 @@
package com.ffii.tsms.modules.project.service

import com.ffii.core.utils.ExcelUtils
import com.ffii.tsms.modules.common.SecurityUtils
import com.ffii.tsms.modules.data.entity.*
import com.ffii.tsms.modules.data.service.CustomerContactService
import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo
import com.ffii.tsms.modules.data.service.CustomerService
import com.ffii.tsms.modules.data.service.GradeService
import com.ffii.tsms.modules.data.service.SubsidiaryContactService
import com.ffii.tsms.modules.data.service.*
import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.project.entity.Milestone
import com.ffii.tsms.modules.project.entity.projections.InvoiceInfoSearchInfo
import com.ffii.tsms.modules.project.entity.projections.InvoiceSearchInfo
import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo
import com.ffii.tsms.modules.project.web.models.*
import com.ffii.tsms.modules.timesheet.entity.TimesheetRepository
import org.apache.commons.logging.LogFactory
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.Workbook
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,
@@ -46,7 +46,11 @@ open class ProjectsService(
private val timesheetRepository: TimesheetRepository,
private val taskTemplateRepository: TaskTemplateRepository,
private val subsidiaryContactService: SubsidiaryContactService,
private val subsidiaryContactRepository: SubsidiaryContactRepository
private val subsidiaryContactRepository: SubsidiaryContactRepository,
private val teamRepository: TeamRepository,
private val customerRepository: CustomerRepository,
private val subsidiaryRepository: SubsidiaryRepository,
private val customerSubsidiaryService: CustomerSubsidiaryService,
) {
open fun allProjects(): List<ProjectSearchInfo> {
return projectRepository.findProjectSearchInfoByOrderByCreatedDesc()
@@ -164,10 +168,15 @@ open class ProjectsService(
.orElseThrow() else null
val teamLead = staffRepository.findById(request.projectLeadId).orElseThrow()
val customer = customerService.findCustomer(request.clientId)
val subsidiaryContact = subsidiaryContactRepository.findById(request.clientContactId).orElse(null)
val clientContact = customerContactService.findByContactId(request.clientContactId)
val subsidiaryContact =
if (request.clientContactId != null) subsidiaryContactRepository.findById(request.clientContactId)
.orElse(null) else null
val clientContact =
if (request.clientContactId != null) customerContactService.findByContactId(request.clientContactId) else null
val customerSubsidiary = request.clientSubsidiaryId?.let { subsidiaryService.findSubsidiary(it) }
val mainProject = if (request.mainProjectId != null && request.mainProjectId > 0) projectRepository.findById(request.mainProjectId).orElse(null) else null
val mainProject =
if (request.mainProjectId != null && request.mainProjectId > 0) projectRepository.findById(request.mainProjectId)
.orElse(null) else null

val allTasksMap = tasksService.allTasks().associateBy { it.id }
val taskGroupMap = tasksService.allTaskGroups().associateBy { it.id }
@@ -179,15 +188,23 @@ open class ProjectsService(
project.apply {
name = request.projectName
description = request.projectDescription
code = if (this.code.isNullOrEmpty() && request.mainProjectId == null) createProjectCode(request.isClpProject, project) else if (this.code.isNullOrEmpty() && request.mainProjectId != null && mainProject != null) createSubProjectCode(mainProject, project) else this.code
code = request.projectCode
?: if (this.code.isNullOrEmpty() && request.mainProjectId == null) createProjectCode(
request.isClpProject,
project
) else if (this.code.isNullOrEmpty() && request.mainProjectId != null && mainProject != null) createSubProjectCode(
mainProject,
project
) else this.code
expectedTotalFee = request.expectedProjectFee
totalManhour = request.totalManhour
actualStart = request.projectActualStart
actualEnd = request.projectActualEnd
status = if (this.status == "Deleted" || this.deleted == true) "Deleted"
else if (this.actualStart != null && this.actualEnd != null) "Completed"
else if (this.actualStart != null) "On-going"
else "Pending To Start"
status = request.projectStatus
?: if (this.status == "Deleted" || this.deleted == true) "Deleted"
else if (this.actualStart != null && this.actualEnd != null) "Completed"
else if (this.actualStart != null) "On-going"
else "Pending To Start"
isClpProject = request.isClpProject
this.mainProject = mainProject

@@ -203,11 +220,11 @@ open class ProjectsService(
this.teamLead = teamLead
this.customer = customer
custLeadName =
if (request.isSubsidiaryContact == null || !request.isSubsidiaryContact) clientContact.name else subsidiaryContact.name
if (request.isSubsidiaryContact == null || !request.isSubsidiaryContact) clientContact?.name else subsidiaryContact?.name
custLeadEmail =
if (request.isSubsidiaryContact == null || !request.isSubsidiaryContact) clientContact.email else subsidiaryContact.email
if (request.isSubsidiaryContact == null || !request.isSubsidiaryContact) clientContact?.email else subsidiaryContact?.email
custLeadPhone =
if (request.isSubsidiaryContact == null || !request.isSubsidiaryContact) clientContact.phone else subsidiaryContact.phone
if (request.isSubsidiaryContact == null || !request.isSubsidiaryContact) clientContact?.phone else subsidiaryContact?.phone
this.customerSubsidiary = customerSubsidiary
this.customerContact = if (customerSubsidiary == null) clientContact else null
this.subsidiaryContact = if (customerSubsidiary != null) subsidiaryContact else null
@@ -279,11 +296,11 @@ open class ProjectsService(
if (milestones.isNotEmpty()) {
project.apply {
planStart = milestones.mapNotNull { it.startDate }.minOrNull()
planEnd = milestones.mapNotNull { it.endDate }.maxOrNull()
planEnd = request.projectPlanEnd ?: milestones.mapNotNull { it.endDate }.maxOrNull()
}
}

val savedProject = projectRepository.save(project)
val savedProject = projectRepository.saveAndFlush(project)

val milestonesToDelete = milestoneRepository.findAllByProject(project).subtract(milestones.toSet())
val tasksToDelete = projectTaskRepository.findAllByProject(project).subtract(tasksToSave.toSet())
@@ -422,8 +439,9 @@ open class ProjectsService(
val subsidiaryContact = project.customerSubsidiary?.id?.let { subsidiaryId ->
subsidiaryContactService.findAllBySubsidiaryId(subsidiaryId)
} ?: emptyList()
val customerContact = project.customer?.id?.let { customerId -> customerContactService.findAllByCustomerId(customerId) }
?: emptyList()
val customerContact =
project.customer?.id?.let { customerId -> customerContactService.findAllByCustomerId(customerId) }
?: emptyList()

MainProjectDetails(
projectId = project.id,
@@ -441,10 +459,238 @@ open class ProjectsService(
buildingTypeIds = project.buildingTypes.mapNotNull { buildingType -> buildingType.id },
workNatureIds = project.workNatures.mapNotNull { workNature -> workNature.id },
clientId = project.customer?.id,
clientContactId = subsidiaryContact.find { contact -> contact.name == project.custLeadName }?.id ?: customerContact.find { contact -> contact.name == project.custLeadName }?.id,
clientContactId = subsidiaryContact.find { contact -> contact.name == project.custLeadName }?.id
?: customerContact.find { contact -> contact.name == project.custLeadName }?.id,
clientSubsidiaryId = project.customerSubsidiary?.id,
expectedProjectFee = project.expectedTotalFee
)
}
}

@Transactional(rollbackFor = [Exception::class])
open fun importFile(workbook: Workbook?): String {
val logger = LogFactory.getLog(javaClass)

if (workbook == null) {
return "No Excel import" // if workbook is null
}

val sheet: Sheet = workbook.getSheetAt(0)

for (i in 2..<sheet.lastRowNum) {
val row = sheet.getRow(i)

if (row.getCell(0) != null && !row.getCell(0).stringCellValue.isNullOrBlank()) {
logger.info("row :$i | lastCellNum" + row.lastCellNum)

// process client
logger.info("---------client-------")
logger.info(customerRepository.findByName(row.getCell(5).stringCellValue.trim()))
val tempClient = customerRepository.findByName(row.getCell(5).stringCellValue.trim())
val currentClient = if (tempClient.isPresent) tempClient.orElseThrow() else customerService.saveCustomer(
SaveCustomerRequest(
code = customerService.createClientCode(),
name = ExcelUtils.getStringValue(row.getCell(5)),
typeId = ExcelUtils.getIntValue(row.getCell(6)).toLong(),
deleteSubsidiaryIds = mutableListOf(),
deleteContactIds = mutableListOf(),
addSubsidiaryIds = mutableListOf(),
addContacts = mutableListOf(),
address = null,
brNo = null,
id = null,
district = null,
)
).customer
val clientId = currentClient.id!!

logger.info("customer: $clientId")

// process project
logger.info("---------project-------")
val projectTeamLead = teamRepository.findByCode(ExcelUtils.getStringValue(row.getCell(4))).staff

var mainProjectId: Long? = null
var projectCode = StringBuilder(row.getCell(0).stringCellValue).insert(1, '-').toString()

if (projectCode.contains('(')) {
val splitProjectCode = projectCode.split('(')
logger.info("splitProjectCode: " + splitProjectCode[1].split(')')[0])
projectCode =
splitProjectCode[0] + '-' + String.format("%04d", splitProjectCode[1].split(')')[0].toInt())

val mainProject =
projectRepository.findByCode(splitProjectCode[0]) ?: projectRepository.saveAndFlush(
Project().apply {
name = row.getCell(1).stringCellValue
description = row.getCell(1).stringCellValue
code = splitProjectCode[0]
status = "Completed"
projectCategory = projectCategoryRepository.findById(1).orElseThrow()
customer = currentClient
teamLead = projectTeamLead
})

mainProjectId = mainProject.id
} else {
val splitProjectCode = projectCode.split('-')
projectCode = splitProjectCode[0] + '-' + String.format("%04d", splitProjectCode[1].toInt())
}

val projectId = projectRepository.findByCode(projectCode)?.id
logger.info("projectCode :$projectCode")

// process subsidiary
logger.info("---------subsidiary-------")
val subsidiary = if (row.getCell(7) != null && !row.getCell(7).stringCellValue.isNullOrBlank()) {
val tempSubsidiary = subsidiaryRepository.findByName(ExcelUtils.getStringValue(row.getCell(7)))

if (tempSubsidiary.isPresent) {
tempSubsidiary.orElseThrow()
} else {
subsidiaryRepository.findByName(ExcelUtils.getStringValue(row.getCell(7))).orElse(
subsidiaryService.saveSubsidiary(
SaveSubsidiaryRequest(
code = subsidiaryService.createSubsidiaryCode(),
name = ExcelUtils.getStringValue(row.getCell(7)),
typeId = ExcelUtils.getIntValue(row.getCell(8)).toLong(),
brNo = null,
address = null,
district = null,
deleteContactIds = mutableListOf(),
addContacts = mutableListOf(),
deleteCustomerIds = mutableListOf(),
addCustomerIds = mutableListOf(clientId),
id = null
)
).subsidiary
)
}
} else null

if (subsidiary != null) {
if (!customerSubsidiaryService.findAllCustomerIdsBySubsidiaryId(subsidiary.id!!)
.contains(clientId)
) {
subsidiaryService.saveSubsidiary(
SaveSubsidiaryRequest(
code = subsidiary.code,
name = subsidiary.name,
typeId = subsidiary.subsidiaryType.id!!,
brNo = subsidiary.brNo,
address = subsidiary.address,
district = subsidiary.district,
deleteContactIds = mutableListOf(),
addContacts = mutableListOf(),
deleteCustomerIds = mutableListOf(),
addCustomerIds = mutableListOf(clientId),
id = subsidiary.id
)
)
}
}

// process building type
logger.info("---------building type-------")
var buildingType = buildingTypeRepository.findByName(row.getCell(13).stringCellValue)
if (buildingType == null) {
buildingType =
buildingTypeRepository.saveAndFlush(BuildingType().apply {
name = row.getCell(13).stringCellValue
})
}

// process work nature
logger.info("---------work nature-------")
var workNature = workNatureRepository.findByName(row.getCell(14).stringCellValue)
if (workNature == null) {
workNature =
workNatureRepository.saveAndFlush(WorkNature().apply { name = row.getCell(14).stringCellValue })
}

// process staff - staff from column R (17)
logger.info("---------staff-------")
val allocatedStaffIds = mutableListOf<Long>()
for (j in 18..<row.lastCellNum step 2) {
logger.info("j: $j | staffId: " + row.getCell(j).stringCellValue)
val tempStaffId = row.getCell(j).stringCellValue

if (!tempStaffId.isNullOrBlank()) {
allocatedStaffIds.add(staffRepository.findByStaffId(tempStaffId).orElseThrow().id!!)
}
}

// get task template - TW-Full QS - stage 5
logger.info("---------task template-------")
val taskTemplate = taskTemplateRepository.findById(3).orElseThrow()

logger.info("---------Import-------")
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
saveProject(
NewProjectRequest(
projectCode = projectCode,
projectName = row.getCell(1).stringCellValue,
projectDescription = row.getCell(1).stringCellValue,
projectActualStart = ExcelUtils.getDateValue(
row.getCell(2),
DateTimeFormatter.ofPattern("MM/dd/yyyy")
),
projectPlanEnd = ExcelUtils.getDateValue(
row.getCell(3),
DateTimeFormatter.ofPattern("MM/dd/yyyy")
),
projectLeadId = projectTeamLead.id!!,
clientId = clientId,
clientSubsidiaryId = subsidiary?.id,
expectedProjectFee = row.getCell(9).numericCellValue,
totalManhour = row.getCell(11).numericCellValue,
locationId = 1, // HK
buildingTypeIds = mutableListOf(buildingType!!.id!!),
workNatureIds = mutableListOf(workNature!!.id!!),
serviceTypeId = 9,
fundingTypeId = row.getCell(16).numericCellValue.toLong(),
allocatedStaffIds = allocatedStaffIds,
isClpProject = projectCode[0] != 'M',
mainProjectId = mainProjectId,
projectCategoryId = 1,
contractTypeId = if (row.getCell(14).stringCellValue == "Maintenance Term Contract") 5 else 2,
projectId = projectId,
projectStatus = "On-going",
clientContactId = null,
isSubsidiaryContact = subsidiary?.id != null && subsidiary.id > 0,
manhourPercentageByGrade = taskTemplate.gradeAllocations.associateBy(
keySelector = { it.grade!!.id!! },
valueTransform = { it.percentage!! }
),
projectActualEnd = null,
taskTemplateId = taskTemplate.id,
taskGroups = mapOf(Pair(5, TaskGroupAllocation(mutableListOf(41), 100.0))),
milestones = mapOf(
Pair(
5, com.ffii.tsms.modules.project.web.models.Milestone(
startDate = ExcelUtils.getDateValue(
row.getCell(2),
DateTimeFormatter.ofPattern("MM/dd/yyyy")
).format(formatter),
endDate = ExcelUtils.getDateValue(
row.getCell(3),
DateTimeFormatter.ofPattern("MM/dd/yyyy")
).format(formatter),
payments = mutableListOf(
PaymentInputs(
-1, "Manhour Import", ExcelUtils.getDateValue(
row.getCell(2),
DateTimeFormatter.ofPattern("MM/dd/yyyy")
).toString(), row.getCell(9).numericCellValue
)
)
)
)
))
)
}
}

return if (sheet.lastRowNum > 0) "Import Excel success" else "Import Excel failure"
}
}

+ 24
- 2
src/main/java/com/ffii/tsms/modules/project/web/ProjectsController.kt 查看文件

@@ -2,15 +2,21 @@ package com.ffii.tsms.modules.project.web

import com.ffii.core.exception.NotFoundException
import com.ffii.tsms.modules.data.entity.*
import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo
import com.ffii.tsms.modules.project.entity.ProjectCategory
import com.ffii.tsms.modules.project.entity.ProjectRepository
import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo
import com.ffii.tsms.modules.project.service.ProjectsService
import com.ffii.tsms.modules.project.web.models.*
import jakarta.servlet.http.HttpServletRequest
import jakarta.validation.Valid
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.ServletRequestBindingException
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartHttpServletRequest


@RestController
@RequestMapping("/projects")
@@ -85,4 +91,20 @@ class ProjectsController(private val projectsService: ProjectsService, private v
fun projectWorkNatures(): List<WorkNature> {
return projectsService.allWorkNatures()
}

@PostMapping("/import")
@Throws(ServletRequestBindingException::class)
fun importFile(request: HttpServletRequest): ResponseEntity<*> {
var workbook: Workbook? = null

try {
val multipartFile = (request as MultipartHttpServletRequest).getFile("multipartFileList")
workbook = XSSFWorkbook(multipartFile?.inputStream)
} catch (e: Exception) {
println("Excel Wrong")
println(e)
}

return ResponseEntity.ok(projectsService.importFile(workbook))
}
}

+ 4
- 2
src/main/java/com/ffii/tsms/modules/project/web/models/NewProjectRequest.kt 查看文件

@@ -7,7 +7,7 @@ import java.time.LocalDate
data class NewProjectRequest(
// Project details
// @field:NotBlank(message = "project code cannot be empty")
// val projectCode: String,
val projectCode: String?,
@field:NotBlank(message = "project name cannot be empty")
val projectName: String,
val projectCategoryId: Long,
@@ -16,8 +16,10 @@ data class NewProjectRequest(
val projectId: Long?,
val projectActualStart: LocalDate?,
val projectActualEnd: LocalDate?,
val projectPlanEnd: LocalDate?,
val isClpProject: Boolean?,
val mainProjectId: Long?,
val projectStatus: String?,

val serviceTypeId: Long,
val fundingTypeId: Long,
@@ -30,7 +32,7 @@ data class NewProjectRequest(

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

// Allocation


+ 9
- 0
src/main/resources/db/changelog/changes/20240617_01_cyril/01_update_task.sql 查看文件

@@ -0,0 +1,9 @@
-- liquibase formatted sql
-- changeset cyril:task

INSERT
INTO
task
(name, taskGroupId)
VALUES
('5.8 Manhour Import', 5);

+ 5
- 0
src/main/resources/db/changelog/changes/20240617_01_cyril/02_update_project.sql 查看文件

@@ -0,0 +1,5 @@
-- liquibase formatted sql
-- changeset cyril:task

ALTER TABLE `project`
CHANGE COLUMN `name` `name` VARCHAR(255) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NOT NULL ;

Loading…
取消
儲存