Skip to content

Commit e03ce46

Browse files
committed
Merge branch 'main' into feature/BCSS-20586-selenium-to-playwright-organisation
# Conflicts: # utils/oracle/oracle_specific_functions.py
2 parents e7b5ed2 + 2884cfd commit e03ce46

File tree

82 files changed

+11001
-717
lines changed

Some content is hidden

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

82 files changed

+11001
-717
lines changed

README.md

Lines changed: 338 additions & 70 deletions
Large diffs are not rendered by default.

classes/address.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import logging
2+
3+
4+
class Address:
5+
"""
6+
Represents a postal address with up to five address lines and a postcode.
7+
Provides methods to set individual lines and to format the address as a string.
8+
"""
9+
10+
def __init__(self) -> None:
11+
self.address_line1: str = ""
12+
self.address_line2: str = ""
13+
self.address_line3: str = ""
14+
self.address_line4: str = ""
15+
self.address_line5: str = ""
16+
self.post_code: str = ""
17+
18+
def set_address_line(self, line_number: int, address_line: str) -> None:
19+
"""
20+
Sets the specified address line (1-5) to the given value.
21+
22+
Args:
23+
line_number (int): The address line number (1-5).
24+
address_line (str): The value to set for the address line.
25+
26+
Raises:
27+
ValueError: If line_number is not between 1 and 5.
28+
"""
29+
logging.debug(
30+
f"start: set_address_line(line_number={line_number}, address_line={address_line})"
31+
)
32+
if line_number == 1:
33+
self.address_line1 = address_line
34+
elif line_number == 2:
35+
self.address_line2 = address_line
36+
elif line_number == 3:
37+
self.address_line3 = address_line
38+
elif line_number == 4:
39+
self.address_line4 = address_line
40+
elif line_number == 5:
41+
self.address_line5 = address_line
42+
else:
43+
raise ValueError(
44+
f"Invalid line number {line_number}, must be between 1 and 5"
45+
)
46+
logging.debug(
47+
f"end: set_address_line(line_number={line_number}, address_line={address_line})"
48+
)
49+
50+
def __str__(self) -> str:
51+
"""
52+
Returns the formatted address as a single string.
53+
"""
54+
address_parts = [
55+
self.address_line1,
56+
self.address_line2,
57+
self.address_line3,
58+
self.address_line4,
59+
self.address_line5,
60+
self.post_code,
61+
]
62+
# Filter out empty or None values and join with ', '
63+
return ", ".join([part for part in address_parts if part])
64+
65+
def get_address_line1(self) -> str:
66+
"""
67+
Returns the first address line.
68+
"""
69+
return self.address_line1
70+
71+
def set_address_line1(self, address_line1: str) -> None:
72+
"""
73+
Sets the first address line.
74+
"""
75+
self.address_line1 = address_line1
76+
77+
def get_address_line2(self) -> str:
78+
"""
79+
Returns the second address line.
80+
"""
81+
return self.address_line2
82+
83+
def set_address_line2(self, address_line2: str) -> None:
84+
"""
85+
Sets the second address line.
86+
"""
87+
self.address_line2 = address_line2
88+
89+
def get_address_line3(self) -> str:
90+
"""
91+
Returns the third address line.
92+
"""
93+
return self.address_line3
94+
95+
def set_address_line3(self, address_line3: str) -> None:
96+
"""
97+
Sets the thrid address line.
98+
"""
99+
self.address_line3 = address_line3
100+
101+
def get_address_line4(self) -> str:
102+
"""
103+
Returns the fourth address line.
104+
"""
105+
return self.address_line4
106+
107+
def set_address_line4(self, address_line4: str) -> None:
108+
"""
109+
Sets the fourth address line.
110+
"""
111+
self.address_line4 = address_line4
112+
113+
def get_address_line5(self) -> str:
114+
"""
115+
Returns the fifth address line.
116+
"""
117+
return self.address_line5
118+
119+
def set_address_line5(self, address_line5: str) -> None:
120+
"""
121+
Sets the fifth address line.
122+
"""
123+
self.address_line5 = address_line5
124+
125+
def get_post_code(self) -> str:
126+
"""
127+
Returns the postcodde.
128+
"""
129+
return self.post_code
130+
131+
def set_post_code(self, post_code: str) -> None:
132+
"""
133+
Sets the postcode.
134+
"""
135+
self.post_code = post_code

classes/analyser.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from dataclasses import dataclass
2+
from typing import Optional
3+
import pandas as pd
4+
5+
6+
@dataclass
7+
class Analyser:
8+
"""
9+
This data class is used to store information about a specific analyser device.
10+
The attributes correspond to the columns in the analyser query results.
11+
Attributes:
12+
analyser_id (Optional[int]): The ID of the analyser.
13+
analyser_code (Optional[str]): The code of the analyser.
14+
hub_id (Optional[int]): The ID of the hub the analyser is connected to.
15+
analyser_type_id (Optional[int]): The type ID of the analyser.
16+
spoil_result_code (Optional[int]): The result code for spoilage.
17+
tech_fail_result_code (Optional[int]): The result code for technical failure.
18+
below_range_result_code (Optional[int]): The result code for below range.
19+
above_range_result_code (Optional[int]): The result code for above range.
20+
"""
21+
22+
analyser_id: Optional[int] = None
23+
analyser_code: Optional[str] = None
24+
hub_id: Optional[int] = None
25+
analyser_type_id: Optional[int] = None
26+
spoil_result_code: Optional[int] = None
27+
tech_fail_result_code: Optional[int] = None
28+
below_range_result_code: Optional[int] = None
29+
above_range_result_code: Optional[int] = None
30+
31+
def __str__(self) -> str:
32+
return (
33+
f"Analyser [analyser_id={self.analyser_id}, analyser_code={self.analyser_code}, "
34+
f"hub_id={self.hub_id}, spoil_result_code={self.spoil_result_code}, "
35+
f"tech_fail_result_code={self.tech_fail_result_code}, "
36+
f"below_range_result_code={self.below_range_result_code}, "
37+
f"above_range_result_code={self.above_range_result_code}]"
38+
)
39+
40+
@staticmethod
41+
def from_dataframe_row(row: pd.Series) -> "Analyser":
42+
"""
43+
Creates an Analyser object from a pandas DataFrame row containing analyser query results.
44+
45+
Args:
46+
row (pd.Series): A row from a pandas DataFrame with columns:
47+
- tk_analyser_id
48+
- analyser_code
49+
- hub_id
50+
- tk_analyser_type_id
51+
The other columns are obtained from the SQL query as so are not present in this method.
52+
53+
Returns:
54+
Analyser: The constructed Analyser object.
55+
"""
56+
return Analyser(
57+
analyser_id=row.get("tk_analyser_id"),
58+
analyser_code=row.get("analyser_code"),
59+
hub_id=row.get("hub_id"),
60+
analyser_type_id=row.get("tk_analyser_type_id"),
61+
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from enum import Enum
2+
from typing import Optional
3+
4+
5+
class AnalyserResultCodeType(Enum):
6+
"""
7+
Enum for analyser result code types, mapped to valid value IDs and descriptions.
8+
"""
9+
10+
ABOVE_DILUTION_RANGE = (309030, "Above dilution range")
11+
BELOW_MEASURING_RANGE = (309028, "Below measuring range")
12+
SPOILT = (309026, "Spoilt")
13+
TECHNICAL_FAIL = (309027, "Technical Fail")
14+
15+
def __init__(self, valid_value_id: int, description: str) -> None:
16+
self._valid_value_id = valid_value_id
17+
self._description = description
18+
19+
@property
20+
def valid_value_id(self) -> int:
21+
"""
22+
Returns the valid value ID for the analyser result code type.
23+
"""
24+
return self._valid_value_id
25+
26+
@property
27+
def description(self) -> str:
28+
"""
29+
Returns the description for the analyser result code type.
30+
"""
31+
return self._description
32+
33+
@classmethod
34+
def by_description(cls, description: str) -> Optional["AnalyserResultCodeType"]:
35+
"""
36+
Returns the enum member matching the given description (case-sensitive).
37+
"""
38+
for member in cls:
39+
if member.description == description:
40+
return member
41+
return None
42+
43+
@classmethod
44+
def by_description_case_insensitive(
45+
cls, description: str
46+
) -> Optional["AnalyserResultCodeType"]:
47+
"""
48+
Returns the enum member matching the given description (case-insensitive).
49+
"""
50+
desc_lower = description.lower()
51+
for member in cls:
52+
if member.description.lower() == desc_lower:
53+
return member
54+
return None
55+
56+
@classmethod
57+
def by_valid_value_id(
58+
cls, valid_value_id: int
59+
) -> Optional["AnalyserResultCodeType"]:
60+
"""
61+
Returns the enum member matching the given valid value ID.
62+
"""
63+
for member in cls:
64+
if member.valid_value_id == valid_value_id:
65+
return member
66+
return None

0 commit comments

Comments
 (0)