Skip to content

Commit 34a16b4

Browse files
add Extract sequential check, send warning if fails
1 parent 9655825 commit 34a16b4

File tree

2 files changed

+78
-2
lines changed

2 files changed

+78
-2
lines changed

manage_breast_screening/notifications/management/commands/create_appointments.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
logger = getLogger(__name__)
2424

2525

26+
class ExtractValidationError(Exception):
27+
pass
28+
2629
class Command(BaseCommand):
2730
"""
2831
Django Admin command which reads NBSS appointment data from Azure blob storage
@@ -56,9 +59,11 @@ def handle(self, *args, **options):
5659
).readall()
5760

5861
data_frame = self.raw_data_to_data_frame(blob_content)
62+
63+
self.validate_extract(blob.name, blob_content)
5964

6065
extract = self.create_extract(blob.name, blob_content)
61-
66+
6267
for idx, row in data_frame.iterrows():
6368
if self.is_not_holding_clinic(row):
6469
clinic, clinic_created = self.find_or_create_clinic(row)
@@ -72,13 +77,33 @@ def handle(self, *args, **options):
7277
extract.appointments.add(appt) if appt is not None else None
7378

7479
logger.info("Processed %s rows from %s", len(data_frame), blob.name)
80+
81+
def validate_extract(self, filename: str, raw_data: str) -> None:
82+
bso_code = filename.split("/")[1].split("_")[0]
83+
type_id, extract_id, start_date, start_time, record_count = raw_data.split(
84+
"\n"
85+
)[0].split("|")
86+
formatted_extract_id = int(extract_id.replace('"', "").replace("\r", ""))
87+
88+
latest_extract = Extract.objects.filter(bso_code = bso_code).order_by("sequence_number").last()
89+
90+
if latest_extract:
91+
if formatted_extract_id != (latest_extract.sequence_number + 1):
92+
93+
log_msg = "Extract ID %s is not sequential to last extract ID %s." % (
94+
formatted_extract_id,
95+
latest_extract.sequence_number,
96+
)
97+
98+
raise ExtractValidationError(log_msg)
7599

76100
def create_extract(self, filename: str, raw_data: str) -> Extract:
77101
bso_code = filename.split("/")[1].split("_")[0]
78102
type_id, extract_id, start_date, start_time, record_count = raw_data.split(
79103
"\n"
80104
)[0].split("|")
81105
formatted_extract_id = int(extract_id.replace('"', "").replace("\r", ""))
106+
82107
formatted_record_count = int(record_count.replace('"', "").replace("\r", ""))
83108

84109
return Extract.objects.create(

manage_breast_screening/notifications/tests/management/commands/test_create_appointments.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from manage_breast_screening.notifications.management.commands.create_appointments import (
1111
Command,
12+
ExtractValidationError,
1213
)
1314
from manage_breast_screening.notifications.models import (
1415
ZONE_INFO,
@@ -60,7 +61,6 @@ def stored_blob_data(prefix_dir: str, filenames: list[str]):
6061
)
6162
yield
6263

63-
6464
@pytest.mark.django_db
6565
class TestCreateAppointments:
6666
def test_handle_creates_records(self):
@@ -391,3 +391,54 @@ def test_errors_with_wrong_format_data(self):
391391
Command().handle(**{"date_str": today_dirname})
392392

393393
assert Extract.objects.count() == 0
394+
395+
def test_extract_id_not_sequential_previous(self, mock_insights_logger):
396+
""" Test when an extract is not sequential to the previous extract, a warning is logged """
397+
today_dirname = datetime.now().strftime("%Y-%m-%d")
398+
399+
filename = f"{today_dirname}/{VALID_DATA_FILE}"
400+
401+
raw_data = '"NBSSAPPT_HDR"|"00000013"|"20250128"|"170922"|"000001"'
402+
403+
previous_raw_data = '"NBSSAPPT_HDR"|"00000012"|"20250128"|"170922"|"000001"'
404+
405+
Command().create_extract(filename, raw_data)
406+
407+
with pytest.raises(ExtractValidationError) as error:
408+
Command().validate_extract(filename, previous_raw_data)
409+
assert str(error.value) == "Extract ID 12 is not sequential to last extract ID 13."
410+
411+
assert Extract.objects.count() == 1
412+
413+
414+
def test_extract_same_bso_and_extract_id(self, mock_insights_logger):
415+
""" Test when an extract has the same extract id and bso code, a warning is logged """
416+
today_dirname = datetime.now().strftime("%Y-%m-%d")
417+
418+
filename = f"{today_dirname}/{VALID_DATA_FILE}"
419+
raw_data = '"NBSSAPPT_HDR"|"00000013"|"20250128"|"170922"|"000001"'
420+
Command().create_extract(filename, raw_data)
421+
422+
same_bso_and_extract_id_raw_data = '"NBSSAPPT_HDR"|"00000013"|"20250128"|"170922"|"000001"'
423+
424+
with pytest.raises(ExtractValidationError) as error:
425+
Command().validate_extract(filename, same_bso_and_extract_id_raw_data)
426+
assert str(error.value) == "Extract ID 13 is not sequential to last extract ID 13."
427+
428+
def test_extract_not_sequential_skipped_extract(self, mock_insights_logger):
429+
""" Test when an extract is not the next extract in order (i.e. skipped an extract), a warning is logged """
430+
today_dirname = datetime.now().strftime("%Y-%m-%d")
431+
filename = f"{today_dirname}/{VALID_DATA_FILE}"
432+
433+
raw_data = '"NBSSAPPT_HDR"|"00000013"|"20250128"|"170922"|"000001"'
434+
435+
Command().create_extract(filename, raw_data)
436+
437+
skip_extract_raw_data = '"NBSSAPPT_HDR"|"00000025"|"20250128"|"170922"|"000001"'
438+
439+
with pytest.raises(ExtractValidationError) as error:
440+
Command().validate_extract(filename, skip_extract_raw_data)
441+
assert str(error.value) == "Extract ID 25 is not sequential to last extract ID 13."
442+
443+
assert Extract.objects.count() == 1
444+

0 commit comments

Comments
 (0)