Skip to content

Commit 710073f

Browse files
wip
1 parent 4694022 commit 710073f

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

src/eligibility_signposting_api/services/calculators/eligibility_calculator.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from collections import defaultdict
55
from collections.abc import Collection, Iterator, Mapping
66
from dataclasses import dataclass, field
7+
from functools import cached_property
78
from itertools import groupby
89
from typing import Any
910

@@ -45,6 +46,13 @@ def campaigns_grouped_by_condition_name(
4546
):
4647
yield condition_name, list(campaign_group)
4748

49+
@cached_property
50+
def person_cohorts(self)-> set[str]:
51+
cohorts_row: Mapping[str, dict[str, dict[str, dict[str, Any]]]] = next(
52+
(row for row in self.person_data if row.get("ATTRIBUTE_TYPE") == "COHORTS"), {}
53+
)
54+
return set(cohorts_row.get("COHORT_MAP", {}).get("cohorts", {}).get("M", {}).keys())
55+
4856
def evaluate_eligibility(self) -> eligibility.EligibilityStatus:
4957
"""Iterates over campaign groups, evaluates eligibility, and returns a consolidated status."""
5058

@@ -78,12 +86,7 @@ def check_base_eligibility(self, iteration: rules.Iteration) -> bool:
7886
}
7987
if magic_cohort in iteration_cohorts:
8088
return True
81-
82-
cohorts_row: Mapping[str, dict[str, dict[str, dict[str, Any]]]] = next(
83-
(row for row in self.person_data if row.get("ATTRIBUTE_TYPE") == "COHORTS"), {}
84-
)
85-
person_cohorts: set[str] = set(cohorts_row.get("COHORT_MAP", {}).get("cohorts", {}).get("M", {}).keys())
86-
return bool(iteration_cohorts & person_cohorts)
89+
return bool(iteration_cohorts & self.person_cohorts)
8790

8891
def evaluate_eligibility_by_iteration_rules(
8992
self, campaign_group: list[rules.CampaignConfig]
@@ -123,8 +126,12 @@ def evaluate_priority_group(
123126
worst_status_so_far_for_condition: eligibility.Status,
124127
) -> tuple[eligibility.Status, list[eligibility.Reason], list[eligibility.Reason]]:
125128
exclusion_reasons, actionable_reasons = [], []
129+
130+
126131
exclude_capable_rules = [
127-
ir for ir in iteration_rule_group if ir.type in (rules.RuleType.filter, rules.RuleType.suppression)
132+
ir for ir in iteration_rule_group
133+
if ir.type in (rules.RuleType.filter, rules.RuleType.suppression)
134+
and (ir.cohort_label is None or ir.cohort_label in self.person_cohorts)
128135
]
129136

130137
best_status = eligibility.Status.not_eligible if exclude_capable_rules else eligibility.Status.actionable

tests/fixtures/builders/model/rule.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class PersonAgeSuppressionRuleFactory(IterationRuleFactory):
7575
attribute_level = rules.RuleAttributeLevel.PERSON
7676
attribute_name = rules.RuleAttributeName("DATE_OF_BIRTH")
7777
comparator = rules.RuleComparator("-75")
78+
cohort_label = None
7879

7980

8081
class PostcodeSuppressionRuleFactory(IterationRuleFactory):

tests/unit/services/calculators/test_eligibility_calculator.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,3 +718,45 @@ def test_not_actionable_status_on_target_when_last_successful_date_lte_today(
718718
),
719719
test_comment,
720720
)
721+
722+
723+
@pytest.mark.parametrize(
724+
("cohort", "expected_status", "test_comment"),
725+
[
726+
("cohort1", Status.not_actionable, "matches the cohort label"),
727+
("cohort2", Status.actionable, "matches the cohort label"),
728+
],
729+
)
730+
def test_status_if_iteration_rules_contains_cohort_label(cohort:str, expected_status: Status, test_comment: str, faker: Faker):
731+
# Given
732+
nhs_number = NHSNumber(faker.nhs_number())
733+
date_of_birth = DateOfBirth(faker.date_of_birth(minimum_age=66, maximum_age=74))
734+
735+
person_rows = person_rows_builder(nhs_number, date_of_birth=date_of_birth, cohorts=["cohort1"])
736+
campaign_configs = [
737+
rule_builder.CampaignConfigFactory.build(
738+
target="RSV",
739+
iterations=[
740+
rule_builder.IterationFactory.build(
741+
iteration_cohorts=[rule_builder.IterationCohortFactory.build(cohort_label="cohort1"),
742+
rule_builder.IterationCohortFactory.build(cohort_label="cohort2")],
743+
iteration_rules=[rule_builder.PersonAgeSuppressionRuleFactory.build(cohort_label=cohort)],
744+
)
745+
],
746+
)
747+
]
748+
749+
calculator = EligibilityCalculator(person_rows, campaign_configs)
750+
751+
# When
752+
actual = calculator.evaluate_eligibility()
753+
754+
# Then
755+
assert_that(
756+
actual,
757+
is_eligibility_status().with_conditions(
758+
has_items(
759+
is_condition().with_condition_name(ConditionName("RSV")).and_status(expected_status)
760+
)
761+
),
762+
)

0 commit comments

Comments
 (0)