feature/#25-dtos #28

Merged
william merged 11 commits from feature/#25-dtos into develop 2022-04-20 22:42:41 -04:00
23 changed files with 575 additions and 486 deletions
Showing only changes of commit d785cfdbe7 - Show all commits

View File

@ -2,13 +2,14 @@ package dev.fyloz.colorrecipesexplorer
object Constants {
object ControllerPaths {
const val file = "/api/file"
const val material = "/api/material"
const val FILE = "/api/file"
const val MATERIAL = "/api/material"
const val MATERIAL_TYPE = "/api/materialtype"
}
object FilePaths {
const val pdfs = "pdf"
const val PDF = "pdf"
const val simdut = "$pdfs/simdut"
const val SIMDUT = "$PDF/simdut"
}
}

View File

@ -2,8 +2,8 @@ package dev.fyloz.colorrecipesexplorer.config.initializers
import dev.fyloz.colorrecipesexplorer.config.annotations.RequireDatabase
import dev.fyloz.colorrecipesexplorer.config.properties.MaterialTypeProperties
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import dev.fyloz.colorrecipesexplorer.logic.MaterialTypeLogic
import dev.fyloz.colorrecipesexplorer.model.MaterialType
import mu.KotlinLogging
import org.springframework.context.annotation.Configuration
@ -23,17 +23,16 @@ class MaterialTypeInitializer(
private fun ensureSystemMaterialTypesExists() {
val systemTypes = materialTypeProperties.systemTypes.map { it.toMaterialType() }
val oldSystemTypes = materialTypeLogic.getAllSystemTypes().toMutableSet()
val oldSystemTypes = materialTypeLogic.getAll(true).toMutableSet()
fun saveOrUpdateSystemType(type: MaterialType) {
if (materialTypeLogic.existsByName(type.name)) {
with(materialTypeLogic.getByName(type.name)) {
if (!this.systemType) {
logger.info("Material type '${type.name}' already exists and will be flagged as a system type")
materialTypeLogic.update(this.copy(systemType = true))
} else {
logger.debug("System material type '${type.name}' already exists")
}
fun saveOrUpdateSystemType(type: MaterialTypeDto) {
val storedMaterialType = materialTypeLogic.getByName(type.name)
if (storedMaterialType != null) {
if (!storedMaterialType.systemType) {
logger.info("Material type '${type.name}' already exists and will be flagged as a system type")
materialTypeLogic.update(storedMaterialType.copy(systemType = true))
} else {
logger.debug("System material type '${type.name}' already exists")
}
} else {
logger.info("System material type '${type.name}' will be created")
@ -50,7 +49,7 @@ class MaterialTypeInitializer(
// Remove old system types
oldSystemTypes.forEach {
logger.info("Material type '${it.name}' is not a system type anymore")
materialTypeLogic.updateSystemType(it.copy(systemType = false))
materialTypeLogic.updateNonSystemType(it.copy(systemType = false))
}
}
}

View File

@ -1,5 +1,6 @@
package dev.fyloz.colorrecipesexplorer.config.properties
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import dev.fyloz.colorrecipesexplorer.model.MaterialType
import dev.fyloz.colorrecipesexplorer.model.materialType
import org.springframework.boot.context.properties.ConfigurationProperties
@ -16,9 +17,9 @@ class MaterialTypeProperties {
var prefix: String = "",
var usePercentages: Boolean = false
) {
fun toMaterialType(): MaterialType {
fun toMaterialType(): MaterialTypeDto {
Assert.hasText(name, "A system material type has an empty name")
return materialType(name = name, prefix = prefix, usePercentages = usePercentages, systemType = true)
return MaterialTypeDto(name = name, prefix = prefix, usePercentages = usePercentages, systemType = true)
}
}
}

View File

@ -1,6 +1,5 @@
package dev.fyloz.colorrecipesexplorer.dtos
import dev.fyloz.colorrecipesexplorer.model.MaterialType
import org.springframework.web.multipart.MultipartFile
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
@ -14,7 +13,7 @@ data class MaterialDto(
val isMixType: Boolean,
val materialType: MaterialType,
val materialType: MaterialTypeDto,
val simdutUrl: String? = null
) : EntityDto

View File

@ -0,0 +1,13 @@
package dev.fyloz.colorrecipesexplorer.dtos
data class MaterialTypeDto(
override val id: Long = 0L,
val name: String,
val prefix: String,
val usePercentages: Boolean,
val systemType: Boolean = false
) : EntityDto

View File

@ -19,13 +19,13 @@ interface Logic<D : EntityDto, S : Service<D, *, *>> {
/** Get all DTOs. */
fun getAll(): Collection<D>
/** Get the DTO for the given [id]. */
/** Get the DTO for the given [id]. Throws if no DTO were found. */
fun getById(id: Long): D
/** Saves the given [dto]. */
fun save(dto: D): D
/** Updates the given [dto]. */
/** Updates the given [dto]. Throws if no DTO with the same id exists. */
fun update(dto: D): D
/** Deletes the dto with the given [id]. */

View File

@ -1,88 +1,75 @@
package dev.fyloz.colorrecipesexplorer.logic
import dev.fyloz.colorrecipesexplorer.config.annotations.RequireDatabase
import dev.fyloz.colorrecipesexplorer.model.*
import dev.fyloz.colorrecipesexplorer.model.validation.isNotNullAndNotBlank
import dev.fyloz.colorrecipesexplorer.repository.MaterialTypeRepository
import org.springframework.stereotype.Service
import dev.fyloz.colorrecipesexplorer.config.annotations.LogicComponent
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import dev.fyloz.colorrecipesexplorer.exception.CannotUpdateException
import dev.fyloz.colorrecipesexplorer.model.MaterialType
import dev.fyloz.colorrecipesexplorer.service.MaterialTypeService
interface MaterialTypeLogic :
ExternalNamedModelService<MaterialType, MaterialTypeSaveDto, MaterialTypeUpdateDto, MaterialType, MaterialTypeRepository> {
/** Checks if a material type with the given [prefix] exists. */
fun existsByPrefix(prefix: String): Boolean
interface MaterialTypeLogic : Logic<MaterialTypeDto, MaterialTypeService> {
/** Gets all material types which are or not [systemType]s. */
fun getAll(systemType: Boolean): Collection<MaterialTypeDto>
/** Gets all system material types. */
fun getAllSystemTypes(): Collection<MaterialType>
/** Gets the material type with the given [name]. */
fun getByName(name: String): MaterialTypeDto?
/** Gets all material types who are not a system type. */
fun getAllNonSystemType(): Collection<MaterialType>
/** Allows to update the given system [materialType], should not be exposed to users. */
fun updateSystemType(materialType: MaterialType): MaterialType
/** Updates the given [dto], and throws if it is a system types. */
fun updateNonSystemType(dto: MaterialTypeDto)
}
@Service
@RequireDatabase
class DefaultMaterialTypeLogic(repository: MaterialTypeRepository) :
AbstractExternalNamedModelService<MaterialType, MaterialTypeSaveDto, MaterialTypeUpdateDto, MaterialType, MaterialTypeRepository>(
repository
), MaterialTypeLogic {
override fun idNotFoundException(id: Long) = materialTypeIdNotFoundException(id)
override fun idAlreadyExistsException(id: Long) = materialIdAlreadyExistsException(id)
override fun nameNotFoundException(name: String) = materialTypeNameNotFoundException(name)
override fun nameAlreadyExistsException(name: String) = materialTypeNameAlreadyExistsException(name)
@LogicComponent
class DefaultMaterialTypeLogic(service: MaterialTypeService) :
BaseLogic<MaterialTypeDto, MaterialTypeService>(service, MaterialType::class.simpleName!!), MaterialTypeLogic {
override fun getAll(systemType: Boolean) = service.getAll(systemType)
override fun getByName(name: String) = service.getByName(name)
override fun MaterialType.toOutput() = this
override fun existsByPrefix(prefix: String): Boolean = repository.existsByPrefix(prefix)
override fun getAllSystemTypes(): Collection<MaterialType> = repository.findAllBySystemTypeIs(true)
override fun getAllNonSystemType(): Collection<MaterialType> = repository.findAllBySystemTypeIs(false)
override fun save(entity: MaterialType): MaterialType {
if (existsByPrefix(entity.prefix))
throw materialTypePrefixAlreadyExistsException(entity.prefix)
return super<AbstractExternalNamedModelService>.save(entity)
}
override fun update(entity: MaterialTypeUpdateDto): MaterialType {
val persistedMaterialType by lazy { getById(entity.id) }
return update(with(entity) {
MaterialType(
id = id,
name = if (isNotNullAndNotBlank(name)) name else persistedMaterialType.name,
prefix = if (isNotNullAndNotBlank(prefix)) prefix else persistedMaterialType.prefix,
systemType = false
override fun updateNonSystemType(dto: MaterialTypeDto) {
if (service.existsById(dto.id, true)) {
throw CannotUpdateException(
typeNameLowerCase,
"Cannot update $typeNameLowerCase",
"Cannot update material type '${dto.name}' because it is a system material type"
)
})
}
override fun updateSystemType(materialType: MaterialType) =
update(materialType, true)
override fun update(entity: MaterialType) =
update(entity, false)
private fun update(entity: MaterialType, allowSystemTypes: Boolean): MaterialType {
if (!allowSystemTypes && repository.existsByIdAndSystemTypeIsTrue(entity.id!!)) {
throw cannotUpdateSystemMaterialTypeException(entity)
}
with(repository.findByPrefix(entity.prefix)) {
if (this != null && id != entity.id)
throw materialTypePrefixAlreadyExistsException(entity.prefix)
}
return super.update(entity)
update(dto)
}
override fun delete(entity: MaterialType) {
if (repository.existsByIdAndSystemTypeIsTrue(entity.id!!)) {
throw cannotDeleteSystemMaterialTypeException(entity)
override fun save(dto: MaterialTypeDto): MaterialTypeDto {
throwIfNameAlreadyExists(dto.name)
throwIfPrefixAlreadyExists(dto.prefix)
return super.save(dto)
}
override fun update(dto: MaterialTypeDto): MaterialTypeDto {
throwIfNameAlreadyExists(dto.name, dto.id)
throwIfPrefixAlreadyExists(dto.prefix, dto.id)
return super.update(dto)
}
override fun deleteById(id: Long) {
if (service.isUsedByMaterial(id)) {
throw cannotDeleteException("Cannot delete material type with the id '$id' because one or more materials depends on it")
}
if (!repository.canBeDeleted(entity.id)) throw cannotDeleteMaterialTypeException(entity)
super.delete(entity)
super.deleteById(id)
}
}
private fun throwIfNameAlreadyExists(name: String, id: Long? = null) {
if (service.existsByName(name, id)) {
throw alreadyExistsException(value = name)
}
}
private fun throwIfPrefixAlreadyExists(prefix: String, id: Long? = null) {
if (service.existsByPrefix(prefix, id)) {
throw alreadyExistsException(PREFIX_IDENTIFIER_NAME, prefix)
}
}
companion object {
const val PREFIX_IDENTIFIER_NAME = "prefix"
}
}

View File

@ -53,7 +53,7 @@ class DefaultMixLogic(
override fun save(entity: MixSaveDto): Mix {
val recipe = recipeLogic.getById(entity.recipeId)
val materialType = materialTypeLogic.getById(entity.materialTypeId)
val mixType = mixTypeLogic.getOrCreateForNameAndMaterialType(entity.name, materialType)
val mixType = mixTypeLogic.getOrCreateForNameAndMaterialType(entity.name, materialType(materialType))
val mixMaterials = if (entity.mixMaterials != null) mixMaterialLogic.create(entity.mixMaterials) else setOf()
mixMaterialLogic.validateMixMaterials(mixMaterials)
@ -72,7 +72,7 @@ class DefaultMixLogic(
if (entity.name != null || entity.materialTypeId != null) {
val name = entity.name ?: mix.mixType.name
val materialType = if (entity.materialTypeId != null)
materialTypeLogic.getById(entity.materialTypeId)
materialType(materialTypeLogic.getById(entity.materialTypeId))
else
mix.mixType.material.materialType!!

View File

@ -32,7 +32,7 @@ data class Material(
) : ModelEntity {
companion object {
fun getSimdutFilePath(name: String) =
"${Constants.FilePaths.simdut}/$name.pdf"
"${Constants.FilePaths.SIMDUT}/$name.pdf"
}
}
@ -66,12 +66,12 @@ fun material(
@Deprecated("Temporary DSL for transition")
fun material(
dto: MaterialDto
) = Material(dto.id, dto.name, dto.inventoryQuantity, dto.isMixType, dto.materialType)
) = Material(dto.id, dto.name, dto.inventoryQuantity, dto.isMixType, materialType(dto.materialType))
@Deprecated("Temporary DSL for transition")
fun materialDto(
entity: Material
) = MaterialDto(entity.id!!, entity.name, entity.inventoryQuantity, entity.isMixType, entity.materialType!!)
) = MaterialDto(entity.id!!, entity.name, entity.inventoryQuantity, entity.isMixType, materialTypeDto(entity.materialType!!))
fun materialQuantityDto(
materialId: Long,

View File

@ -1,171 +1,62 @@
package dev.fyloz.colorrecipesexplorer.model
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException
import dev.fyloz.colorrecipesexplorer.exception.CannotUpdateException
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import org.hibernate.annotations.ColumnDefault
import javax.persistence.*
import javax.validation.constraints.NotBlank
import javax.validation.constraints.Size
private const val VALIDATION_PREFIX_SIZE = "Must contains exactly 3 characters"
@Entity
@Table(name = "material_type")
data class MaterialType(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
override val id: Long? = null,
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
override val id: Long? = null,
@Column(unique = true)
override val name: String = "",
@Column(unique = true)
val name: String = "",
@Column(unique = true)
val prefix: String = "",
@Column(unique = true)
val prefix: String = "",
@Column(name = "use_percentages")
@ColumnDefault("false")
val usePercentages: Boolean = false,
@Column(name = "use_percentages")
@ColumnDefault("false")
val usePercentages: Boolean = false,
@Column(name = "system_type")
@ColumnDefault("false")
val systemType: Boolean = false
) : NamedModelEntity
open class MaterialTypeSaveDto(
@field:NotBlank
val name: String,
@field:NotBlank
@field:Size(min = 3, max = 3, message = VALIDATION_PREFIX_SIZE)
val prefix: String,
val usePercentages: Boolean = false
) : EntityDto<MaterialType> {
override fun toEntity(): MaterialType =
MaterialType(null, name, prefix, usePercentages)
}
open class MaterialTypeUpdateDto(
val id: Long,
@field:NotBlank
val name: String?,
@field:Size(min = 3, max = 3, message = VALIDATION_PREFIX_SIZE)
val prefix: String?
) : EntityDto<MaterialType> {
override fun toEntity(): MaterialType =
MaterialType(id, name ?: "", prefix ?: "")
}
@Column(name = "system_type")
@ColumnDefault("false")
val systemType: Boolean = false
) : ModelEntity
// ==== DSL ====
fun materialType(
id: Long? = null,
name: String = "name",
prefix: String = "PRE",
usePercentages: Boolean = false,
systemType: Boolean = false,
op: MaterialType.() -> Unit = {}
id: Long? = null,
name: String = "name",
prefix: String = "PRE",
usePercentages: Boolean = false,
systemType: Boolean = false,
op: MaterialType.() -> Unit = {}
) = MaterialType(id, name, prefix, usePercentages, systemType).apply(op)
fun materialType(
materialType: MaterialType,
newId: Long? = null,
newName: String? = null,
newSystemType: Boolean? = null
materialType: MaterialType,
newId: Long? = null,
newName: String? = null,
newSystemType: Boolean? = null
) = with(materialType) {
MaterialType(
newId ?: id,
newName ?: name,
prefix,
usePercentages,
newSystemType ?: systemType
newId ?: id,
newName ?: name,
prefix,
usePercentages,
newSystemType ?: systemType
)
}
fun materialTypeSaveDto(
name: String = "name",
prefix: String = "PRE",
usePercentages: Boolean = false,
op: MaterialTypeSaveDto.() -> Unit = {}
) = MaterialTypeSaveDto(name, prefix, usePercentages).apply(op)
@Deprecated("Temporary DSL for transition")
fun materialType(
dto: MaterialTypeDto
) = MaterialType(dto.id, dto.name, dto.prefix, dto.usePercentages, dto.systemType)
fun materialTypeUpdateDto(
id: Long = 0L,
name: String? = null,
prefix: String? = null,
op: MaterialTypeUpdateDto.() -> Unit = {}
) = MaterialTypeUpdateDto(id, name, prefix).apply(op)
// ==== Exceptions ====
private const val MATERIAL_TYPE_NOT_FOUND_EXCEPTION_TITLE = "Material type not found"
private const val MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE = "Material type already exists"
private const val MATERIAL_TYPE_CANNOT_DELETE_EXCEPTION_TITLE = "Cannot delete material type"
private const val MATERIAL_TYPE_CANNOT_UPDATE_EXCEPTION_TITLE = "Cannot update material type"
private const val MATERIAL_TYPE_EXCEPTION_ERROR_CODE = "materialtype"
fun materialTypeIdNotFoundException(id: Long) =
NotFoundException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_NOT_FOUND_EXCEPTION_TITLE,
"A material type with the id $id could not be found",
id
)
fun materialTypeNameNotFoundException(name: String) =
NotFoundException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_NOT_FOUND_EXCEPTION_TITLE,
"A material type with the name $name could not be found",
name,
"name"
)
fun materialTypeIdAlreadyExistsException(id: Long) =
AlreadyExistsException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE,
"A material type with the id $id already exists",
id
)
fun materialTypeNameAlreadyExistsException(name: String) =
AlreadyExistsException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE,
"A material type with the name $name already exists",
name,
"name"
)
fun materialTypePrefixAlreadyExistsException(prefix: String) =
AlreadyExistsException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE,
"A material type with the prefix $prefix already exists",
prefix,
"prefix"
)
fun cannotUpdateSystemMaterialTypeException(materialType: MaterialType) =
CannotUpdateException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_CANNOT_UPDATE_EXCEPTION_TITLE,
"Cannot update material type ${materialType.name} because it is a system material type"
)
fun cannotDeleteMaterialTypeException(materialType: MaterialType) =
CannotDeleteException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_CANNOT_DELETE_EXCEPTION_TITLE,
"Cannot delete material type ${materialType.name} because one or more materials depends on it"
)
fun cannotDeleteSystemMaterialTypeException(materialType: MaterialType) =
CannotDeleteException(
MATERIAL_TYPE_EXCEPTION_ERROR_CODE,
MATERIAL_TYPE_CANNOT_DELETE_EXCEPTION_TITLE,
"Cannot delete material type ${materialType.name} because it is a system material type"
)
@Deprecated("Temporary DSL for transition")
fun materialTypeDto(
entity: MaterialType
) = MaterialTypeDto(entity.id!!, entity.name, entity.prefix, entity.usePercentages, entity.systemType)

View File

@ -70,7 +70,7 @@ data class Recipe(
groupsInformation.firstOrNull { it.group.id == groupId }
fun imageUrl(deploymentUrl: String, name: String) =
"$deploymentUrl${Constants.ControllerPaths.file}?path=${
"$deploymentUrl${Constants.ControllerPaths.FILE}?path=${
URLEncoder.encode(
"${this.imagesDirectoryPath}/$name",
StandardCharsets.UTF_8

View File

@ -12,7 +12,7 @@ interface MaterialRepository : JpaRepository<Material, Long> {
fun existsByNameAndIdNot(name: String, id: Long): Boolean
/** Gets all non mix type materials. */
fun getAllByIsMixTypeIsFalse(): Collection<Material>
fun findAllByIsMixTypeIsFalse(): Collection<Material>
/** Updates the [inventoryQuantity] of the [Material] with the given [id]. */
@Modifying

View File

@ -1,30 +1,33 @@
package dev.fyloz.colorrecipesexplorer.repository
import dev.fyloz.colorrecipesexplorer.model.MaterialType
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.stereotype.Repository
@Repository
interface MaterialTypeRepository : NamedJpaRepository<MaterialType> {
/** Checks if a material type exists with the given [prefix]. */
fun existsByPrefix(prefix: String): Boolean
interface MaterialTypeRepository : JpaRepository<MaterialType, Long> {
/** Checks if a system material type with the given [id] exists. */
fun existsByIdAndSystemTypeIsTrue(id: Long): Boolean
fun existsByIdAndSystemTypeIs(id: Long, systemType: Boolean): Boolean
/** Gets all material types which are not system types. */
fun findAllBySystemTypeIs(value: Boolean): Collection<MaterialType>
/** Checks if a material type with the given [name] and a different [id] exists. */
fun existsByNameAndIdNot(name: String, id: Long): Boolean
/** Gets the material type with the given [prefix]. */
fun findByPrefix(prefix: String): MaterialType?
/** Checks if a material type with the given [prefix] and a different [id] exists. */
fun existsByPrefixAndIdNot(prefix: String, id: Long): Boolean
/** Find all material types which are or not [systemType]s. */
fun findAllBySystemTypeIs(systemType: Boolean): Collection<MaterialType>
/** Find the material type with the given [name]. */
fun findByName(name: String): MaterialType?
/** Checks if a material depends on the material type with the given [id]. */
@Query(
"""
select case when(count(m.id) > 0) then false else true end
from MaterialType t
left join Material m on t.id = m.materialType.id
where t.id = :id
"""
"""
select case when(count(m) > 0) then true else false end
from Material m where m.materialType.id = :id
"""
)
fun canBeDeleted(id: Long): Boolean
fun isUsedByMaterial(id: Long): Boolean
}

View File

@ -12,7 +12,7 @@ import org.springframework.web.multipart.MultipartFile
import java.net.URI
@RestController
@RequestMapping(Constants.ControllerPaths.file)
@RequestMapping(Constants.ControllerPaths.FILE)
class FileController(
private val fileLogic: WriteableFileLogic,
private val configurationLogic: ConfigurationLogic
@ -43,6 +43,6 @@ class FileController(
private fun created(path: String): ResponseEntity<Void> =
ResponseEntity
.created(URI.create("${configurationLogic.get(ConfigurationType.INSTANCE_URL)}${Constants.ControllerPaths.file}?path=$path"))
.created(URI.create("${configurationLogic.get(ConfigurationType.INSTANCE_URL)}${Constants.ControllerPaths.FILE}?path=$path"))
.build()
}

View File

@ -13,7 +13,7 @@ import org.springframework.web.multipart.MultipartFile
import javax.validation.Valid
@RestController
@RequestMapping(Constants.ControllerPaths.material)
@RequestMapping(Constants.ControllerPaths.MATERIAL)
@Profile("!emergency")
@PreAuthorizeViewCatalog
class MaterialController(
@ -34,7 +34,7 @@ class MaterialController(
@PostMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
@PreAuthorize("hasAuthority('EDIT_MATERIALS')")
fun save(@Valid material: MaterialSaveDto, simdutFile: MultipartFile?) =
created<MaterialDto>(Constants.ControllerPaths.material) {
created<MaterialDto>(Constants.ControllerPaths.MATERIAL) {
materialLogic.save(material.copy(simdutFile = simdutFile))
}

View File

@ -1,49 +1,46 @@
package dev.fyloz.colorrecipesexplorer.rest
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeViewCatalog
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import dev.fyloz.colorrecipesexplorer.logic.MaterialTypeLogic
import dev.fyloz.colorrecipesexplorer.model.MaterialType
import dev.fyloz.colorrecipesexplorer.model.MaterialTypeSaveDto
import dev.fyloz.colorrecipesexplorer.model.MaterialTypeUpdateDto
import org.springframework.context.annotation.Profile
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.*
import javax.validation.Valid
private const val MATERIAL_TYPE_CONTROLLER_PATH = "api/materialtype"
@RestController
@RequestMapping(MATERIAL_TYPE_CONTROLLER_PATH)
@RequestMapping(Constants.ControllerPaths.MATERIAL_TYPE)
@Profile("!emergency")
@PreAuthorizeViewCatalog
class MaterialTypeController(private val materialTypeLogic: MaterialTypeLogic) {
@GetMapping
fun getAll() =
ok(materialTypeLogic.getAllForOutput())
ok(materialTypeLogic.getAll())
@GetMapping("{id}")
fun getById(@PathVariable id: Long) =
ok(materialTypeLogic.getByIdForOutput(id))
ok(materialTypeLogic.getById(id))
@PostMapping
@PreAuthorize("hasAuthority('EDIT_MATERIAL_TYPES')")
fun save(@Valid @RequestBody materialType: MaterialTypeSaveDto) =
created<MaterialType>(MATERIAL_TYPE_CONTROLLER_PATH) {
materialTypeLogic.save(materialType)
}
fun save(@Valid @RequestBody materialType: MaterialTypeDto) =
created<MaterialTypeDto>(Constants.ControllerPaths.MATERIAL_TYPE) {
materialTypeLogic.save(materialType)
}
@PutMapping
@PreAuthorize("hasAuthority('EDIT_MATERIAL_TYPES')")
fun update(@Valid @RequestBody materialType: MaterialTypeUpdateDto) =
noContent {
materialTypeLogic.update(materialType)
}
fun update(@Valid @RequestBody materialType: MaterialTypeDto) =
noContent {
materialTypeLogic.updateNonSystemType(materialType)
}
@DeleteMapping("{id}")
@PreAuthorize("hasAuthority('EDIT_MATERIAL_TYPES')")
fun deleteById(@PathVariable id: Long) =
noContent {
materialTypeLogic.deleteById(id)
}
noContent {
materialTypeLogic.deleteById(id)
}
}

View File

@ -25,11 +25,17 @@ interface MaterialService : Service<MaterialDto, Material, MaterialRepository> {
}
@ServiceComponent
class DefaultMaterialService(repository: MaterialRepository, @Qualifier("defaultFileLogic") val fileLogic: FileLogic) :
class DefaultMaterialService(
repository: MaterialRepository,
private val materialTypeService: MaterialTypeService,
@Qualifier("defaultFileLogic") val fileLogic: FileLogic
) :
BaseService<MaterialDto, Material, MaterialRepository>(repository), MaterialService {
override fun existsByName(name: String, id: Long?) = repository.existsByNameAndIdNot(name, id ?: 0)
override fun getAllNotMixType() = repository.getAllByIsMixTypeIsFalse().map(this::toDto)
override fun updateInventoryQuantityById(id: Long, inventoryQuantity: Float) = repository.updateInventoryQuantityById(id, inventoryQuantity)
override fun getAllNotMixType() = repository.findAllByIsMixTypeIsFalse().map(::toDto)
override fun updateInventoryQuantityById(id: Long, inventoryQuantity: Float) =
repository.updateInventoryQuantityById(id, inventoryQuantity)
override fun isUsedByMixMaterialOrMixType(id: Long) = repository.isUsedByMixMaterialOrMixType(id)
override fun toDto(entity: Material) =
@ -38,21 +44,21 @@ class DefaultMaterialService(repository: MaterialRepository, @Qualifier("default
entity.name,
entity.inventoryQuantity,
entity.isMixType,
entity.materialType!!,
materialTypeService.toDto(entity.materialType!!),
getSimdutUrl(entity)
)
override fun toEntity(dto: MaterialDto) =
Material(dto.id, dto.name, dto.inventoryQuantity, dto.isMixType, dto.materialType)
Material(dto.id, dto.name, dto.inventoryQuantity, dto.isMixType, materialTypeService.toEntity(dto.materialType))
private fun getSimdutUrl(material: Material): String? {
val filePath = "${Constants.FilePaths.simdut}/${material.name}.pdf"
val filePath = "${Constants.FilePaths.SIMDUT}/${material.name}.pdf"
if (!fileLogic.exists(filePath)) {
return null
}
val encodedPath = URLEncoder.encode(filePath, StandardCharsets.UTF_8)
return "${Constants.ControllerPaths.file}?path=$encodedPath"
return "${Constants.ControllerPaths.FILE}?path=$encodedPath"
}
}

View File

@ -0,0 +1,44 @@
package dev.fyloz.colorrecipesexplorer.service
import dev.fyloz.colorrecipesexplorer.config.annotations.ServiceComponent
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import dev.fyloz.colorrecipesexplorer.model.MaterialType
import dev.fyloz.colorrecipesexplorer.repository.MaterialTypeRepository
interface MaterialTypeService : Service<MaterialTypeDto, MaterialType, MaterialTypeRepository> {
/** Checks if a system material type with the given [id] exists. */
fun existsById(id: Long, systemType: Boolean): Boolean
/** Checks if a material type with the given [name] and a different [id] exists. */
fun existsByName(name: String, id: Long?): Boolean
/** Checks if a material type with the given [prefix] and a different [id] exists. */
fun existsByPrefix(prefix: String, id: Long?): Boolean
/** Gets all material types which are or not a [systemType]. */
fun getAll(systemType: Boolean): Collection<MaterialTypeDto>
/** Gets the material type with the given [name]. */
fun getByName(name: String): MaterialTypeDto?
/** Checks if a material depends on the material type with the given [id]. */
fun isUsedByMaterial(id: Long): Boolean
}
@ServiceComponent
class DefaultMaterialTypeService(repository: MaterialTypeRepository) :
BaseService<MaterialTypeDto, MaterialType, MaterialTypeRepository>(repository), MaterialTypeService {
override fun existsById(id: Long, systemType: Boolean) = repository.existsByIdAndSystemTypeIs(id, systemType)
override fun existsByName(name: String, id: Long?) = repository.existsByNameAndIdNot(name, id ?: 0)
override fun existsByPrefix(prefix: String, id: Long?) = repository.existsByPrefixAndIdNot(prefix, id ?: 0)
override fun getAll(systemType: Boolean) = repository.findAllBySystemTypeIs(systemType).map(::toDto)
override fun getByName(name: String) = repository.findByName(name)?.let(::toDto)
override fun isUsedByMaterial(id: Long) = repository.isUsedByMaterial(id)
override fun toDto(entity: MaterialType) =
MaterialTypeDto(entity.id!!, entity.name, entity.prefix, entity.usePercentages, entity.systemType)
override fun toEntity(dto: MaterialTypeDto) =
MaterialType(dto.id, dto.name, dto.prefix, dto.usePercentages, dto.systemType)
}

View File

@ -31,6 +31,12 @@ interface Service<D : EntityDto, E : ModelEntity, R : JpaRepository<E, Long>> {
/** Deletes the entity with the given [id]. */
fun deleteById(id: Long)
/** Converts the given [entity] to a DTO. */
fun toDto(entity: E): D
/** Converts the given [dto] to an entity. */
fun toEntity(dto: D): E
}
abstract class BaseService<D : EntityDto, E : ModelEntity, R : JpaRepository<E, Long>>(protected val repository: R) :
@ -58,7 +64,4 @@ abstract class BaseService<D : EntityDto, E : ModelEntity, R : JpaRepository<E,
override fun deleteById(id: Long) {
repository.deleteById(id)
}
abstract fun toDto(entity: E): D
abstract fun toEntity(dto: D): E
}

View File

@ -2,6 +2,7 @@ package dev.fyloz.colorrecipesexplorer.logic
import dev.fyloz.colorrecipesexplorer.dtos.MaterialDto
import dev.fyloz.colorrecipesexplorer.dtos.MaterialSaveDto
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException
import dev.fyloz.colorrecipesexplorer.logic.files.WriteableFileLogic
@ -31,9 +32,7 @@ class DefaultMaterialLogicTest {
)
)
private val materialType = MaterialType(
1L, "Unit test material type", "UNT", usePercentages = false, systemType = false
) // TODO move to DTO
private val materialType = MaterialTypeDto(1L, "Unit test material type", "UNT", usePercentages = false)
private val material = MaterialDto(1L, "Unit test material", 1000f, false, materialType)
private val materialMixType = material.copy(id = 2L, isMixType = true)
private val materialMixType2 = material.copy(id = 3L, isMixType = true)
@ -59,8 +58,8 @@ class DefaultMaterialLogicTest {
private val simdutFileMock = MockMultipartFile(
"Unit test SIMDUT",
byteArrayOf(1, 2, 3, 4)
) // Put some content in the mock file so it is not ignored
private val materialSaveDto = MaterialSaveDto(1L, "Unit test material", 1000f, materialType.id!!, simdutFileMock)
) // Put some content in the mock file, so it is not ignored
private val materialSaveDto = MaterialSaveDto(1L, "Unit test material", 1000f, materialType.id, simdutFileMock)
init {
recipe.mixes.addAll(listOf(mix, mix2))

View File

@ -0,0 +1,146 @@
package dev.fyloz.colorrecipesexplorer.logic
import dev.fyloz.colorrecipesexplorer.dtos.MaterialTypeDto
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException
import dev.fyloz.colorrecipesexplorer.exception.CannotUpdateException
import dev.fyloz.colorrecipesexplorer.service.MaterialTypeService
import io.mockk.*
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
import kotlin.test.assertNull
class DefaultMaterialTypeLogicTest {
private val materialTypeServiceMock = mockk<MaterialTypeService>()
private val materialTypeLogic = spyk(DefaultMaterialTypeLogic(materialTypeServiceMock))
private val materialType = MaterialTypeDto(1L, "Unit test material type", "UTMT", false)
private val systemMaterialType =
MaterialTypeDto(2L, "Unit test system material type", "UTSMT", false, systemType = true)
@AfterEach
internal fun afterEach() {
clearAllMocks()
}
@Test
fun getAll_normalBehavior_returnsFromService() {
// Arrange
val expectedMaterialTypes = listOf(materialType, systemMaterialType)
every { materialTypeServiceMock.getAll(any()) } returns expectedMaterialTypes
// Act
val actualMaterialTypes = materialTypeLogic.getAll(true)
// Assert
assertEquals(expectedMaterialTypes, actualMaterialTypes)
}
@Test
fun getByName_normalBehavior_returnsMaterialType() {
// Arrange
every { materialTypeServiceMock.getByName(any()) } returns materialType
// Act
val actualMaterialType = materialTypeLogic.getByName(materialType.name)
// Assert
assertEquals(materialType, actualMaterialType)
}
@Test
fun getByName_nameNotFound_returnsNull() {
// Arrange
every { materialTypeServiceMock.getByName(any()) } returns null
// Act
val actualMaterialType = materialTypeLogic.getByName(materialType.name)
// Assert
assertNull(actualMaterialType)
}
@Test
fun updateNonSystemType_normalBehavior_callsUpdate() {
// Arrange
every { materialTypeServiceMock.existsById(any(), any()) } returns false
every { materialTypeLogic.update(any()) } returnsArgument 0
// Act
materialTypeLogic.updateNonSystemType(materialType)
// Assert
verify {
materialTypeLogic.update(materialType)
}
}
@Test
fun updateNonSystemType_isSystemType_throwsCannotUpdateException() {
// Arrange
every { materialTypeServiceMock.existsById(any(), any()) } returns true
every { materialTypeLogic.update(any()) } returnsArgument 0
// Act
// Assert
assertThrows<CannotUpdateException> { materialTypeLogic.updateNonSystemType(materialType) }
}
@Test
fun save_nameExists_throwsAlreadyExistsException() {
// Arrange
every { materialTypeServiceMock.existsByName(any(), any()) } returns true
every { materialTypeServiceMock.existsByPrefix(any(), any()) } returns false
// Act
// Assert
assertThrows<AlreadyExistsException> { materialTypeLogic.save(materialType) }
}
@Test
fun save_prefixExists_throwsAlreadyExistsException() {
// Arrange
every { materialTypeServiceMock.existsByName(any(), any()) } returns false
every { materialTypeServiceMock.existsByPrefix(any(), any()) } returns true
// Act
// Assert
assertThrows<AlreadyExistsException> { materialTypeLogic.save(materialType) }
}
@Test
fun update_nameExists_throwsAlreadyExistsException() {
// Arrange
every { materialTypeServiceMock.existsByName(any(), any()) } returns true
every { materialTypeServiceMock.existsByPrefix(any(), any()) } returns false
// Act
// Assert
assertThrows<AlreadyExistsException> { materialTypeLogic.update(materialType) }
}
@Test
fun update_prefixExists_throwsAlreadyExistsException() {
// Arrange
every { materialTypeServiceMock.existsByName(any(), any()) } returns false
every { materialTypeServiceMock.existsByPrefix(any(), any()) } returns true
// Act
// Assert
assertThrows<AlreadyExistsException> { materialTypeLogic.update(materialType) }
}
@Test
fun deleteById_usedByMaterial_throwsCannotDeleteException() {
// Arrange
every { materialTypeServiceMock.isUsedByMaterial(any()) } returns true
// Act
// Assert
assertThrows<CannotDeleteException> { materialTypeLogic.deleteById(materialType.id) }
}
}

View File

@ -1,182 +1,182 @@
package dev.fyloz.colorrecipesexplorer.logic
import com.nhaarman.mockitokotlin2.*
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException
import dev.fyloz.colorrecipesexplorer.exception.CannotUpdateException
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.model.*
import dev.fyloz.colorrecipesexplorer.repository.MaterialTypeRepository
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MaterialTypeLogicTest :
AbstractExternalNamedModelServiceTest<MaterialType, MaterialTypeSaveDto, MaterialTypeUpdateDto, MaterialTypeLogic, MaterialTypeRepository>() {
override val repository: MaterialTypeRepository = mock()
private val materialService: MaterialLogic = mock()
override val logic: MaterialTypeLogic = spy(DefaultMaterialTypeLogic(repository))
override val entity: MaterialType = materialType(id = 0L, name = "material type", prefix = "MAT")
override val anotherEntity: MaterialType = materialType(id = 1L, name = "another material type", prefix = "AMT")
override val entityWithEntityName: MaterialType = materialType(2L, name = entity.name, prefix = "EEN")
private val systemType = materialType(id = 3L, name = "systype", prefix = "SYS", systemType = true)
private val anotherSystemType = materialType(id = 4L, name = "another systype", prefix = "ASY", systemType = true)
override val entitySaveDto: MaterialTypeSaveDto = spy(materialTypeSaveDto(name = "material type", prefix = "MAT"))
override val entityUpdateDto: MaterialTypeUpdateDto =
spy(materialTypeUpdateDto(id = 0L, name = "material type", prefix = "MAT"))
@AfterEach
override fun afterEach() {
reset(materialService)
super.afterEach()
}
// existsByPrefix()
@Test
fun `existsByPrefix() returns true when a material type with the given prefix exists`() {
whenever(repository.existsByPrefix(entity.prefix)).doReturn(true)
val found = logic.existsByPrefix(entity.prefix)
assertTrue(found)
}
@Test
fun `existsByPrefix() returns false when no material type with the given prefix exists`() {
whenever(repository.existsByPrefix(entity.prefix)).doReturn(false)
val found = logic.existsByPrefix(entity.prefix)
assertFalse(found)
}
// getAllSystemTypes()
@Test
fun `getAllSystemTypes() returns all system types`() {
whenever(repository.findAllBySystemTypeIs(true)).doReturn(listOf(systemType, anotherSystemType))
val found = logic.getAllSystemTypes()
assertTrue(found.contains(systemType))
assertTrue(found.contains(anotherSystemType))
}
// getAllNonSystemTypes()
@Test
fun `getAllNonSystemTypes() returns all non system types`() {
whenever(repository.findAllBySystemTypeIs(false)).doReturn(listOf(entity, anotherEntity))
val found = logic.getAllNonSystemType()
assertTrue(found.contains(entity))
assertTrue(found.contains(anotherEntity))
}
// save()
@Test
override fun `save(dto) calls and returns save() with the created entity`() {
withBaseSaveDtoTest(entity, entitySaveDto, logic)
}
// saveMaterialType()
@Test
fun `saveMaterialType() throws AlreadyExistsException when a material type with the given prefix already exists`() {
doReturn(true).whenever(logic).existsByPrefix(entity.prefix)
assertThrows<AlreadyExistsException> { logic.save(entity) }
.assertErrorCode("prefix")
}
// update()
@Test
override fun `update(dto) calls and returns update() with the created entity`() =
withBaseUpdateDtoTest(entity, entityUpdateDto, logic, { any() })
override fun `update() saves in the repository and returns the updated value`() {
whenever(repository.save(entity)).doReturn(entity)
whenever(repository.findByName(entity.name)).doReturn(null)
whenever(repository.findByPrefix(entity.prefix)).doReturn(null)
doReturn(true).whenever(logic).existsById(entity.id!!)
doReturn(entity).whenever(logic).getById(entity.id!!)
val found = logic.update(entity)
verify(repository).save(entity)
assertEquals(entity, found)
}
override fun `update() throws NotFoundException when no entity with the given id exists in the repository`() {
whenever(repository.findByName(entity.name)).doReturn(null)
whenever(repository.findByPrefix(entity.prefix)).doReturn(null)
doReturn(false).whenever(logic).existsById(entity.id!!)
doReturn(null).whenever(logic).getById(entity.id!!)
assertThrows<NotFoundException> { logic.update(entity) }
.assertErrorCode()
}
override fun `update() throws AlreadyExistsException when an entity with the updated name exists`() {
whenever(repository.findByName(entity.name)).doReturn(entityWithEntityName)
whenever(repository.findByPrefix(entity.prefix)).doReturn(null)
doReturn(true).whenever(logic).existsById(entity.id!!)
doReturn(entity).whenever(logic).getById(entity.id!!)
assertThrows<AlreadyExistsException> { logic.update(entity) }
.assertErrorCode("name")
}
@Test
fun `update() throws AlreadyExistsException when an entity with the updated prefix exists`() {
val anotherMaterialType = materialType(prefix = entity.prefix)
whenever(repository.findByPrefix(entity.prefix)).doReturn(anotherMaterialType)
doReturn(entity).whenever(logic).getById(entity.id!!)
assertThrows<AlreadyExistsException> { logic.update(entity) }
.assertErrorCode("prefix")
}
@Test
fun `update() throws CannotUpdateException when updating a system material type`() {
whenever(repository.existsByIdAndSystemTypeIsTrue(systemType.id!!)).doReturn(true)
assertThrows<CannotUpdateException> { logic.update(systemType) }
}
// delete()
@Test
fun `delete() throws CannotDeleteException when deleting a system material type`() {
whenever(repository.existsByIdAndSystemTypeIsTrue(systemType.id!!)).doReturn(true)
assertThrows<CannotDeleteException> { logic.delete(systemType) }
}
override fun `delete() deletes in the repository`() {
whenCanBeDeleted {
super.`delete() deletes in the repository`()
}
}
override fun `deleteById() deletes the entity with the given id in the repository`() {
whenCanBeDeleted {
super.`deleteById() deletes the entity with the given id in the repository`()
}
}
private fun whenCanBeDeleted(id: Long = any(), test: () -> Unit) {
whenever(repository.canBeDeleted(id)).doReturn(true)
test()
}
}
//package dev.fyloz.colorrecipesexplorer.logic
//
//import com.nhaarman.mockitokotlin2.*
//import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
//import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException
//import dev.fyloz.colorrecipesexplorer.exception.CannotUpdateException
//import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
//import dev.fyloz.colorrecipesexplorer.model.*
//import dev.fyloz.colorrecipesexplorer.repository.MaterialTypeRepository
//import org.junit.jupiter.api.AfterEach
//import org.junit.jupiter.api.Test
//import org.junit.jupiter.api.TestInstance
//import org.junit.jupiter.api.assertThrows
//import kotlin.test.assertEquals
//import kotlin.test.assertFalse
//import kotlin.test.assertTrue
//
//@TestInstance(TestInstance.Lifecycle.PER_CLASS)
//class MaterialTypeLogicTest :
// AbstractExternalNamedModelServiceTest<MaterialType, MaterialTypeSaveDto, MaterialTypeUpdateDto, MaterialTypeLogic, MaterialTypeRepository>() {
// override val repository: MaterialTypeRepository = mock()
// private val materialService: MaterialLogic = mock()
// override val logic: MaterialTypeLogic = spy(DefaultMaterialTypeLogic(repository))
// override val entity: MaterialType = materialType(id = 0L, name = "material type", prefix = "MAT")
// override val anotherEntity: MaterialType = materialType(id = 1L, name = "another material type", prefix = "AMT")
// override val entityWithEntityName: MaterialType = materialType(2L, name = entity.name, prefix = "EEN")
// private val systemType = materialType(id = 3L, name = "systype", prefix = "SYS", systemType = true)
// private val anotherSystemType = materialType(id = 4L, name = "another systype", prefix = "ASY", systemType = true)
// override val entitySaveDto: MaterialTypeSaveDto = spy(materialTypeSaveDto(name = "material type", prefix = "MAT"))
// override val entityUpdateDto: MaterialTypeUpdateDto =
// spy(materialTypeUpdateDto(id = 0L, name = "material type", prefix = "MAT"))
//
// @AfterEach
// override fun afterEach() {
// reset(materialService)
// super.afterEach()
// }
//
// // existsByPrefix()
//
// @Test
// fun `existsByPrefix() returns true when a material type with the given prefix exists`() {
// whenever(repository.existsByPrefix(entity.prefix)).doReturn(true)
//
// val found = logic.existsByPrefix(entity.prefix)
//
// assertTrue(found)
// }
//
// @Test
// fun `existsByPrefix() returns false when no material type with the given prefix exists`() {
// whenever(repository.existsByPrefix(entity.prefix)).doReturn(false)
//
// val found = logic.existsByPrefix(entity.prefix)
//
// assertFalse(found)
// }
//
// // getAllSystemTypes()
//
// @Test
// fun `getAllSystemTypes() returns all system types`() {
// whenever(repository.findAllBySystemTypeIs(true)).doReturn(listOf(systemType, anotherSystemType))
//
// val found = logic.getAllSystemTypes()
//
// assertTrue(found.contains(systemType))
// assertTrue(found.contains(anotherSystemType))
// }
//
// // getAllNonSystemTypes()
//
// @Test
// fun `getAllNonSystemTypes() returns all non system types`() {
// whenever(repository.findAllBySystemTypeIs(false)).doReturn(listOf(entity, anotherEntity))
//
// val found = logic.getAllNonSystemType()
//
// assertTrue(found.contains(entity))
// assertTrue(found.contains(anotherEntity))
// }
//
// // save()
//
// @Test
// override fun `save(dto) calls and returns save() with the created entity`() {
// withBaseSaveDtoTest(entity, entitySaveDto, logic)
// }
//
// // saveMaterialType()
//
// @Test
// fun `saveMaterialType() throws AlreadyExistsException when a material type with the given prefix already exists`() {
// doReturn(true).whenever(logic).existsByPrefix(entity.prefix)
//
// assertThrows<AlreadyExistsException> { logic.save(entity) }
// .assertErrorCode("prefix")
// }
//
// // update()
//
// @Test
// override fun `update(dto) calls and returns update() with the created entity`() =
// withBaseUpdateDtoTest(entity, entityUpdateDto, logic, { any() })
//
// override fun `update() saves in the repository and returns the updated value`() {
// whenever(repository.save(entity)).doReturn(entity)
// whenever(repository.findByName(entity.name)).doReturn(null)
// whenever(repository.findByPrefix(entity.prefix)).doReturn(null)
// doReturn(true).whenever(logic).existsById(entity.id!!)
// doReturn(entity).whenever(logic).getById(entity.id!!)
//
// val found = logic.update(entity)
//
// verify(repository).save(entity)
// assertEquals(entity, found)
// }
//
// override fun `update() throws NotFoundException when no entity with the given id exists in the repository`() {
// whenever(repository.findByName(entity.name)).doReturn(null)
// whenever(repository.findByPrefix(entity.prefix)).doReturn(null)
// doReturn(false).whenever(logic).existsById(entity.id!!)
// doReturn(null).whenever(logic).getById(entity.id!!)
//
// assertThrows<NotFoundException> { logic.update(entity) }
// .assertErrorCode()
// }
//
// override fun `update() throws AlreadyExistsException when an entity with the updated name exists`() {
// whenever(repository.findByName(entity.name)).doReturn(entityWithEntityName)
// whenever(repository.findByPrefix(entity.prefix)).doReturn(null)
// doReturn(true).whenever(logic).existsById(entity.id!!)
// doReturn(entity).whenever(logic).getById(entity.id!!)
//
// assertThrows<AlreadyExistsException> { logic.update(entity) }
// .assertErrorCode("name")
// }
//
// @Test
// fun `update() throws AlreadyExistsException when an entity with the updated prefix exists`() {
// val anotherMaterialType = materialType(prefix = entity.prefix)
// whenever(repository.findByPrefix(entity.prefix)).doReturn(anotherMaterialType)
// doReturn(entity).whenever(logic).getById(entity.id!!)
//
// assertThrows<AlreadyExistsException> { logic.update(entity) }
// .assertErrorCode("prefix")
// }
//
// @Test
// fun `update() throws CannotUpdateException when updating a system material type`() {
// whenever(repository.existsByIdAndSystemTypeIsTrue(systemType.id!!)).doReturn(true)
//
// assertThrows<CannotUpdateException> { logic.update(systemType) }
// }
//
// // delete()
//
// @Test
// fun `delete() throws CannotDeleteException when deleting a system material type`() {
// whenever(repository.existsByIdAndSystemTypeIsTrue(systemType.id!!)).doReturn(true)
//
// assertThrows<CannotDeleteException> { logic.delete(systemType) }
// }
//
// override fun `delete() deletes in the repository`() {
// whenCanBeDeleted {
// super.`delete() deletes in the repository`()
// }
// }
//
// override fun `deleteById() deletes the entity with the given id in the repository`() {
// whenCanBeDeleted {
// super.`deleteById() deletes the entity with the given id in the repository`()
// }
// }
//
// private fun whenCanBeDeleted(id: Long = any(), test: () -> Unit) {
// whenever(repository.canBeDeleted(id)).doReturn(true)
//
// test()
// }
//}

View File

@ -62,7 +62,7 @@ class MixLogicTest : AbstractExternalModelServiceTest<Mix, MixSaveDto, MixUpdate
val mixMaterials = setOf(mixMaterial(material = material(id = 1L), quantity = 1000f))
whenever(recipeService.getById(recipe.id!!)).doReturn(recipe)
whenever(materialTypeService.getById(materialType.id!!)).doReturn(materialType)
whenever(materialTypeService.getById(materialType.id!!)).doReturn(materialTypeDto(materialType))
whenever(mixMaterialService.create(entitySaveDto.mixMaterials!!)).doReturn(mixMaterials)
whenever(
mixTypeService.getOrCreateForNameAndMaterialType(
@ -98,7 +98,7 @@ class MixLogicTest : AbstractExternalModelServiceTest<Mix, MixSaveDto, MixUpdate
doAnswer { it.arguments[0] }.whenever(logic).update(any<Mix>())
if (mixUpdateDto.materialTypeId != null) {
whenever(materialTypeService.getById(materialType.id!!)).doReturn(materialType)
whenever(materialTypeService.getById(materialType.id!!)).doReturn(materialTypeDto(materialType))
}
op()