|
21 | 21 | from eligibility_signposting_api.model.campaign_config import ( |
22 | 22 | AvailableAction, |
23 | 23 | CampaignConfig, |
| 24 | + CommsRouting, |
24 | 25 | EndDate, |
| 26 | + RuleAttributeLevel, |
| 27 | + RuleAttributeName, |
25 | 28 | RuleCode, |
| 29 | + RuleDescription, |
26 | 30 | RuleEntry, |
27 | 31 | RuleName, |
| 32 | + RuleOperator, |
| 33 | + RulePriority, |
28 | 34 | RuleText, |
29 | 35 | RuleType, |
30 | 36 | StartDate, |
@@ -1119,6 +1125,160 @@ def get_secret_previous(self, secret_name: str) -> dict[str, str]: # noqa: ARG0 |
1119 | 1125 | return {} |
1120 | 1126 |
|
1121 | 1127 |
|
| 1128 | +@pytest.fixture |
| 1129 | +def person_with_covid_vaccination( |
| 1130 | + person_table: Any, faker: Faker, hashing_service: HashingService |
| 1131 | +) -> Generator[eligibility_status.NHSNumber]: |
| 1132 | + """ |
| 1133 | + Creates a person with a COVID vaccination record. |
| 1134 | + LAST_SUCCESSFUL_DATE is set to 2026-01-28 (20260128). |
| 1135 | + Used for testing derived values like NEXT_DOSE_DUE with ADD_DAYS function. |
| 1136 | + """ |
| 1137 | + nhs_num = faker.nhs_number() |
| 1138 | + nhs_number = eligibility_status.NHSNumber(nhs_num) |
| 1139 | + nhs_num_hash = hashing_service.hash_with_current_secret(nhs_num) |
| 1140 | + |
| 1141 | + date_of_birth = eligibility_status.DateOfBirth(datetime.date(1960, 5, 15)) |
| 1142 | + |
| 1143 | + for row in ( |
| 1144 | + rows := person_rows_builder( |
| 1145 | + nhs_number=nhs_num_hash, |
| 1146 | + date_of_birth=date_of_birth, |
| 1147 | + postcode="SW1A", |
| 1148 | + cohorts=["covid_eligible"], |
| 1149 | + vaccines={"COVID": {"LAST_SUCCESSFUL_DATE": "20260128", "CONDITION_NAME": "COVID"}}, |
| 1150 | + ).data |
| 1151 | + ): |
| 1152 | + person_table.put_item(Item=row) |
| 1153 | + |
| 1154 | + yield nhs_number |
| 1155 | + |
| 1156 | + for row in rows: |
| 1157 | + person_table.delete_item(Key={"NHS_NUMBER": row["NHS_NUMBER"], "ATTRIBUTE_TYPE": row["ATTRIBUTE_TYPE"]}) |
| 1158 | + |
| 1159 | + |
| 1160 | +@pytest.fixture(scope="class") |
| 1161 | +def campaign_config_with_derived_values(s3_client: BaseClient, rules_bucket: BucketName) -> Generator[CampaignConfig]: |
| 1162 | + """ |
| 1163 | + Creates a campaign config that uses the ADD_DAYS derived value function. |
| 1164 | + Contains actions for: |
| 1165 | + - DateOfLastVaccination: Shows the raw LAST_SUCCESSFUL_DATE |
| 1166 | + - DateOfNextEarliestVaccination: Shows NEXT_DOSE_DUE derived by adding 91 days |
| 1167 | + """ |
| 1168 | + campaign: CampaignConfig = rule.CampaignConfigFactory.build( |
| 1169 | + target="COVID", |
| 1170 | + iterations=[ |
| 1171 | + rule.IterationFactory.build( |
| 1172 | + actions_mapper=rule.ActionsMapperFactory.build( |
| 1173 | + root={ |
| 1174 | + "VACCINATION_DATES": AvailableAction( |
| 1175 | + ActionType="DataValue", |
| 1176 | + ExternalRoutingCode="DateOfLastVaccination", |
| 1177 | + ActionDescription="[[TARGET.COVID.LAST_SUCCESSFUL_DATE]]", |
| 1178 | + ), |
| 1179 | + "NEXT_DOSE_DATE": AvailableAction( |
| 1180 | + ActionType="DataValue", |
| 1181 | + ExternalRoutingCode="DateOfNextEarliestVaccination", |
| 1182 | + ActionDescription="[[TARGET.COVID.NEXT_DOSE_DUE:ADD_DAYS(91)]]", |
| 1183 | + ), |
| 1184 | + } |
| 1185 | + ), |
| 1186 | + iteration_cohorts=[ |
| 1187 | + rule.IterationCohortFactory.build( |
| 1188 | + cohort_label="covid_eligible", |
| 1189 | + cohort_group="covid_vaccination", |
| 1190 | + positive_description="Eligible for COVID vaccination", |
| 1191 | + negative_description="Not eligible for COVID vaccination", |
| 1192 | + ), |
| 1193 | + ], |
| 1194 | + iteration_rules=[ |
| 1195 | + rule.IterationRuleFactory.build( |
| 1196 | + type=RuleType.redirect, |
| 1197 | + name=RuleName("Provide vaccination dates"), |
| 1198 | + description=RuleDescription("Provide vaccination dates to patient"), |
| 1199 | + priority=RulePriority(10), |
| 1200 | + operator=RuleOperator.is_not_null, |
| 1201 | + attribute_level=RuleAttributeLevel.TARGET, |
| 1202 | + attribute_target="COVID", |
| 1203 | + attribute_name=RuleAttributeName("LAST_SUCCESSFUL_DATE"), |
| 1204 | + comms_routing=CommsRouting("VACCINATION_DATES|NEXT_DOSE_DATE"), |
| 1205 | + ), |
| 1206 | + ], |
| 1207 | + default_comms_routing="VACCINATION_DATES", |
| 1208 | + default_not_eligible_routing="VACCINATION_DATES", |
| 1209 | + default_not_actionable_routing="VACCINATION_DATES", |
| 1210 | + ) |
| 1211 | + ], |
| 1212 | + ) |
| 1213 | + campaign_data = {"CampaignConfig": campaign.model_dump(by_alias=True)} |
| 1214 | + s3_client.put_object( |
| 1215 | + Bucket=rules_bucket, Key=f"{campaign.name}.json", Body=json.dumps(campaign_data), ContentType="application/json" |
| 1216 | + ) |
| 1217 | + yield campaign |
| 1218 | + s3_client.delete_object(Bucket=rules_bucket, Key=f"{campaign.name}.json") |
| 1219 | + |
| 1220 | + |
| 1221 | +@pytest.fixture(scope="class") |
| 1222 | +def campaign_config_with_derived_values_formatted( |
| 1223 | + s3_client: BaseClient, rules_bucket: BucketName |
| 1224 | +) -> Generator[CampaignConfig]: |
| 1225 | + """ |
| 1226 | + Creates a campaign config that uses ADD_DAYS with DATE formatting. |
| 1227 | + The NEXT_DOSE_DUE is formatted as "29 April 2026" instead of raw "20260429". |
| 1228 | + """ |
| 1229 | + campaign: CampaignConfig = rule.CampaignConfigFactory.build( |
| 1230 | + target="COVID", |
| 1231 | + iterations=[ |
| 1232 | + rule.IterationFactory.build( |
| 1233 | + actions_mapper=rule.ActionsMapperFactory.build( |
| 1234 | + root={ |
| 1235 | + "VACCINATION_DATES": AvailableAction( |
| 1236 | + ActionType="DataValue", |
| 1237 | + ExternalRoutingCode="DateOfLastVaccination", |
| 1238 | + ActionDescription="[[TARGET.COVID.LAST_SUCCESSFUL_DATE:DATE(%d %B %Y)]]", |
| 1239 | + ), |
| 1240 | + "NEXT_DOSE_DATE": AvailableAction( |
| 1241 | + ActionType="DataValue", |
| 1242 | + ExternalRoutingCode="DateOfNextEarliestVaccination", |
| 1243 | + ActionDescription="[[TARGET.COVID.NEXT_DOSE_DUE:ADD_DAYS(91):DATE(%d %B %Y)]]", |
| 1244 | + ), |
| 1245 | + } |
| 1246 | + ), |
| 1247 | + iteration_cohorts=[ |
| 1248 | + rule.IterationCohortFactory.build( |
| 1249 | + cohort_label="covid_eligible", |
| 1250 | + cohort_group="covid_vaccination", |
| 1251 | + positive_description="Eligible for COVID vaccination", |
| 1252 | + negative_description="Not eligible for COVID vaccination", |
| 1253 | + ), |
| 1254 | + ], |
| 1255 | + iteration_rules=[ |
| 1256 | + rule.IterationRuleFactory.build( |
| 1257 | + type=RuleType.redirect, |
| 1258 | + name=RuleName("Provide vaccination dates"), |
| 1259 | + description=RuleDescription("Provide vaccination dates to patient"), |
| 1260 | + priority=RulePriority(10), |
| 1261 | + operator=RuleOperator.is_not_null, |
| 1262 | + attribute_level=RuleAttributeLevel.TARGET, |
| 1263 | + attribute_target="COVID", |
| 1264 | + attribute_name=RuleAttributeName("LAST_SUCCESSFUL_DATE"), |
| 1265 | + comms_routing=CommsRouting("VACCINATION_DATES|NEXT_DOSE_DATE"), |
| 1266 | + ), |
| 1267 | + ], |
| 1268 | + default_comms_routing="VACCINATION_DATES", |
| 1269 | + default_not_eligible_routing="VACCINATION_DATES", |
| 1270 | + default_not_actionable_routing="VACCINATION_DATES", |
| 1271 | + ) |
| 1272 | + ], |
| 1273 | + ) |
| 1274 | + campaign_data = {"CampaignConfig": campaign.model_dump(by_alias=True)} |
| 1275 | + s3_client.put_object( |
| 1276 | + Bucket=rules_bucket, Key=f"{campaign.name}.json", Body=json.dumps(campaign_data), ContentType="application/json" |
| 1277 | + ) |
| 1278 | + yield campaign |
| 1279 | + s3_client.delete_object(Bucket=rules_bucket, Key=f"{campaign.name}.json") |
| 1280 | + |
| 1281 | + |
1122 | 1282 | @pytest.fixture |
1123 | 1283 | def hashing_service() -> HashingService: |
1124 | 1284 | secret_repo = StubSecretRepo( |
|
0 commit comments