Skip to content

Commit 9bb49e5

Browse files
Adding compartment 3 and fixing broken imports in other files
1 parent b6c7c99 commit 9bb49e5

File tree

5 files changed

+327
-12
lines changed

5 files changed

+327
-12
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import logging
2+
import pytest
3+
from playwright.sync_api import Page
4+
from pages.logout.log_out_page import Logout
5+
from utils.batch_processing import batch_processing
6+
from utils.fit_kit_logged import process_kit_data
7+
from utils.screening_subject_page_searcher import verify_subject_event_status_by_nhs_no
8+
from utils.oracle.oracle_specific_functions import (
9+
update_kit_service_management_entity,
10+
execute_stored_procedures,
11+
)
12+
from utils.user_tools import UserTools
13+
14+
15+
@pytest.mark.smokescreen
16+
@pytest.mark.compartment3
17+
def test_compartment_3(page: Page) -> None:
18+
"""
19+
This is the main compartment 3 method
20+
First it finds any relevant test data from the DB and stores it in a pandas dataframe
21+
Then it separates it out into normal and abnormal results
22+
Once that is done it updates a table on the DB and runs two stored procedures so that these subjects will not have normal/abnormal results on BCSS
23+
It then checks that the status of the subject is as expected using the subject screening summary page
24+
Then it process two batches performing checks on the subjects to ensure they always have the correct event status
25+
"""
26+
UserTools.user_login(page, "Hub Manager State Registered")
27+
28+
# Find data , separate it into normal and abnormal, Add results to the test records in the KIT_QUEUE table (i.e. mimic receiving results from the middleware)
29+
# and get device IDs and their flags
30+
device_ids = process_kit_data()
31+
# Retrieve NHS numbers for each device_id and determine normal/abnormal status
32+
nhs_numbers = []
33+
normal_flags = []
34+
35+
for device_id, is_normal in device_ids:
36+
nhs_number = update_kit_service_management_entity(device_id, is_normal)
37+
nhs_numbers.append(nhs_number)
38+
normal_flags.append(
39+
is_normal
40+
) # Store the flag (True for normal, False for abnormal)
41+
42+
# Run two stored procedures to process any kit queue records at status BCSS_READY
43+
try:
44+
execute_stored_procedures()
45+
logging.info("Stored procedures executed successfully.")
46+
except Exception as e:
47+
logging.error(f"Error executing stored procedures: {str(e)}")
48+
raise
49+
# Check the results of the processed FIT kits have correctly updated the status of the associated subjects
50+
# Verify subject event status based on normal or abnormal classification
51+
for nhs_number, is_normal in zip(nhs_numbers, normal_flags):
52+
expected_status = (
53+
"S2 - Normal" if is_normal else "A8 - Abnormal"
54+
) # S2 for normal, A8 for abnormal
55+
logging.info(
56+
f"Verifying NHS number: {nhs_number} with expected status: {expected_status}"
57+
)
58+
59+
try:
60+
verify_subject_event_status_by_nhs_no(page, nhs_number, expected_status)
61+
logging.info(
62+
f"Successfully verified NHS number {nhs_number} with status {expected_status}"
63+
)
64+
except Exception as e:
65+
logging.error(
66+
f"Verification failed for NHS number {nhs_number} with status {expected_status}: {str(e)}"
67+
)
68+
raise
69+
70+
# Process S2 batch
71+
batch_processing(
72+
page,
73+
"S2",
74+
"Subject Result (Normal)",
75+
"S158 - Subject Discharge Sent (Normal)",
76+
True,
77+
)
78+
79+
# Process S158 batch
80+
batch_processing(
81+
page,
82+
"S158",
83+
"GP Result (Normal)",
84+
"S159 - GP Discharge Sent (Normal)",
85+
)
86+
87+
# Log out
88+
Logout(page).log_out()

tests/test_fit_test_kits_page.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
from pages.base_page import BasePage
44
from pages.fit_test_kits.fit_test_kits_page import FITTestKits
55
from pages.fit_test_kits.fit_rollout_summary_page import FITRolloutSummary
6-
from pages.log_devices_page import LogDevices
6+
from pages.fit_test_kits.log_devices_page import LogDevices
77
from pages.fit_test_kits.view_fit_kit_result_page import ViewFITKitResult
88
from pages.fit_test_kits.kit_service_management_page import KitServiceManagement
99
from pages.fit_test_kits.kit_result_audit_page import KitResultAudit
10-
from pages.view_algorithms_page import ViewAlgorithms
11-
from pages.view_screening_centre_fit_configuration_page import (
10+
from pages.fit_test_kits.view_algorithms_page import ViewAlgorithms
11+
from pages.fit_test_kits.view_screening_centre_fit_configuration_page import (
1212
ViewScreeningCentreFITConfiguration,
1313
)
14-
from pages.screening_incidents_list_page import ScreeningIncidentsList
15-
from pages.manage_qc_products_page import ManageQCProducts
16-
from pages.maintain_analysers_page import MaintainAnalysers
14+
from pages.fit_test_kits.screening_incidents_list_page import ScreeningIncidentsList
15+
from pages.fit_test_kits.manage_qc_products_page import ManageQCProducts
16+
from pages.fit_test_kits.maintain_analysers_page import MaintainAnalysers
1717
from utils.user_tools import UserTools
1818

1919

utils/fit_kit_logged.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from oracle.oracle import OracleDB
2+
from oracle.oracle_specific_functions import get_kit_id_logged_from_db
3+
import pandas as pd
4+
import logging
5+
import pytest
6+
7+
8+
def process_kit_data() -> list:
9+
"""
10+
This method retrieved the test data needed for compartment 3 and then splits it into two data frames:
11+
- 1 normal
12+
- 1 abnormal
13+
Once the dataframe is split in two it then creates two lists, one for normal and one for abnormal
14+
Each list will either have true or false appended depending on if it is normal or abnormal
15+
"""
16+
# Get test data for compartment 3
17+
kit_id_df = get_kit_id_logged_from_db()
18+
19+
# Split dataframe into two different dataframes, normal and abnormal
20+
normal_fit_kit_df, abnormal_fit_kit_df = split_fit_kits(kit_id_df)
21+
22+
# Prepare a list to store device IDs and their respective flags
23+
device_ids = []
24+
25+
# Process normal kits (only 1)
26+
if not normal_fit_kit_df.empty:
27+
device_id = normal_fit_kit_df["device_id"].iloc[0]
28+
logging.info(
29+
f"Processing normal kit with Device ID: {device_id}"
30+
) # Logging normal device_id
31+
device_ids.append((device_id, True)) # Add to the list with normal flag
32+
else:
33+
pytest.fail("No normal kits found for processing.")
34+
35+
# Process abnormal kits (multiple, loop through)
36+
if not abnormal_fit_kit_df.empty:
37+
for index, row in abnormal_fit_kit_df.iterrows():
38+
device_id = row["device_id"]
39+
logging.info(
40+
f"Processing abnormal kit with Device ID: {device_id}"
41+
) # Logging abnormal device_id
42+
device_ids.append((device_id, False)) # Add to the list with abnormal flag
43+
else:
44+
pytest.fail("No abnormal kits found for processing.")
45+
46+
return device_ids
47+
48+
49+
# Seperate kits into normal and abnormal
50+
def split_fit_kits(kit_id_df) -> pd.DataFrame:
51+
"""
52+
This method splits the dataframe into two, 1 normal and 1 abnormal
53+
"""
54+
number_of_normal = 1
55+
number_of_abnormal = 9
56+
# Split dataframe into two dataframes
57+
normal_fit_kit_df = kit_id_df.iloc[:number_of_normal]
58+
abnormal_fit_kit_df = kit_id_df.iloc[
59+
number_of_normal : number_of_normal + number_of_abnormal
60+
]
61+
return normal_fit_kit_df, abnormal_fit_kit_df

utils/oracle/oracle_specific_functions.py

Lines changed: 168 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from oracle.oracle import OracleDB
22
import logging
33
import pandas as pd
4+
from datetime import datetime
5+
46

57
def get_kit_id_from_db() -> pd.DataFrame:
68
"""
@@ -11,7 +13,8 @@ def get_kit_id_from_db() -> pd.DataFrame:
1113
- se.latest_event_status_id is 11198 or 11213 (Only kits at the status we want S10/S19 are retrieved)
1214
"""
1315
logging.info("Retrieving useable test kit ids")
14-
kit_id_df = OracleDB().execute_query("""select tk.kitid, tk.screening_subject_id, sst.subject_nhs_number
16+
kit_id_df = OracleDB().execute_query(
17+
"""select tk.kitid, tk.screening_subject_id, sst.subject_nhs_number
1518
from tk_items_t tk
1619
inner join ep_subject_episode_t se on se.screening_subject_id = tk.screening_subject_id
1720
inner join screening_subject_t sst on (sst.screening_subject_id = tk.screening_subject_id)
@@ -23,15 +26,18 @@ def get_kit_id_from_db() -> pd.DataFrame:
2326
and tk.invalidated_date is null
2427
and se.latest_event_status_id in (11198, 11213)
2528
order by tk.kitid DESC
26-
fetch first 10 rows only""")
29+
fetch first 10 rows only"""
30+
)
2731
return kit_id_df
2832

33+
2934
def get_nhs_no_from_batch_id(batch_id) -> pd.DataFrame:
3035
"""
3136
This query returns a dataframe of NHS Numbers of the subjects in a certain batch
3237
We provide the batch ID e.g. 8812 and then we have a list of NHS Numbers we can verify the statuses
3338
"""
34-
nhs_number_df = OracleDB().execute_query(f"""
39+
nhs_number_df = OracleDB().execute_query(
40+
f"""
3541
SELECT SUBJECT_NHS_NUMBER
3642
FROM SCREENING_SUBJECT_T ss
3743
INNER JOIN sd_contact_t c ON ss.subject_nhs_number = c.nhs_number
@@ -40,5 +46,163 @@ def get_nhs_no_from_batch_id(batch_id) -> pd.DataFrame:
4046
WHERE lbr.BATCH_ID IN {batch_id}
4147
AND ss.screening_status_id != 4008
4248
ORDER BY ss.subject_nhs_number
43-
""")
49+
"""
50+
)
4451
return nhs_number_df
52+
53+
54+
def get_kit_id_logged_from_db() -> pd.DataFrame:
55+
"""
56+
This query is used to obtain test data used in compartment 3
57+
It searches for kits that have not been logged and meet the following criteria:
58+
- tk.tk_type_id = 2 (Only FIT Kits)
59+
- tk.logged_in_at = 23159 (Hub ID that the compartments are running in)
60+
"""
61+
kit_id_df = OracleDB().execute_query(
62+
"""SELECT tk.kitid,tk.device_id,tk.screening_subject_id
63+
FROM tk_items_t tk
64+
INNER JOIN kit_queue kq ON kq.device_id = tk.device_id
65+
INNER JOIN ep_subject_episode_t se ON se.screening_subject_id = tk.screening_subject_id
66+
WHERE tk.logged_in_flag = 'Y'
67+
AND kq.test_kit_status IN ('LOGGED', 'POSTED')
68+
AND se.episode_status_id = 11352
69+
AND tk.tk_type_id = 2
70+
AND se.latest_event_status_id = 11223
71+
AND tk.logged_in_at = 23159
72+
AND tk.reading_flag = 'N'
73+
AND tk.test_results IS NULL
74+
fetch first 9 rows only
75+
"""
76+
)
77+
78+
return kit_id_df
79+
80+
81+
def get_service_management_by_device_id(deviceid) -> pd.DataFrame:
82+
"""
83+
This SQL is similar to the one used in pkg_test_kit_queue.p_get_fit_monitor_details, but adapted to allow us to pick out sub-sets of records
84+
"""
85+
get_service_management_df = OracleDB().execute_query(
86+
f"""SELECT kq.device_id, kq.test_kit_name, kq.test_kit_type, kq.test_kit_status,
87+
CASE WHEN tki.logged_in_flag = 'Y' THEN kq.logged_by_hub END AS logged_by_hub,
88+
CASE WHEN tki.logged_in_flag = 'Y' THEN kq.date_time_logged END AS date_time_logged,
89+
tki.logged_in_on AS tk_logged_date_time, kq.test_result, kq.calculated_result,
90+
kq.error_code,
91+
(SELECT vvt.description
92+
FROM tk_analyser_t tka
93+
INNER JOIN tk_analyser_type_error tkate ON tkate.tk_analyser_type_id = tka.tk_analyser_type_id
94+
INNER JOIN valid_values vvt ON tkate.tk_analyser_error_type_id = vvt.valid_value_id
95+
WHERE tka.analyser_code = kq.analyser_code AND tkate.error_code = kq.error_code)
96+
AS analyser_error_description, kq.analyser_code, kq.date_time_authorised,
97+
kq.authoriser_user_code, kq.datestamp, kq.bcss_error_id,
98+
REPLACE(mt.description, 'ERROR - ', '') AS error_type,
99+
NVL(mta.allowed_value, 'N') AS error_ok_to_archive,
100+
kq.post_response, kq.post_attempts, kq.put_response,
101+
kq.put_attempts, kq.date_time_error_archived,
102+
kq.error_archived_user_code, sst.screening_subject_id,
103+
sst.subject_nhs_number, tki.test_results, tki.issue_date,
104+
o.org_code AS issued_by_hub
105+
FROM kit_queue kq
106+
LEFT OUTER JOIN tk_items_t tki ON tki.device_id = kq.device_id
107+
OR (tki.device_id IS NULL AND tki.kitid = pkg_test_kit.f_get_kit_id_from_device_id(kq.device_id))
108+
LEFT OUTER JOIN screening_subject_t sst ON sst.screening_subject_id = tki.screening_subject_id
109+
LEFT OUTER JOIN ep_subject_episode_t ep ON ep.subject_epis_id = tki.subject_epis_id
110+
LEFT OUTER JOIN message_types mt ON kq.bcss_error_id = mt.message_type_id
111+
LEFT OUTER JOIN valid_values mta ON mta.valid_value_id = mt.message_attribute_id AND mta.valid_value_id = 305482
112+
LEFT OUTER JOIN ORG o ON ep.start_hub_id = o.org_id
113+
LEFT OUTER JOIN ORG lo ON lo.org_code = kq.logged_by_hub
114+
WHERE kq.test_kit_type = 'FIT' AND kq.device_id = '{deviceid}'
115+
"""
116+
)
117+
return get_service_management_df
118+
119+
120+
def update_kit_service_management_entity(device_id, normal) -> str:
121+
"""
122+
This method is used to update the KIT_QUEUE table on the DB
123+
This is done so that we can then run two stored procedures to update the subjects and kits status to either normal or abnormal
124+
"""
125+
get_service_management_df = get_service_management_by_device_id(device_id)
126+
127+
# Extract the NHS number from the DataFrame
128+
subject_nhs_number = get_service_management_df["subject_nhs_number"].iloc[0]
129+
test_kit_name = get_service_management_df["test_kit_name"].iloc[0]
130+
test_kit_type = get_service_management_df["test_kit_type"].iloc[0]
131+
logged_by_hub = get_service_management_df["logged_by_hub"].iloc[0]
132+
date_time_logged = get_service_management_df["date_time_logged"].iloc[0]
133+
calculated_result = get_service_management_df["calculated_result"].iloc[0]
134+
post_response = get_service_management_df["post_response"].iloc[0]
135+
post_attempts = get_service_management_df["post_attempts"].iloc[0]
136+
put_response = get_service_management_df["put_response"].iloc[0]
137+
put_attempts = get_service_management_df["put_attempts"].iloc[0]
138+
# format date
139+
date_time_authorised = (
140+
datetime.now().strftime("%d-%b-%y %H.%M.%S.")
141+
+ f"{datetime.now().microsecond:06d}000"
142+
)
143+
if normal:
144+
test_result = 75
145+
else:
146+
test_result = 150
147+
# Parameterized query
148+
update_query = """
149+
UPDATE kit_queue kq
150+
SET kq.test_kit_name = :test_kit_name,
151+
kq.test_kit_type = :test_kit_type,
152+
kq.test_kit_status =:test_kit_status,
153+
kq.logged_by_hub = :logged_by_hub,
154+
kq.date_time_logged = :date_time_logged,
155+
kq.test_result = :test_result,
156+
kq.calculated_result = :calculated_result,
157+
kq.error_code = NULL,
158+
kq.analyser_code = 'UU2_tdH3',
159+
kq.date_time_authorised = TO_TIMESTAMP(:date_time_authorised, 'DD-Mon-YY HH24.MI.SS.FF9'),
160+
kq.authoriser_user_code = 'AUTO1',
161+
kq.post_response = :post_response,
162+
kq.post_attempts = :post_attempts,
163+
kq.put_response = :put_response,
164+
kq.put_attempts = :put_attempts
165+
WHERE kq.device_id = :device_id
166+
"""
167+
168+
# Parameters dictionary
169+
params = {
170+
"test_kit_name": test_kit_name,
171+
"test_kit_type": test_kit_type,
172+
"test_kit_status": "BCSS_READY",
173+
"logged_by_hub": logged_by_hub,
174+
"date_time_logged": date_time_logged,
175+
"test_result": int(test_result),
176+
"calculated_result": calculated_result,
177+
"date_time_authorised": str(date_time_authorised),
178+
"post_response": int(post_response) if post_response is not None else 0,
179+
"post_attempts": int(post_attempts) if post_attempts is not None else 0,
180+
"put_response": put_response,
181+
"put_attempts": put_attempts,
182+
"device_id": device_id,
183+
}
184+
185+
# Execute query
186+
logging.info("Parameters before execution:", params)
187+
rows_affected = OracleDB().update_or_insert_data_to_table(update_query, params)
188+
logging.info(f"Rows affected: {rows_affected}")
189+
# Return the subject NHS number
190+
return subject_nhs_number
191+
192+
193+
def execute_stored_procedures() -> None:
194+
"""
195+
This method executes two stored procedures:
196+
- PKG_TEST_KIT_QUEUE.p_validate_kit_queue
197+
- PKG_TEST_KIT_QUEUE.p_calculate_result
198+
This is needed for compartment 3 after we update the KIT_QUE table on the DB
199+
"""
200+
db_instance = OracleDB() # Create an instance of the OracleDB class
201+
logging.info("start: oracle.OracleDB.execute_stored_procedure")
202+
db_instance.execute_stored_procedure(
203+
"PKG_TEST_KIT_QUEUE.p_validate_kit_queue"
204+
) # Run stored procedure - validate kit queue
205+
db_instance.execute_stored_procedure(
206+
"PKG_TEST_KIT_QUEUE.p_calculate_result"
207+
) # Run stored procedure - calculate result
208+
logging.info("exit: oracle.OracleDB.execute_stored_procedure")

utils/screening_subject_page_searcher.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from pages.base_page import BasePage
2-
from pages.subject_screening_search_page import (
2+
from pages.screening_subject_search.subject_screening_search_page import (
33
SubjectScreeningPage,
44
SearchAreaSearchOptions,
55
)
6-
from pages.subject_screening_summary import SubjectScreeningSummary
6+
from pages.screening_subject_search.subject_screening_summary import (
7+
SubjectScreeningSummary,
8+
)
79
from playwright.sync_api import Page, expect
810

911

0 commit comments

Comments
 (0)