Skip to content

Commit f02fb28

Browse files
ELI-615 | campaign having recent - active start_date supersedes the others sharing same best-status
1 parent 4ff5a3e commit f02fb28

2 files changed

Lines changed: 142 additions & 3 deletions

File tree

src/eligibility_signposting_api/services/calculators/eligibility_calculator.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ def get_eligibility_status(self, include_actions: str, conditions: list[str], ca
124124
return eligibility_status.EligibilityStatus(conditions=final_result)
125125

126126
def get_best_iteration_result(self, campaign_group: list[CampaignConfig]) -> BestIterationResult | None:
127-
iteration_results = self.get_iteration_results(campaign_group)
127+
sorted_campaigns = sorted(campaign_group, key=lambda c: c.start_date, reverse=True)
128+
129+
iteration_results = self.get_iteration_results(sorted_campaigns)
128130

129131
if not iteration_results:
130132
return None

tests/integration/in_process/test_eligibility_endpoint.py

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
from datetime import date, timedelta, datetime, timezone
23
from http import HTTPStatus
34

45
import pytest
@@ -25,6 +26,7 @@
2526
from tests.fixtures.builders.model import rule
2627
from tests.integration.conftest import UNIQUE_CONSUMER_HEADER
2728

29+
today = lambda: datetime.now(timezone.utc).date()
2830

2931
class TestBaseLine:
3032
def test_nhs_number_given(
@@ -1192,10 +1194,11 @@ def test_valid_response_when_consumer_has_a_valid_campaign_config_mapping( # no
11921194
(
11931195
[
11941196
# Campaign configs in S3
1197+
# Note: Configs are uploaded in order so the start date would be newer down the order.
11951198
("RSV", "RSV_campaign_id_1"),
11961199
("RSV", "RSV_campaign_id_2"),
1197-
("RSV", "RSV_campaign_id_3"),
11981200
("RSV", "RSV_campaign_id_4"),
1201+
("RSV", "RSV_campaign_id_3"),
11991202
("RSV", "inactive_RSV_campaign_id_5", "inactive"), # inactive iteration
12001203
("RSV", "RSV_campaign_id_6"),
12011204
],
@@ -1223,7 +1226,7 @@ def test_valid_response_when_consumer_has_a_valid_campaign_config_mapping( # no
12231226
],
12241227
indirect=["campaign_configs", "consumer_mappings"],
12251228
)
1226-
def test_if_correct_campaign_is_chosen_for_the_consumer_when_multiple_campaign_exists_per_target_giving_same_status( # noqa : PLR0913
1229+
def test_if_correct_campaign_is_chosen_for_the_consumer_when_multiple_campaign_exists_per_target_giving_same_status(
12271230
self,
12281231
client: FlaskClient,
12291232
persisted_person: NHSNumber,
@@ -1379,3 +1382,137 @@ def test_if_campaign_having_best_status_is_chosen_if_there_exists_multiple_campa
13791382
)
13801383
),
13811384
)
1385+
1386+
@pytest.mark.parametrize(
1387+
("campaign_1_start_date", "campaign_2_start_date", "postcode_for_comparator", "expected_campaign_id"),
1388+
[
1389+
(
1390+
("RSV_campaign_id_1", today()),
1391+
("RSV_campaign_id_2", today() - timedelta(days=1)),
1392+
"SW19", # postcode for resulting in not-actionable
1393+
"RSV_campaign_id_1",
1394+
),
1395+
(
1396+
("RSV_campaign_id_1", today() - timedelta(days=1)),
1397+
("RSV_campaign_id_2", today()),
1398+
"SW19", # postcode for resulting in not-actionable
1399+
"RSV_campaign_id_2",
1400+
),
1401+
(
1402+
("RSV_campaign_id_1", today()),
1403+
("RSV_campaign_id_2", today() - timedelta(days=1)),
1404+
"M4", # postcode for resulting in actionable
1405+
"RSV_campaign_id_1",
1406+
),
1407+
(
1408+
("RSV_campaign_id_1", today() - timedelta(days=1)),
1409+
("RSV_campaign_id_2", today()),
1410+
"M4", # postcode for resulting in actionable
1411+
"RSV_campaign_id_2",
1412+
),
1413+
],
1414+
)
1415+
def test_if_campaign_having_best_status_is_chosen_if_there_exists_multiple_campaign_per_target_diff_start_date(
1416+
self,
1417+
client: FlaskClient,
1418+
persisted_person_pc_sw19: NHSNumber,
1419+
s3_client: BaseClient,
1420+
consumer_mapping_bucket: BucketName,
1421+
rules_bucket: BucketName,
1422+
audit_bucket: BucketName,
1423+
secretsmanager_client: BaseClient, # noqa: ARG002
1424+
campaign_1_start_date: tuple[str, date],
1425+
campaign_2_start_date: tuple[str, date],
1426+
postcode_for_comparator: str,
1427+
expected_campaign_id: NHSNumber,
1428+
):
1429+
# Given
1430+
consumer_id = "consumer-n3bs-jo4hn-ce4na"
1431+
headers = {"nhs-login-nhs-number": str(persisted_person_pc_sw19), UNIQUE_CONSUMER_HEADER: consumer_id}
1432+
1433+
# Consumer Mapping Data
1434+
s3_client.put_object(
1435+
Bucket=consumer_mapping_bucket,
1436+
Key="consumer_mapping_config.json",
1437+
Body=json.dumps(
1438+
{
1439+
consumer_id: [
1440+
{"CampaignConfigID": "RSV_campaign_id_1"},
1441+
{"CampaignConfigID": "RSV_campaign_id_2"},
1442+
],
1443+
}
1444+
),
1445+
ContentType="application/json",
1446+
)
1447+
1448+
# Campaign configs
1449+
campaign_1 = rule.CampaignConfigFactory.build(
1450+
id=campaign_1_start_date[0],
1451+
target="RSV",
1452+
start_date=campaign_1_start_date[1],
1453+
type="V",
1454+
iterations=[
1455+
rule.IterationFactory.build(
1456+
iteration_rules=[
1457+
rule.PostcodeSuppressionRuleFactory.build(
1458+
name="Exclude M4", comparator=RuleComparator(postcode_for_comparator)
1459+
),
1460+
],
1461+
iteration_cohorts=[
1462+
rule.IterationCohortFactory.build(
1463+
cohort_label="cohort1",
1464+
cohort_group="cohort_group1",
1465+
positive_description="positive_description",
1466+
)
1467+
],
1468+
status_text=None,
1469+
)
1470+
],
1471+
)
1472+
1473+
campaign_2 = rule.CampaignConfigFactory.build(
1474+
id=campaign_2_start_date[0],
1475+
target="RSV",
1476+
type="V",
1477+
start_date=campaign_2_start_date[1],
1478+
iterations=[
1479+
rule.IterationFactory.build(
1480+
iteration_rules=[
1481+
rule.PostcodeSuppressionRuleFactory.build(
1482+
name="Exclude M4", comparator=RuleComparator(postcode_for_comparator)
1483+
),
1484+
],
1485+
iteration_cohorts=[
1486+
rule.IterationCohortFactory.build(
1487+
cohort_label="cohort1",
1488+
cohort_group="cohort_group1",
1489+
positive_description="positive_description",
1490+
)
1491+
],
1492+
status_text=None,
1493+
)
1494+
],
1495+
)
1496+
1497+
for campaign in [campaign_1, campaign_2]:
1498+
s3_client.put_object(
1499+
Bucket=rules_bucket,
1500+
Key=f"{campaign.id}.json",
1501+
Body=json.dumps({"CampaignConfig": campaign.model_dump(by_alias=True)}),
1502+
ContentType="application/json",
1503+
)
1504+
1505+
# When
1506+
client.get(f"/patient-check/{persisted_person_pc_sw19}", headers=headers)
1507+
1508+
objects = s3_client.list_objects_v2(Bucket=audit_bucket).get("Contents", [])
1509+
object_keys = [obj["Key"] for obj in objects]
1510+
latest_key = sorted(object_keys)[-1]
1511+
audit_data = json.loads(s3_client.get_object(Bucket=audit_bucket, Key=latest_key)["Body"].read())
1512+
1513+
# Then
1514+
if expected_campaign_id is not None:
1515+
assert_that(len(audit_data["response"]["condition"]), equal_to(1))
1516+
assert_that(audit_data["response"]["condition"][0].get("campaignId"), equal_to(expected_campaign_id))
1517+
else:
1518+
assert_that(len(audit_data["response"]["condition"]), equal_to(0))

0 commit comments

Comments
 (0)