Skip to content

Commit

Permalink
Validate unique sample names (#3480)
Browse files Browse the repository at this point in the history
  • Loading branch information
seallard authored Jul 29, 2024
1 parent 9a4708a commit 3391bdf
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 4 deletions.
5 changes: 5 additions & 0 deletions cg/services/order_validation_service/models/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,8 @@ class OrderNameRequiredError(OrderError):
class OccupiedWellError(CaseSampleError):
field: str = "well_position"
message: str = "Well is already occupied"


class RepeatedSampleNameError(CaseSampleError):
field: str = "name"
message: str = "Sample name already used"
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
from cg.services.order_validation_service.models.errors import OccupiedWellError
from cg.services.order_validation_service.models.errors import (
OccupiedWellError,
RepeatedSampleNameError,
)
from cg.services.order_validation_service.workflows.tomte.models.order import TomteOrder
from cg.services.order_validation_service.workflows.tomte.validation.inter_field.utils import (
_get_errors,
_get_excess_samples,
_get_plate_samples,
get_duplicate_sample_name_errors,
)


def validate_wells_contain_at_most_one_sample(order: TomteOrder) -> list[OccupiedWellError]:
samples_with_cases = _get_plate_samples(order)
samples = _get_excess_samples(samples_with_cases)
return _get_errors(samples)


def validate_unique_sample_names_in_cases(order: TomteOrder) -> list[RepeatedSampleNameError]:
errors: list[RepeatedSampleNameError] = []
for case in order.cases:
case_errors = get_duplicate_sample_name_errors(case)
errors.extend(case_errors)
return errors
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from collections import Counter
from cg.models.orders.sample_base import ContainerEnum
from cg.services.order_validation_service.models.errors import OccupiedWellError
from cg.services.order_validation_service.models.errors import (
OccupiedWellError,
RepeatedSampleNameError,
)
from cg.services.order_validation_service.workflows.tomte.models.case import TomteCase
from cg.services.order_validation_service.workflows.tomte.models.order import TomteOrder
from cg.services.order_validation_service.workflows.tomte.models.sample import (
Expand Down Expand Up @@ -47,3 +51,14 @@ def _get_sample_well_map(plate_samples_with_cases: list[tuple[TomteSample, Tomte
sample_well_map[sample.well_position] = []
sample_well_map[sample.well_position].append((sample, case))
return sample_well_map


def get_duplicate_sample_names(case: TomteCase) -> list[str]:
sample_names = [sample.name for sample in case.samples]
count = Counter(sample_names)
return [name for name, freq in count.items() if freq > 1]


def get_duplicate_sample_name_errors(case: TomteCase) -> list[RepeatedSampleNameError]:
sample_names = get_duplicate_sample_names(case)
return [RepeatedSampleNameError(sample_name=name, case_name=case.name) for name in sample_names]
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
validate_ticket_number_required_if_connected,
)
from cg.services.order_validation_service.workflows.tomte.validation.inter_field.rules import (
validate_unique_sample_names_in_cases,
validate_wells_contain_at_most_one_sample,
)

Expand All @@ -17,4 +18,7 @@
validate_customer_can_skip_reception_control,
]

TOMTE_CASE_SAMPLE_RULES = [validate_wells_contain_at_most_one_sample]
TOMTE_CASE_SAMPLE_RULES = [
validate_unique_sample_names_in_cases,
validate_wells_contain_at_most_one_sample,
]
15 changes: 15 additions & 0 deletions tests/services/order_validation_service/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,18 @@ def valid_order(valid_case: TomteCase) -> TomteOrder:
@pytest.fixture
def order_with_samples_in_same_well(case_with_samples_in_same_well: TomteCase) -> TomteOrder:
return create_order([case_with_samples_in_same_well])


@pytest.fixture
def case_with_samples_with_duplicate_names() -> TomteCase:
sample_1: TomteSample = create_sample(1)
sample_2: TomteSample = create_sample(1)
sample_1.name = sample_2.name
return create_case([sample_1, sample_2])


@pytest.fixture
def order_with_duplicate_sample_names(
case_with_samples_with_duplicate_names: TomteCase,
) -> TomteOrder:
return create_order([case_with_samples_with_duplicate_names])
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from cg.services.order_validation_service.models.errors import OccupiedWellError
from cg.services.order_validation_service.models.errors import (
OccupiedWellError,
RepeatedSampleNameError,
)
from cg.services.order_validation_service.workflows.tomte.models.order import TomteOrder
from cg.services.order_validation_service.workflows.tomte.validation.inter_field.rules import (
validate_unique_sample_names_in_cases,
validate_wells_contain_at_most_one_sample,
)

Expand Down Expand Up @@ -28,3 +32,16 @@ def test_order_without_multiple_samples_in_well(valid_order: TomteOrder):

# THEN no errors should be returned
assert not errors


def test_duplicate_sample_names_not_allowed(order_with_duplicate_sample_names: TomteOrder):
# Given an order with samples in a case with the same name

# WHEN validating the order
errors = validate_unique_sample_names_in_cases(order_with_duplicate_sample_names)

# THEN errors are returned
assert errors

# THEN the errors are about the sample names
assert isinstance(errors[0], RepeatedSampleNameError)

0 comments on commit 3391bdf

Please sign in to comment.