diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/AccountModel.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/AccountModel.kt index 47c2247..b83dce7 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/AccountModel.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/AccountModel.kt @@ -138,7 +138,7 @@ data class EmployeeGroup( val permissions: MutableSet = mutableSetOf(), @OneToMany(mappedBy = "group") - @JsonIgnore + @field:JsonIgnore val employees: MutableSet = mutableSetOf() ) : NamedModel { @JsonProperty("employeeCount") diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/MaterialController.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/MaterialController.kt index 3738732..0f90c24 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/MaterialController.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/MaterialController.kt @@ -97,15 +97,13 @@ class InventoryController( private val inventoryService: InventoryService ) { @PutMapping("add") - fun add(@RequestBody quantities: Collection): ResponseEntity { - inventoryService.add(quantities) - return ResponseEntity.ok().build() + fun add(@RequestBody quantities: Collection): ResponseEntity> { + return ResponseEntity.ok(inventoryService.add(quantities)) } @PutMapping("deduct") - fun deduct(@RequestBody quantities: Collection): ResponseEntity { - inventoryService.deduct(quantities) - return ResponseEntity.ok().build() + fun deduct(@RequestBody quantities: Collection): ResponseEntity> { + return ResponseEntity.ok(inventoryService.deduct(quantities)) } } diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt index 47a5f0b..9984b2e 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt @@ -3,22 +3,23 @@ package dev.fyloz.trial.colorrecipesexplorer.service import dev.fyloz.trial.colorrecipesexplorer.exception.LowQuantitiesException import dev.fyloz.trial.colorrecipesexplorer.exception.LowQuantityException import dev.fyloz.trial.colorrecipesexplorer.model.MaterialQuantityDto -import dev.fyloz.trial.colorrecipesexplorer.service.utils.filterThrows +import dev.fyloz.trial.colorrecipesexplorer.model.materialQuantityDto +import dev.fyloz.trial.colorrecipesexplorer.service.utils.mapMayThrow import org.springframework.stereotype.Service import javax.transaction.Transactional interface InventoryService { - /** Adds each given [MaterialQuantityDto] to the inventory. */ - fun add(materialQuantities: Collection) + /** Adds each given [MaterialQuantityDto] to the inventory and returns the updated quantities. */ + fun add(materialQuantities: Collection): Collection - /** Adds a given quantity to the given [Material]'s inventory quantity according to the given [materialQuantity]. */ - fun add(materialQuantity: MaterialQuantityDto) + /** Adds a given quantity to the given [Material]'s inventory quantity according to the given [materialQuantity] and returns the updated quantity. */ + fun add(materialQuantity: MaterialQuantityDto): Float - /** Deducts the inventory quantity of each given [MaterialQuantityDto]. */ - fun deduct(materialQuantities: Collection) + /** Deducts the inventory quantity of each given [MaterialQuantityDto] and returns the updated quantities. */ + fun deduct(materialQuantities: Collection): Collection - /** Deducts the inventory quantity of a given [Material] by a given quantity according to the given [materialQuantity]. */ - fun deduct(materialQuantity: MaterialQuantityDto) + /** Deducts the inventory quantity of a given [Material] by a given quantity according to the given [materialQuantity] and returns the updated quantity. */ + fun deduct(materialQuantity: MaterialQuantityDto): Float } @Service @@ -26,37 +27,39 @@ class InventoryServiceImpl( private val materialService: MaterialService ) : InventoryService { @Transactional - override fun add(materialQuantities: Collection) { - materialQuantities.forEach(::add) - } + override fun add(materialQuantities: Collection) = + materialQuantities.map { + materialQuantityDto(materialId = it.material, quantity = add(it)) + } - override fun add(materialQuantity: MaterialQuantityDto) { + override fun add(materialQuantity: MaterialQuantityDto) = materialService.updateQuantity( materialService.getById(materialQuantity.material), materialQuantity.quantity ) - } @Transactional - override fun deduct(materialQuantities: Collection) { - with(materialQuantities.filterThrows { - deduct(it) - }) { - if (this.isNotEmpty()) { - throw LowQuantitiesException(this) + override fun deduct(materialQuantities: Collection): Collection { + val thrown = mutableListOf() + val updatedQuantities = + materialQuantities.mapMayThrow( + { thrown.add(it.materialQuantity) } + ) { + materialQuantityDto(materialId = it.material, quantity = deduct(it)) } + + if (thrown.isNotEmpty()) { + throw LowQuantitiesException(thrown) } + return updatedQuantities } - override fun deduct(materialQuantity: MaterialQuantityDto) { - val material = materialService.getById(materialQuantity.material) - if (material.inventoryQuantity >= materialQuantity.quantity) { - materialService.updateQuantity( - material, - -materialQuantity.quantity - ) - } else { - throw LowQuantityException(materialQuantity) + override fun deduct(materialQuantity: MaterialQuantityDto): Float = + with(materialService.getById(materialQuantity.material)) { + if (this.inventoryQuantity >= materialQuantity.quantity) { + materialService.updateQuantity(this, -materialQuantity.quantity) + } else { + throw LowQuantityException(materialQuantity) + } } - } } diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt index b11748c..8040844 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt @@ -30,8 +30,8 @@ interface MaterialService : /** Gets the identifier of materials for which a SIMDUT exists. */ fun getAllIdsWithSimdut(): Collection - /** Updates the quantity of the given [material] with the given [factor]. */ - fun updateQuantity(material: Material, factor: Float) + /** Updates the quantity of the given [material] with the given [factor] and returns the updated quantity. */ + fun updateQuantity(material: Material, factor: Float): Float } @Service @@ -80,7 +80,9 @@ class MaterialServiceImpl( } override fun updateQuantity(material: Material, factor: Float) = with(material) { - repository.updateInventoryQuantityById(this.id!!, this.inventoryQuantity + factor) + val updatedQuantity = this.inventoryQuantity + factor + repository.updateInventoryQuantityById(this.id!!, updatedQuantity) + updatedQuantity } override fun getAllForMixCreation(recipeId: Long): Collection { diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/utils/Collections.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/utils/Collections.kt index 52d430a..a102fd0 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/utils/Collections.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/utils/Collections.kt @@ -1,11 +1,18 @@ package dev.fyloz.trial.colorrecipesexplorer.service.utils -/** Returns a list containing only the elements which causes the given [consumer] to throw the given throwable [E]. */ -inline fun Iterable.filterThrows(consumer: (T) -> Unit): List = this.filter { +/** Returns a list containing the result of the given [transform] applied to each item of the [Iterable]. If the given [transform] throws, the [Throwable] will be passed to the given [throwableConsumer]. */ +inline fun Iterable.mapMayThrow( + throwableConsumer: (E) -> Unit = {}, + transform: (T) -> R +): List = this.mapNotNull { try { - consumer(it) - false + transform(it) } catch (th: Throwable) { - th is E + if (th is E) { + throwableConsumer(th) + null + } else { + throw th + } } } diff --git a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryServiceTest.kt b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryServiceTest.kt index 0356433..8810d66 100644 --- a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryServiceTest.kt @@ -31,23 +31,32 @@ class InventoryServiceTest { materialQuantityDto(materialId = 3, quantity = 3456f), materialQuantityDto(materialId = 4, quantity = 4567f) ) + val storedQuantity = 2000f - service.add(materialQuantities) + doAnswer { storedQuantity + (it.arguments[0] as MaterialQuantityDto).quantity }.whenever(service) + .add(any()) + + val found = service.add(materialQuantities) materialQuantities.forEach { verify(service).add(it) + assertTrue { found.any { updated -> updated.material == it.material && updated.quantity == storedQuantity + it.quantity } } } } @Test fun `add(materialQuantity) updates material's quantity`() { withGivenQuantities(0f, 1000f) { - service.add(it) + val updatedQuantity = it + this.quantity + whenever(materialService.updateQuantity(any(), eq(this.quantity))).doReturn(updatedQuantity) + + val found = service.add(this) verify(materialService).updateQuantity( - argThat { this.id == it.material }, - eq(it.quantity) + argThat { this.id == this@withGivenQuantities.material }, + eq(this.quantity) ) + assertEquals(updatedQuantity, found) } } @@ -61,11 +70,16 @@ class InventoryServiceTest { materialQuantityDto(materialId = 3, quantity = 3456f), materialQuantityDto(materialId = 4, quantity = 4567f) ) + val storedQuantity = 5000f - service.deduct(materialQuantities) + doAnswer { storedQuantity - (it.arguments[0] as MaterialQuantityDto).quantity }.whenever(service) + .deduct(any()) + + val found = service.deduct(materialQuantities) materialQuantities.forEach { verify(service).deduct(it) + assertTrue { found.any { updated -> updated.material == it.material && updated.quantity == storedQuantity - it.quantity } } } } @@ -91,43 +105,47 @@ class InventoryServiceTest { @Test fun `deduct(materialQuantity) updates material's quantity`() { withGivenQuantities(5000f, 1000f) { - service.deduct(it) + val updatedQuantity = it - this.quantity + whenever(materialService.updateQuantity(any(), eq(-this.quantity))).doReturn(updatedQuantity) + + val found = service.deduct(this) verify(materialService).updateQuantity( - argThat { this.id == it.material }, - eq(-it.quantity) + argThat { this.id == this@withGivenQuantities.material }, + eq(-this.quantity) ) + assertEquals(updatedQuantity, found) } } @Test fun `deduct(materialQuantity) throws LowQuantityException when there is not enough inventory of the given material`() { withGivenQuantities(0f, 1000f) { - val exception = assertThrows { service.deduct(it) } - assertEquals(it, exception.materialQuantity) + val exception = assertThrows { service.deduct(this) } + assertEquals(this, exception.materialQuantity) } } private fun withGivenQuantities( - inventory: Float, - deductedQuantity: Float, + stored: Float, + quantity: Float, materialId: Long = 0L, - test: (MaterialQuantityDto) -> Unit = {} + test: MaterialQuantityDto.(Float) -> Unit = {} ) { - val materialQuantity = materialQuantityDto(materialId = materialId, quantity = deductedQuantity) + val materialQuantity = materialQuantityDto(materialId = materialId, quantity = quantity) - withGivenQuantities(inventory, materialQuantity, test) + withGivenQuantities(stored, materialQuantity, test) } private fun withGivenQuantities( - inventory: Float, + stored: Float, materialQuantity: MaterialQuantityDto, - test: (MaterialQuantityDto) -> Unit = {} + test: MaterialQuantityDto.(Float) -> Unit = {} ) { - val material = material(id = materialQuantity.material, inventoryQuantity = inventory) + val material = material(id = materialQuantity.material, inventoryQuantity = stored) whenever(materialService.getById(material.id!!)).doReturn(material) - test(materialQuantity) + materialQuantity.test(stored) } } diff --git a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialServiceTest.kt b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialServiceTest.kt index 09d74ef..e163c97 100644 --- a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialServiceTest.kt @@ -171,9 +171,10 @@ class MaterialServiceTest : val quantity = 1234f val totalQuantity = material.inventoryQuantity + quantity - service.updateQuantity(material, quantity) + val found = service.updateQuantity(material, quantity) verify(repository).updateInventoryQuantityById(material.id!!, totalQuantity) + assertEquals(totalQuantity, found) } // getAllForMixCreation()