diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategory.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategory.kt index be45bc1..0946dd2 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategory.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategory.kt @@ -1,14 +1,10 @@ package com.ffii.fpsms.modules.master.entity +import com.fasterxml.jackson.annotation.JsonBackReference import com.fasterxml.jackson.annotation.JsonManagedReference import com.ffii.core.entity.BaseEntity -import jakarta.persistence.CascadeType -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.JoinColumn -import jakarta.persistence.JoinTable -import jakarta.persistence.OneToMany -import jakarta.persistence.Table +import com.ffii.core.entity.IdEntity +import jakarta.persistence.* import jakarta.validation.constraints.NotNull @Entity @@ -22,6 +18,10 @@ open class QcCategory : BaseEntity() { @Column(name = "name") open var name: String? = null + @NotNull + @Column(name = "description") + open var description: String? = null + // @OneToMany(cascade = [CascadeType.ALL]) // @JoinTable( // name = "qc_item_category", @@ -33,4 +33,24 @@ open class QcCategory : BaseEntity() { @JsonManagedReference @OneToMany(mappedBy = "qcCategory", cascade = [CascadeType.ALL], orphanRemoval = true) open var qcItemCategory: MutableList = mutableListOf() +} + +@Entity +@Table(name = "items_qc_category_mapping") +open class ItemsQcCategoryMapping : IdEntity() { + @NotNull + @Column(name = "itemId") + open var itemId: Long? = null + + @NotNull + @Column(name = "qcCategoryId") + open var qcCategoryId: Long? = null + + @NotNull + @Column(name = "type") + open var type: String? = null +// +// @ManyToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "qcCategoryId") +// val qcCategory: QcCategory? = null } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategoryRepository.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategoryRepository.kt index 6fd7a66..d25cd15 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategoryRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/QcCategoryRepository.kt @@ -2,6 +2,8 @@ package com.ffii.fpsms.modules.master.entity import com.ffii.core.support.AbstractRepository import com.ffii.fpsms.modules.master.entity.projections.QcCategoryCombo +import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo +import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository @Repository @@ -9,4 +11,24 @@ interface QcCategoryRepository : AbstractRepository { fun findAllByDeletedIsFalse(): List; fun findQcCategoryComboByDeletedIsFalse(): List; + +// @Query( +// value = """ +// SELECT qcc.* FROM qc_category qcc +// LEFT JOIN items_qc_category_mapping map ON map.qcCategoryId = qcc.id +// WHERE map.type = :type AND map.itemId = :itemId AND qcc.deleted = false +// ORDER BY qcc.id +// LIMIT 1 +// """, +// nativeQuery = true +// ) + @Query( + """ + SELECT qcc FROM QcCategory qcc + JOIN ItemsQcCategoryMapping map ON qcc.id = map.qcCategoryId + WHERE map.itemId = :itemId AND map.type = :type AND qcc.deleted = false + """ + ) + fun findQcCategoryInfoByItemIdAndType(itemId: Long, type: String): QcCategoryInfo?; +// fun findByItemIdAndType(itemId: Long, type: String): QcCategory?; } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategory.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategory.kt index 8145eb1..d9ea2db 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategory.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategory.kt @@ -22,7 +22,12 @@ open class QcItemCategory : IdEntity() { @JoinColumn(name = "qcItemId") open var qcItem: QcItem? = null + @NotNull + @Column(name = "order") + open var order: Int = 0 + @Size(max = 1000) @Column(name = "description", length = 1000) open var description: String? = null + } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategoryRepository.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategoryRepository.kt index 1528ddf..c4d3376 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategoryRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/QcItemCategoryRepository.kt @@ -1,8 +1,11 @@ package com.ffii.fpsms.modules.master.entity import com.ffii.core.support.AbstractRepository +import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo +import com.ffii.fpsms.modules.qc.entity.projection.QcItemInfo import org.springframework.stereotype.Repository @Repository interface QcItemCategoryRepository : AbstractRepository { + fun findAllByQcCategoryId(qcCategoryId : Long): List } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt index 26e5e73..f51e840 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt @@ -373,4 +373,16 @@ open class ItemsService( return jdbcDao.queryForList(sql.toString(), args); } + + open fun getItemsIdWithSameCategoryForQc(args: Map): List { + val sql = StringBuilder("SELECT" + + " i.id " + + " FROM items i " + + " INNER JOIN items_qc_category_mapping iqcm ON iqcm.itemId = i.id AND iqcm.type = :qcType " + + " WHERE i.deleted = false " + + " AND LEFT(i.code, 2) = (SELECT LEFT(code, 2) FROM items WHERE id = :itemId)" + + " AND i.id != :itemId " + ) + return jdbcDao.queryForInts(sql.toString(), args); + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt index 055d2c1..4c76f02 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt @@ -4,11 +4,13 @@ import com.ffii.core.support.AbstractBaseEntityService import com.ffii.fpsms.modules.master.entity.QcCategory import com.ffii.fpsms.modules.master.entity.QcCategoryRepository import com.ffii.fpsms.modules.master.entity.projections.QcCategoryCombo +import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo import org.springframework.stereotype.Service @Service open class QcCategoryService( - private val qcCategoryRepository: QcCategoryRepository + private val qcCategoryRepository: QcCategoryRepository, + private val itemsService: ItemsService ) { open fun allQcCategories(): List { return qcCategoryRepository.findAllByDeletedIsFalse() @@ -17,4 +19,17 @@ open class QcCategoryService( open fun getQcCategoryCombo(): List { return qcCategoryRepository.findQcCategoryComboByDeletedIsFalse(); } + + open fun getQcCategoryInfoByMapping(itemId : Long, type: String): QcCategoryInfo? { + var result = qcCategoryRepository.findQcCategoryInfoByItemIdAndType(itemId, type) + if (result == null) { // Temporarily fix for missing QC template (Auto find template from similar items) + val args = mapOf( + "itemId" to itemId, + "qcType" to type + ) + val similarItemIds = itemsService.getItemsIdWithSameCategoryForQc(args); + result = qcCategoryRepository.findQcCategoryInfoByItemIdAndType(similarItemIds[0].toLong(), type) + } + return result; + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/QcItemService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/QcItemService.kt index 75f9edc..d5641a0 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/QcItemService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/QcItemService.kt @@ -1,11 +1,14 @@ package com.ffii.fpsms.modules.master.service -import com.ffii.core.support.AbstractBaseEntityService -import com.ffii.core.support.JdbcDao +import com.ffii.core.exception.NotFoundException +import com.ffii.fpsms.modules.master.entity.QcCategoryRepository import com.ffii.fpsms.modules.master.entity.QcItem +import com.ffii.fpsms.modules.master.entity.QcItemCategoryRepository import com.ffii.fpsms.modules.master.entity.QcItemRepository import com.ffii.fpsms.modules.master.web.models.SaveQcItemRequest import com.ffii.fpsms.modules.master.web.models.SaveQcItemResponse +import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo +import com.ffii.fpsms.modules.qc.entity.projection.QcItemInfo import jakarta.validation.Valid import org.springframework.stereotype.Service import org.springframework.web.bind.annotation.RequestBody @@ -13,6 +16,8 @@ import org.springframework.web.bind.annotation.RequestBody @Service open class QcItemService( private val qcItemRepository: QcItemRepository, + private val qcCategoryRepository: QcCategoryRepository, + private val qcItemCategoryRepository: QcItemCategoryRepository, ) { open fun allQcItems(): List { return qcItemRepository.findAllByDeletedIsFalse() @@ -26,6 +31,11 @@ open class QcItemService( return qcItemRepository.findByIdAndDeletedIsFalse(id) } + open fun findQcItemsByTemplate(itemId: Long, type: String): List? { + val qcCategoryInfo = qcCategoryRepository.findQcCategoryInfoByItemIdAndType(itemId, type) ?: throw NotFoundException() + return qcItemCategoryRepository.findAllByQcCategoryId(qcCategoryInfo.id) + } + open fun markDeleted(id: Long): List { val qcItem = qcItemRepository.findById(id).orElseThrow().apply { deleted = true diff --git a/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt b/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt index 0eac19f..e493c1d 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt @@ -1,11 +1,11 @@ package com.ffii.fpsms.modules.master.web +import com.ffii.core.exception.NotFoundException import com.ffii.fpsms.modules.master.entity.QcCategory import com.ffii.fpsms.modules.master.entity.projections.QcCategoryCombo import com.ffii.fpsms.modules.master.service.QcCategoryService -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/qcCategories") @@ -21,4 +21,9 @@ class QcCategoryController( fun getQcCategoryCombo(): List { return qcCategoryService.getQcCategoryCombo(); } + + @GetMapping("/items") + fun getQcCategoryByTemplate(@RequestParam itemId: Long, @RequestParam(defaultValue = "IQC") type: String): QcCategoryInfo { + return qcCategoryService.getQcCategoryInfoByMapping(itemId, type) ?: throw NotFoundException() + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/web/QcItemController.kt b/src/main/java/com/ffii/fpsms/modules/master/web/QcItemController.kt index 02bd270..ab9ed0d 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/web/QcItemController.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/web/QcItemController.kt @@ -7,7 +7,10 @@ import com.ffii.fpsms.modules.master.entity.QcItemRepository import com.ffii.fpsms.modules.master.service.QcItemService import com.ffii.fpsms.modules.master.web.models.SaveQcItemRequest import com.ffii.fpsms.modules.master.web.models.SaveQcItemResponse +import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo +import com.ffii.fpsms.modules.qc.entity.projection.QcItemInfo import jakarta.validation.Valid +import jakarta.validation.constraints.NotBlank import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.web.bind.annotation.* @@ -37,8 +40,20 @@ class QcItemController( return qcItemService.findQcItemById(id) ?: throw NotFoundException() } + @GetMapping("/template") + fun qcItemsByTemplate(@RequestParam itemId: Long, @RequestParam(defaultValue = "IQC") type: String): List { + return qcItemService.findQcItemsByTemplate(itemId, type) ?: throw NotFoundException() + } + @PostMapping("/save") fun saveQcItem(@Valid @RequestBody request: SaveQcItemRequest): SaveQcItemResponse { return qcItemService.saveQcItem(request) } -} \ No newline at end of file +} + +data class GetQcItemRequest( + @field:NotBlank(message = "Item Id cannot be empty") + val itemId: Long, + @field:NotBlank(message = "Type cannot be empty") + val type: String, +) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/qc/entity/projection/QcCategoryInfo.kt b/src/main/java/com/ffii/fpsms/modules/qc/entity/projection/QcCategoryInfo.kt new file mode 100644 index 0000000..8b6513d --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/qc/entity/projection/QcCategoryInfo.kt @@ -0,0 +1,26 @@ +package com.ffii.fpsms.modules.qc.entity.projection + +import com.ffii.fpsms.modules.master.entity.QcItemCategory +import org.springframework.beans.factory.annotation.Value + +interface QcCategoryInfo { + val id: Long + val code: String + val name: String? + val description: String? + @get:Value("#{target.qcItemCategory}") + var qcItems: List +} + +interface QcItemInfo { + val id: Long + val order: Int + @get:Value("#{target.qcItem.id}") + val qcItemId: Long + @get:Value("#{target.qcItem.code}") + val code: String + @get:Value("#{target.qcItem.name}") + val name: String? + @get:Value("#{target.qcItem.description}") + val description: String? +} \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20251009_01_kelvinS/01_create_items_qc_category_mapping.sql b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/01_create_items_qc_category_mapping.sql new file mode 100644 index 0000000..9322699 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/01_create_items_qc_category_mapping.sql @@ -0,0 +1,9 @@ +-- liquibase formatted sql +-- changeset kelvinS:create items qc category mapping table + +CREATE TABLE `items_qc_category_mapping` ( + `id` INT NOT NULL, + `itemId` INT NOT NULL, + `qcCategoryId` INT NOT NULL, + `type` VARCHAR(45) NOT NULL, + PRIMARY KEY (`id`)); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20251009_01_kelvinS/02_alter_qc_item_category.sql b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/02_alter_qc_item_category.sql new file mode 100644 index 0000000..a7a1e37 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/02_alter_qc_item_category.sql @@ -0,0 +1,5 @@ +-- liquibase formatted sql +-- changeset kelvinS:alter qc item category table + +ALTER TABLE `qc_item_category` +ADD COLUMN `order` INT NOT NULL AFTER `qcCategoryId`; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20251009_01_kelvinS/03_alter_qc_category.sql b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/03_alter_qc_category.sql new file mode 100644 index 0000000..22ab73f --- /dev/null +++ b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/03_alter_qc_category.sql @@ -0,0 +1,5 @@ +-- liquibase formatted sql +-- changeset kelvinS:alter qc category table + +ALTER TABLE `qc_category` +ADD COLUMN `description` VARCHAR(255) NULL AFTER `name`; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20251009_01_kelvinS/04_alter_items_qc_category_mapping.sql b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/04_alter_items_qc_category_mapping.sql new file mode 100644 index 0000000..b55b74c --- /dev/null +++ b/src/main/resources/db/changelog/changes/20251009_01_kelvinS/04_alter_items_qc_category_mapping.sql @@ -0,0 +1,5 @@ +-- liquibase formatted sql +-- changeset kelvinS:alter item qc category mapping table + +ALTER TABLE `items_qc_category_mapping` +CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT ;