Merge branch 'inventory' into 'master'
Inventory See merge request color-recipes-explorer/backend!17
This commit is contained in:
commit
91927eca84
|
@ -309,6 +309,16 @@ private enum class ControllerAuthorizations(
|
|||
val antMatcher: String,
|
||||
val permissions: Map<HttpMethod, EmployeePermission>
|
||||
) {
|
||||
INVENTORY_ADD(
|
||||
"/api/material/inventory/add", mapOf(
|
||||
HttpMethod.PUT to EmployeePermission.EDIT_MATERIAL
|
||||
)
|
||||
),
|
||||
INVENTORY_DEDUCT(
|
||||
"/api/material/inventory/deduct", mapOf(
|
||||
HttpMethod.PUT to EmployeePermission.VIEW_MATERIAL
|
||||
)
|
||||
),
|
||||
MATERIALS(
|
||||
"/api/material/**", mapOf(
|
||||
HttpMethod.GET to EmployeePermission.VIEW_MATERIAL,
|
||||
|
|
|
@ -15,6 +15,7 @@ import javax.persistence.*
|
|||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotNull
|
||||
import javax.validation.constraints.Size
|
||||
import kotlin.jvm.Transient
|
||||
|
||||
|
||||
private const val EMPLOYEE_ID_NULL_MESSAGE = "Un numéro d'employé est requis"
|
||||
|
@ -136,14 +137,7 @@ data class EmployeeGroup(
|
|||
@Column(name = "permission")
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
val permissions: MutableSet<EmployeePermission> = mutableSetOf(),
|
||||
|
||||
@OneToMany(mappedBy = "group")
|
||||
@field:JsonIgnore
|
||||
val employees: MutableSet<Employee> = mutableSetOf()
|
||||
) : NamedModel {
|
||||
@JsonProperty("employeeCount")
|
||||
fun getEmployeeCount() = employees.size - 1 // -1 removes the default employee
|
||||
}
|
||||
) : NamedModel
|
||||
|
||||
open class EmployeeGroupSaveDto(
|
||||
@field:NotBlank(message = GROUP_NAME_NULL_MESSAGE)
|
||||
|
@ -327,9 +321,8 @@ fun employeeGroup(
|
|||
id: Long? = null,
|
||||
name: String = "name",
|
||||
permissions: MutableSet<EmployeePermission> = mutableSetOf(),
|
||||
employees: MutableSet<Employee> = mutableSetOf(),
|
||||
op: EmployeeGroup.() -> Unit = {}
|
||||
) = EmployeeGroup(id, name, permissions, employees).apply(op)
|
||||
) = EmployeeGroup(id, name, permissions).apply(op)
|
||||
|
||||
fun employeeGroupSaveDto(
|
||||
name: String = "name",
|
||||
|
|
|
@ -107,18 +107,20 @@ class GroupsController(groupService: EmployeeGroupServiceImpl) :
|
|||
@PutMapping("{groupId}/{employeeId}")
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
fun addEmployeeToGroup(@PathVariable groupId: Long, @PathVariable employeeId: Long): ResponseEntity<Void> {
|
||||
service.addEmployeeToGroup(groupId, employeeId)
|
||||
return ResponseEntity
|
||||
.noContent()
|
||||
.build()
|
||||
// service.addEmployeeToGroup(groupId, employeeId)
|
||||
// return ResponseEntity
|
||||
// .noContent()
|
||||
// .build()
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build() // TODO Go to employee controller
|
||||
}
|
||||
|
||||
@DeleteMapping("{groupId}/{employeeId}")
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
fun removeEmployeeFromGroup(@PathVariable groupId: Long, @PathVariable employeeId: Long): ResponseEntity<Void> {
|
||||
service.removeEmployeeFromGroup(groupId, employeeId)
|
||||
return ResponseEntity
|
||||
.noContent()
|
||||
.build()
|
||||
// service.removeEmployeeFromGroup(groupId, employeeId)
|
||||
// return ResponseEntity
|
||||
// .noContent()
|
||||
// .build()
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build() // TODO Go to employee controller
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,23 +66,6 @@ interface EmployeeGroupService :
|
|||
|
||||
/** Sets the default group cookie for the given HTTP [response]. */
|
||||
fun setResponseDefaultGroup(groupId: Long, response: HttpServletResponse)
|
||||
|
||||
/** Adds the employee with the given [employeeId] to the group with the given [groupId]. */
|
||||
fun addEmployeeToGroup(groupId: Long, employeeId: Long)
|
||||
|
||||
/**
|
||||
* Adds a given [employee] to a given [group].
|
||||
*
|
||||
* If the [employee] is already in the [group], nothing will be done.
|
||||
* If the [employee] is already in a group, it will be removed from it.
|
||||
*/
|
||||
fun addEmployeeToGroup(group: EmployeeGroup, employee: Employee)
|
||||
|
||||
/** Removes the employee with the given [employeeId] from the group with the given [groupId]. */
|
||||
fun removeEmployeeFromGroup(groupId: Long, employeeId: Long)
|
||||
|
||||
/** Removes a given [employee] from the given [group]. */
|
||||
fun removeEmployeeFromGroup(group: EmployeeGroup, employee: Employee)
|
||||
}
|
||||
|
||||
interface EmployeeUserDetailsService : UserDetailsService {
|
||||
|
@ -240,7 +223,7 @@ class EmployeeGroupServiceImpl(
|
|||
EmployeeGroupService {
|
||||
override fun existsByName(name: String): Boolean = repository.existsByName(name)
|
||||
override fun getEmployeesForGroup(id: Long): Collection<Employee> =
|
||||
getById(id).employees
|
||||
employeeService.getByGroup(getById(id))
|
||||
|
||||
@Transactional
|
||||
override fun save(entity: EmployeeGroup): EmployeeGroup {
|
||||
|
@ -255,8 +238,7 @@ class EmployeeGroupServiceImpl(
|
|||
EmployeeGroup(
|
||||
entity.id,
|
||||
if (name.isNotBlank()) entity.name else persistedGroup.name,
|
||||
if (permissions.isNotEmpty()) entity.permissions else persistedGroup.permissions,
|
||||
persistedGroup.employees
|
||||
if (permissions.isNotEmpty()) entity.permissions else persistedGroup.permissions
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -286,34 +268,6 @@ class EmployeeGroupServiceImpl(
|
|||
"$defaultGroupCookieName=${defaultGroupUser.id}; Max-Age=${defaultGroupCookieMaxAge}; Path=/api; HttpOnly; Secure; SameSite=strict"
|
||||
)
|
||||
}
|
||||
|
||||
override fun addEmployeeToGroup(groupId: Long, employeeId: Long) {
|
||||
addEmployeeToGroup(getById(groupId), employeeService.getById(employeeId))
|
||||
}
|
||||
|
||||
@Transactional
|
||||
override fun addEmployeeToGroup(group: EmployeeGroup, employee: Employee) {
|
||||
if (employee.group == group) return
|
||||
if (employee.group != null) removeEmployeeFromGroup(employee.group!!, employee)
|
||||
|
||||
group.employees.add(employee)
|
||||
employee.group = group
|
||||
update(group)
|
||||
employeeService.update(employee)
|
||||
}
|
||||
|
||||
override fun removeEmployeeFromGroup(groupId: Long, employeeId: Long) =
|
||||
removeEmployeeFromGroup(getById(groupId), employeeService.getById(employeeId))
|
||||
|
||||
@Transactional
|
||||
override fun removeEmployeeFromGroup(group: EmployeeGroup, employee: Employee) {
|
||||
if (employee.group == null || employee.group != group) return
|
||||
|
||||
group.employees.removeIf { it.id == employee.id }
|
||||
employee.group = null
|
||||
update(group)
|
||||
employeeService.update(employee)
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,9 +222,10 @@ class EmployeeGroupServiceTest :
|
|||
|
||||
@Test
|
||||
fun `getEmployeesForGroup() returns all employees in the given group`() {
|
||||
val group = employeeGroup(id = 1L, employees = mutableSetOf(groupEmployee))
|
||||
val group = employeeGroup(id = 1L)
|
||||
|
||||
doReturn(group).whenever(service).getById(group.id!!)
|
||||
whenever(employeeService.getByGroup(group)).doReturn(listOf(groupEmployee))
|
||||
|
||||
val found = service.getEmployeesForGroup(group.id!!)
|
||||
|
||||
|
@ -286,122 +287,6 @@ class EmployeeGroupServiceTest :
|
|||
assertTrue(found.secure)
|
||||
}
|
||||
|
||||
// addEmployeeToGroup()
|
||||
|
||||
@Test
|
||||
fun `addEmployeeToGroup() calls addEmployeeToGroup() with the group of the given groupId and the employee of the given employeeId`() {
|
||||
whenever(employeeService.getById(groupEmployeeId)).doReturn(groupEmployee)
|
||||
doReturn(entity).whenever(service).getById(entity.id!!)
|
||||
doAnswer { }.whenever(service).addEmployeeToGroup(entity, groupEmployee)
|
||||
|
||||
service.addEmployeeToGroup(entity.id!!, groupEmployeeId)
|
||||
|
||||
verify(service).addEmployeeToGroup(entity, groupEmployee)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `addEmployeeToGroup() calls update() and employeeService_update() with the updated entities`() {
|
||||
val group = employeeGroup()
|
||||
val employee = employee()
|
||||
|
||||
whenever(employeeService.update(employee)).doReturn(employee)
|
||||
doReturn(group).whenever(service).update(group)
|
||||
|
||||
service.addEmployeeToGroup(group, employee)
|
||||
|
||||
verify(service).update(group)
|
||||
verify(employeeService).update(employee)
|
||||
|
||||
assertTrue(group.employees.any { it.id == employee.id })
|
||||
assertEquals(group, employee.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `addEmployeeToGroup() do nothing when the given employee is already in the given group`() {
|
||||
val group = employeeGroup()
|
||||
val employee = employee(group = group)
|
||||
|
||||
service.addEmployeeToGroup(group, employee)
|
||||
|
||||
verify(service, times(0)).update(group)
|
||||
verify(employeeService, times(0)).update(employee)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `addEmployeeToGroup() remove previous group from the given employee and add it the the given group`() {
|
||||
val group = employeeGroup(id = 0L)
|
||||
val previousGroup = employeeGroup(id = 1L)
|
||||
val employee = employee(group = previousGroup)
|
||||
|
||||
whenever(employeeService.update(employee)).doReturn(employee)
|
||||
doReturn(group).whenever(service).update(group)
|
||||
doReturn(group).whenever(service).update(previousGroup)
|
||||
|
||||
service.addEmployeeToGroup(group, employee)
|
||||
|
||||
verify(service).removeEmployeeFromGroup(previousGroup, employee)
|
||||
verify(service).update(group)
|
||||
verify(employeeService, times(2)).update(employee)
|
||||
|
||||
assertTrue(group.employees.any { it.id == employee.id })
|
||||
assertEquals(group, employee.group)
|
||||
}
|
||||
|
||||
// removeEmployeeFromGroup()
|
||||
|
||||
@Test
|
||||
fun `removeEmployeeFromGroup() calls removeEmployeeFromGroup() with the group of the given group id and the employee of the given employee id`() {
|
||||
whenever(employeeService.getById(groupEmployeeId)).doReturn(groupEmployee)
|
||||
doReturn(entity).whenever(service).getById(entity.id!!)
|
||||
doAnswer { it.arguments[0] }.whenever(service).update(any<EmployeeGroup>())
|
||||
|
||||
service.removeEmployeeFromGroup(entity.id!!, groupEmployeeId)
|
||||
|
||||
verify(service).removeEmployeeFromGroup(entity, groupEmployee)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeEmployeeFromGroup() calls update() and employeeService_update() with the updated entities`() {
|
||||
val employee = employee()
|
||||
val group = employeeGroup(employees = mutableSetOf(employee))
|
||||
employee.group = group
|
||||
|
||||
whenever(employeeService.update(any<Employee>())).doReturn(employee)
|
||||
doReturn(group).whenever(service).update(group)
|
||||
|
||||
service.removeEmployeeFromGroup(group, employee)
|
||||
|
||||
verify(service).update(group)
|
||||
verify(employeeService).update(argThat<Employee> { this.group == null })
|
||||
|
||||
assertFalse(group.employees.contains(employee))
|
||||
assertNull(employee.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeEmployeeFromGroup() do nothing when the given employee is not in the given group`() {
|
||||
val employee = employee()
|
||||
val group = employeeGroup(id = 0L)
|
||||
val anotherGroup = employeeGroup(id = 1L, employees = mutableSetOf(employee))
|
||||
employee.group = anotherGroup
|
||||
|
||||
service.removeEmployeeFromGroup(group, employee)
|
||||
|
||||
verify(service, times(0)).update(anotherGroup)
|
||||
verify(employeeService, times(0)).update(employee)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeEmployeeFromGroup() do nothing when the given employee is not in a group`() {
|
||||
val employee = employee()
|
||||
val group = employeeGroup()
|
||||
|
||||
service.removeEmployeeFromGroup(group, employee)
|
||||
|
||||
verify(service, times(0)).update(group)
|
||||
verify(employeeService, times(0)).update(employee)
|
||||
}
|
||||
|
||||
// save()
|
||||
|
||||
@Test
|
||||
|
|
|
@ -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