Skip to content

Commit b9ef56f

Browse files
adrianoaru-nhsAndyg79vidhya-chandra1
committed
Feature/bcss 20679 selenium to playwright subject selection query builder (#97)
<!-- markdownlint-disable-next-line first-line-heading --> ## Description <!-- Describe your changes in detail. --> Adding a new util to be able to generate SQL queries to be used as part of the selenium to playwright migration. ## Context <!-- Why is this change required? What problem does it solve? --> Instead of writing out a new SQL query for each bit of test data needed a generic utility can be used at achieve the same effect. ## Type of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply. --> - [ ] Refactoring (non-breaking change) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would change existing functionality) - [ ] Bug fix (non-breaking change which fixes an issue) ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [x] I am familiar with the [contributing guidelines](https://github.com/nhs-england-tools/playwright-python-blueprint/blob/main/CONTRIBUTING.md) - [x] I have followed the code style of the project - [x] I have added tests to cover my changes (where appropriate) - [x] I have updated the documentation accordingly - [x] This PR is a result of pair or mob programming --- ## Sensitive Information Declaration To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including [PII (Personal Identifiable Information) / PID (Personal Identifiable Data)](https://digital.nhs.uk/data-and-information/keeping-data-safe-and-benefitting-the-public) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter. - [x] I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes. --------- Co-authored-by: AndyG <[email protected]> Co-authored-by: vidhya-chandra1 <[email protected]>
1 parent 95793af commit b9ef56f

File tree

62 files changed

+10375
-28
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+10375
-28
lines changed

classes/address_contact_type.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from enum import Enum
2+
from typing import Optional
3+
4+
5+
class AddressContactType(Enum):
6+
"""
7+
Enum representing the type of address contact for a subject.
8+
9+
Attributes:
10+
WORK: Represents a work address contact type.
11+
HOME: Represents a home address contact type.
12+
"""
13+
14+
WORK = (13056, "WORK")
15+
HOME = (13057, "HOME")
16+
17+
def __init__(self, valid_value_id: int, allowed_value: str):
18+
"""
19+
Initialize an AddressContactType enum member.
20+
21+
Args:
22+
valid_value_id (int): The unique identifier for the address contact type.
23+
allowed_value (str): The string representation of the address contact type.
24+
"""
25+
self._valid_value_id = valid_value_id
26+
self._allowed_value = allowed_value
27+
28+
@property
29+
def valid_value_id(self) -> int:
30+
"""
31+
Returns the unique identifier for the address contact type.
32+
33+
Returns:
34+
int: The valid value ID.
35+
"""
36+
return self._valid_value_id
37+
38+
@property
39+
def allowed_value(self) -> str:
40+
"""
41+
Returns the string representation of the address contact type.
42+
43+
Returns:
44+
str: The allowed value.
45+
"""
46+
return self._allowed_value
47+
48+
@classmethod
49+
def by_valid_value_id(
50+
cls, address_contact_type_id: int
51+
) -> Optional["AddressContactType"]:
52+
"""
53+
Returns the AddressContactType enum member matching the given valid value ID.
54+
55+
Args:
56+
address_contact_type_id (int): The valid value ID to search for.
57+
58+
Returns:
59+
Optional[AddressContactType]: The matching enum member, or None if not found.
60+
"""
61+
return next(
62+
(item for item in cls if item.valid_value_id == address_contact_type_id),
63+
None,
64+
)

classes/address_type.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from enum import Enum
2+
from typing import Optional
3+
4+
5+
class AddressType(Enum):
6+
"""
7+
Enum representing the type of address for a subject.
8+
9+
Attributes:
10+
MAIN_REGISTERED_ADDRESS: Represents the main registered address (code "H").
11+
TEMPORARY_ADDRESS: Represents a temporary address (code "T").
12+
"""
13+
14+
MAIN_REGISTERED_ADDRESS = (13042, "H")
15+
TEMPORARY_ADDRESS = (13043, "T")
16+
17+
def __init__(self, valid_value_id: int, allowed_value: str):
18+
"""
19+
Initialize an AddressType enum member.
20+
21+
Args:
22+
valid_value_id (int): The unique identifier for the address type.
23+
allowed_value (str): The string representation of the address type.
24+
"""
25+
self._valid_value_id = valid_value_id
26+
self._allowed_value = allowed_value
27+
28+
@property
29+
def valid_value_id(self) -> int:
30+
"""
31+
Returns the unique identifier for the address type.
32+
33+
Returns:
34+
int: The valid value ID.
35+
"""
36+
return self._valid_value_id
37+
38+
@property
39+
def allowed_value(self) -> str:
40+
"""
41+
Returns the string representation of the address type.
42+
43+
Returns:
44+
str: The allowed value.
45+
"""
46+
return self._allowed_value
47+
48+
@classmethod
49+
def by_valid_value_id(cls, address_type_id: int) -> Optional["AddressType"]:
50+
"""
51+
Returns the AddressType enum member matching the given valid value ID.
52+
53+
Args:
54+
address_type_id (int): The valid value ID to search for.
55+
56+
Returns:
57+
Optional[AddressType]: The matching enum member, or None if not found.
58+
"""
59+
return next(
60+
(item for item in cls if item.valid_value_id == address_type_id), None
61+
)

classes/appointment_status_type.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class AppointmentStatusType:
2+
"""
3+
Utility class for mapping descriptive appointment statuses to internal IDs.
4+
5+
This class provides a mapping between human-readable appointment status descriptions
6+
(such as "booked", "attended", "cancelled", "dna") and their corresponding internal
7+
integer IDs used in the system.
8+
9+
Methods:
10+
get_id(description: str) -> int:
11+
Returns the internal ID for a given appointment status description.
12+
Raises ValueError if the description is not recognized.
13+
"""
14+
15+
_mapping = {
16+
"booked": 2001,
17+
"attended": 2002,
18+
"cancelled": 2003,
19+
"dna": 2004, # Did Not Attend
20+
}
21+
22+
@classmethod
23+
def get_id(cls, description: str) -> int:
24+
"""
25+
Returns the internal ID for a given appointment status description.
26+
27+
Args:
28+
description (str): The appointment status description (e.g., "booked").
29+
30+
Returns:
31+
int: The internal ID corresponding to the description.
32+
33+
Raises:
34+
ValueError: If the description is not recognized.
35+
"""
36+
key = description.strip().lower()
37+
if key not in cls._mapping:
38+
raise ValueError(f"Unknown appointment status: {description}")
39+
return cls._mapping[key]

classes/appointments_slot_type.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
class AppointmentSlotType:
2+
"""
3+
Utility class for mapping symbolic appointment slot types to their internal IDs.
4+
5+
This class provides a mapping between human-readable appointment slot type descriptions
6+
(such as "clinic", "phone", "video") and their corresponding internal integer IDs used in the system.
7+
8+
Methods:
9+
get_id(description: str) -> int:
10+
Returns the internal ID for a given appointment slot type description.
11+
Raises ValueError if the description is not recognized.
12+
"""
13+
14+
_mapping = {
15+
"clinic": 1001,
16+
"phone": 1002,
17+
"video": 1003,
18+
# Add more mappings here as needed
19+
}
20+
21+
@classmethod
22+
def get_id(cls, description: str) -> int:
23+
"""
24+
Returns the internal ID for a given appointment slot type description.
25+
26+
Args:
27+
description (str): The appointment slot type description (e.g., "clinic").
28+
29+
Returns:
30+
int: The internal ID corresponding to the description.
31+
32+
Raises:
33+
ValueError: If the description is not recognized.
34+
"""
35+
key = description.strip().lower()
36+
if key not in cls._mapping:
37+
raise ValueError(f"Unknown appointment slot type: {description}")
38+
return cls._mapping[key]
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
from enum import Enum
2+
from typing import Optional, Dict
3+
4+
5+
class BowelScopeDDReasonForChangeType(Enum):
6+
"""
7+
Enum representing reasons for change to Bowel Scope Due Date.
8+
9+
Attributes:
10+
Ceased: Ceased
11+
DateOfBirthAmendment: Date of birth amendment
12+
EligibleToBeInvitedForFsScreening: Eligible to be invited for FS Screening
13+
FsScreeningEpisodeOpened: FS Screening episode opened
14+
MultipleDateOfBirthChanges: Multiple Date of Birth Changes
15+
NoLongerEligibleToBeInvitedForFsScreening: No longer eligible to be invited for FS Screening
16+
ReopenedFsEpisode: Reopened FS Episode
17+
SeekingFurtherData: Seeking further data
18+
"""
19+
20+
Ceased = (200669, "Ceased")
21+
DateOfBirthAmendment = (205266, "Date of birth amendment")
22+
EligibleToBeInvitedForFsScreening = (
23+
200685,
24+
"Eligible to be invited for FS Screening",
25+
)
26+
FsScreeningEpisodeOpened = (205002, "FS Screening episode opened")
27+
MultipleDateOfBirthChanges = (202426, "Multiple Date of Birth Changes")
28+
NoLongerEligibleToBeInvitedForFsScreening = (
29+
200668,
30+
"No longer eligible to be invited for FS Screening",
31+
)
32+
ReopenedFsEpisode = (205012, "Reopened FS Episode")
33+
SeekingFurtherData = (200670, "Seeking further data")
34+
35+
def __init__(self, valid_value_id: int, description: str):
36+
"""
37+
Initialize a BowelScopeDDReasonForChangeType enum member.
38+
39+
Args:
40+
valid_value_id (int): The unique identifier for the reason.
41+
description (str): The string description of the reason.
42+
"""
43+
self._valid_value_id: int = valid_value_id
44+
self._description: str = description
45+
46+
@property
47+
def valid_value_id(self) -> int:
48+
"""
49+
Returns the unique identifier for the reason.
50+
51+
Returns:
52+
int: The valid value ID.
53+
"""
54+
return self._valid_value_id
55+
56+
@property
57+
def description(self) -> str:
58+
"""
59+
Returns the string description of the reason.
60+
61+
Returns:
62+
str: The description.
63+
"""
64+
return self._description
65+
66+
@classmethod
67+
def _descriptions(cls) -> Dict[str, "BowelScopeDDReasonForChangeType"]:
68+
"""
69+
Returns a mapping from description to enum member.
70+
71+
Returns:
72+
Dict[str, BowelScopeDDReasonForChangeType]: Mapping from description to enum member.
73+
"""
74+
return {item.description: item for item in cls}
75+
76+
@classmethod
77+
def _lowercase_descriptions(cls) -> Dict[str, "BowelScopeDDReasonForChangeType"]:
78+
"""
79+
Returns a mapping from lowercase description to enum member.
80+
81+
Returns:
82+
Dict[str, BowelScopeDDReasonForChangeType]: Mapping from lowercase description to enum member.
83+
"""
84+
return {item.description.lower(): item for item in cls}
85+
86+
@classmethod
87+
def _valid_value_ids(cls) -> Dict[int, "BowelScopeDDReasonForChangeType"]:
88+
"""
89+
Returns a mapping from valid value ID to enum member.
90+
91+
Returns:
92+
Dict[int, BowelScopeDDReasonForChangeType]: Mapping from valid value ID to enum member.
93+
"""
94+
return {item.valid_value_id: item for item in cls}
95+
96+
@classmethod
97+
def by_description(
98+
cls, description: Optional[str]
99+
) -> Optional["BowelScopeDDReasonForChangeType"]:
100+
"""
101+
Returns the enum member matching the given description (case-insensitive).
102+
103+
Args:
104+
description (Optional[str]): The description to search for.
105+
106+
Returns:
107+
Optional[BowelScopeDDReasonForChangeType]: The matching enum member, or None if not found.
108+
"""
109+
if description is None:
110+
return None
111+
return cls._lowercase_descriptions().get(description.lower())
112+
113+
@classmethod
114+
def by_valid_value_id(
115+
cls, valid_value_id: int
116+
) -> Optional["BowelScopeDDReasonForChangeType"]:
117+
"""
118+
Returns the enum member matching the given valid value ID.
119+
120+
Args:
121+
valid_value_id (int): The valid value ID to search for.
122+
123+
Returns:
124+
Optional[BowelScopeDDReasonForChangeType]: The matching enum member, or None if not found.
125+
"""
126+
return cls._valid_value_ids().get(valid_value_id)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from enum import Enum
2+
from typing import Optional
3+
4+
5+
class CeasedConfirmationDetails(Enum):
6+
"""
7+
Enum representing ceased confirmation details for a subject.
8+
9+
Members:
10+
NULL: Represents a null ceased confirmation detail.
11+
NOT_NULL: Represents a non-null ceased confirmation detail.
12+
"""
13+
14+
NULL = "null"
15+
NOT_NULL = "not null"
16+
17+
@classmethod
18+
def by_description(cls, description: str) -> Optional["CeasedConfirmationDetails"]:
19+
"""
20+
Returns the enum member matching the given description.
21+
22+
Args:
23+
description (str): The description to search for.
24+
25+
Returns:
26+
Optional[CeasedConfirmationDetails]: The matching enum member, or None if not found.
27+
"""
28+
for item in cls:
29+
if item.value == description:
30+
return item
31+
return None
32+
33+
def get_description(self) -> str:
34+
"""
35+
Returns the string description of the ceased confirmation detail.
36+
37+
Returns:
38+
str: The description value.
39+
"""
40+
return self.value

0 commit comments

Comments
 (0)