From 86adda382237dc10e87c60615711eff081f4ceba Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Thu, 22 Aug 2024 14:51:41 +0200 Subject: [PATCH 01/14] Begin implementing update endpoint --- .../wls/order/controller/OrderController.kt | 4 +++ .../nb/mlt/wls/order/service/OrderService.kt | 29 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt index c2ea2856..326d07f6 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt @@ -72,4 +72,8 @@ class OrderController(val orderService: OrderService) { suspend fun createOrder( @RequestBody payload: ApiOrderPayload ): ResponseEntity = orderService.createOrder(payload) + + suspend fun updateOrder( + @RequestBody payload: ApiOrderPayload + ): ResponseEntity = orderService.updateOrder(payload) } diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index 94607bd4..c2783b30 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -11,6 +11,7 @@ import no.nb.mlt.wls.order.repository.OrderRepository import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.stereotype.Service +import org.springframework.web.server.ResponseStatusException import org.springframework.web.server.ServerErrorException import org.springframework.web.server.ServerWebInputException import java.time.Duration @@ -65,6 +66,34 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { return ResponseEntity.status(HttpStatus.CREATED).body(order.toApiOrderPayload()) } + suspend fun updateOrder(payload: ApiOrderPayload): ResponseEntity { + throwIfInvalidPayload(payload) + + val existingOrder = + db.findByHostNameAndHostOrderId(payload.hostName, payload.orderId) + .timeout(Duration.ofSeconds(8)) + .onErrorMap { + if (it is TimeoutException) { + logger.error(it) { + "Timed out while fetching from WLS database. Relevant payload: $payload" + } + } else { + logger.error(it) { "Unexpected error for $payload" } + } + ServerErrorException("Failed while checking if order already exists in the database", it) + } + .awaitSingleOrNull() + + if (existingOrder == null) { + throw ResponseStatusException( + HttpStatus.BAD_REQUEST, + "Order with id $payload.hostOrderId from $payload.hostName does not exist in the database" + ) + } + + TODO("Implement SynQ integration") + } + private fun throwIfInvalidPayload(payload: ApiOrderPayload) { if (payload.orderId.isBlank()) { throw ServerWebInputException("The order's orderId is required, and can not be blank") From 1a0ec61a1bce9c55c07b496996fc50300b71e868 Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Fri, 23 Aug 2024 11:02:42 +0200 Subject: [PATCH 02/14] Order update against SynQ --- .../wls/order/controller/OrderController.kt | 2 ++ .../nb/mlt/wls/order/service/OrderService.kt | 3 ++- .../mlt/wls/order/service/SynqOrderService.kt | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt index 326d07f6..82b29c8d 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt @@ -10,6 +10,7 @@ import no.nb.mlt.wls.order.payloads.ApiOrderPayload import no.nb.mlt.wls.order.service.OrderService import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @@ -73,6 +74,7 @@ class OrderController(val orderService: OrderService) { @RequestBody payload: ApiOrderPayload ): ResponseEntity = orderService.createOrder(payload) + @PutMapping("/order") suspend fun updateOrder( @RequestBody payload: ApiOrderPayload ): ResponseEntity = orderService.updateOrder(payload) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index c2783b30..be066124 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -91,7 +91,8 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { ) } - TODO("Implement SynQ integration") + val response = synqService.updateOrder(payload) + TODO("Update internal database with response") } private fun throwIfInvalidPayload(payload: ApiOrderPayload) { diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt index 740e6252..75b744fb 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt @@ -3,8 +3,11 @@ package no.nb.mlt.wls.order.service import kotlinx.coroutines.reactor.awaitSingle import no.nb.mlt.wls.core.data.synq.SynqError import no.nb.mlt.wls.core.data.synq.SynqError.Companion.createServerError +import no.nb.mlt.wls.order.payloads.ApiOrderPayload import no.nb.mlt.wls.order.payloads.SynqOrder import no.nb.mlt.wls.order.payloads.SynqOrderPayload +import no.nb.mlt.wls.order.payloads.toOrder +import no.nb.mlt.wls.order.payloads.toSynqPayload import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.http.ResponseEntity @@ -47,6 +50,22 @@ class SynqOrderService( .onErrorReturn(DuplicateOrderException::class.java, ResponseEntity.ok().build()) .awaitSingle() } + + suspend fun updateOrder(payload: ApiOrderPayload): ResponseEntity { + val uri = URI.create("$baseUrl/orders/batch") + + val orders = SynqOrder(listOf(payload.toOrder().toSynqPayload())) + + // TODO - Extend error handling + return webClient + .put() + .uri(uri) + .bodyValue(orders) + .retrieve() + .toEntity(SynqError::class.java) + .onErrorMap(WebClientResponseException::class.java) { createServerError(it) } + .awaitSingle() + } } class DuplicateOrderException(override val cause: Throwable) : ServerErrorException("Order already exists in SynQ", cause) From 386a70948460eee33df0715767db67c9670eeaed Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Mon, 26 Aug 2024 10:18:33 +0200 Subject: [PATCH 03/14] Add id to Orders, allows for updating --- src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt | 2 ++ .../kotlin/no/nb/mlt/wls/order/service/OrderService.kt | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt b/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt index 28fccea8..b55ece15 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt @@ -4,11 +4,13 @@ import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY import no.nb.mlt.wls.core.data.HostName import no.nb.mlt.wls.core.data.Owner +import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document @Document(collection = "orders") data class Order( val hostName: HostName, + @Id val hostOrderId: String, val status: OrderStatus, val productLine: List, diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index be066124..2e282d21 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -91,8 +91,14 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { ) } - val response = synqService.updateOrder(payload) - TODO("Update internal database with response") + synqService.updateOrder(payload) + + // Saving here will override the existing order, as the id's match + val updatedOrder = + db.save(payload.toOrder()) + .awaitSingle() + + return ResponseEntity.ok(updatedOrder.toApiOrderPayload()) } private fun throwIfInvalidPayload(payload: ApiOrderPayload) { From 19535344759057bd3c22c7e21098479fd662e6c9 Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Mon, 26 Aug 2024 11:12:35 +0200 Subject: [PATCH 04/14] Compound Index for hostName + hostOrderId --- src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt b/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt index b55ece15..b8b673c0 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt @@ -5,13 +5,15 @@ import io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY import no.nb.mlt.wls.core.data.HostName import no.nb.mlt.wls.core.data.Owner import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.index.CompoundIndex import org.springframework.data.mongodb.core.mapping.Document +@CompoundIndex(unique = true, def = "{'hostName':1,'hostOrderId':1}") @Document(collection = "orders") data class Order( - val hostName: HostName, @Id val hostOrderId: String, + val hostName: HostName, val status: OrderStatus, val productLine: List, val orderType: OrderType, @@ -37,7 +39,7 @@ data class ProductLine( val hostId: String, @Schema( description = "Current status of the order line.", - examples = [ "NOT_STARTED", "PICKED", "FAILED" ], + examples = ["NOT_STARTED", "PICKED", "FAILED"], defaultValue = "NOT_STARTED", accessMode = READ_ONLY ) @@ -113,7 +115,7 @@ enum class OrderLineStatus(private val status: String) { enum class OrderType(private val type: String) { LOAN("Loan"), - DIGITIZATION("Digitization") ; + DIGITIZATION("Digitization"); override fun toString(): String { return type From 0cbf8f304e6aacebc538b4b97b20040a219f3768 Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Mon, 26 Aug 2024 13:43:57 +0200 Subject: [PATCH 05/14] Disallow editing status while order is in progress --- src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index 2e282d21..20642016 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -3,6 +3,7 @@ package no.nb.mlt.wls.order.service import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactor.awaitSingleOrNull +import no.nb.mlt.wls.order.model.OrderStatus import no.nb.mlt.wls.order.payloads.ApiOrderPayload import no.nb.mlt.wls.order.payloads.toApiOrderPayload import no.nb.mlt.wls.order.payloads.toOrder @@ -91,6 +92,10 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { ) } + if (existingOrder.status != OrderStatus.NOT_STARTED) { + throw ResponseStatusException(HttpStatus.CONFLICT, "Order is already being processed, and can not be edited") + } + synqService.updateOrder(payload) // Saving here will override the existing order, as the id's match From 7f01da7f54dfe535f0f5b81d6ba697b8da46a24d Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Mon, 26 Aug 2024 15:39:42 +0200 Subject: [PATCH 06/14] Add basic SwaggerDoc --- .../wls/order/controller/OrderController.kt | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt index 82b29c8d..7688652e 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt @@ -53,8 +53,8 @@ class OrderController(val orderService: OrderService) { ), ApiResponse( responseCode = "400", - description = """Order payload is invalid and was not created. - An empty error message means the order already exists with the current ID. + description = """Order payload is invalid and was not updated. + This error is produced if the order specified does not exist. Otherwise, the error message contains information about the invalid fields.""", content = [Content(schema = Schema())] ), @@ -74,6 +74,55 @@ class OrderController(val orderService: OrderService) { @RequestBody payload: ApiOrderPayload ): ResponseEntity = orderService.createOrder(payload) + @Operation( + summary = "Updates an existing order in the storage system", + description = """Updates a specified order to the various storage systems via Hermes WLS. + If the storage systems support it, updates are also sent to them for processing the respective product(s). + """ + ) + @ApiResponses( + ApiResponse( + responseCode = "200", + description = """Order with given 'hostName' and 'hostOrderId' already exists in the system. + No new order was created, neither was the old order updated. + Existing order information is returned for inspection. + In rare cases the response body may be empty, that can happen if Hermes WLS does not + have the information about the order stored in its database and is unable to retrieve + the existing order information from the storage system.""", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = ApiOrderPayload::class) + ) + ] + ), + ApiResponse( + responseCode = "200", + description = "The order was updated with the new products, and sent to appropriate systems", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = ApiOrderPayload::class) + ) + ] + ), + ApiResponse( + responseCode = "400", + description = """Order payload is invalid and the order was not updated. + The error message contains information about the invalid fields.""", + content = [Content(schema = Schema())] + ), + ApiResponse( + responseCode = "401", + description = "Client sending the request is not authorized order products.", + content = [Content(schema = Schema())] + ), + ApiResponse( + responseCode = "403", + description = "A valid 'Authorization' header is missing from the request.", + content = [Content(schema = Schema())] + ) + ) @PutMapping("/order") suspend fun updateOrder( @RequestBody payload: ApiOrderPayload From c6e85b6a8cad86dd134927cfe94c1bcc64d55be4 Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Tue, 27 Aug 2024 10:09:02 +0200 Subject: [PATCH 07/14] Fix and improve SwaggerDoc --- .../wls/order/controller/OrderController.kt | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt index 7688652e..73ecbffc 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt @@ -54,7 +54,7 @@ class OrderController(val orderService: OrderService) { ApiResponse( responseCode = "400", description = """Order payload is invalid and was not updated. - This error is produced if the order specified does not exist. + An empty error message means the order already exists with the current ID. Otherwise, the error message contains information about the invalid fields.""", content = [Content(schema = Schema())] ), @@ -75,27 +75,11 @@ class OrderController(val orderService: OrderService) { ): ResponseEntity = orderService.createOrder(payload) @Operation( - summary = "Updates an existing order in the storage system", + summary = "Updates an existing order in the storage system(s)", description = """Updates a specified order to the various storage systems via Hermes WLS. - If the storage systems support it, updates are also sent to them for processing the respective product(s). """ ) @ApiResponses( - ApiResponse( - responseCode = "200", - description = """Order with given 'hostName' and 'hostOrderId' already exists in the system. - No new order was created, neither was the old order updated. - Existing order information is returned for inspection. - In rare cases the response body may be empty, that can happen if Hermes WLS does not - have the information about the order stored in its database and is unable to retrieve - the existing order information from the storage system.""", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = ApiOrderPayload::class) - ) - ] - ), ApiResponse( responseCode = "200", description = "The order was updated with the new products, and sent to appropriate systems", @@ -109,7 +93,8 @@ class OrderController(val orderService: OrderService) { ApiResponse( responseCode = "400", description = """Order payload is invalid and the order was not updated. - The error message contains information about the invalid fields.""", + This error is also produced if the order specified does not exist. + Otherwise, the error message contains information about the invalid fields.""", content = [Content(schema = Schema())] ), ApiResponse( @@ -121,6 +106,11 @@ class OrderController(val orderService: OrderService) { responseCode = "403", description = "A valid 'Authorization' header is missing from the request.", content = [Content(schema = Schema())] + ), + ApiResponse( + responseCode = "409", + description = "The order is already being processed, and can not be edited at this point.", + content = [Content(schema = Schema())] ) ) @PutMapping("/order") From dbf6848deaa7920dbfc8af386121454ae47b5363 Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Tue, 27 Aug 2024 10:10:27 +0200 Subject: [PATCH 08/14] Fix typo --- .../kotlin/no/nb/mlt/wls/order/controller/OrderController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt index 73ecbffc..e7e30724 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt @@ -53,7 +53,7 @@ class OrderController(val orderService: OrderService) { ), ApiResponse( responseCode = "400", - description = """Order payload is invalid and was not updated. + description = """Order payload is invalid and was not created. An empty error message means the order already exists with the current ID. Otherwise, the error message contains information about the invalid fields.""", content = [Content(schema = Schema())] From 8ddd22f41ca3677437d65875a2d05a2d404a8371 Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Tue, 27 Aug 2024 10:45:28 +0200 Subject: [PATCH 09/14] Introduce ObjectID --- src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt | 2 ++ .../no/nb/mlt/wls/order/service/OrderService.kt | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt b/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt index b8b673c0..c97d70e8 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/model/Order.kt @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY import no.nb.mlt.wls.core.data.HostName import no.nb.mlt.wls.core.data.Owner +import org.bson.types.ObjectId import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.index.CompoundIndex import org.springframework.data.mongodb.core.mapping.Document @@ -12,6 +13,7 @@ import org.springframework.data.mongodb.core.mapping.Document @Document(collection = "orders") data class Order( @Id + private val id: ObjectId = ObjectId(), val hostOrderId: String, val hostName: HostName, val status: OrderStatus, diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index 20642016..e5001c04 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -95,13 +95,21 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { if (existingOrder.status != OrderStatus.NOT_STARTED) { throw ResponseStatusException(HttpStatus.CONFLICT, "Order is already being processed, and can not be edited") } - synqService.updateOrder(payload) // Saving here will override the existing order, as the id's match val updatedOrder = - db.save(payload.toOrder()) - .awaitSingle() + db.save( + existingOrder.copy( + hostOrderId = payload.hostOrderId, + hostName = payload.hostName, + productLine = payload.productLine, + orderType = payload.orderType, + owner = payload.owner, + receiver = payload.receiver, + callbackUrl = payload.callbackUrl + ) + ).awaitSingle() return ResponseEntity.ok(updatedOrder.toApiOrderPayload()) } From 990f59055566395977935fd16a2dbd9ae240bebd Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Thu, 29 Aug 2024 09:48:08 +0200 Subject: [PATCH 10/14] Deduplicate fetching orders from internal DB --- .../wls/order/controller/OrderController.kt | 3 +- .../nb/mlt/wls/order/service/OrderService.kt | 80 +++++++++---------- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt index 992f3205..669f9c50 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt @@ -160,6 +160,7 @@ class OrderController(val orderService: OrderService) { ) @PutMapping("/order") suspend fun updateOrder( + @AuthenticationPrincipal jwt: JwtAuthenticationToken, @RequestBody payload: ApiOrderPayload - ): ResponseEntity = orderService.updateOrder(payload) + ): ResponseEntity = orderService.updateOrder(payload, jwt.name) } diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index 221c4db7..e452964d 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -34,21 +34,7 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { ): ResponseEntity { throwIfInvalidClientName(clientName, payload.hostName) throwIfInvalidPayload(payload) - - val existingOrder = - db.findByHostNameAndHostOrderId(payload.hostName, payload.hostOrderId) - .timeout(Duration.ofSeconds(8)) - .onErrorMap { - if (it is TimeoutException) { - logger.error(it) { - "Timed out while fetching from WLS database. Relevant payload: $payload" - } - } else { - logger.error(it) { "Unexpected error for $payload" } - } - ServerErrorException("Failed while checking if order already exists in the database", it) - } - .awaitSingleOrNull() + val existingOrder = findOrderInDb(payload.hostName, payload.hostOrderId) if (existingOrder != null) { return ResponseEntity.ok(existingOrder.toApiOrderPayload()) @@ -77,30 +63,19 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { return ResponseEntity.status(HttpStatus.CREATED).body(order.toApiOrderPayload()) } - suspend fun updateOrder(payload: ApiOrderPayload): ResponseEntity { + suspend fun updateOrder( + payload: ApiOrderPayload, + clientName: String + ): ResponseEntity { + throwIfInvalidClientName(clientName, payload.hostName) throwIfInvalidPayload(payload) val existingOrder = - db.findByHostNameAndHostOrderId(payload.hostName, payload.orderId) - .timeout(Duration.ofSeconds(8)) - .onErrorMap { - if (it is TimeoutException) { - logger.error(it) { - "Timed out while fetching from WLS database. Relevant payload: $payload" - } - } else { - logger.error(it) { "Unexpected error for $payload" } - } - ServerErrorException("Failed while checking if order already exists in the database", it) - } - .awaitSingleOrNull() - - if (existingOrder == null) { - throw ResponseStatusException( - HttpStatus.BAD_REQUEST, - "Order with id $payload.hostOrderId from $payload.hostName does not exist in the database" - ) - } + findOrderInDb(payload.hostName, payload.hostOrderId) + ?: throw ResponseStatusException( + HttpStatus.BAD_REQUEST, + "Order with id $payload.hostOrderId from $payload.hostName does not exist in the database" + ) if (existingOrder.status != OrderStatus.NOT_STARTED) { throw ResponseStatusException(HttpStatus.CONFLICT, "Order is already being processed, and can not be edited") @@ -134,12 +109,33 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { ): ResponseEntity { throwIfInvalidClientName(clientName, hostName) val order = - db.findByHostNameAndHostOrderId(hostName, hostOrderId) - .awaitSingleOrNull() - if (order != null) { - return ResponseEntity.ok(order) - } - throw ResponseStatusException(HttpStatus.NOT_FOUND, "Order with id $hostOrderId from $hostName was not found") + findOrderInDb(hostName, hostOrderId) ?: throw ResponseStatusException( + HttpStatus.NOT_FOUND, + "Order with id $hostOrderId from $hostName was not found" + ) + return ResponseEntity.ok(order) + } + + /** + * Query the WLS database if an order exists + */ + private suspend fun findOrderInDb( + hostName: HostName, + hostOrderId: String + ): Order? { + return db.findByHostNameAndHostOrderId(hostName, hostOrderId) + .timeout(Duration.ofSeconds(8)) + .onErrorMap { + if (it is TimeoutException) { + logger.error(it) { + "Timed out while fetching order $hostOrderId from WLS database. Owner: $hostName" + } + } else { + logger.error(it) { "Unexpected error for getting $hostOrderId from $hostName" } + } + ServerErrorException("Failed while checking if order already exists in the database", it) + } + .awaitSingleOrNull() } private fun throwIfInvalidPayload(payload: ApiOrderPayload) { From b0ca4d758fc2261de68f7718bedec12e73ddd9ae Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Thu, 29 Aug 2024 10:41:55 +0200 Subject: [PATCH 11/14] Add tests for updating orders --- .../mlt/wls/order/service/OrderServiceTest.kt | 96 +++++++++++++++++-- 1 file changed, 90 insertions(+), 6 deletions(-) diff --git a/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt b/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt index 395164de..1a86e91a 100644 --- a/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt +++ b/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt @@ -25,6 +25,7 @@ import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS import org.junit.jupiter.api.extension.ExtendWith import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity +import org.springframework.web.server.ResponseStatusException import org.springframework.web.server.ServerErrorException import org.springframework.web.server.ServerWebInputException import reactor.core.publisher.Mono @@ -65,7 +66,7 @@ class OrderServiceTest { fun `save when order exists throws`() { runTest { every { db.findByHostNameAndHostOrderId(top.hostName, top.hostOrderId) } returns Mono.just(top.toOrder()) - assertThat(cut.createOrder(testClientName, top).statusCode.is4xxClientError) + assertThat(cut.createOrder(tcn, top).statusCode.is4xxClientError) } } @@ -86,7 +87,7 @@ class OrderServiceTest { assertThatExceptionOfType(ServerErrorException::class.java).isThrownBy { runBlocking { - cut.createOrder(testClientName, top) + cut.createOrder(tcn, top) } } } @@ -98,7 +99,7 @@ class OrderServiceTest { assertThatExceptionOfType(ServerErrorException::class.java).isThrownBy { runBlocking { - cut.createOrder(testClientName, top) + cut.createOrder(tcn, top) } } } @@ -111,7 +112,65 @@ class OrderServiceTest { coEvery { synq.createOrder(any()) } returns ResponseEntity(HttpStatus.CREATED) every { db.save(any()) } returns Mono.just(top.toOrder()) - assertThat(cut.createOrder(testClientName, top).statusCode.is2xxSuccessful) + assertThat(cut.createOrder(tcn, top).statusCode.is2xxSuccessful) + } + } + + @Test + fun `update existing order with no errors returns ok`() { + runTest { + every { db.findByHostNameAndHostOrderId(top.hostName, top.hostOrderId) } returns Mono.just(top.toOrder()) + coEvery { synq.updateOrder(any()) } returns ResponseEntity.ok().build() + every { db.save(any()) } returns Mono.just(nop.toOrder()) + + assertThat(cut.updateOrder(nop, tcn).statusCode.is2xxSuccessful) + } + } + + @Test + fun `update order which doesn't exist throws`() { + every { db.findByHostNameAndHostOrderId(top.hostName, top.hostOrderId) } returns Mono.empty() + + assertThatExceptionOfType(ResponseStatusException::class.java).isThrownBy { + runTest { + cut.updateOrder(nop, tcn) + } + }.withMessageContaining("does not exist") + } + + @Test + fun `update order which is being processed is conflict`() { + every { db.findByHostNameAndHostOrderId(top.hostName, top.hostOrderId) } returns + Mono.just( + top.toOrder().copy(status = OrderStatus.IN_PROGRESS) + ) + coEvery { synq.updateOrder(any()) } returns ResponseEntity.notFound().build() + + assertThatExceptionOfType(ResponseStatusException::class.java).isThrownBy { + runTest { + cut.updateOrder(nop, tcn) + } + }.withMessageContaining("409 CONFLICT") + } + + @Test + fun `update order which you don't own throws`() { + assertThatExceptionOfType(ResponseStatusException::class.java).isThrownBy { + runBlocking { + cut.updateOrder(nop, "Alma") + } + }.withMessageContaining("403 FORBIDDEN") + } + + @Test + fun `update order which doesn't exist in synq throws`() { + every { db.findByHostNameAndHostOrderId(top.hostName, top.hostOrderId) } returns Mono.just(top.toOrder()) + coEvery { synq.updateOrder(any()) } throws ServerErrorException("Not found", null) + + assertThatExceptionOfType(ServerErrorException::class.java).isThrownBy { + runTest { + cut.updateOrder(nop, tcn) + } } } @@ -141,13 +200,38 @@ class OrderServiceTest { callbackUrl = "callbackUrl" ) - private val testClientName = HostName.AXIELL.name + // Will be used in most tests (nop = new order payload) + private val nop = + ApiOrderPayload( + orderId = "axiell-order-69", + hostName = HostName.AXIELL, + hostOrderId = "axiell-order-69", + status = OrderStatus.NOT_STARTED, + productLine = listOf(ProductLine("mlt-420", OrderLineStatus.NOT_STARTED)), + orderType = OrderType.LOAN, + owner = Owner.NB, + receiver = + OrderReceiver( + name = "name", + address = "address", + postalCode = "postalCode", + city = "city", + phoneNumber = "phoneNumber", + location = "location" + ), + callbackUrl = "callbackUrl" + ) + + /** + * tcn = test client name + */ + private val tcn = HostName.AXIELL.name private fun assertExceptionThrownWithMessage( payload: ApiOrderPayload, message: String, exception: Class ) = assertThatExceptionOfType(exception).isThrownBy { - runBlocking { cut.createOrder(testClientName, payload) } + runBlocking { cut.createOrder(tcn, payload) } }.withMessageContaining(message) } From aac92b35f996925e22801f3bf47eb763cbeb9ebc Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Thu, 29 Aug 2024 11:27:05 +0200 Subject: [PATCH 12/14] Use custom payload for updating orders --- .../wls/order/controller/OrderController.kt | 3 +- .../mlt/wls/order/payloads/ApiOrderPayload.kt | 13 +++ .../order/payloads/ApiUpdateOrderPayload.kt | 110 ++++++++++++++++++ .../nb/mlt/wls/order/service/OrderService.kt | 18 +-- .../mlt/wls/order/service/SynqOrderService.kt | 4 +- .../mlt/wls/order/service/OrderServiceTest.kt | 10 +- 6 files changed, 134 insertions(+), 24 deletions(-) create mode 100644 src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiUpdateOrderPayload.kt diff --git a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt index 669f9c50..8a396fa6 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/controller/OrderController.kt @@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag import no.nb.mlt.wls.core.data.HostName import no.nb.mlt.wls.order.model.Order import no.nb.mlt.wls.order.payloads.ApiOrderPayload +import no.nb.mlt.wls.order.payloads.ApiUpdateOrderPayload import no.nb.mlt.wls.order.service.OrderService import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal @@ -161,6 +162,6 @@ class OrderController(val orderService: OrderService) { @PutMapping("/order") suspend fun updateOrder( @AuthenticationPrincipal jwt: JwtAuthenticationToken, - @RequestBody payload: ApiOrderPayload + @RequestBody payload: ApiUpdateOrderPayload ): ResponseEntity = orderService.updateOrder(payload, jwt.name) } diff --git a/src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiOrderPayload.kt b/src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiOrderPayload.kt index f268ff8b..04f86e2e 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiOrderPayload.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiOrderPayload.kt @@ -9,6 +9,7 @@ import no.nb.mlt.wls.order.model.OrderReceiver import no.nb.mlt.wls.order.model.OrderStatus import no.nb.mlt.wls.order.model.OrderType import no.nb.mlt.wls.order.model.ProductLine +import org.springframework.web.server.ServerWebInputException @Schema( description = "Payload for creating and editing an order in Hermes WLS, and appropriate storage system(s).", @@ -112,3 +113,15 @@ fun Order.toApiOrderPayload() = receiver = receiver, callbackUrl = callbackUrl ) + +fun throwIfInvalidPayload(payload: ApiOrderPayload) { + if (payload.orderId.isBlank()) { + throw ServerWebInputException("The order's orderId is required, and can not be blank") + } + if (payload.hostOrderId.isBlank()) { + throw ServerWebInputException("The order's hostOrderId is required, and can not be blank") + } + if (payload.productLine.isEmpty()) { + throw ServerWebInputException("The order must contain product lines") + } +} diff --git a/src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiUpdateOrderPayload.kt b/src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiUpdateOrderPayload.kt new file mode 100644 index 00000000..9a4fe0a8 --- /dev/null +++ b/src/main/kotlin/no/nb/mlt/wls/order/payloads/ApiUpdateOrderPayload.kt @@ -0,0 +1,110 @@ +package no.nb.mlt.wls.order.payloads + +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY +import no.nb.mlt.wls.core.data.HostName +import no.nb.mlt.wls.order.model.Order +import no.nb.mlt.wls.order.model.OrderReceiver +import no.nb.mlt.wls.order.model.OrderStatus +import no.nb.mlt.wls.order.model.OrderType +import no.nb.mlt.wls.order.model.ProductLine +import org.springframework.web.server.ServerWebInputException + +@Schema( + description = "Payload for creating and editing an order in Hermes WLS, and appropriate storage system(s).", + example = """ + { + "hostName": "AXIELL", + "hostOrderId": "mlt-12345-order", + "productLine": [ + { + "hostId": "mlt-12345", + "status": "NOT_STARTED" + } + ], + "orderType": "LOAN", + "receiver": { + "name": "Doug Dimmadome", + "location": "Doug Dimmadome's office in the Dimmsdale Dimmadome", + "address": "Dimmsdale Dimmadome", + "city": "Dimmsdale", + "postalCode": "69-420", + "phoneNum": "+47 666 69 420" + }, + "callbackUrl": "https://example.com/send/callback/here" + } + """ +) +data class ApiUpdateOrderPayload( + @Schema( + description = "Name of the host system which made the order.", + examples = [ "AXIELL", "ALMA", "ASTA", "BIBLIOFIL" ] + ) + val hostName: HostName, + @Schema( + description = "Order ID from the host system which made the order.", + example = "mlt-12345-order" + ) + val hostOrderId: String, + @Schema( + description = "List of products in the order, also called order lines, or product lines.", + accessMode = READ_ONLY + ) + val productLine: List, + @Schema( + description = "Describes what type of order this is", + examples = [ "LOAN", "DIGITIZATION" ] + ) + val orderType: OrderType, + @Schema( + description = "Who's the receiver of the material in the order." + ) + val receiver: OrderReceiver, + @Schema( + description = "URL to send a callback to when the order is completed.", + example = "https://example.com/send/callback/here" + ) + val callbackUrl: String +) + +fun ApiOrderPayload.toUpdateOrderPayload() = + ApiUpdateOrderPayload( + hostName = hostName, + hostOrderId = hostOrderId, + productLine = productLine, + orderType = orderType, + receiver = receiver, + callbackUrl = callbackUrl + ) + +fun ApiUpdateOrderPayload.toOrder() = + Order( + hostOrderId = hostOrderId, + hostName = hostName, + status = OrderStatus.NOT_STARTED, + productLine = productLine, + orderType = orderType, + // TODO - validate if this is ok to do + owner = null, + receiver = receiver, + callbackUrl = callbackUrl + ) + +fun Order.toUpdateOrderPayload() = + ApiUpdateOrderPayload( + hostName = hostName, + hostOrderId = hostOrderId, + productLine = productLine, + orderType = orderType, + receiver = receiver, + callbackUrl = callbackUrl + ) + +fun throwIfInvalidPayload(payload: ApiUpdateOrderPayload) { + if (payload.hostOrderId.isBlank()) { + throw ServerWebInputException("The order's hostOrderId is required, and can not be blank") + } + if (payload.productLine.isEmpty()) { + throw ServerWebInputException("The order must contain product lines") + } +} diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index e452964d..1086eca8 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -8,6 +8,8 @@ import no.nb.mlt.wls.core.data.throwIfInvalidClientName import no.nb.mlt.wls.order.model.Order import no.nb.mlt.wls.order.model.OrderStatus import no.nb.mlt.wls.order.payloads.ApiOrderPayload +import no.nb.mlt.wls.order.payloads.ApiUpdateOrderPayload +import no.nb.mlt.wls.order.payloads.throwIfInvalidPayload import no.nb.mlt.wls.order.payloads.toApiOrderPayload import no.nb.mlt.wls.order.payloads.toOrder import no.nb.mlt.wls.order.payloads.toSynqPayload @@ -17,7 +19,6 @@ import org.springframework.http.ResponseEntity import org.springframework.stereotype.Service import org.springframework.web.server.ResponseStatusException import org.springframework.web.server.ServerErrorException -import org.springframework.web.server.ServerWebInputException import java.time.Duration import java.util.concurrent.TimeoutException @@ -64,7 +65,7 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { } suspend fun updateOrder( - payload: ApiOrderPayload, + payload: ApiUpdateOrderPayload, clientName: String ): ResponseEntity { throwIfInvalidClientName(clientName, payload.hostName) @@ -90,7 +91,6 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { hostName = payload.hostName, productLine = payload.productLine, orderType = payload.orderType, - owner = payload.owner, receiver = payload.receiver, callbackUrl = payload.callbackUrl ) @@ -137,16 +137,4 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { } .awaitSingleOrNull() } - - private fun throwIfInvalidPayload(payload: ApiOrderPayload) { - if (payload.orderId.isBlank()) { - throw ServerWebInputException("The order's orderId is required, and can not be blank") - } - if (payload.hostOrderId.isBlank()) { - throw ServerWebInputException("The order's hostOrderId is required, and can not be blank") - } - if (payload.productLine.isEmpty()) { - throw ServerWebInputException("The order must contain product lines") - } - } } diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt index 455e0001..e70aa50a 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/SynqOrderService.kt @@ -3,7 +3,7 @@ package no.nb.mlt.wls.order.service import kotlinx.coroutines.reactor.awaitSingle import no.nb.mlt.wls.core.data.synq.SynqError import no.nb.mlt.wls.core.data.synq.SynqError.Companion.createServerError -import no.nb.mlt.wls.order.payloads.ApiOrderPayload +import no.nb.mlt.wls.order.payloads.ApiUpdateOrderPayload import no.nb.mlt.wls.order.payloads.SynqOrder import no.nb.mlt.wls.order.payloads.SynqOrderPayload import no.nb.mlt.wls.order.payloads.toOrder @@ -56,7 +56,7 @@ class SynqOrderService( .awaitSingle() } - suspend fun updateOrder(payload: ApiOrderPayload): ResponseEntity { + suspend fun updateOrder(payload: ApiUpdateOrderPayload): ResponseEntity { val uri = URI.create("$baseUrl/orders/batch") val orders = SynqOrder(listOf(payload.toOrder().toSynqPayload())) diff --git a/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt b/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt index 1a86e91a..fba4033d 100644 --- a/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt +++ b/src/test/kotlin/no/nb/mlt/wls/order/service/OrderServiceTest.kt @@ -15,6 +15,7 @@ import no.nb.mlt.wls.order.model.OrderStatus import no.nb.mlt.wls.order.model.OrderType import no.nb.mlt.wls.order.model.ProductLine import no.nb.mlt.wls.order.payloads.ApiOrderPayload +import no.nb.mlt.wls.order.payloads.ApiUpdateOrderPayload import no.nb.mlt.wls.order.payloads.toOrder import no.nb.mlt.wls.order.repository.OrderRepository import org.assertj.core.api.Assertions.assertThat @@ -119,9 +120,9 @@ class OrderServiceTest { @Test fun `update existing order with no errors returns ok`() { runTest { - every { db.findByHostNameAndHostOrderId(top.hostName, top.hostOrderId) } returns Mono.just(top.toOrder()) + every { db.findByHostNameAndHostOrderId(nop.hostName, nop.hostOrderId) } returns Mono.just(top.toOrder()) coEvery { synq.updateOrder(any()) } returns ResponseEntity.ok().build() - every { db.save(any()) } returns Mono.just(nop.toOrder()) + every { db.save(any()) } returns Mono.just(top.toOrder()) assertThat(cut.updateOrder(nop, tcn).statusCode.is2xxSuccessful) } @@ -202,14 +203,11 @@ class OrderServiceTest { // Will be used in most tests (nop = new order payload) private val nop = - ApiOrderPayload( - orderId = "axiell-order-69", + ApiUpdateOrderPayload( hostName = HostName.AXIELL, hostOrderId = "axiell-order-69", - status = OrderStatus.NOT_STARTED, productLine = listOf(ProductLine("mlt-420", OrderLineStatus.NOT_STARTED)), orderType = OrderType.LOAN, - owner = Owner.NB, receiver = OrderReceiver( name = "name", From 890745932b5f08023001a7162b35c9f45d9f97eb Mon Sep 17 00:00:00 2001 From: Noah Bjerkli Aanonli Date: Thu, 29 Aug 2024 11:27:37 +0200 Subject: [PATCH 13/14] Revert SynqOrderType changes Fixes an issue with case-sensitivity and SynQ --- .../no/nb/mlt/wls/order/payloads/SynqOrderPayload.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/payloads/SynqOrderPayload.kt b/src/main/kotlin/no/nb/mlt/wls/order/payloads/SynqOrderPayload.kt index 75062c4c..a9cd39d2 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/payloads/SynqOrderPayload.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/payloads/SynqOrderPayload.kt @@ -1,6 +1,7 @@ package no.nb.mlt.wls.order.payloads import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.annotation.JsonValue import jakarta.validation.constraints.Min import no.nb.mlt.wls.core.data.HostName import no.nb.mlt.wls.core.data.synq.SynqOwner @@ -31,8 +32,13 @@ data class SynqOrderPayload( val quantityOrdered: Double ) - enum class SynqOrderType { - STANDARD + enum class SynqOrderType(private val type: String) { + STANDARD("Standard"); + + @JsonValue + override fun toString(): String { + return type + } } } From 511879791bc7b4a78c95c77f0c8fbf66ac213604 Mon Sep 17 00:00:00 2001 From: Daniel Aaron Salwerowicz Date: Thu, 29 Aug 2024 15:12:06 +0200 Subject: [PATCH 14/14] Update src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt --- src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt index 1086eca8..e83bccdd 100644 --- a/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt +++ b/src/main/kotlin/no/nb/mlt/wls/order/service/OrderService.kt @@ -87,8 +87,6 @@ class OrderService(val db: OrderRepository, val synqService: SynqOrderService) { val updatedOrder = db.save( existingOrder.copy( - hostOrderId = payload.hostOrderId, - hostName = payload.hostName, productLine = payload.productLine, orderType = payload.orderType, receiver = payload.receiver,