Skip to content

Commit e1d20a9

Browse files
authored
Merge pull request #280 from NHSDigital/bug/te-ELI-373-cohortlabel
Bug/te eli 373 cohortlabel
2 parents 1e55114 + 6893966 commit e1d20a9

4 files changed

Lines changed: 199 additions & 35 deletions

File tree

src/eligibility_signposting_api/services/processors/rule_processor.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,13 @@ def is_eligible(
5050
) -> bool:
5151
is_eligible = True
5252
priority_getter = attrgetter("priority")
53-
sorted_rules_by_priority = sorted(self.get_exclusion_rules(cohort, filter_rules), key=priority_getter)
53+
sorted_rules_by_priority = sorted(filter_rules, key=priority_getter)
5454

5555
for _, rule_group in groupby(sorted_rules_by_priority, key=priority_getter):
56-
status, group_exclusion_reasons, _ = self.evaluate_rules_priority_group(person, rule_group)
56+
group_rules = list(rule_group)
57+
if self._should_skip_rule_group(cohort, group_rules):
58+
continue
59+
status, group_exclusion_reasons, _ = self.evaluate_rules_priority_group(person, iter(group_rules))
5760
if status.is_exclusion:
5861
if cohort.cohort_label is not None:
5962
cohort_results[cohort.cohort_label] = CohortGroupResult(
@@ -65,6 +68,7 @@ def is_eligible(
6568
)
6669
is_eligible = False
6770
break
71+
6872
return is_eligible
6973

7074
def is_actionable(
@@ -78,10 +82,14 @@ def is_actionable(
7882
priority_getter = attrgetter("priority")
7983
suppression_reasons = []
8084

81-
sorted_rules_by_priority = sorted(self.get_exclusion_rules(cohort, suppression_rules), key=priority_getter)
85+
sorted_rules_by_priority = sorted(suppression_rules, key=priority_getter)
8286

8387
for _, rule_group in groupby(sorted_rules_by_priority, key=priority_getter):
84-
status, group_exclusion_reasons, rule_stop = self.evaluate_rules_priority_group(person, rule_group)
88+
group_rules = list(rule_group)
89+
if self._should_skip_rule_group(cohort, group_rules):
90+
continue
91+
92+
status, group_exclusion_reasons, rule_stop = self.evaluate_rules_priority_group(person, iter(group_rules))
8593
if status.is_exclusion:
8694
is_actionable = False
8795
suppression_reasons.extend(group_exclusion_reasons)
@@ -103,6 +111,12 @@ def is_actionable(
103111
suppression_reasons,
104112
)
105113

114+
@staticmethod
115+
def _should_skip_rule_group(cohort: IterationCohort, group_rules: list[IterationRule]) -> bool:
116+
cohort_specific_rules = [rule for rule in group_rules if rule.cohort_label is not None]
117+
matching_specific_rules = [rule for rule in cohort_specific_rules if rule.cohort_label == cohort.cohort_label]
118+
return bool(cohort_specific_rules and not matching_specific_rules)
119+
106120
def evaluate_rules_priority_group(
107121
self, person: Person, rules_group: Iterator[IterationRule]
108122
) -> tuple[eligibility_status.Status, list[eligibility_status.Reason], bool]:

tests/integration/conftest.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,43 @@ def campaign_config(s3_client: BaseClient, rules_bucket: BucketName) -> Generato
484484
s3_client.delete_object(Bucket=rules_bucket, Key=f"{campaign.name}.json")
485485

486486

487+
@pytest.fixture(scope="class")
488+
def campaign_config_with_and_rule(s3_client: BaseClient, rules_bucket: BucketName) -> Generator[CampaignConfig]:
489+
campaign: CampaignConfig = rule.CampaignConfigFactory.build(
490+
target="RSV",
491+
iterations=[
492+
rule.IterationFactory.build(
493+
iteration_rules=[
494+
rule.PostcodeSuppressionRuleFactory.build(
495+
cohort_label="cohort2",
496+
),
497+
rule.PersonAgeSuppressionRuleFactory.build(),
498+
],
499+
iteration_cohorts=[
500+
rule.IterationCohortFactory.build(
501+
cohort_label="cohort1",
502+
cohort_group="cohort_group1",
503+
positive_description="positive_description",
504+
negative_description="negative_description",
505+
),
506+
rule.IterationCohortFactory.build(
507+
cohort_label="cohort2",
508+
cohort_group="cohort_group2",
509+
positive_description="positive_description",
510+
negative_description="negative_description",
511+
),
512+
],
513+
)
514+
],
515+
)
516+
campaign_data = {"CampaignConfig": campaign.model_dump(by_alias=True)}
517+
s3_client.put_object(
518+
Bucket=rules_bucket, Key=f"{campaign.name}.json", Body=json.dumps(campaign_data), ContentType="application/json"
519+
)
520+
yield campaign
521+
s3_client.delete_object(Bucket=rules_bucket, Key=f"{campaign.name}.json")
522+
523+
487524
@pytest.fixture(scope="class")
488525
def multiple_campaign_configs(s3_client: BaseClient, rules_bucket: BucketName) -> Generator[list[CampaignConfig]]:
489526
"""Create and upload multiple campaign configs to S3, then clean up after tests."""

tests/integration/in_process/test_eligibility_endpoint.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,57 @@ def test_actionable(
237237
),
238238
)
239239

240+
def test_actionable_with_and_rule(
241+
self,
242+
client: FlaskClient,
243+
persisted_person: NHSNumber,
244+
campaign_config_with_and_rule: CampaignConfig, # noqa: ARG002
245+
):
246+
# Given
247+
248+
# When
249+
response = client.get(f"/patient-check/{persisted_person}?includeActions=Y")
250+
251+
# Then
252+
assert_that(
253+
response,
254+
is_response()
255+
.with_status_code(HTTPStatus.OK)
256+
.and_text(
257+
is_json_that(
258+
has_entry(
259+
"processedSuggestions",
260+
equal_to(
261+
[
262+
{
263+
"condition": "RSV",
264+
"status": "Actionable",
265+
"eligibilityCohorts": [
266+
{
267+
"cohortCode": "cohort_group1",
268+
"cohortStatus": "Actionable",
269+
"cohortText": "positive_description",
270+
}
271+
],
272+
"actions": [
273+
{
274+
"actionCode": "action_code",
275+
"actionType": "defaultcomms",
276+
"description": "",
277+
"urlLabel": "",
278+
"urlLink": "",
279+
}
280+
],
281+
"suitabilityRules": [],
282+
"statusText": "You should have the RSV vaccine",
283+
}
284+
]
285+
),
286+
)
287+
)
288+
),
289+
)
290+
240291

241292
class TestMagicCohortResponse:
242293
def test_not_eligible_by_rule_when_only_magic_cohort_is_present(

0 commit comments

Comments
 (0)