Skip to content

Commit d308c2d

Browse files
authored
ELI-405: Regardless of final status audit all types of cohort status … (#315)
* ELI-405: Regardless of final status audit all types of cohort status rules * ELI-405: Fixes Cognitive Complexity
1 parent 3fe53ad commit d308c2d

File tree

4 files changed

+123
-18
lines changed

4 files changed

+123
-18
lines changed

src/eligibility_signposting_api/audit/audit_context.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ def append_audit_condition(
6464
condition_name: ConditionName,
6565
best_iteration_result: BestIterationResult,
6666
action_detail: MatchedActionDetail,
67-
cohort_results: list[CohortGroupResult],
6867
) -> None:
6968
audit_eligibility_cohorts, audit_eligibility_cohort_groups, audit_actions = [], [], []
7069
best_active_iteration = best_iteration_result.active_iteration
7170
best_candidate = best_iteration_result.iteration_result
7271
best_cohort_results = best_iteration_result.cohort_results
72+
filter_audit_rules, suitability_audit_rules = [], []
7373

7474
if best_cohort_results:
7575
for cohort_label, result in sorted(best_cohort_results.items(), key=lambda item: item[1].cohort_code):
@@ -84,13 +84,7 @@ def append_audit_condition(
8484
)
8585
)
8686

87-
filter_audit_rules, suitability_audit_rules = [], []
88-
for result in cohort_results:
89-
for rule in result.audit_rules:
90-
if rule.rule_type == RuleType.filter:
91-
filter_audit_rules.append(rule)
92-
if rule.rule_type == RuleType.suppression:
93-
suitability_audit_rules.append(rule)
87+
AuditContext.get_audit_rules(filter_audit_rules, suitability_audit_rules, result)
9488

9589
audit_filter_rule = AuditContext.create_audit_filter_rule(filter_audit_rules)
9690
audit_suitability_rule = AuditContext.create_audit_suitability_rule(suitability_audit_rules)
@@ -116,6 +110,14 @@ def append_audit_condition(
116110

117111
g.audit_log.response.condition.append(audit_condition)
118112

113+
@staticmethod
114+
def get_audit_rules(filter_audit_rules: list, suitability_audit_rules: list, result: CohortGroupResult) -> None:
115+
for rule in result.audit_rules:
116+
if rule.rule_type == RuleType.filter:
117+
filter_audit_rules.append(rule)
118+
if rule.rule_type == RuleType.suppression:
119+
suitability_audit_rules.append(rule)
120+
119121
@staticmethod
120122
def add_rule_name_and_priority_to_audit(
121123
best_candidate: IterationResult | None,

src/eligibility_signposting_api/services/calculators/eligibility_calculator.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ def get_eligibility_status(self, include_actions: str, conditions: list[str], ca
117117
condition_name,
118118
best_iteration_result,
119119
matched_action_detail,
120-
condition_results[condition_name].cohort_results,
121120
)
122121

123122
# Consolidate all the results and return

tests/unit/audit/test_audit_context.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,7 @@ def test_append_audit_condition_adds_condition_to_audit_log_on_g_for_actionable_
150150
with app.app_context():
151151
g.audit_log = AuditEvent()
152152

153-
AuditContext.append_audit_condition(
154-
condition_name, best_iteration_results, matched_action_detail, [cohort_group_result]
155-
)
153+
AuditContext.append_audit_condition(condition_name, best_iteration_results, matched_action_detail)
156154

157155
expected_audit_action = [
158156
AuditAction(
@@ -226,9 +224,7 @@ def test_should_append_audit_suppression_rules_for_actionable_status(app):
226224
with app.app_context():
227225
g.audit_log = AuditEvent()
228226

229-
AuditContext.append_audit_condition(
230-
condition_name, best_iteration_results, MatchedActionDetail(), [cohort_group_result]
231-
)
227+
AuditContext.append_audit_condition(condition_name, best_iteration_results, MatchedActionDetail())
232228

233229
assert g.audit_log.response.condition, condition_name
234230
cond = g.audit_log.response.condition[0]
@@ -283,9 +279,7 @@ def test_should_append_audit_filter_rules_for_not_actionable_status(app):
283279
with app.app_context():
284280
g.audit_log = AuditEvent()
285281

286-
AuditContext.append_audit_condition(
287-
condition_name, best_iteration_results, MatchedActionDetail(), [cohort_group_result]
288-
)
282+
AuditContext.append_audit_condition(condition_name, best_iteration_results, MatchedActionDetail())
289283

290284
assert g.audit_log.response.condition, condition_name
291285
cond = g.audit_log.response.condition[0]

tests/unit/services/calculators/test_eligibility_calculator.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,116 @@ def test_eligibility_status_replaces_tokens_with_attribute_data(faker: Faker):
756756
assert audit_condition.actions[0].action_url_label == "Your GP practice code is ."
757757

758758

759+
def test_regardless_of_final_status_audit_all_types_of_cohort_status_rules(faker: Faker):
760+
# Given
761+
nhs_number = NHSNumber(faker.nhs_number())
762+
date_of_birth = DateOfBirth(faker.date_of_birth(minimum_age=85, maximum_age=85))
763+
764+
person_rows = person_rows_builder(
765+
nhs_number,
766+
date_of_birth=date_of_birth,
767+
cohorts=[
768+
"rsv_eli_376_cohort_1",
769+
"rsv_eli_376_cohort_2",
770+
"rsv_eli_376_cohort_3",
771+
"rsv_eli_376_cohort_4",
772+
"rsv_eli_376_cohort_5",
773+
],
774+
icb="ABC",
775+
)
776+
777+
available_action = AvailableAction(
778+
ActionType="ButtonAuthLink",
779+
ExternalRoutingCode="BookNBS",
780+
ActionDescription="## Get vaccinated at your GP surgery in [[PERSON.ICB]].",
781+
UrlLink=HttpUrl("https://www.nhs.uk/book-rsv"),
782+
UrlLabel="Your GP practice code is [[PERSON.GP_PRACTICE]].",
783+
)
784+
785+
campaign_configs = [
786+
rule_builder.CampaignConfigFactory.build(
787+
target="RSV",
788+
iterations=[
789+
rule_builder.IterationFactory.build(
790+
default_comms_routing="TOKEN_TEST",
791+
default_not_actionable_routing="TOKEN_TEST",
792+
default_not_eligible_routing="TOKEN_TEST",
793+
iteration_cohorts=[
794+
rule_builder.IterationCohortFactory.build(
795+
cohort_label="rsv_eli_376_cohort_1", cohort_group="rsv_eli_376_cohort_group", priority=0
796+
),
797+
rule_builder.IterationCohortFactory.build(
798+
cohort_label="rsv_eli_376_cohort_2", cohort_group="rsv_eli_376_cohort_group", priority=1
799+
),
800+
rule_builder.IterationCohortFactory.build(
801+
cohort_label="rsv_eli_376_cohort_3", cohort_group="rsv_eli_376_cohort_group", priority=2
802+
),
803+
rule_builder.IterationCohortFactory.build(
804+
cohort_label="rsv_eli_376_cohort_4",
805+
cohort_group="rsv_eli_376_cohort_group_other",
806+
priority=3,
807+
),
808+
rule_builder.IterationCohortFactory.build(
809+
cohort_label="rsv_eli_376_cohort_5",
810+
cohort_group="rsv_eli_376_cohort_group_another",
811+
priority=4,
812+
),
813+
],
814+
iteration_rules=[
815+
rule_builder.PersonAgeSuppressionRuleFactory.build(
816+
type=RuleType.filter,
817+
name=RuleName("NotEligible Reason 1"),
818+
description=RuleDescription("NotEligible Description 1"),
819+
priority=RulePriority("100"),
820+
operator=RuleOperator.year_lte,
821+
attribute_level=RuleAttributeLevel.PERSON,
822+
attribute_name=RuleAttributeName("DATE_OF_BIRTH"),
823+
comparator=RuleComparator("-80"),
824+
cohort_label=CohortLabel("rsv_eli_376_cohort_1"),
825+
),
826+
rule_builder.ICBRedirectRuleFactory.build(
827+
operator=RuleOperator.ne, comparator=RuleComparator("ABC")
828+
),
829+
rule_builder.PersonAgeSuppressionRuleFactory.build(
830+
type=RuleType.suppression,
831+
name=RuleName("NotActionable Reason 1"),
832+
description=RuleDescription("NotActionable Description 1"),
833+
priority=RulePriority("110"),
834+
operator=RuleOperator.year_lte,
835+
attribute_level=RuleAttributeLevel.PERSON,
836+
attribute_name=RuleAttributeName("DATE_OF_BIRTH"),
837+
comparator=RuleComparator("-80"),
838+
cohort_label=CohortLabel("rsv_eli_376_cohort_5"),
839+
),
840+
],
841+
actions_mapper=rule_builder.ActionsMapperFactory.build(root={"TOKEN_TEST": available_action}),
842+
)
843+
],
844+
)
845+
]
846+
847+
calculator = EligibilityCalculator(person_rows, campaign_configs)
848+
849+
# When
850+
actual = calculator.get_eligibility_status("Y", ["ALL"], "ALL")
851+
852+
# Then
853+
assert_that(
854+
actual,
855+
is_eligibility_status().with_conditions(
856+
has_item(is_condition().with_condition_name(ConditionName("RSV")).and_status(Status.actionable))
857+
),
858+
)
859+
860+
assert len(g.audit_log.response.condition[0].filter_rules) == 1
861+
assert g.audit_log.response.condition[0].filter_rules[0].rule_name == "NotEligible Reason 1"
862+
assert g.audit_log.response.condition[0].filter_rules[0].rule_priority == "100"
863+
assert len(g.audit_log.response.condition[0].suitability_rules) == 1
864+
assert g.audit_log.response.condition[0].suitability_rules[0].rule_name == "NotActionable Reason 1"
865+
assert g.audit_log.response.condition[0].suitability_rules[0].rule_message == "NotActionable Description 1"
866+
assert g.audit_log.response.condition[0].suitability_rules[0].rule_priority == "110"
867+
868+
759869
def test_eligibility_status_with_invalid_tokens_raises_attribute_error(faker: Faker):
760870
# Given
761871
nhs_number = NHSNumber(faker.nhs_number())

0 commit comments

Comments
 (0)