| @@ -4,6 +4,7 @@ plugins { | |||
| id 'io.spring.dependency-management' version '1.1.0' | |||
| id 'org.jetbrains.kotlin.jvm' | |||
| id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0' | |||
| } | |||
| group = 'com.ffii' | |||
| @@ -2,8 +2,10 @@ package com.ffii.fpsms; | |||
| import org.springframework.boot.SpringApplication; | |||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| import org.springframework.context.annotation.ComponentScan; | |||
| @SpringBootApplication | |||
| @ComponentScan(basePackages = {"com.ffii.fpsms", "com.ffii.core"}) | |||
| public class FpsmsApplication { | |||
| public static void main(String[] args) { | |||
| @@ -6,6 +6,13 @@ import java.util.Optional | |||
| @Repository | |||
| interface EquipmentRepository : AbstractRepository<Equipment, Long> { | |||
| fun findByNameAndDeletedIsFalse(name: String): Equipment? | |||
| fun findByCodeAndDeletedIsFalse(code: String): Equipment? | |||
| fun findAllByDeletedFalse(): List<Equipment>; | |||
| fun findByCodeAndDeletedFalse(code: String): Equipment? | |||
| fun findByIdAndDeletedFalse(id: Long): Equipment?; | |||
| fun findByCodeAndDeletedIsFalse(code: String): Equipment?; | |||
| fun findByNameAndDeletedIsFalse(name: String): Equipment?; | |||
| fun findByDescriptionAndDeletedIsFalse(description: String): Equipment?; | |||
| } | |||
| @@ -24,4 +24,6 @@ open class EquipmentType : BaseEntity<Long>() { | |||
| @NotNull | |||
| @Column(name = "description", nullable = false, length = 500) | |||
| open var description: String? = null | |||
| } | |||
| @@ -5,4 +5,13 @@ import org.springframework.stereotype.Repository | |||
| @Repository | |||
| interface EquipmentTypeRepository : AbstractRepository<EquipmentType, Long> { | |||
| fun findAllByDeletedFalse(): List<EquipmentType>; | |||
| fun findByCodeAndDeletedFalse(code: String): EquipmentType? | |||
| fun findByIdAndDeletedFalse(id: Long): EquipmentType?; | |||
| fun findByCodeAndDeletedIsFalse(code: String): EquipmentType?; | |||
| fun findByNameAndDeletedIsFalse(name: String): EquipmentType?; | |||
| fun findByDescriptionAndDeletedIsFalse(description: String): EquipmentType?; | |||
| } | |||
| @@ -0,0 +1,94 @@ | |||
| package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.core.support.AbstractBaseEntityService | |||
| import com.ffii.core.support.JdbcDao | |||
| import com.ffii.fpsms.modules.master.entity.Equipment | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentRepository | |||
| import org.springframework.stereotype.Service | |||
| import org.springframework.transaction.annotation.Transactional | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentRequest | |||
| @Service | |||
| open class EquipmentService( | |||
| private val jdbcDao: JdbcDao, | |||
| private val equipmentRepository: EquipmentRepository, | |||
| ) : AbstractBaseEntityService<Equipment, Long, EquipmentRepository>(jdbcDao, equipmentRepository) { | |||
| open fun allEquipments(): List<Equipment> { | |||
| return equipmentRepository.findAll() | |||
| } | |||
| open fun getEquipmentsByPage(args: Map<String, Any>): List<Map<String, Any>> { | |||
| val sql = StringBuilder( | |||
| "SELECT e.id, e.code, e.name, e.description, e.equipmentTypeId FROM equipment e WHERE e.deleted = FALSE" | |||
| ) | |||
| if (args.containsKey("code")) { | |||
| sql.append(" AND e.code like :code ") | |||
| } | |||
| if (args.containsKey("id")) { | |||
| sql.append(" AND e.id like :id ") | |||
| } | |||
| if (args.containsKey("name")) { | |||
| sql.append(" AND e.name like :name ") | |||
| } | |||
| if (args.containsKey("description")) { | |||
| sql.append(" AND e.description like :description ") | |||
| } | |||
| if (args.containsKey("equipmentTypeId")) { | |||
| sql.append(" AND e.equipmentTypeId like :equipmentTypeId ") | |||
| } | |||
| return jdbcDao.queryForList(sql.toString(), args) | |||
| } | |||
| open fun findById(id: Long): Equipment? { | |||
| return equipmentRepository.findByIdAndDeletedFalse(id) | |||
| } | |||
| open fun findByCode(code: String): Equipment? { | |||
| return equipmentRepository.findByCodeAndDeletedIsFalse(code) | |||
| } | |||
| open fun findByName(name: String): Equipment? { | |||
| return equipmentRepository.findByNameAndDeletedIsFalse(name) | |||
| } | |||
| open fun findByDescription(description: String): Equipment? { | |||
| return equipmentRepository.findByDescriptionAndDeletedIsFalse(description) | |||
| } | |||
| @Transactional | |||
| open fun saveEquipment(request: NewEquipmentRequest): Equipment { | |||
| if (request.code.isNullOrBlank()) { | |||
| throw IllegalArgumentException("Equipment type code cannot be null or blank") | |||
| } | |||
| val duplicated = equipmentRepository.findByCodeAndDeletedFalse(request.code!!) | |||
| if (duplicated != null && duplicated.id != request.id) { | |||
| throw IllegalArgumentException("Equipment type code already exists") | |||
| } | |||
| val entity = if (request.id != null && request.id > 0) { | |||
| equipmentRepository.findByIdAndDeletedFalse(request.id) ?: Equipment() | |||
| } else { | |||
| Equipment() | |||
| } | |||
| entity.code = request.code | |||
| entity.name = request.name | |||
| entity.description = request.description | |||
| entity.equipmentType= request.equipmentType | |||
| return equipmentRepository.saveAndFlush(entity) | |||
| } | |||
| @Transactional | |||
| open fun deleteEquipment(id: Long) { | |||
| val Equipment = equipmentRepository.findByIdAndDeletedFalse(id) | |||
| Equipment?.let { et -> | |||
| et.deleted = true | |||
| equipmentRepository.saveAndFlush(et) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.core.support.AbstractBaseEntityService | |||
| import com.ffii.core.support.JdbcDao | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentType | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentTypeRepository | |||
| import org.springframework.stereotype.Service | |||
| import org.springframework.transaction.annotation.Transactional | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentTypeRequest | |||
| @Service | |||
| open class EquipmentTypeService( | |||
| private val jdbcDao: JdbcDao, | |||
| private val equipmentTypeRepository: EquipmentTypeRepository, | |||
| ) : AbstractBaseEntityService<EquipmentType, Long, EquipmentTypeRepository>(jdbcDao, equipmentTypeRepository) { | |||
| open fun allEquipmentTypes(): List<EquipmentType> { | |||
| return equipmentTypeRepository.findAll() | |||
| } | |||
| open fun getEquipmentTypesByPage(args: Map<String, Any>): List<Map<String, Any>> { | |||
| val sql = StringBuilder( | |||
| "SELECT e.id, e.code, e.name, e.description FROM equipment_type e WHERE e.deleted = FALSE" | |||
| ) | |||
| if (args.containsKey("code")) { | |||
| sql.append(" AND e.code like :code ") | |||
| } | |||
| if (args.containsKey("id")) { | |||
| sql.append(" AND e.id like :id ") | |||
| } | |||
| if (args.containsKey("name")) { | |||
| sql.append(" AND e.name like :name ") | |||
| } | |||
| if (args.containsKey("description")) { | |||
| sql.append(" AND e.description like :description ") | |||
| } | |||
| return jdbcDao.queryForList(sql.toString(), args) | |||
| } | |||
| open fun findById(id: Long): EquipmentType? { | |||
| return equipmentTypeRepository.findByIdAndDeletedFalse(id) | |||
| } | |||
| open fun findByCode(code: String): EquipmentType? { | |||
| return equipmentTypeRepository.findByCodeAndDeletedIsFalse(code) | |||
| } | |||
| open fun findByName(name: String): EquipmentType? { | |||
| return equipmentTypeRepository.findByNameAndDeletedIsFalse(name) | |||
| } | |||
| open fun findByDescription(description: String): EquipmentType? { | |||
| return equipmentTypeRepository.findByDescriptionAndDeletedIsFalse(description) | |||
| } | |||
| @Transactional | |||
| open fun saveEquipmentType(request: NewEquipmentTypeRequest): EquipmentType { | |||
| if (request.code.isNullOrBlank()) { | |||
| throw IllegalArgumentException("Equipment type code cannot be null or blank") | |||
| } | |||
| val duplicated = equipmentTypeRepository.findByCodeAndDeletedFalse(request.code!!) | |||
| if (duplicated != null && duplicated.id != request.id) { | |||
| throw IllegalArgumentException("Equipment type code already exists") | |||
| } | |||
| val entity = if (request.id != null && request.id > 0) { | |||
| equipmentTypeRepository.findByIdAndDeletedFalse(request.id) ?: EquipmentType() | |||
| } else { | |||
| EquipmentType() | |||
| } | |||
| entity.code = request.code | |||
| entity.name = request.name | |||
| entity.description = request.description | |||
| return equipmentTypeRepository.saveAndFlush(entity) | |||
| } | |||
| @Transactional | |||
| open fun deleteEquipmentType(id: Long) { | |||
| val equipmentType = equipmentTypeRepository.findByIdAndDeletedFalse(id) | |||
| equipmentType?.let { et -> | |||
| et.deleted = true | |||
| equipmentTypeRepository.saveAndFlush(et) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| package com.ffii.fpsms.modules.master.web | |||
| import com.ffii.core.response.RecordsRes | |||
| import com.ffii.core.utils.CriteriaArgsBuilder | |||
| import com.ffii.core.utils.PagingUtils | |||
| import com.ffii.fpsms.modules.master.entity.Equipment | |||
| import com.ffii.fpsms.modules.master.service.EquipmentService | |||
| import jakarta.servlet.http.HttpServletRequest | |||
| import jakarta.validation.Valid | |||
| import org.springframework.web.bind.annotation.* | |||
| import java.util.Collections.emptyList | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentRequest | |||
| @RestController | |||
| @RequestMapping("/Equipment") | |||
| class EquipmentController( | |||
| private val equipmentService: EquipmentService | |||
| ) { | |||
| @GetMapping | |||
| fun allEquipment(): List<Equipment> { | |||
| return equipmentService.allEquipments() | |||
| } | |||
| // @GetMapping("/getRecordByPage") | |||
| // fun getAllItemsByPage(@RequestBody filterRequest: HttpServletRequest): RecordsRes<Map<String, Any>> { | |||
| // val pageSize = filterRequest.getParameter("pageSize").toString().toInt(); // Default to 10 if not provided | |||
| // val pageNumber = filterRequest.getParameter("pageNum").toString().toInt(); // Default to 0 if not provided | |||
| // val criteriaArgs = CriteriaArgsBuilder.withRequest(filterRequest) | |||
| // .addStringLike("name") | |||
| // .build(); | |||
| // | |||
| // val fullList = itemsService.getItemsByPage(criteriaArgs)?.subList(pageSize*pageNumber+1, pageSize*pageNumber+pageSize) | |||
| // val outputList = fullList?.subList(pageSize*pageNumber+1, pageSize*pageNumber+pageSize) | |||
| // | |||
| // return RecordsRes(outputList as List<Map<String, Any>>?, fullList?.size) | |||
| // } | |||
| @GetMapping("/getRecordByPage") | |||
| fun getAllEquipmentByPage( | |||
| request: HttpServletRequest | |||
| ): RecordsRes<Map<String, Any>> { | |||
| val criteriaArgs = CriteriaArgsBuilder.withRequest(request) | |||
| .addStringLike("name") | |||
| .addStringLike("code") | |||
| .addStringLike("description") | |||
| .addStringLike("id") | |||
| .build() | |||
| val pageSize = request.getParameter("pageSize")?.toIntOrNull() ?: 10 | |||
| val pageNum = request.getParameter("pageNum")?.toIntOrNull() ?: 1 | |||
| // 方法名和变量名都要和 Service 保持一致 | |||
| val fullList = equipmentService.getEquipmentsByPage(criteriaArgs) ?: emptyList() | |||
| val paginatedList = PagingUtils.getPaginatedList(fullList, pageSize, pageNum) | |||
| return RecordsRes(paginatedList as List<Map<String, Any>>, fullList.size) | |||
| } | |||
| // 详情 | |||
| @GetMapping("/details/{id}") | |||
| fun getEquipment(@PathVariable id: Long): Equipment? { | |||
| return equipmentService.findById(id) | |||
| } | |||
| // 新增/编辑 | |||
| @PostMapping("/save") | |||
| fun saveEquipment(@Valid @RequestBody equipment: NewEquipmentRequest): Equipment { | |||
| return equipmentService.saveEquipment(equipment) | |||
| } | |||
| // 逻辑删除 | |||
| @DeleteMapping("/delete/{id}") | |||
| fun deleteEquipment(@PathVariable id: Long) { | |||
| equipmentService.deleteEquipment(id) | |||
| } | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| package com.ffii.fpsms.modules.master.web | |||
| import com.ffii.core.response.RecordsRes | |||
| import com.ffii.core.utils.CriteriaArgsBuilder | |||
| import com.ffii.core.utils.PagingUtils | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentType | |||
| import com.ffii.fpsms.modules.master.service.EquipmentTypeService | |||
| import jakarta.servlet.http.HttpServletRequest | |||
| import jakarta.validation.Valid | |||
| import org.springframework.web.bind.annotation.* | |||
| import java.util.Collections.emptyList | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentTypeRequest | |||
| @RestController | |||
| @RequestMapping("/EquipmentType") | |||
| class EquipmentTypeController( | |||
| private val equipmentTypeService: EquipmentTypeService | |||
| ) { | |||
| @GetMapping | |||
| fun allEquipmentType(): List<EquipmentType> { | |||
| return equipmentTypeService.allEquipmentTypes() | |||
| } | |||
| // @GetMapping("/getRecordByPage") | |||
| // fun getAllItemsByPage(@RequestBody filterRequest: HttpServletRequest): RecordsRes<Map<String, Any>> { | |||
| // val pageSize = filterRequest.getParameter("pageSize").toString().toInt(); // Default to 10 if not provided | |||
| // val pageNumber = filterRequest.getParameter("pageNum").toString().toInt(); // Default to 0 if not provided | |||
| // val criteriaArgs = CriteriaArgsBuilder.withRequest(filterRequest) | |||
| // .addStringLike("name") | |||
| // .build(); | |||
| // | |||
| // val fullList = itemsService.getItemsByPage(criteriaArgs)?.subList(pageSize*pageNumber+1, pageSize*pageNumber+pageSize) | |||
| // val outputList = fullList?.subList(pageSize*pageNumber+1, pageSize*pageNumber+pageSize) | |||
| // | |||
| // return RecordsRes(outputList as List<Map<String, Any>>?, fullList?.size) | |||
| // } | |||
| @GetMapping("/getRecordByPage") | |||
| fun getAllEquipmentTypeByPage( | |||
| request: HttpServletRequest | |||
| ): RecordsRes<Map<String, Any>> { | |||
| val criteriaArgs = CriteriaArgsBuilder.withRequest(request) | |||
| .addStringLike("name") | |||
| .addStringLike("code") | |||
| .addStringLike("description") | |||
| .addStringLike("id") | |||
| .build() | |||
| val pageSize = request.getParameter("pageSize")?.toIntOrNull() ?: 10 | |||
| val pageNum = request.getParameter("pageNum")?.toIntOrNull() ?: 1 | |||
| // 方法名和变量名都要和 Service 保持一致 | |||
| val fullList = equipmentTypeService.getEquipmentTypesByPage(criteriaArgs) ?: emptyList() | |||
| val paginatedList = PagingUtils.getPaginatedList(fullList, pageSize, pageNum) | |||
| return RecordsRes(paginatedList as List<Map<String, Any>>, fullList.size) | |||
| } | |||
| // 详情 | |||
| @GetMapping("/details/{id}") | |||
| fun getEquipmentType(@PathVariable id: Long): EquipmentType? { | |||
| return equipmentTypeService.findById(id) | |||
| } | |||
| // 新增/编辑 | |||
| @PostMapping("/save") | |||
| fun saveEquipmentType(@Valid @RequestBody equipmentType: NewEquipmentTypeRequest): EquipmentType { | |||
| return equipmentTypeService.saveEquipmentType(equipmentType) | |||
| } | |||
| // 逻辑删除 | |||
| @DeleteMapping("/delete/{id}") | |||
| fun deleteEquipmentType(@PathVariable id: Long) { | |||
| equipmentTypeService.deleteEquipmentType(id) | |||
| } | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| package com.ffii.fpsms.modules.master.web.models | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentType | |||
| import jakarta.validation.constraints.NotBlank | |||
| import jakarta.validation.constraints.NotNull | |||
| import java.time.LocalDateTime | |||
| /* | |||
| enum class EquipmentType(val type: String) { | |||
| MATERIAL("mat"), | |||
| BY_PRODUCT("byp"), | |||
| PRODUCT("product"), | |||
| CONSUMABLE("consumables"), | |||
| } | |||
| */ | |||
| data class NewEquipmentRequest( | |||
| @field:NotBlank(message = "material code cannot be empty") | |||
| val code: String, | |||
| @field:NotBlank(message = "material name cannot be empty") | |||
| val name: String, | |||
| val id: Long?, | |||
| val description: String?, | |||
| val equipmentType: EquipmentType?, | |||
| // val type: List<NewTypeRequest>?, | |||
| // val uom: List<NewUomRequest>?, | |||
| // val weightUnit: List<NewWeightUnitRequest>?, | |||
| ) | |||
| @@ -0,0 +1,26 @@ | |||
| package com.ffii.fpsms.modules.master.web.models | |||
| import jakarta.validation.constraints.NotBlank | |||
| import jakarta.validation.constraints.NotNull | |||
| import java.time.LocalDateTime | |||
| /* | |||
| enum class EquipmentType(val type: String) { | |||
| MATERIAL("mat"), | |||
| BY_PRODUCT("byp"), | |||
| PRODUCT("product"), | |||
| CONSUMABLE("consumables"), | |||
| } | |||
| */ | |||
| data class NewEquipmentTypeRequest( | |||
| @field:NotBlank(message = "material code cannot be empty") | |||
| val code: String, | |||
| @field:NotBlank(message = "material name cannot be empty") | |||
| val name: String, | |||
| val id: Long?, | |||
| val description: String?, | |||
| // val type: List<NewTypeRequest>?, | |||
| // val uom: List<NewUomRequest>?, | |||
| // val weightUnit: List<NewWeightUnitRequest>?, | |||
| ) | |||
| @@ -69,4 +69,5 @@ class PurchaseOrderController( | |||
| fun checkPolAndCompletePo(@PathVariable id: Long): MessageResponse { | |||
| return purchaseOrderService.checkPolAndCompletePo(id) | |||
| } | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| spring: | |||
| datasource: | |||
| jdbc-url: jdbc:mysql://127.0.0.1:3306/fpsmsdb?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8 | |||
| jdbc-url: jdbc:mysql://127.0.0.1:3308/fpsmsdb?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8 | |||
| username: root | |||
| password: secret | |||
| @@ -0,0 +1,10 @@ | |||
| -- liquibase formatted sql | |||
| -- changeset enson:add_EquipmentType_column | |||
| ALTER TABLE `equipment_type` | |||
| ADD COLUMN `equipmentTypeID` VARCHAR(30) NULL AFTER `description`, | |||
| ADD COLUMN `equipmentTypeCapacity` INT(11) NULL AFTER `EquipmentTypeID`, | |||
| ADD COLUMN `equipmentTypeUom` VARCHAR(30) NULL AFTER `equipmentTypeCapacity` | |||
| ; | |||
| @@ -14,4 +14,5 @@ Configutation: | |||
| Root: | |||
| level: info | |||
| AppenderRef: | |||
| - ref: Console_Appender | |||
| - ref: Console_Appender | |||