diff --git a/src/eligibility_signposting_api/services/eligibility_services.py b/src/eligibility_signposting_api/services/eligibility_services.py index 3494e884..f5de4a23 100644 --- a/src/eligibility_signposting_api/services/eligibility_services.py +++ b/src/eligibility_signposting_api/services/eligibility_services.py @@ -71,7 +71,7 @@ def get_attribute_value(iteration_rule: IterationRule, person_data: list[dict[st match iteration_rule.attribute_level: case RuleAttributeLevel.PERSON: person: dict[str, Any] | None = next( - (r for r in person_data if r.get("ATTRIBUTE_TYPE", "").startswith("PERSON")), None + (r for r in person_data if r.get("ATTRIBUTE_TYPE", "") == "PERSON"), None ) attribute_value = person.get(iteration_rule.attribute_name) if person else None case _: @@ -87,13 +87,13 @@ def evaluate_rule(iteration_rule: IterationRule, attribute_value: Any) -> bool: case RuleOperator.ne: return attribute_value != iteration_rule.comparator case RuleOperator.lt: - return int(attribute_value) < int(iteration_rule.comparator) + return int(attribute_value or 0) < int(iteration_rule.comparator) case RuleOperator.lte: - return int(attribute_value) <= int(iteration_rule.comparator) + return int(attribute_value or 0) <= int(iteration_rule.comparator) case RuleOperator.gt: - return int(attribute_value) > int(iteration_rule.comparator) + return int(attribute_value or 0) > int(iteration_rule.comparator) case RuleOperator.gte: - return int(attribute_value) >= int(iteration_rule.comparator) + return int(attribute_value or 0) >= int(iteration_rule.comparator) case RuleOperator.year_gt: attribute_date = datetime.strptime(str(attribute_value), "%Y%m%d") if attribute_value else None # noqa: DTZ007 today = datetime.today() # noqa: DTZ002 diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 39273398..596e6eb8 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -229,7 +229,7 @@ def persisted_person(eligibility_table: Any, faker: Faker) -> Generator[tuple[NH eligibility_table.put_item( Item={ "NHS_NUMBER": f"PERSON#{nhs_number}", - "ATTRIBUTE_TYPE": f"PERSON#{nhs_number}", + "ATTRIBUTE_TYPE": "PERSON", "DATE_OF_BIRTH": date_of_birth.strftime("%Y%m%d"), "POSTCODE": postcode, } @@ -238,7 +238,7 @@ def persisted_person(eligibility_table: Any, faker: Faker) -> Generator[tuple[NH Item={"NHS_NUMBER": f"PERSON#{nhs_number}", "ATTRIBUTE_TYPE": "COHORTS", "COHORT_MAP": {}} ) yield nhs_number, date_of_birth, postcode - eligibility_table.delete_item(Key={"NHS_NUMBER": f"PERSON#{nhs_number}", "ATTRIBUTE_TYPE": f"PERSON#{nhs_number}"}) + eligibility_table.delete_item(Key={"NHS_NUMBER": f"PERSON#{nhs_number}", "ATTRIBUTE_TYPE": "PERSON"}) eligibility_table.delete_item(Key={"NHS_NUMBER": f"PERSON#{nhs_number}", "ATTRIBUTE_TYPE": "COHORTS"}) diff --git a/tests/integration/repo/test_eligibility_repo.py b/tests/integration/repo/test_eligibility_repo.py index 6f1c9a6d..9e38a6c6 100644 --- a/tests/integration/repo/test_eligibility_repo.py +++ b/tests/integration/repo/test_eligibility_repo.py @@ -23,7 +23,7 @@ def test_person_found(eligibility_table: Any, persisted_person: tuple[NHSNumber, contains_inanyorder( { "NHS_NUMBER": f"PERSON#{nhs_number}", - "ATTRIBUTE_TYPE": f"PERSON#{nhs_number}", + "ATTRIBUTE_TYPE": "PERSON", "DATE_OF_BIRTH": date_of_birth.strftime("%Y%m%d"), "POSTCODE": postcode, }, diff --git a/tests/unit/services/test_eligibility_services.py b/tests/unit/services/test_eligibility_services.py index f8e0a5d3..749af4bc 100644 --- a/tests/unit/services/test_eligibility_services.py +++ b/tests/unit/services/test_eligibility_services.py @@ -58,10 +58,11 @@ def test_simple_rule_eligible(faker: Faker): return_value=[ { "NHS_NUMBER": f"PERSON#{nhs_number}", - "ATTRIBUTE_TYPE": f"PERSON#{nhs_number}", + "ATTRIBUTE_TYPE": "PERSON", "DATE_OF_BIRTH": date_of_birth.strftime("%Y%m%d"), "POSTCODE": postcode, - } + }, + {"NHS_NUMBER": f"PERSON#{nhs_number}", "ATTRIBUTE_TYPE": "COHORT", "COHORT_MAP": {}}, ] ) rules_repo.get_campaign_configs = MagicMock( @@ -113,10 +114,11 @@ def test_simple_rule_ineligible(faker: Faker): return_value=[ { "NHS_NUMBER": f"PERSON#{nhs_number}", - "ATTRIBUTE_TYPE": f"PERSON#{nhs_number}", + "ATTRIBUTE_TYPE": "PERSON", "DATE_OF_BIRTH": date_of_birth.strftime("%Y%m%d"), "POSTCODE": postcode, - } + }, + {"NHS_NUMBER": f"PERSON#{nhs_number}", "ATTRIBUTE_TYPE": "COHORT", "COHORT_MAP": {}}, ] ) rules_repo.get_campaign_configs = MagicMock( @@ -160,12 +162,16 @@ def test_equals_rule(): rule = IterationRuleFactory.build(operator=RuleOperator.equals, comparator="42") assert EligibilityService.evaluate_rule(rule, "42") assert not EligibilityService.evaluate_rule(rule, "99") + assert not EligibilityService.evaluate_rule(rule, "") + assert not EligibilityService.evaluate_rule(rule, None) def test_not_equals_rule(): rule = IterationRuleFactory.build(operator=RuleOperator.ne, comparator="42") assert EligibilityService.evaluate_rule(rule, "99") assert not EligibilityService.evaluate_rule(rule, "42") + assert EligibilityService.evaluate_rule(rule, "") + assert EligibilityService.evaluate_rule(rule, None) def test_less_than_rule(): @@ -174,6 +180,8 @@ def test_less_than_rule(): assert EligibilityService.evaluate_rule(rule, "99") assert not EligibilityService.evaluate_rule(rule, "100") assert not EligibilityService.evaluate_rule(rule, "101") + assert EligibilityService.evaluate_rule(rule, "") + assert EligibilityService.evaluate_rule(rule, None) def test_less_than_or_equal_rule(): @@ -181,6 +189,8 @@ def test_less_than_or_equal_rule(): assert EligibilityService.evaluate_rule(rule, "99") assert EligibilityService.evaluate_rule(rule, "100") assert not EligibilityService.evaluate_rule(rule, "101") + assert EligibilityService.evaluate_rule(rule, "") + assert EligibilityService.evaluate_rule(rule, None) def test_greater_than_rule(): @@ -188,6 +198,8 @@ def test_greater_than_rule(): assert EligibilityService.evaluate_rule(rule, "101") assert not EligibilityService.evaluate_rule(rule, "100") assert not EligibilityService.evaluate_rule(rule, "99") + assert not EligibilityService.evaluate_rule(rule, "") + assert not EligibilityService.evaluate_rule(rule, None) def test_greater_than_or_equal_rule(): @@ -195,6 +207,8 @@ def test_greater_than_or_equal_rule(): assert EligibilityService.evaluate_rule(rule, "100") assert EligibilityService.evaluate_rule(rule, "101") assert not EligibilityService.evaluate_rule(rule, "99") + assert not EligibilityService.evaluate_rule(rule, "") + assert not EligibilityService.evaluate_rule(rule, None) def test_year_gt_rule_future_date(): @@ -204,6 +218,8 @@ def test_year_gt_rule_future_date(): attribute_value = future_date.strftime("%Y%m%d") rule = IterationRuleFactory.build(operator=RuleOperator.year_gt, comparator=str(years_offset)) assert EligibilityService.evaluate_rule(rule, attribute_value) + assert not EligibilityService.evaluate_rule(rule, "") + assert not EligibilityService.evaluate_rule(rule, None) def test_year_gt_rule_past_date(): @@ -213,12 +229,8 @@ def test_year_gt_rule_past_date(): attribute_value = past_date.strftime("%Y%m%d") rule = IterationRuleFactory.build(operator=RuleOperator.year_gt, comparator=str(years_offset)) assert not EligibilityService.evaluate_rule(rule, attribute_value) - - -def test_year_gt_rule_empty_value(): - rule = IterationRuleFactory.build(operator=RuleOperator.year_gt, comparator="2") - assert not EligibilityService.evaluate_rule(rule, None) assert not EligibilityService.evaluate_rule(rule, "") + assert not EligibilityService.evaluate_rule(rule, None) def test_unimplemented_operator():