diff --git a/infrastructure/condition/parsing/calico_parser.py b/infrastructure/condition/parsing/calico_parser.py index 30b5887a1..bc41a8c42 100644 --- a/infrastructure/condition/parsing/calico_parser.py +++ b/infrastructure/condition/parsing/calico_parser.py @@ -16,6 +16,18 @@ logger = setup_logger() class CalicoParser(Parser): def __init__(self, uprn_lookup: UprnLookup) -> None: self._uprn_lookup = uprn_lookup + self._blank_placeholder_count = 0 + self._unmatched_reference_count = 0 + + @property + def blank_placeholder_count(self) -> int: + """Rows dropped on parse for a blank / N/A covering type.""" + return self._blank_placeholder_count + + @property + def unmatched_reference_count(self) -> int: + """Distinct asset references dropped for not resolving to a portfolio UPRN.""" + return self._unmatched_reference_count def parse(self, file_stream: BinaryIO) -> List[CalicoProperty]: workbook = load_workbook(file_stream, data_only=True) diff --git a/tests/condition/parsing/test_calico_parser.py b/tests/condition/parsing/test_calico_parser.py index f8ca9e557..fed9812e0 100644 --- a/tests/condition/parsing/test_calico_parser.py +++ b/tests/condition/parsing/test_calico_parser.py @@ -40,6 +40,28 @@ def _workbook(rows: List[List[object]]) -> BytesIO: return buffer +def test_calico_parser_counts_blank_and_unmatched_drops(): + # Arrange -- one loaded, one blank placeholder, one unmatched (not in lookup) + workbook = _workbook( + [ + [443, "HOUSE", "31 Venice Avenue", "Roof Covering", "Concrete Tiles", + date(1998, 4, 1), 55, 36], + [438, "FLAT", "137 Brownhill Avenue", "Roof Covering", "N/A", + date(2000, 4, 1), 0, 973], + [777, "HOUSE", "8 Marine Avenue", "Roof Covering", "Natural Slate", + date(2010, 4, 1), 60, 50], + ] + ) + parser = CalicoParser(FakeUprnLookup({"443": 100093305101})) + + # Act + parser.parse(workbook) + + # Assert + assert parser.blank_placeholder_count == 1 + assert parser.unmatched_reference_count == 1 + + def test_calico_parser_drops_na_sentinel_covering_rows(): # Arrange -- Calico writes the literal string "N/A" for a placeholder row # (no roof-covering record captured), not an empty cell.