Les endpoints pour déduire et ajouter une quantité de produit retournent maintenant les quantités mises à jour.

This commit is contained in:
FyloZ 2021-03-19 22:08:01 -04:00
parent 261ff046ec
commit 582236b72e
7 changed files with 94 additions and 65 deletions

View File

@ -138,7 +138,7 @@ data class EmployeeGroup(
val permissions: MutableSet<EmployeePermission> = mutableSetOf(),
@OneToMany(mappedBy = "group")
@JsonIgnore
@field:JsonIgnore
val employees: MutableSet<Employee> = mutableSetOf()
) : NamedModel {
@JsonProperty("employeeCount")

View File

@ -97,15 +97,13 @@ class InventoryController(
private val inventoryService: InventoryService
) {
@PutMapping("add")
fun add(@RequestBody quantities: Collection<MaterialQuantityDto>): ResponseEntity<Void> {
inventoryService.add(quantities)
return ResponseEntity.ok().build()
fun add(@RequestBody quantities: Collection<MaterialQuantityDto>): ResponseEntity<Collection<MaterialQuantityDto>> {
return ResponseEntity.ok(inventoryService.add(quantities))
}
@PutMapping("deduct")
fun deduct(@RequestBody quantities: Collection<MaterialQuantityDto>): ResponseEntity<Void> {
inventoryService.deduct(quantities)
return ResponseEntity.ok().build()
fun deduct(@RequestBody quantities: Collection<MaterialQuantityDto>): ResponseEntity<Collection<MaterialQuantityDto>> {
return ResponseEntity.ok(inventoryService.deduct(quantities))
}
}

View File

@ -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<MaterialQuantityDto>)
/** Adds each given [MaterialQuantityDto] to the inventory and returns the updated quantities. */
fun add(materialQuantities: Collection<MaterialQuantityDto>): Collection<MaterialQuantityDto>
/** 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<MaterialQuantityDto>)
/** Deducts the inventory quantity of each given [MaterialQuantityDto] and returns the updated quantities. */
fun deduct(materialQuantities: Collection<MaterialQuantityDto>): Collection<MaterialQuantityDto>
/** 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<MaterialQuantityDto>) {
materialQuantities.forEach(::add)
}
override fun add(materialQuantities: Collection<MaterialQuantityDto>) =
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<MaterialQuantityDto>) {
with(materialQuantities.filterThrows<MaterialQuantityDto, LowQuantityException> {
deduct(it)
}) {
if (this.isNotEmpty()) {
throw LowQuantitiesException(this)
override fun deduct(materialQuantities: Collection<MaterialQuantityDto>): Collection<MaterialQuantityDto> {
val thrown = mutableListOf<MaterialQuantityDto>()
val updatedQuantities =
materialQuantities.mapMayThrow<MaterialQuantityDto, MaterialQuantityDto, LowQuantityException>(
{ 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)
}
}
}
}

View File

@ -30,8 +30,8 @@ interface MaterialService :
/** Gets the identifier of materials for which a SIMDUT exists. */
fun getAllIdsWithSimdut(): Collection<Long>
/** 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<Material> {

View File

@ -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 <T, reified E : Throwable> Iterable<T>.filterThrows(consumer: (T) -> Unit): List<T> = 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 <T, R, reified E : Throwable> Iterable<T>.mapMayThrow(
throwableConsumer: (E) -> Unit = {},
transform: (T) -> R
): List<R> = this.mapNotNull {
try {
consumer(it)
false
transform(it)
} catch (th: Throwable) {
th is E
if (th is E) {
throwableConsumer(th)
null
} else {
throw th
}
}
}

View File

@ -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<MaterialQuantityDto>())
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<MaterialQuantityDto>())
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<LowQuantityException> { service.deduct(it) }
assertEquals(it, exception.materialQuantity)
val exception = assertThrows<LowQuantityException> { 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)
}
}

View File

@ -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()