Skip to content

Commit 29cd915

Browse files
committed
Update date ignore option
1 parent 3052f0f commit 29cd915

2 files changed

Lines changed: 89 additions & 68 deletions

File tree

gateway-api/src/gateway_api/pds_search.py

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def __init__(
103103
base_url: str = SANDBOX_URL,
104104
nhsd_session_urid: str | None = None,
105105
timeout: int = 10,
106+
ignore_dates: bool = False,
106107
) -> None:
107108
"""
108109
Create a PDS client.
@@ -113,12 +114,15 @@ def __init__(
113114
:attr:`INT_URL`, :attr:`PROD_URL`). Trailing slashes are stripped.
114115
:param nhsd_session_urid: Optional ``NHSD-Session-URID`` header value.
115116
:param timeout: Default timeout in seconds for HTTP calls.
117+
:param ignore_dates: If ``True`` just get the most recent name or GP record,
118+
ignoring the date ranges.
116119
"""
117120
self.auth_token = auth_token
118121
self.end_user_org_ods = end_user_org_ods
119122
self.base_url = base_url.rstrip("/")
120123
self.nhsd_session_urid = nhsd_session_urid
121124
self.timeout = timeout
125+
self.ignore_dates = ignore_dates
122126

123127
def _build_headers(
124128
self,
@@ -134,12 +138,15 @@ def _build_headers(
134138
:return: Dictionary of HTTP headers for the outbound request.
135139
"""
136140
headers = {
137-
"Authorization": f"Bearer {self.auth_token}",
138141
"X-Request-ID": request_id or str(uuid.uuid4()),
139142
"NHSD-End-User-Organisation-ODS": self.end_user_org_ods,
140143
"Accept": "application/fhir+json",
141144
}
142145

146+
# Trying to pass an auth token to the sandbox makes PDS unhappy
147+
if self.base_url != self.SANDBOX_URL:
148+
headers["Authorization"] = f"Bearer {self.auth_token}"
149+
143150
# NHSD-Session-URID is required in some flows; include only if configured.
144151
if self.nhsd_session_urid:
145152
headers["NHSD-Session-URID"] = self.nhsd_session_urid
@@ -200,8 +207,7 @@ def search_patient_by_nhs_number(
200207

201208
# --------------- internal helpers for result extraction -----------------
202209

203-
@staticmethod
204-
def _get_gp_ods_code(general_practitioners: ResultList) -> str | None:
210+
def _get_gp_ods_code(self, general_practitioners: ResultList) -> str | None:
205211
"""
206212
Extract the current GP ODS code from ``Patient.generalPractitioner``.
207213
@@ -221,7 +227,7 @@ def _get_gp_ods_code(general_practitioners: ResultList) -> str | None:
221227
if len(general_practitioners) == 0:
222228
return None
223229

224-
gp = find_current_gp(general_practitioners)
230+
gp = self.find_current_gp(general_practitioners)
225231
if gp is None:
226232
return None
227233

@@ -272,7 +278,7 @@ def _extract_single_search_result(
272278

273279
# Select current name record and extract names.
274280
names = cast("ResultList", patient.get("name", []))
275-
current_name = find_current_name_record(names)
281+
current_name = self.find_current_name_record(names)
276282
if current_name is None:
277283
raise RuntimeError("PDS patient has no current name record")
278284

@@ -291,79 +297,88 @@ def _extract_single_search_result(
291297
gp_ods_code=gp_ods_code,
292298
)
293299

300+
def find_current_gp(
301+
self, records: ResultList, today: date | None = None
302+
) -> ResultStructureDict | None:
303+
"""
304+
Select the current record from a ``generalPractitioner`` list.
294305
295-
def find_current_gp(
296-
records: ResultList, today: date | None = None
297-
) -> ResultStructureDict | None:
298-
"""
299-
Select the current record from a ``generalPractitioner`` list.
306+
A record is "current" if its ``identifier.period`` covers ``today`` (inclusive):
300307
301-
A record is "current" if its ``identifier.period`` covers ``today`` (inclusive):
308+
``start <= today <= end``
302309
303-
``start <= today <= end``
310+
Or else if self.ignore_dates is True, the last record in the list is returned.
304311
305-
The list may be in any of the following states:
312+
The list may be in any of the following states:
306313
307-
* empty
308-
* contains one or more records, none current
309-
* contains one or more records, exactly one current
314+
* empty
315+
* contains one or more records, none current
316+
* contains one or more records, exactly one current
310317
311-
:param records: List of ``generalPractitioner`` records.
312-
:param today: Optional override date, intended for deterministic tests.
313-
If not supplied, the current UTC date is used.
314-
:return: The first record whose ``identifier.period`` covers ``today``, or ``None``
315-
if no record is current.
316-
:raises KeyError: If required keys are missing for a record being evaluated.
317-
:raises ValueError: If ``start`` or ``end`` are not valid ISO date strings.
318-
"""
319-
if today is None:
320-
today = datetime.now(timezone.utc).date()
318+
:param records: List of ``generalPractitioner`` records.
319+
:param today: Optional override date, intended for deterministic tests.
320+
If not supplied, the current UTC date is used.
321+
:return: The first record whose ``identifier.period`` covers ``today``, or
322+
``None`` if no record is current.
323+
:raises KeyError: If required keys are missing for a record being evaluated.
324+
:raises ValueError: If ``start`` or ``end`` are not valid ISO date strings.
325+
"""
326+
if today is None:
327+
today = datetime.now(timezone.utc).date()
321328

322-
for record in records:
323-
identifier = cast("ResultStructureDict", record["identifier"])
324-
periods = cast("dict[str, str]", identifier["period"])
325-
start_str = periods["start"]
326-
end_str = periods["end"]
329+
if self.ignore_dates:
330+
return records[-1]
327331

328-
start = date.fromisoformat(start_str)
329-
end = date.fromisoformat(end_str)
332+
for record in records:
333+
identifier = cast("ResultStructureDict", record["identifier"])
334+
periods = cast("dict[str, str]", identifier["period"])
335+
start_str = periods["start"]
336+
end_str = periods["end"]
330337

331-
if start <= today <= end:
332-
return record
338+
start = date.fromisoformat(start_str)
339+
end = date.fromisoformat(end_str)
333340

334-
return None
341+
if start <= today <= end:
342+
return record
335343

344+
return None
336345

337-
def find_current_name_record(
338-
records: ResultList, today: date | None = None
339-
) -> ResultStructureDict | None:
340-
"""
341-
Select the current record from a ``Patient.name`` list.
346+
def find_current_name_record(
347+
self, records: ResultList, today: date | None = None
348+
) -> ResultStructureDict | None:
349+
"""
350+
Select the current record from a ``Patient.name`` list.
342351
343-
A record is "current" if its ``period`` covers ``today`` (inclusive):
352+
A record is "current" if its ``period`` covers ``today`` (inclusive):
344353
345-
``start <= today <= end``
354+
``start <= today <= end``
346355
347-
:param records: List of ``Patient.name`` records.
348-
:param today: Optional override date, intended for deterministic tests.
349-
If not supplied, the current UTC date is used.
350-
:return: The first name record whose ``period`` covers ``today``, or ``None`` if no
351-
record is current.
352-
:raises KeyError: If required keys (``period.start`` / ``period.end``) are missing.
353-
:raises ValueError: If ``start`` or ``end`` are not valid ISO date strings.
354-
"""
355-
if today is None:
356-
today = datetime.now(timezone.utc).date()
356+
Or else if self.ignore_dates is True, the last record in the list is returned.
357+
358+
:param records: List of ``Patient.name`` records.
359+
:param today: Optional override date, intended for deterministic tests.
360+
If not supplied, the current UTC date is used.
361+
:return: The first name record whose ``period`` covers ``today``, or ``None`` if
362+
no record is current.
363+
:raises KeyError: If required keys (``period.start`` / ``period.end``) are
364+
missing.
365+
:raises ValueError: If ``start`` or ``end`` are not valid ISO date strings.
366+
"""
367+
if today is None:
368+
today = datetime.now(timezone.utc).date()
369+
370+
if self.ignore_dates:
371+
return records[-1]
357372

358-
for record in records:
359-
periods = cast("dict[str, str]", record["period"])
360-
start_str = periods["start"]
361-
end_str = periods["end"]
373+
for record in records:
374+
periods = cast("dict[str, str]", record["period"])
375+
start_str = periods["start"]
376+
end_str = periods["end"]
362377

363-
start = date.fromisoformat(start_str)
364-
end = date.fromisoformat(end_str)
378+
start = date.fromisoformat(start_str)
379+
end = date.fromisoformat(end_str)
365380

366-
if start <= today <= end:
367-
return record
381+
if start <= today <= end:
382+
return record
368383

369-
return None
384+
return None

gateway-api/src/gateway_api/test_pds_search.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
ExternalServiceError,
1919
PdsClient,
2020
ResultList,
21-
find_current_gp,
22-
find_current_name_record,
2321
)
2422

2523

@@ -449,6 +447,9 @@ def test_find_current_gp_with_today_override() -> None:
449447
450448
:return: ``None``.
451449
"""
450+
pds = PdsClient("test-token", "A12345")
451+
pds_ignore_dates = PdsClient("test-token", "A12345", ignore_dates=True)
452+
452453
records = cast(
453454
"ResultList",
454455
[
@@ -467,9 +468,10 @@ def test_find_current_gp_with_today_override() -> None:
467468
],
468469
)
469470

470-
assert find_current_gp(records, today=date(2020, 6, 1)) == records[0]
471-
assert find_current_gp(records, today=date(2021, 6, 1)) == records[1]
472-
assert find_current_gp(records, today=date(2019, 6, 1)) is None
471+
assert pds.find_current_gp(records, today=date(2020, 6, 1)) == records[0]
472+
assert pds.find_current_gp(records, today=date(2021, 6, 1)) == records[1]
473+
assert pds.find_current_gp(records, today=date(2019, 6, 1)) is None
474+
assert pds_ignore_dates.find_current_gp(records, today=date(2019, 6, 1)) is not None
473475

474476

475477
def test_find_current_name_record_no_current_name() -> None:
@@ -479,6 +481,9 @@ def test_find_current_name_record_no_current_name() -> None:
479481
480482
:return: ``None``.
481483
"""
484+
pds = PdsClient("test-token", "A12345")
485+
pds_ignore_date = PdsClient("test-token", "A12345", ignore_dates=True)
486+
482487
records = cast(
483488
"ResultList",
484489
[
@@ -497,7 +502,8 @@ def test_find_current_name_record_no_current_name() -> None:
497502
],
498503
)
499504

500-
assert find_current_name_record(records) is None
505+
assert pds.find_current_name_record(records) is None
506+
assert pds_ignore_date.find_current_name_record(records) is not None
501507

502508

503509
def test_extract_single_search_result_invalid_body_raises_runtime_error() -> None:

0 commit comments

Comments
 (0)