| @@ -4,6 +4,7 @@ plugins { | |||||
| id 'io.spring.dependency-management' version '1.1.0' | id 'io.spring.dependency-management' version '1.1.0' | ||||
| id 'org.jetbrains.kotlin.jvm' | id 'org.jetbrains.kotlin.jvm' | ||||
| id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0' | id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0' | ||||
| } | } | ||||
| group = 'com.ffii' | group = 'com.ffii' | ||||
| @@ -2,8 +2,10 @@ package com.ffii.fpsms; | |||||
| import org.springframework.boot.SpringApplication; | import org.springframework.boot.SpringApplication; | ||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||
| import org.springframework.context.annotation.ComponentScan; | |||||
| @SpringBootApplication | @SpringBootApplication | ||||
| @ComponentScan(basePackages = {"com.ffii.fpsms", "com.ffii.core"}) | |||||
| public class FpsmsApplication { | public class FpsmsApplication { | ||||
| public static void main(String[] args) { | public static void main(String[] args) { | ||||
| @@ -6,6 +6,13 @@ import java.util.Optional | |||||
| @Repository | @Repository | ||||
| interface EquipmentRepository : AbstractRepository<Equipment, Long> { | 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 | @NotNull | ||||
| @Column(name = "description", nullable = false, length = 500) | @Column(name = "description", nullable = false, length = 500) | ||||
| open var description: String? = null | open var description: String? = null | ||||
| } | } | ||||
| @@ -5,4 +5,13 @@ import org.springframework.stereotype.Repository | |||||
| @Repository | @Repository | ||||
| interface EquipmentTypeRepository : AbstractRepository<EquipmentType, Long> { | 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 { | fun checkPolAndCompletePo(@PathVariable id: Long): MessageResponse { | ||||
| return purchaseOrderService.checkPolAndCompletePo(id) | return purchaseOrderService.checkPolAndCompletePo(id) | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,5 @@ | |||||
| spring: | spring: | ||||
| datasource: | 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 | username: root | ||||
| password: secret | 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: | Root: | ||||
| level: info | level: info | ||||
| AppenderRef: | AppenderRef: | ||||
| - ref: Console_Appender | |||||
| - ref: Console_Appender | |||||