Skip to content

Commit 7c791a9

Browse files
committed
added tests and refactored calculate age for vaccination from bday
1 parent b49dfe4 commit 7c791a9

2 files changed

Lines changed: 57 additions & 49 deletions

File tree

lambdas/mns_publisher/src/create_notification.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
import os
33
import uuid
4-
from datetime import datetime
4+
from datetime import date, datetime
55
from typing import Any
66

77
from aws_lambda_typing.events.sqs import SQSMessage
@@ -59,22 +59,36 @@ def create_mns_notification(sqs_event: SQSMessage) -> MnsNotificationPayload:
5959
}
6060

6161

62+
def _parse_compact_date(value: str, field_name: str) -> date:
63+
if not isinstance(value, str) or not value:
64+
raise ValueError(f"{field_name} is required")
65+
66+
date_part = value[:8]
67+
if len(date_part) != 8 or not date_part.isdigit():
68+
raise ValueError(f"{field_name} must start with YYYYMMDD")
69+
70+
try:
71+
return datetime.strptime(date_part, "%Y%m%d").date()
72+
except ValueError as e:
73+
raise ValueError(f"{field_name} must contain a valid date in YYYYMMDD format") from e
74+
75+
6276
def calculate_age_at_vaccination(birth_date: str, vaccination_date: str) -> int:
6377
"""
6478
Calculate patient age in years at time of vaccination.
6579
Expects dates in format: YYYYMMDD or YYYYMMDDThhmmsszz
6680
"""
67-
birth_date_str = birth_date[:8] if len(birth_date) >= 8 else birth_date
68-
vacc_date_str = vaccination_date[:8] if len(vaccination_date) >= 8 else vaccination_date
81+
date_of_birth = _parse_compact_date(birth_date, "PERSON_DOB")
82+
date_of_vaccination = _parse_compact_date(vaccination_date, "DATE_AND_TIME")
6983

70-
date_of_birth = datetime.strptime(birth_date_str, "%Y%m%d")
71-
date_of_vaccination = datetime.strptime(vacc_date_str, "%Y%m%d")
84+
if date_of_vaccination < date_of_birth:
85+
raise ValueError("DATE_AND_TIME cannot be before PERSON_DOB")
7286

73-
age_in_year = date_of_vaccination.year - date_of_birth.year
87+
age = date_of_vaccination.year - date_of_birth.year
7488
if (date_of_vaccination.month, date_of_vaccination.day) < (date_of_birth.month, date_of_birth.day):
75-
age_in_year -= 1
89+
age -= 1
7690

77-
return age_in_year
91+
return age
7892

7993

8094
def get_practitioner_details_from_pds(nhs_number: str) -> str | None:

lambdas/mns_publisher/tests/test_create_notification.py

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,41 @@
1616
class TestCalculateAgeAtVaccination(unittest.TestCase):
1717
"""Tests for age calculation at vaccination time."""
1818

19-
def test_age_calculation_yyyymmdd_format(self):
20-
birth_date = "20040609"
21-
vaccination_date = "20260212"
22-
age = calculate_age_at_vaccination(birth_date, vaccination_date)
23-
self.assertEqual(age, 21)
24-
25-
def test_age_calculation_with_time(self):
26-
birth_date = "20040609T120000"
27-
vaccination_date = "20260212T174437"
28-
age = calculate_age_at_vaccination(birth_date, vaccination_date)
29-
self.assertEqual(age, 21)
30-
31-
def test_age_calculation_after_birthday(self):
32-
birth_date = "20040609"
33-
vaccination_date = "20260815"
34-
age = calculate_age_at_vaccination(birth_date, vaccination_date)
35-
self.assertEqual(age, 22)
36-
37-
def test_age_calculation_on_birthday(self):
38-
birth_date = "20040609"
39-
vaccination_date = "20260609"
40-
age = calculate_age_at_vaccination(birth_date, vaccination_date)
41-
self.assertEqual(age, 22)
42-
43-
def test_age_calculation_infant(self):
44-
birth_date = "20260609"
45-
vaccination_date = "20260915"
46-
age = calculate_age_at_vaccination(birth_date, vaccination_date)
47-
self.assertEqual(age, 0)
48-
49-
def test_age_calculation_leap_year_birthday(self):
50-
birth_date = "20000229"
51-
vaccination_date = "20240228"
52-
age = calculate_age_at_vaccination(birth_date, vaccination_date)
53-
self.assertEqual(age, 23)
54-
55-
def test_age_calculation_same_day_different_year(self):
56-
birth_date = "20000101"
57-
vaccination_date = "20250101"
58-
age = calculate_age_at_vaccination(birth_date, vaccination_date)
59-
self.assertEqual(age, 25)
19+
def test_age_calculation_core_cases(self):
20+
cases = [
21+
("20040609", "20260212", 21), # YYYYMMDD format
22+
("20040609", "20260609", 22), # On birthday
23+
("20040609", "20260815", 22), # After birthday
24+
("20260609", "20260915", 0), # Infant
25+
("20040609T120000", "20260212T17443700", 21), # With time
26+
("20000101", "20250101", 25), # Same day different year
27+
("20000229", "20240228", 23), # Leap year birthday
28+
("20000229", "20240229", 24), # Leap year birthday on leap day
29+
("20000229", "20250228", 24), # day before; birthday hasn't happened yet
30+
]
31+
32+
for birth_date, vaccination_date, expected_age in cases:
33+
with self.subTest(birth_date=birth_date, vaccination_date=vaccination_date):
34+
self.assertEqual(
35+
calculate_age_at_vaccination(birth_date, vaccination_date),
36+
expected_age,
37+
)
38+
39+
def test_rejects_invalid_birth_date_format(self):
40+
with self.assertRaisesRegex(ValueError, "PERSON_DOB"):
41+
calculate_age_at_vaccination("2004-06-09", "20260212")
42+
43+
def test_rejects_invalid_vaccination_date_format(self):
44+
with self.assertRaisesRegex(ValueError, "DATE_AND_TIME"):
45+
calculate_age_at_vaccination("20040609", "2026-02-12")
46+
47+
def test_rejects_nonexistent_birth_date(self):
48+
with self.assertRaisesRegex(ValueError, "PERSON_DOB"):
49+
calculate_age_at_vaccination("20040230", "20260212")
50+
51+
def test_rejects_vaccination_before_birth(self):
52+
with self.assertRaisesRegex(ValueError, "cannot be before"):
53+
calculate_age_at_vaccination("20260212", "20250212")
6054

6155

6256
class TestCreateMnsNotification(unittest.TestCase):

0 commit comments

Comments
 (0)