Les endpoints pour déduire et ajouter une quantité de produit retournent maintenant les quantités mises à jour.
This commit is contained in:
parent
261ff046ec
commit
582236b72e
|
@ -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")
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue