From 88d79fe02c244fa91cb6a6e818372101d72bf7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isak=20Ohlsson=20=C3=85ngnell?= <40887124+islean@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:57:37 +0100 Subject: [PATCH] Fix handle pre-existing ticket (#3006) (patch) ### Fixed - If there is an order with the given ticket_id, an error is raised upon order submission. --- cg/exc.py | 4 ++++ cg/server/api.py | 8 +++++++- cg/services/orders/order_service/order_service.py | 8 +++++--- cg/store/crud/read.py | 9 +++++++++ cg/store/filters/status_order_filters.py | 10 +++++++++- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/cg/exc.py b/cg/exc.py index 65edb63689..2077b1d115 100644 --- a/cg/exc.py +++ b/cg/exc.py @@ -262,5 +262,9 @@ class OrderNotFoundError(CgError): """Exception raised when an order is not found.""" +class OrderExistsError(CgError): + """Exception raised when cases and samples are added to a pre-existing order.""" + + class OverrideCyclesError(CgError): """Exception raised when the override cycles are not correct.""" diff --git a/cg/server/api.py b/cg/server/api.py index 49184cad72..29f66c6587 100644 --- a/cg/server/api.py +++ b/cg/server/api.py @@ -25,17 +25,19 @@ from cg.exc import ( CaseNotFoundError, OrderError, + OrderExistsError, OrderFormError, TicketCreationError, ) from cg.io.controller import WriteStream from cg.meta.orders import OrdersAPI +from cg.meta.orders.ticket_handler import TicketHandler from cg.models.orders.order import OrderIn, OrderType from cg.models.orders.orderform_schema import Orderform from cg.server.dto.delivery_message_response import DeliveryMessageResponse from cg.server.dto.orders.orders_request import OrdersRequest from cg.server.dto.orders.orders_response import Order, OrdersResponse -from cg.server.ext import db, lims, osticket, order_service +from cg.server.ext import db, lims, order_service, osticket from cg.server.utils import parse_orders_request from cg.services.delivery_message.delivery_message_service import DeliveryMessageService from cg.services.orders.order_service.exceptions import OrderNotFoundError @@ -128,6 +130,9 @@ def submit_order(order_type): ) project = OrderType(order_type) order_in = OrderIn.parse_obj(request_json, project=project) + existing_ticket: str | None = TicketHandler.parse_ticket_number(order_in.name) + if existing_ticket and order_service.store.get_order_by_ticket_id(existing_ticket): + raise OrderExistsError(f"Order with ticket id {existing_ticket} already exists.") result: dict = api.submit( project=project, @@ -139,6 +144,7 @@ def submit_order(order_type): except ( # user misbehaviour OrderError, + OrderExistsError, OrderFormError, ValidationError, ValueError, diff --git a/cg/services/orders/order_service/order_service.py b/cg/services/orders/order_service/order_service.py index c3085fe6c6..b5d4751ef1 100644 --- a/cg/services/orders/order_service/order_service.py +++ b/cg/services/orders/order_service/order_service.py @@ -8,8 +8,10 @@ create_orders_response, ) from cg.services.orders.order_status_service import OrderStatusService -from cg.services.orders.order_status_service.dto.order_status_summary import OrderSummary -from cg.store.models import Order +from cg.services.orders.order_status_service.dto.order_status_summary import ( + OrderSummary, +) +from cg.store.models import Case, Order from cg.store.store import Store @@ -37,7 +39,7 @@ def get_orders(self, orders_request: OrdersRequest) -> OrdersResponse: def create_order(self, order_data: OrderIn) -> OrderResponse: """Creates an order and links it to the given cases.""" order: Order = self.store.add_order(order_data) - cases = self.store.get_cases_by_ticket_id(order_data.ticket) + cases: list[Case] = self.store.get_cases_by_ticket_id(order_data.ticket) for case in cases: self.store.link_case_to_order(order_id=order.id, case_id=case.id) return create_order_response(order) diff --git a/cg/store/crud/read.py b/cg/store/crud/read.py index f668e5be15..c47f0b64dc 100644 --- a/cg/store/crud/read.py +++ b/cg/store/crud/read.py @@ -1757,6 +1757,15 @@ def get_order_by_id(self, order_id: int) -> Order | None: ) return orders.first() + def get_order_by_ticket_id(self, ticket_id: int) -> Order | None: + """Returns the entry in Order matching the given id.""" + orders: Query = self._get_query(table=Order) + order_filter_functions: list[Callable] = [OrderFilter.BY_TICKET_ID] + orders: Query = apply_order_filters( + orders=orders, filters=order_filter_functions, ticket_id=ticket_id + ) + return orders.first() + def _calculate_estimated_turnaround_time( self, is_rerun, diff --git a/cg/store/filters/status_order_filters.py b/cg/store/filters/status_order_filters.py index 8db060baf2..d03e099d80 100644 --- a/cg/store/filters/status_order_filters.py +++ b/cg/store/filters/status_order_filters.py @@ -18,6 +18,10 @@ def filter_orders_by_ids(orders: Query, ids: list[int] | None, **kwargs) -> Quer return orders.filter(Order.id.in_(ids)) if ids else orders +def filter_orders_by_ticket_id(orders: Query, ticket_id: int | None, **kwargs) -> Query: + return orders.filter(Order.ticket_id == ticket_id) if ticket_id else orders + + def apply_limit(orders: Query, limit: int | None, **kwargs) -> Query: return orders.limit(limit) if limit else orders @@ -25,6 +29,7 @@ def apply_limit(orders: Query, limit: int | None, **kwargs) -> Query: class OrderFilter(Enum): BY_ID: Callable = filter_orders_by_id BY_IDS: Callable = filter_orders_by_ids + BY_TICKET_ID: Callable = filter_orders_by_ticket_id BY_WORKFLOW: Callable = filter_orders_by_workflow APPLY_LIMIT: Callable = apply_limit @@ -34,9 +39,12 @@ def apply_order_filters( orders: Query, id: int = None, ids: list[int] = None, + ticket_id: int = None, workflow: str = None, limit: int = None, ) -> Query: for filter in filters: - orders: Query = filter(orders=orders, id=id, ids=ids, workflow=workflow, limit=limit) + orders: Query = filter( + orders=orders, id=id, ids=ids, ticket_id=ticket_id, workflow=workflow, limit=limit + ) return orders