| @@ -3,8 +3,4 @@ package com.ffii.fpsms.enums | |||||
| enum class Status(val value: Int) { | enum class Status(val value: Int) { | ||||
| PENDING(1), | PENDING(1), | ||||
| COMPLETE(2) | COMPLETE(2) | ||||
| } | |||||
| enum class RelationColumnType(val col: String) { | |||||
| MATERIAL("materialId"), | |||||
| PRODUCT("productId") | |||||
| } | } | ||||
| @@ -0,0 +1,15 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.fasterxml.jackson.annotation.JsonBackReference | |||||
| import com.ffii.core.entity.IdEntity | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| @Entity | |||||
| @Table(name = "item_type") | |||||
| open class ItemType: IdEntity<Long>() { | |||||
| @NotNull | |||||
| @Column(name = "name") | |||||
| open var name: String? = null | |||||
| } | |||||
| @@ -0,0 +1,10 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.stereotype.Repository | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Repository | |||||
| interface ItemTypeRepository : AbstractRepository<ItemType, Long> { | |||||
| } | |||||
| @@ -7,8 +7,8 @@ import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | import jakarta.validation.constraints.NotNull | ||||
| @Entity | @Entity | ||||
| @Table(name = "product") | |||||
| open class Product : BaseEntity<Long>() { | |||||
| @Table(name = "items") | |||||
| open class Items : BaseEntity<Long>() { | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "code") | @Column(name = "code") | ||||
| open var code: String? = null | open var code: String? = null | ||||
| @@ -23,20 +23,10 @@ open class Product : BaseEntity<Long>() { | |||||
| @Column(name = "remarks") | @Column(name = "remarks") | ||||
| open var remarks: String? = null | open var remarks: String? = null | ||||
| @OneToMany(mappedBy = "product", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| @JsonManagedReference("product-weight-unit") | |||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | |||||
| private val weightUnit: Set<ProductMaterialWeightUnit> = HashSet() | |||||
| @OneToMany(mappedBy = "product", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| @JsonManagedReference("product-uom") | |||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | |||||
| private val uom: Set<ProductMaterialWeightUnit> = HashSet() | |||||
| @OneToMany(mappedBy = "product", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| @JsonManagedReference("product-uom") | |||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | |||||
| private val type: Set<ProductMaterialType> = HashSet() | |||||
| // (mappedBy = "items", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| @OneToOne | |||||
| @JoinColumn(name = "typeId", referencedColumnName = "id") | |||||
| open var type: ItemType? = null | |||||
| @Column(name = "shelfLife") | @Column(name = "shelfLife") | ||||
| open var shelfLife: Double? = null | open var shelfLife: Double? = null | ||||
| @@ -0,0 +1,11 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.stereotype.Repository | |||||
| @Repository | |||||
| interface ItemsRepository : AbstractRepository<Items, Long> { | |||||
| fun findAllByDeletedFalse(): List<Items>; | |||||
| fun findByIdAndTypeIdAndDeletedFalse(id: Long, typeId: Long): Items; | |||||
| fun findByCodeAndTypeIdAndDeletedFalse(code: String, typeId: Long): Items?; | |||||
| } | |||||
| @@ -1,71 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.fasterxml.jackson.annotation.JsonInclude | |||||
| import com.fasterxml.jackson.annotation.JsonManagedReference | |||||
| import com.ffii.core.entity.BaseEntity | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| @Entity | |||||
| @Table(name = "material") | |||||
| open class Material : BaseEntity<Long>() { | |||||
| @NotNull | |||||
| @Column(name = "code") | |||||
| open var code: String? = null | |||||
| @NotNull | |||||
| @Column(name = "name") | |||||
| open var name: String? = null | |||||
| @Column(name = "description") | |||||
| open var description: String? = null | |||||
| @Column(name = "remarks") | |||||
| open var remarks: String? = null | |||||
| @NotNull | |||||
| @Column(name = "isConsumables") | |||||
| open var isConsumables: Boolean? = null | |||||
| @OneToMany(mappedBy = "material", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| @JsonManagedReference("material-weight-unit") | |||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | |||||
| private val weightUnit: Set<ProductMaterialWeightUnit> = HashSet() | |||||
| @OneToMany(mappedBy = "material", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| @JsonManagedReference("material-uom") | |||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | |||||
| private val uom: Set<ProductMaterialUom> = HashSet() | |||||
| @OneToMany(mappedBy = "material", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| @JsonManagedReference("material-type") | |||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | |||||
| private val type: Set<ProductMaterialType> = HashSet() | |||||
| @Column(name = "shelfLife") | |||||
| open var shelfLife: Double? = null | |||||
| @Column(name = "countryOfOrigin") | |||||
| open var countryOfOrigin: String? = null | |||||
| @Column(name = "minHumid") | |||||
| open var minHumid: Double? = null | |||||
| @Column(name = "maxHumid") | |||||
| open var maxHumid: Double? = null | |||||
| @Column(name = "minTemp") | |||||
| open var minTemp: Double? = null | |||||
| @Column(name = "maxTemp") | |||||
| open var maxTemp: Double? = null | |||||
| @Column(name = "sampleRate") | |||||
| open var sampleRate: Double? = null | |||||
| @Column(name = "passingRate") | |||||
| open var passingRate: Double? = null | |||||
| @Column(name = "netWeight") | |||||
| open var netWeight: Double? = null | |||||
| } | |||||
| @@ -1,12 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.stereotype.Repository | |||||
| import java.util.Optional | |||||
| @Repository | |||||
| interface MaterialRepository : AbstractRepository<Material, Long> { | |||||
| fun findAllByDeletedFalse(): List<Material>; | |||||
| fun findByIdAndDeletedFalse(id: Long): Material; | |||||
| fun findByCodeAndDeletedIsFalse(code: String): Material?; | |||||
| } | |||||
| @@ -1,25 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.fasterxml.jackson.annotation.JsonBackReference | |||||
| import com.ffii.core.entity.IdEntity | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| @Entity | |||||
| @Table(name = "product_material_type") | |||||
| open class ProductMaterialType: IdEntity<Long>() { | |||||
| @ManyToOne | |||||
| @JoinColumn(name = "productId") | |||||
| @JsonBackReference | |||||
| open var product: Product? = null | |||||
| @ManyToOne | |||||
| @JoinColumn(name = "materialId") | |||||
| @JsonBackReference | |||||
| open var material: Material? = null | |||||
| @NotNull | |||||
| @Column(name = "type") | |||||
| open var type: String? = null | |||||
| } | |||||
| @@ -1,14 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.stereotype.Repository | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| import java.util.Optional | |||||
| @Repository | |||||
| interface ProductMaterialTypeRepository : AbstractRepository<ProductMaterialType, Long> { | |||||
| @Transactional | |||||
| fun deleteAllByMaterialId(id: Long) | |||||
| @Transactional | |||||
| fun deleteAllByProductId(id: Long) | |||||
| } | |||||
| @@ -1,24 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.fasterxml.jackson.annotation.JsonBackReference | |||||
| import com.ffii.core.entity.IdEntity | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| @Entity | |||||
| @Table(name = "product_material_uom") | |||||
| open class ProductMaterialUom: IdEntity<Long>() { | |||||
| @ManyToOne | |||||
| @JoinColumn(name = "productId") | |||||
| @JsonBackReference | |||||
| open var product: Product? = null | |||||
| @ManyToOne | |||||
| @JoinColumn(name = "materialId") | |||||
| @JsonBackReference | |||||
| open var material: Material? = null | |||||
| @NotNull | |||||
| @Column(name = "uom") | |||||
| open var uom: String? = null | |||||
| } | |||||
| @@ -1,17 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.data.jpa.repository.Modifying | |||||
| import org.springframework.data.jpa.repository.Query | |||||
| import org.springframework.stereotype.Repository | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Repository | |||||
| interface ProductMaterialUomRepository : AbstractRepository<ProductMaterialUom, Long> { | |||||
| @Transactional | |||||
| fun deleteAllByMaterialId(id: Long) | |||||
| @Transactional | |||||
| fun deleteAllByProductId(id: Long) | |||||
| } | |||||
| @@ -1,29 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.fasterxml.jackson.annotation.JsonBackReference | |||||
| import com.ffii.core.entity.IdEntity | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| @Entity | |||||
| @Table(name = "product_material_weightUnit") | |||||
| open class ProductMaterialWeightUnit: IdEntity<Long>() { | |||||
| @ManyToOne | |||||
| @JoinColumn(name = "productId") | |||||
| @JsonBackReference | |||||
| open var product: Product? = null | |||||
| @ManyToOne | |||||
| @JoinColumn(name = "materialId") | |||||
| @JsonBackReference | |||||
| open var material: Material? = null | |||||
| @NotNull | |||||
| @Column(name = "weightUnit") | |||||
| open var weightUnit: String? = null | |||||
| @NotNull | |||||
| @Column(name = "conversion") | |||||
| open var conversion: Double? = null | |||||
| } | |||||
| @@ -1,12 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.stereotype.Repository | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Repository | |||||
| interface ProductMaterialWeightUnitRepository : AbstractRepository<ProductMaterialWeightUnit, Long> { | |||||
| @Transactional | |||||
| fun deleteAllByMaterialId(id: Long) | |||||
| @Transactional | |||||
| fun deleteAllByProductId(id: Long) | |||||
| } | |||||
| @@ -1,10 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| interface ProductRepository: AbstractRepository<Product, Long> { | |||||
| fun findAllByDeletedFalse(): List<Product>; | |||||
| fun findByIdAndDeletedFalse(id: Long): Product; | |||||
| fun findByCodeAndDeletedIsFalse(code: String): Product?; | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| package com.ffii.fpsms.modules.master.service | |||||
| import com.ffii.core.support.AbstractBaseEntityService | |||||
| import com.ffii.core.support.AbstractIdEntityService | |||||
| import com.ffii.core.support.JdbcDao | |||||
| import com.ffii.fpsms.modules.master.entity.* | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Service | |||||
| open class ItemTypeService( | |||||
| private val jdbcDao: JdbcDao, | |||||
| private val itemTypeRepository: ItemTypeRepository | |||||
| ): AbstractIdEntityService<ItemType, Long, ItemTypeRepository>(jdbcDao, itemTypeRepository) { | |||||
| } | |||||
| @@ -0,0 +1,72 @@ | |||||
| 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.ItemTypeRepository | |||||
| import com.ffii.fpsms.modules.master.entity.Items | |||||
| import com.ffii.fpsms.modules.master.entity.ItemsRepository | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import com.ffii.fpsms.modules.master.web.models.NewItemRequest | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| import kotlin.jvm.optionals.getOrNull | |||||
| @Service | |||||
| open class ItemsService( | |||||
| private val jdbcDao: JdbcDao, | |||||
| private val itemsRepository: ItemsRepository, | |||||
| private val itemTypeRepository: ItemTypeRepository, | |||||
| ): AbstractBaseEntityService<Items, Long, ItemsRepository>(jdbcDao, itemsRepository) { | |||||
| // do mapping with projection | |||||
| open fun allItems(): List<Items> { | |||||
| // TODO: Replace by actual logic | |||||
| val items = itemsRepository.findAll() | |||||
| return items | |||||
| } | |||||
| open fun getItem(id: Long): Items? { | |||||
| return itemsRepository.findById(id).getOrNull() | |||||
| } | |||||
| @Transactional | |||||
| open fun saveItem(request: NewItemRequest): MessageResponse { | |||||
| val type = itemTypeRepository.findById(request.typeId).get() | |||||
| val duplicatedItem = itemsRepository.findByCodeAndTypeIdAndDeletedFalse(request.code, request.typeId) | |||||
| if (duplicatedItem != null && duplicatedItem.id != request.id) { | |||||
| return MessageResponse( | |||||
| id = request.id, | |||||
| code = request.code, | |||||
| name = request.name, | |||||
| type = type.name, | |||||
| message = "The item code has already existed", | |||||
| errorPosition = "code" | |||||
| ) | |||||
| } | |||||
| val item = if (request.id != null && request.id > 0) itemsRepository.findByIdAndTypeIdAndDeletedFalse(request.id, request.typeId) | |||||
| else Items() | |||||
| println(request.netWeight) | |||||
| item.apply { | |||||
| code = request.code | |||||
| name = request.name | |||||
| description = request.description | |||||
| remarks = request.remarks | |||||
| shelfLife = request.shelfLife | |||||
| countryOfOrigin = request.countryOfOrigin | |||||
| minHumid = request.minHumid | |||||
| maxHumid = request.maxHumid | |||||
| minTemp = request.minTemp | |||||
| maxTemp = request.maxTemp | |||||
| sampleRate = request.sampleRate | |||||
| passingRate = request.passingRate | |||||
| netWeight = request.netWeight | |||||
| this.type = type | |||||
| } | |||||
| val savedItem = itemsRepository.saveAndFlush(item) | |||||
| return MessageResponse( | |||||
| id = savedItem.id, | |||||
| name = savedItem.name, | |||||
| code = savedItem.code, | |||||
| type = type.name, | |||||
| message = "Item Save Success", | |||||
| errorPosition = null, | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -1,76 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.service | |||||
| import com.ffii.core.support.AbstractBaseEntityService | |||||
| import com.ffii.core.support.JdbcDao | |||||
| import com.ffii.fpsms.enums.RelationColumnType | |||||
| import com.ffii.fpsms.modules.master.entity.Material | |||||
| import com.ffii.fpsms.modules.master.entity.MaterialRepository | |||||
| import com.ffii.fpsms.modules.master.web.models.NewMaterialRequest | |||||
| import com.ffii.fpsms.modules.master.web.models.NewMaterialResponse | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| import kotlin.jvm.optionals.getOrNull | |||||
| @Service | |||||
| open class MaterialService( | |||||
| private val jdbcDao: JdbcDao, | |||||
| private val materialRepository: MaterialRepository, | |||||
| private val uomService: ProductMaterialUomService, | |||||
| private val typeService: ProductMaterialTypeService, | |||||
| private val weightUnitService: ProductMaterialWeightUnitService, | |||||
| ): AbstractBaseEntityService<Material, Long, MaterialRepository>(jdbcDao, materialRepository) { | |||||
| // do mapping with projection | |||||
| open fun allMaterials(): List<Material> { | |||||
| // TODO: Replace by actual logic | |||||
| val materials = materialRepository.findAll() | |||||
| return materials | |||||
| } | |||||
| open fun getMaterial(id: Long): Material? { | |||||
| return materialRepository.findById(id).getOrNull() | |||||
| } | |||||
| @Transactional | |||||
| open fun saveMaterial(request: NewMaterialRequest): NewMaterialResponse { | |||||
| val duplicateMaterial = materialRepository.findByCodeAndDeletedIsFalse(request.code) | |||||
| val material = | |||||
| if (request.id != null && request.id > 0) materialRepository.findByIdAndDeletedFalse(request.id) | |||||
| else Material() | |||||
| if (duplicateMaterial != null && duplicateMaterial.id != request.id) { | |||||
| return NewMaterialResponse( | |||||
| id = request.id, | |||||
| code = request.code, | |||||
| name = request.name, | |||||
| message = "The material code has already existed", | |||||
| errorPosition = "code" | |||||
| ) | |||||
| } | |||||
| material.apply { | |||||
| code = request.code | |||||
| name = request.name | |||||
| isConsumables = request.isConsumables | |||||
| description = request.description | |||||
| remarks = request.remarks | |||||
| shelfLife = request.shelfLife | |||||
| countryOfOrigin = request.countryOfOrigin | |||||
| minHumid = request.minHumid | |||||
| maxHumid = request.maxHumid | |||||
| minTemp = request.minTemp | |||||
| maxTemp = request.maxTemp | |||||
| sampleRate = request.sampleRate | |||||
| passingRate = request.passingRate | |||||
| netWeight = request.netWeight | |||||
| } | |||||
| val savedMaterial = materialRepository.saveAndFlush(material) | |||||
| val columnName = RelationColumnType.MATERIAL | |||||
| if (!request.uom.isNullOrEmpty()) uomService.saveUom(savedMaterial.id!!, columnName, request.uom) | |||||
| if (!request.weightUnit.isNullOrEmpty()) weightUnitService.saveWeightUnit(savedMaterial.id!!, columnName, request.weightUnit) | |||||
| if (!request.type.isNullOrEmpty()) typeService.saveType(savedMaterial.id!!, columnName, request.type) | |||||
| return NewMaterialResponse( | |||||
| id = savedMaterial.id, | |||||
| name = savedMaterial.name, | |||||
| code = savedMaterial.code, | |||||
| message = "Material Save Success", | |||||
| errorPosition = null, | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -1,48 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.service | |||||
| import com.ffii.core.support.JdbcDao | |||||
| import com.ffii.fpsms.enums.RelationColumnType | |||||
| import com.ffii.fpsms.modules.master.entity.* | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import com.ffii.fpsms.modules.master.web.models.NewTypeRequest | |||||
| import com.ffii.fpsms.modules.master.web.models.NewWeightUnitRequest | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Service | |||||
| open class ProductMaterialTypeService( | |||||
| private val jdbcDao: JdbcDao, | |||||
| private val materialRepository: MaterialRepository, | |||||
| private val productRepository: ProductRepository, | |||||
| private val productMaterialTypeRepository: ProductMaterialTypeRepository | |||||
| ) { | |||||
| @Transactional | |||||
| open fun saveType(id: Long, columnType: RelationColumnType, typeList: List<NewTypeRequest>): MessageResponse { | |||||
| var material: Material? = null | |||||
| var product: Product? = null | |||||
| when (columnType) { | |||||
| RelationColumnType.MATERIAL -> { | |||||
| productMaterialTypeRepository.deleteAllByMaterialId(id) | |||||
| material = materialRepository.findByIdAndDeletedFalse(id) | |||||
| } | |||||
| RelationColumnType.PRODUCT -> { | |||||
| productMaterialTypeRepository.deleteAllByProductId(id) | |||||
| product = productRepository.findByIdAndDeletedFalse(id) | |||||
| } | |||||
| } | |||||
| val entries = mutableListOf<ProductMaterialType>() | |||||
| for (entry in typeList) { | |||||
| entries += ProductMaterialType().apply { | |||||
| this.material = material | |||||
| this.product = product | |||||
| type = entry.type | |||||
| } | |||||
| } | |||||
| productMaterialTypeRepository.saveAll(entries) | |||||
| return MessageResponse( | |||||
| id = id, | |||||
| message = "Weight unit save success", | |||||
| errorPosition = null | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -1,48 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.service | |||||
| import com.ffii.core.support.AbstractIdEntityService | |||||
| import com.ffii.core.support.JdbcDao | |||||
| import com.ffii.fpsms.enums.RelationColumnType | |||||
| import com.ffii.fpsms.modules.master.entity.* | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import com.ffii.fpsms.modules.master.web.models.NewUomRequest | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Service | |||||
| open class ProductMaterialUomService( | |||||
| private val jdbcDao: JdbcDao, | |||||
| private val uomRepository: ProductMaterialUomRepository, | |||||
| private val materialRepository: MaterialRepository, | |||||
| private val productRepository: ProductRepository, | |||||
| ): AbstractIdEntityService<ProductMaterialUom, Long, ProductMaterialUomRepository>(jdbcDao, uomRepository) { | |||||
| @Transactional | |||||
| open fun saveUom(id: Long, columnType: RelationColumnType, uomList: List<NewUomRequest>): MessageResponse { | |||||
| var material: Material? = null | |||||
| var product: Product? = null | |||||
| when (columnType) { | |||||
| RelationColumnType.MATERIAL -> { | |||||
| uomRepository.deleteAllByMaterialId(id) | |||||
| material = materialRepository.findByIdAndDeletedFalse(id) | |||||
| } | |||||
| RelationColumnType.PRODUCT -> { | |||||
| uomRepository.deleteAllByProductId(id) | |||||
| product = productRepository.findByIdAndDeletedFalse(id) | |||||
| } | |||||
| } | |||||
| val entries = mutableListOf<ProductMaterialUom>() | |||||
| for (entry in uomList) { | |||||
| entries += ProductMaterialUom().apply { | |||||
| this.material = material | |||||
| this.product = product | |||||
| uom = entry.uom | |||||
| } | |||||
| } | |||||
| uomRepository.saveAll(entries) | |||||
| return MessageResponse( | |||||
| id = id, | |||||
| message = "Uom save success", | |||||
| errorPosition = null | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -1,48 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.service | |||||
| import com.ffii.core.support.JdbcDao | |||||
| import com.ffii.fpsms.enums.RelationColumnType | |||||
| import com.ffii.fpsms.modules.master.entity.* | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import com.ffii.fpsms.modules.master.web.models.NewWeightUnitRequest | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| @Service | |||||
| open class ProductMaterialWeightUnitService( | |||||
| private val jdbcDao: JdbcDao, | |||||
| private val weightUnitRepository: ProductMaterialWeightUnitRepository, | |||||
| private val materialRepository: MaterialRepository, | |||||
| private val productRepository: ProductRepository, | |||||
| ) { | |||||
| @Transactional | |||||
| open fun saveWeightUnit(id: Long, columnType: RelationColumnType, weightUnits: List<NewWeightUnitRequest>): MessageResponse { | |||||
| var material: Material? = null | |||||
| var product: Product? = null | |||||
| when (columnType) { | |||||
| RelationColumnType.MATERIAL -> { | |||||
| weightUnitRepository.deleteAllByMaterialId(id) | |||||
| material = materialRepository.findByIdAndDeletedFalse(id) | |||||
| } | |||||
| RelationColumnType.PRODUCT -> { | |||||
| weightUnitRepository.deleteAllByProductId(id) | |||||
| product = productRepository.findByIdAndDeletedFalse(id) | |||||
| } | |||||
| } | |||||
| val entries = mutableListOf<ProductMaterialWeightUnit>() | |||||
| for (entry in weightUnits) { | |||||
| entries += ProductMaterialWeightUnit().apply { | |||||
| this.material = material | |||||
| this.product = product | |||||
| weightUnit = entry.weightUnit | |||||
| conversion = entry.conversion | |||||
| } | |||||
| } | |||||
| weightUnitRepository.saveAll(entries) | |||||
| return MessageResponse( | |||||
| id = id, | |||||
| message = "Weight unit save success", | |||||
| errorPosition = null | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -1,75 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.service | |||||
| import com.ffii.core.support.AbstractBaseEntityService | |||||
| import com.ffii.core.support.JdbcDao | |||||
| import com.ffii.fpsms.enums.RelationColumnType | |||||
| import com.ffii.fpsms.modules.master.entity.Product | |||||
| import com.ffii.fpsms.modules.master.entity.ProductRepository | |||||
| import com.ffii.fpsms.modules.master.web.models.NewProductRequest | |||||
| import com.ffii.fpsms.modules.master.web.models.NewProductResponse | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| import kotlin.jvm.optionals.getOrNull | |||||
| @Service | |||||
| open class ProductService( | |||||
| private val jdbcDao: JdbcDao, | |||||
| private val productRepository: ProductRepository, | |||||
| private val uomService: ProductMaterialUomService, | |||||
| private val typeService: ProductMaterialTypeService, | |||||
| private val weightUnitService: ProductMaterialWeightUnitService, | |||||
| ): AbstractBaseEntityService<Product, Long, ProductRepository>(jdbcDao, productRepository) { | |||||
| // do mapping with projection | |||||
| open fun allProduct(): List<Product> { | |||||
| // TODO: Replace by actual logic | |||||
| val materials = productRepository.findAll() | |||||
| return materials | |||||
| } | |||||
| open fun getProduct(id: Long): Product? { | |||||
| return productRepository.findById(id).getOrNull() | |||||
| } | |||||
| @Transactional | |||||
| open fun saveProduct(request: NewProductRequest): NewProductResponse { | |||||
| val duplicateProduct = productRepository.findByCodeAndDeletedIsFalse(request.code) | |||||
| val product = | |||||
| if (request.id != null && request.id > 0) productRepository.findByIdAndDeletedFalse(request.id) | |||||
| else Product() | |||||
| if (duplicateProduct != null && duplicateProduct.id != request.id) { | |||||
| return NewProductResponse( | |||||
| id = request.id, | |||||
| code = request.code, | |||||
| name = request.name, | |||||
| message = "The product code has already existed", | |||||
| errorPosition = "code" | |||||
| ) | |||||
| } | |||||
| product.apply { | |||||
| code = request.code | |||||
| name = request.name | |||||
| description = request.description | |||||
| remarks = request.remarks | |||||
| shelfLife = request.shelfLife | |||||
| countryOfOrigin = request.countryOfOrigin | |||||
| minHumid = request.minHumid | |||||
| maxHumid = request.maxHumid | |||||
| minTemp = request.minTemp | |||||
| maxTemp = request.maxTemp | |||||
| sampleRate = request.sampleRate | |||||
| passingRate = request.passingRate | |||||
| netWeight = request.netWeight | |||||
| } | |||||
| val savedProduct = productRepository.saveAndFlush(product) | |||||
| val columnName = RelationColumnType.PRODUCT | |||||
| if (!request.uom.isNullOrEmpty()) uomService.saveUom(savedProduct.id!!, columnName, request.uom) | |||||
| if (!request.weightUnit.isNullOrEmpty()) weightUnitService.saveWeightUnit(savedProduct.id!!, columnName, request.weightUnit) | |||||
| if (!request.type.isNullOrEmpty()) typeService.saveType(savedProduct.id!!, columnName, request.type) | |||||
| return NewProductResponse( | |||||
| id = savedProduct.id, | |||||
| name = savedProduct.name, | |||||
| code = savedProduct.code, | |||||
| message = "Product Save Success", | |||||
| errorPosition = null, | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,28 @@ | |||||
| package com.ffii.fpsms.modules.master.web | |||||
| import com.ffii.core.exception.NotFoundException | |||||
| import com.ffii.fpsms.modules.master.entity.Items | |||||
| import com.ffii.fpsms.modules.master.service.ItemsService | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import com.ffii.fpsms.modules.master.web.models.NewItemRequest | |||||
| import jakarta.validation.Valid | |||||
| import org.springframework.web.bind.annotation.* | |||||
| @RestController | |||||
| @RequestMapping("/items") | |||||
| class ItemsController( | |||||
| private val materialService: ItemsService | |||||
| ) { | |||||
| @GetMapping | |||||
| fun allItems(): List<Items> { | |||||
| return materialService.allItems() | |||||
| } | |||||
| @GetMapping("/details/{id}") | |||||
| fun getItems(@PathVariable id: Long): Items { | |||||
| return materialService.getItem(id) ?: throw NotFoundException() | |||||
| } | |||||
| @PostMapping("/new") | |||||
| fun saveItem(@Valid @RequestBody newItem: NewItemRequest): MessageResponse { | |||||
| return materialService.saveItem(newItem) | |||||
| } | |||||
| } | |||||
| @@ -1,28 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.web | |||||
| import com.ffii.core.exception.NotFoundException | |||||
| import com.ffii.fpsms.modules.master.entity.Material | |||||
| import com.ffii.fpsms.modules.master.service.MaterialService | |||||
| import com.ffii.fpsms.modules.master.web.models.NewMaterialRequest | |||||
| import com.ffii.fpsms.modules.master.web.models.NewMaterialResponse | |||||
| import jakarta.validation.Valid | |||||
| import org.springframework.web.bind.annotation.* | |||||
| @RestController | |||||
| @RequestMapping("/material") | |||||
| class MaterialController( | |||||
| private val materialService: MaterialService | |||||
| ) { | |||||
| @GetMapping | |||||
| fun allMaterial(): List<Material> { | |||||
| return materialService.allMaterials() | |||||
| } | |||||
| @GetMapping("/details/{id}") | |||||
| fun getMaterial(@PathVariable id: Long): Material { | |||||
| return materialService.getMaterial(id) ?: throw NotFoundException() | |||||
| } | |||||
| @PostMapping("/new") | |||||
| fun saveMaterial(@Valid @RequestBody newMaterial: NewMaterialRequest): NewMaterialResponse { | |||||
| return materialService.saveMaterial(newMaterial) | |||||
| } | |||||
| } | |||||
| @@ -1,28 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.web | |||||
| import com.ffii.core.exception.NotFoundException | |||||
| import com.ffii.fpsms.modules.master.entity.Product | |||||
| import com.ffii.fpsms.modules.master.service.ProductService | |||||
| import com.ffii.fpsms.modules.master.web.models.NewProductRequest | |||||
| import com.ffii.fpsms.modules.master.web.models.NewProductResponse | |||||
| import jakarta.validation.Valid | |||||
| import org.springframework.web.bind.annotation.* | |||||
| @RestController | |||||
| @RequestMapping("/product") | |||||
| class ProductController( | |||||
| private val productService: ProductService | |||||
| ) { | |||||
| @GetMapping | |||||
| fun allProduct(): List<Product> { | |||||
| return productService.allProduct() | |||||
| } | |||||
| @GetMapping("/details/{id}") | |||||
| fun getProduct(@PathVariable id: Long): Product { | |||||
| return productService.getProduct(id) ?: throw NotFoundException() | |||||
| } | |||||
| @PostMapping("/new") | |||||
| fun saveProduct(@Valid @RequestBody newProduct: NewProductRequest): NewProductResponse { | |||||
| return productService.saveProduct(newProduct) | |||||
| } | |||||
| } | |||||
| @@ -1,9 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.web.models | |||||
| data class NewMaterialResponse( | |||||
| val id: Long?, | |||||
| val name: String?, | |||||
| val code: String?, | |||||
| val message: String?, // e.g. duplicated code | |||||
| val errorPosition: String?, //error field | |||||
| ) | |||||
| @@ -2,6 +2,9 @@ package com.ffii.fpsms.modules.master.web.models | |||||
| data class MessageResponse( | data class MessageResponse( | ||||
| val id: Long?, | val id: Long?, | ||||
| val name: String?, | |||||
| val code: String?, | |||||
| val type: String?, | |||||
| val message: String?, | val message: String?, | ||||
| val errorPosition: String?, // e.g. duplicated code | val errorPosition: String?, // e.g. duplicated code | ||||
| ) | ) | ||||
| @@ -3,13 +3,13 @@ package com.ffii.fpsms.modules.master.web.models | |||||
| import jakarta.validation.constraints.NotBlank | import jakarta.validation.constraints.NotBlank | ||||
| import jakarta.validation.constraints.NotNull | import jakarta.validation.constraints.NotNull | ||||
| data class NewMaterialRequest( | |||||
| data class NewItemRequest( | |||||
| @field:NotBlank(message = "material code cannot be empty") | @field:NotBlank(message = "material code cannot be empty") | ||||
| val code: String, | val code: String, | ||||
| @field:NotBlank(message = "material name cannot be empty") | @field:NotBlank(message = "material name cannot be empty") | ||||
| val name: String, | val name: String, | ||||
| @field:NotNull(message = "isConsumables cannot be null") | |||||
| val isConsumables: Boolean, | |||||
| @field:NotNull(message = "typeId cannot be null") | |||||
| val typeId: Long, | |||||
| val id: Long?, | val id: Long?, | ||||
| val description: String?, | val description: String?, | ||||
| @@ -23,18 +23,8 @@ data class NewMaterialRequest( | |||||
| val sampleRate: Double?, | val sampleRate: Double?, | ||||
| val passingRate: Double?, | val passingRate: Double?, | ||||
| val netWeight: Double?, | val netWeight: Double?, | ||||
| val type: List<NewTypeRequest>?, | |||||
| val uom: List<NewUomRequest>?, | |||||
| val weightUnit: List<NewWeightUnitRequest>?, | |||||
| // val type: List<NewTypeRequest>?, | |||||
| // val uom: List<NewUomRequest>?, | |||||
| // val weightUnit: List<NewWeightUnitRequest>?, | |||||
| ) | ) | ||||
| data class NewUomRequest( | |||||
| val uom: String | |||||
| ) | |||||
| data class NewTypeRequest( | |||||
| val type: String, | |||||
| ) | |||||
| data class NewWeightUnitRequest( | |||||
| val conversion: Double?, | |||||
| val weightUnit: String, | |||||
| ) | |||||
| @@ -1,30 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.web.models | |||||
| import jakarta.validation.constraints.NotBlank | |||||
| import jakarta.validation.constraints.NotNull | |||||
| data class NewProductRequest( | |||||
| @field:NotBlank(message = "product name cannot be empty") | |||||
| val code: String, | |||||
| @field:NotBlank(message = "product name cannot be empty") | |||||
| val name: String, | |||||
| @field:NotNull(message = "isConsumables cannot be empty") | |||||
| val isConsumables: Boolean, | |||||
| val id: Long?, | |||||
| val description: String?, | |||||
| val remarks: String?, | |||||
| val shelfLife: Double?, | |||||
| val countryOfOrigin: String?, | |||||
| val minHumid: Double?, | |||||
| val maxHumid: Double?, | |||||
| val minTemp: Double?, | |||||
| val maxTemp: Double?, | |||||
| val sampleRate: Double?, | |||||
| val passingRate: Double?, | |||||
| val netWeight: Double?, | |||||
| val type: List<NewTypeRequest>?, | |||||
| val uom: List<NewUomRequest>?, | |||||
| val weightUnit: List<NewWeightUnitRequest>?, | |||||
| ) | |||||
| @@ -1,9 +0,0 @@ | |||||
| package com.ffii.fpsms.modules.master.web.models | |||||
| data class NewProductResponse( | |||||
| val id: Long?, | |||||
| val name: String?, | |||||
| val code: String?, | |||||
| val message: String?, | |||||
| val errorPosition: String?, // e.g. duplicated code | |||||
| ) | |||||
| @@ -1,77 +0,0 @@ | |||||
| CREATE TABLE material ( | |||||
| id INT NOT NULL AUTO_INCREMENT, | |||||
| version INT NOT NULL DEFAULT '0', | |||||
| created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| createdBy VARCHAR(30) NULL, | |||||
| modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| modifiedBy VARCHAR(30) NULL, | |||||
| deleted TINYINT(1) NOT NULL DEFAULT '0', | |||||
| `code` VARCHAR(50) NOT NULL, | |||||
| `name` VARCHAR(50) NOT NULL, | |||||
| description VARCHAR(100) NULL, | |||||
| remarks varchar(500) NULL, | |||||
| isConsumables TINYINT(1) NOT NULL default 0, | |||||
| shelfLife INT(11) NULL, | |||||
| countryOfOrigin varchar(50) NULL, | |||||
| minHumid DECIMAL(16,2) NULL, | |||||
| maxHumid DECIMAL(16,2) NULL, | |||||
| minTemp DECIMAL(16,2) NULL, | |||||
| maxTemp DECIMAL(16,2) NULL, | |||||
| sampleRate DECIMAL(16,2) NULL, | |||||
| passingRate DECIMAL(16,2) NULL, | |||||
| netWeight DECIMAL(16,2) NULL, | |||||
| CONSTRAINT pk_material PRIMARY KEY (id) | |||||
| ); | |||||
| CREATE TABLE product ( | |||||
| id INT NOT NULL AUTO_INCREMENT, | |||||
| version INT NOT NULL DEFAULT '0', | |||||
| created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| createdBy VARCHAR(30) NULL, | |||||
| modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| modifiedBy VARCHAR(30) NULL, | |||||
| deleted TINYINT(1) NOT NULL DEFAULT '0', | |||||
| `code` VARCHAR(50) NOT NULL, | |||||
| `name` VARCHAR(50) NOT NULL, | |||||
| description VARCHAR(100) NULL, | |||||
| remarks varchar(500) NULL, | |||||
| isConsumables TINYINT(1) NOT NULL default 0, | |||||
| shelfLife INT(11) NULL, | |||||
| countryOfOrigin varchar(50) NULL, | |||||
| minHumid DECIMAL(16,2) NULL, | |||||
| maxHumid DECIMAL(16,2) NULL, | |||||
| minTemp DECIMAL(16,2) NULL, | |||||
| maxTemp DECIMAL(16,2) NULL, | |||||
| sampleRate DECIMAL(16,2) NULL, | |||||
| passingRate DECIMAL(16,2) NULL, | |||||
| netWeight DECIMAL(16,2) NULL, | |||||
| CONSTRAINT pk_product PRIMARY KEY (id) | |||||
| ); | |||||
| CREATE TABLE product_material_weightUnit ( | |||||
| productId INT NULL, | |||||
| materialId INT NULL, | |||||
| weightUnit VARCHAR(30) NOT NULL, | |||||
| conversion DECIMAL(16,2) NOT NULL DEFAULT 1 | |||||
| ); | |||||
| CREATE TABLE product_material_uom ( | |||||
| productId INT NULL, | |||||
| materialId INT NULL, | |||||
| uom VARCHAR(30) NOT NULL | |||||
| ); | |||||
| CREATE TABLE product_material_type ( | |||||
| productId INT NULL, | |||||
| materialId INT NULL, | |||||
| name VARCHAR(30) NOT NULL | |||||
| ); | |||||
| ALTER TABLE product_material_weightUnit ADD CONSTRAINT FK_PRODUCT_ON_WEIGHTUNIT FOREIGN KEY (productId) REFERENCES product (id); | |||||
| ALTER TABLE product_material_weightUnit ADD CONSTRAINT FK_MATERIAL_ON_WEIGHTUNIT FOREIGN KEY (materialId) REFERENCES material (id); | |||||
| ALTER TABLE product_material_uom ADD CONSTRAINT FK_PRODUCT_ON_UOM FOREIGN KEY (productId) REFERENCES product (id); | |||||
| ALTER TABLE product_material_uom ADD CONSTRAINT FK_MATERIAL_ON_UOM FOREIGN KEY (materialId) REFERENCES material (id); | |||||
| ALTER TABLE product_material_type ADD CONSTRAINT FK_PRODUCT_ON_TYPE FOREIGN KEY (productId) REFERENCES product (id); | |||||
| ALTER TABLE product_material_type ADD CONSTRAINT FK_MATERIAL_ON_TYPE FOREIGN KEY (materialId) REFERENCES material (id); | |||||
| @@ -1,10 +0,0 @@ | |||||
| ALTER TABLE `product_material_type` | |||||
| ADD COLUMN `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST; | |||||
| ALTER TABLE `product_material_uom` | |||||
| ADD COLUMN `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST; | |||||
| ALTER TABLE `product_material_weightUnit` | |||||
| ADD COLUMN `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST; | |||||
| @@ -1,6 +0,0 @@ | |||||
| ALTER TABLE `product_material_type` | |||||
| CHANGE COLUMN `name` `type` VARCHAR(30) NOT NULL; | |||||
| @@ -1,9 +0,0 @@ | |||||
| ALTER TABLE `product` | |||||
| CHANGE COLUMN `shelfLife` `shelfLife` DECIMAL(14,1) NOT NULL; | |||||
| ALTER TABLE `material` | |||||
| CHANGE COLUMN `shelfLife` `shelfLife` DECIMAL(14,1) NOT NULL; | |||||
| @@ -1,6 +0,0 @@ | |||||
| ALTER TABLE `product` | |||||
| DROP COLUMN `isConsumables`; | |||||
| @@ -0,0 +1,54 @@ | |||||
| --liquibase formatted sql | |||||
| --changeset derek:master item table | |||||
| CREATE TABLE item_type ( | |||||
| id INT NOT NULL AUTO_INCREMENT, | |||||
| name VARCHAR(50) NOT NULL, | |||||
| CONSTRAINT pk_item_type PRIMARY KEY (id) | |||||
| ); | |||||
| INSERT INTO item_type (name) VALUES | |||||
| ('material'), | |||||
| ('product'), | |||||
| ('by-product'), | |||||
| ('consumables'); | |||||
| CREATE TABLE items ( | |||||
| id INT NOT NULL AUTO_INCREMENT, | |||||
| version INT NOT NULL DEFAULT '0', | |||||
| created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| createdBy VARCHAR(30) NULL, | |||||
| modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| modifiedBy VARCHAR(30) NULL, | |||||
| deleted TINYINT(1) NOT NULL DEFAULT '0', | |||||
| `code` VARCHAR(50) NOT NULL, | |||||
| `name` VARCHAR(50) NOT NULL, | |||||
| description VARCHAR(100) NULL, | |||||
| remarks varchar(500) NULL, | |||||
| typeId INT(11) NOT NULL, | |||||
| shelfLife INT(11) NULL, | |||||
| countryOfOrigin varchar(50) NULL, | |||||
| minHumid DECIMAL(16,2) NULL, | |||||
| maxHumid DECIMAL(16,2) NULL, | |||||
| minTemp DECIMAL(16,2) NULL, | |||||
| maxTemp DECIMAL(16,2) NULL, | |||||
| sampleRate DECIMAL(16,2) NULL, | |||||
| passingRate DECIMAL(16,2) NULL, | |||||
| netWeight DECIMAL(16,2) NULL, | |||||
| CONSTRAINT pk_material PRIMARY KEY (id), | |||||
| CONSTRAINT fk_items FOREIGN KEY (`typeId`) REFERENCES `item_type` (`id`) | |||||
| ); | |||||
| CREATE TABLE uom_conversion ( | |||||
| id INT NOT NULL AUTO_INCREMENT, | |||||
| version INT NOT NULL DEFAULT '0', | |||||
| created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| createdBy VARCHAR(30) NULL, | |||||
| modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| modifiedBy VARCHAR(30) NULL, | |||||
| deleted TINYINT(1) NOT NULL DEFAULT '0', | |||||
| inQty DECIMAL(16,2) NOT NULL DEFAULT 1, | |||||
| inUom VARCHAR(50) NOT NULL, | |||||
| ratio DECIMAL(16,2) NOT NULL, | |||||
| outQty DECIMAL(16,2) NOT NULL DEFAULT 1, | |||||
| outUom VARCHAR(50) NOT NULL, | |||||
| CONSTRAINT pk_uom_conversion PRIMARY KEY (id) | |||||
| ); | |||||