diff --git a/cg/services/__init__.py b/cg/services/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/cg/services/order_validation_service/models/errors.py b/cg/services/order_validation_service/models/errors.py index 2bbec19056..3eff92b049 100644 --- a/cg/services/order_validation_service/models/errors.py +++ b/cg/services/order_validation_service/models/errors.py @@ -53,3 +53,8 @@ class OrderNameRequiredError(OrderError): class OccupiedWellError(CaseSampleError): field: str = "well_position" message: str = "Well is already occupied" + + +class ApplicationNotValidError(SampleError): + field: str = "application" + message: str = "Application is not valid" diff --git a/cg/services/order_validation_service/utils.py b/cg/services/order_validation_service/utils.py index 5492ff57af..6c0a9cd4ba 100644 --- a/cg/services/order_validation_service/utils.py +++ b/cg/services/order_validation_service/utils.py @@ -5,6 +5,7 @@ from cg.services.order_validation_service.models.errors import ( CaseSampleError, OrderError, + SampleError, ValidationErrors, ) from cg.services.order_validation_service.models.order import Order @@ -20,11 +21,19 @@ def apply_order_validation(rules: list[Callable], order: Order, store: Store) -> def apply_case_sample_validation( - rules: list[Callable], case, store: Store + rules: list[Callable], order: Order, store: Store ) -> list[CaseSampleError]: errors: list[CaseSampleError] = [] for rule in rules: - rule_errors: list[CaseSampleError] = rule(case=case, store=store) + rule_errors: list[CaseSampleError] = rule(order=order, store=store) + errors.extend(rule_errors) + return errors + + +def apply_sample_validation(rules: list[Callable], order: Order, store: Store) -> list[SampleError]: + errors: list[SampleError] = [] + for rule in rules: + rule_errors: list[CaseSampleError] = rule(order=order, store=store) errors.extend(rule_errors) return errors diff --git a/cg/services/order_validation_service/validators/data/rules.py b/cg/services/order_validation_service/validators/data/rules.py index fee70b99db..07d1e97c1e 100644 --- a/cg/services/order_validation_service/validators/data/rules.py +++ b/cg/services/order_validation_service/validators/data/rules.py @@ -1,8 +1,10 @@ from cg.services.order_validation_service.models.errors import ( + ApplicationNotValidError, CustomerCannotSkipReceptionControlError, CustomerDoesNotExistError, - UserNotAssociatedWithCustomerError, OrderError, + SampleError, + UserNotAssociatedWithCustomerError, ) from cg.services.order_validation_service.models.order import Order from cg.store.store import Store @@ -41,3 +43,13 @@ def validate_customer_exists(order: Order, store: Store, **kwargs) -> list[Order error = CustomerDoesNotExistError() errors.append(error) return errors + + +def validate_application_exists(order: Order, store: Store, **kwargs) -> list[SampleError]: + errors: list[SampleError] = [] + for case in order.cases: + for sample in case.samples: + if not store.get_application_by_tag(sample.application): + error = ApplicationNotValidError(sample_name=sample.name) + errors.append(error) + return errors diff --git a/cg/services/order_validation_service/workflows/tomte/validation_rules.py b/cg/services/order_validation_service/workflows/tomte/validation_rules.py index 4a173c9d09..842d98f54e 100644 --- a/cg/services/order_validation_service/workflows/tomte/validation_rules.py +++ b/cg/services/order_validation_service/workflows/tomte/validation_rules.py @@ -1,4 +1,5 @@ from cg.services.order_validation_service.validators.data.rules import ( + validate_application_exists, validate_customer_can_skip_reception_control, validate_customer_exists, validate_user_belongs_to_customer, @@ -18,3 +19,5 @@ ] TOMTE_CASE_SAMPLE_RULES = [validate_wells_contain_at_most_one_sample] + +TOMTE_SAMPLE_RULES = [validate_application_exists] diff --git a/cg/services/order_validation_service/workflows/tomte/validation_service.py b/cg/services/order_validation_service/workflows/tomte/validation_service.py index fedd8a6f4c..6c9da7e099 100644 --- a/cg/services/order_validation_service/workflows/tomte/validation_service.py +++ b/cg/services/order_validation_service/workflows/tomte/validation_service.py @@ -1,6 +1,7 @@ from cg.services.order_validation_service.models.errors import ( CaseSampleError, OrderError, + SampleError, ValidationErrors, ) from cg.services.order_validation_service.order_validation_service import ( @@ -9,6 +10,7 @@ from cg.services.order_validation_service.utils import ( apply_case_sample_validation, apply_order_validation, + apply_sample_validation, ) from cg.services.order_validation_service.workflows.tomte.validation.field.model_validator import ( TomteModelValidator, @@ -16,6 +18,7 @@ from cg.services.order_validation_service.workflows.tomte.validation_rules import ( TOMTE_CASE_SAMPLE_RULES, TOMTE_ORDER_RULES, + TOMTE_SAMPLE_RULES, ) from cg.store.store import Store @@ -36,6 +39,14 @@ def validate(self, order_json: str) -> ValidationErrors: rules=TOMTE_ORDER_RULES, order=order, store=self.store ) case_sample_errors: list[CaseSampleError] = apply_case_sample_validation( - rules=TOMTE_CASE_SAMPLE_RULES, case=order.cases, store=self.store + rules=TOMTE_CASE_SAMPLE_RULES, order=order, store=self.store + ) + sample_errors: list[SampleError] = apply_sample_validation( + rules=TOMTE_SAMPLE_RULES, order=order, store=self.store + ) + + return ValidationErrors( + order_errors=order_errors, + case_sample_errors=case_sample_errors, + sample_errors=sample_errors, ) - return ValidationErrors(order_errors=order_errors, case_sample_errors=case_sample_errors) diff --git a/tests/services/order_validation_service/conftest.py b/tests/services/order_validation_service/conftest.py index 4f4101291b..5db614af52 100644 --- a/tests/services/order_validation_service/conftest.py +++ b/tests/services/order_validation_service/conftest.py @@ -15,7 +15,7 @@ def create_sample(id: int) -> TomteSample: return TomteSample( name=f"name{id}", - application="application", + application="WGSPCFC030", container=ContainerEnum.plate, require_qc_ok=True, reference_genome=GenomeVersion.hg19, diff --git a/tests/services/order_validation_service/test_data_validators.py b/tests/services/order_validation_service/test_data_validators.py index e69de29bb2..7745607f14 100644 --- a/tests/services/order_validation_service/test_data_validators.py +++ b/tests/services/order_validation_service/test_data_validators.py @@ -0,0 +1,21 @@ +from cg.services.order_validation_service.models.errors import ApplicationNotValidError +from cg.services.order_validation_service.models.order import Order +from cg.services.order_validation_service.validators.data.rules import ( + validate_application_exists, +) +from cg.store.store import Store + + +def test_applications_exist(valid_order: Order, base_store: Store): + # GIVEN an order where one of the samples has an invalid application + for case in valid_order.cases: + case.samples[0].application = "Invalid application" + + # WHEN validating the order + errors = validate_application_exists(order=valid_order, store=base_store) + + # THEN an error should be returned + assert errors + + # THEN the error should be about the ticket number + assert isinstance(errors[0], ApplicationNotValidError)