Skip to content

Commit

Permalink
Changed handling of duplicate orders
Browse files Browse the repository at this point in the history
  • Loading branch information
MormonJesus69420 committed Aug 20, 2024
1 parent 31328bf commit 3a4285d
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 11 deletions.
11 changes: 7 additions & 4 deletions src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,18 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) {
.awaitSingleOrNull()

if (existingOrder != null) {
return ResponseEntity.badRequest().build()
return ResponseEntity.ok(existingOrder.toApiOrderPayload())
}

val synqResponse = synqService.createOrder(payload.toOrder().toSynqPayload())
// If SynQ didn't throw an error, but returned something that wasn't a new order,
// then it is likely some error or edge-case
if (!synqResponse.statusCode.isSameCodeAs(HttpStatus.CREATED)) {
// If SynQ didn't throw an error, but returned 4xx/5xx, then it is likely some error or edge-case we haven't handled
if (synqResponse.statusCode.is4xxClientError || synqResponse.statusCode.is5xxServerError) {
throw ServerErrorException("Unexpected error with SynQ", null)
}
// If SynQ returned a 200 OK then it means it exists from before, and we can return empty response (since we don't have any order info)
if (synqResponse.statusCode.isSameCodeAs(HttpStatus.OK)) {
return ResponseEntity.ok().build()
}

// Return what the database saved, as it could contain changes
val order =
Expand Down
15 changes: 13 additions & 2 deletions src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.BodyInserters
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.WebClientResponseException
import org.springframework.web.server.ServerErrorException
import reactor.core.publisher.Mono
import java.net.URI

@Service
Expand All @@ -33,9 +35,18 @@ class SynqOrderService(
.body(BodyInserters.fromValue(orders))
.retrieve()
.toEntity(SynqError::class.java)
.onErrorMap(WebClientResponseException::class.java) {
createServerError(it)
.onErrorResume(WebClientResponseException::class.java) { error ->
val errorText = error.getResponseBodyAs(SynqError::class.java)?.errorText
if (errorText != null && errorText.contains("Duplicate order")) {
Mono.error(DuplicateOrderException(error))
} else {
Mono.error(error)
}
}
.onErrorMap(WebClientResponseException::class.java) { createServerError(it) }
.onErrorReturn(DuplicateOrderException::class.java, ResponseEntity.ok().build())
.awaitSingle()
}
}

class DuplicateOrderException(override val cause: Throwable) : ServerErrorException("Order already exists in SynQ", cause)
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class ProductService(val db: ProductRepository, val synqProductService: SynqProd
ServerErrorException("Failed to save product in the database", it)
}
.awaitSingleOrNull()

if (existingProduct != null) {
return ResponseEntity.ok(existingProduct.toApiPayload())
}
Expand All @@ -47,7 +48,13 @@ class ProductService(val db: ProductRepository, val synqProductService: SynqProd
val product = payload.toProduct().copy(quantity = 0.0, location = null)

// Product service should create the product in the storage system, and return error message if it fails
if (synqProductService.createProduct(product.toSynqPayload()).statusCode.isSameCodeAs(HttpStatus.OK)) {
val synqResponse = synqProductService.createProduct(product.toSynqPayload())
// If SynQ didn't throw an error, but returned 4xx/5xx, then it is likely some error or edge-case we haven't handled
if (synqResponse.statusCode.is4xxClientError || synqResponse.statusCode.is5xxServerError) {
throw ServerErrorException("Unexpected error with SynQ", null)
}
// If SynQ returned a 200 OK then it means it exists from before, and we can return empty response (since we don't have any order info)
if (synqResponse.statusCode.isSameCodeAs(HttpStatus.OK)) {
return ResponseEntity.ok().build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import org.springframework.http.ResponseEntity
import org.springframework.security.test.context.support.WithMockUser
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
import java.net.URI

@EnableTestcontainers
Expand Down Expand Up @@ -92,19 +93,57 @@ class OrderControllerTest(
@Test
@WithMockUser
fun `createOrder with duplicate payload returns OK`() {
// How to handle this? OK or error?
webTestClient
.mutateWith(csrf())
.post()
.uri("/batch/create")
.accept(MediaType.APPLICATION_JSON)
.bodyValue(duplicateOrderPayload)
.exchange()
.expectStatus().isOk
.expectBody<ApiOrderPayload>()
.consumeWith { response ->
assertThat(response.responseBody?.hostOrderId).isEqualTo(duplicateOrderPayload.hostOrderId)
assertThat(response.responseBody?.hostName).isEqualTo(duplicateOrderPayload.hostName)
assertThat(response.responseBody?.productLine).isEqualTo(duplicateOrderPayload.productLine)
}
}

@Test
@WithMockUser
fun `createOrder payload with different data but same ID returns DB entry`() {
// How to handle this? OK or error?
webTestClient
.mutateWith(csrf())
.post()
.uri("/batch/create")
.accept(MediaType.APPLICATION_JSON)
.bodyValue(
duplicateOrderPayload.copy(productLine = listOf(ProductLine("AAAAAAAAA", OrderLineStatus.PICKED)))
)
.exchange()
.expectStatus().isOk
.expectBody<ApiOrderPayload>()
.consumeWith { response ->
assertThat(response.responseBody?.productLine).isEqualTo(duplicateOrderPayload.productLine)
}
}

@Test
@WithMockUser
fun `createOrder where SynQ says it's a duplicate returns OK`() {
// How to handle this? OK or error?
fun `createOrder where SynQ says it's a duplicate returns OK`() { // SynqService converts an error to return OK if it finds a duplicate product
coEvery {
synqOrderService.createOrder(any())
} returns ResponseEntity.ok().build()

webTestClient
.mutateWith(csrf())
.post()
.uri("/batch/create")
.accept(MediaType.APPLICATION_JSON)
.bodyValue(testOrderPayload)
.exchange()
.expectStatus().isOk
.expectBody().isEmpty
}

@Test
Expand Down

0 comments on commit 3a4285d

Please sign in to comment.