Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/services/mwl/c_find.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ def call(self, event: evt.Event) -> Iterator[Tuple[int, Dataset | None]]:
query_modality = procedure_sequence[0].get("Modality")
query_date = procedure_sequence[0].get("ScheduledProcedureStepStartDate")
query_accession_number = identifier.get("AccessionNumber")
query_time = procedure_sequence[0].get("ScheduledProcedureStepStartTime")

try:
items = self.storage.find_worklist_items(
accession_number=query_accession_number if query_accession_number else None,
modality=query_modality if query_modality else None,
scheduled_date=query_date if query_date else None,
scheduled_time=query_time if query_time else None,
patient_id=query_patient_id if query_patient_id else None,
)

Expand Down
35 changes: 32 additions & 3 deletions src/services/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ def find_worklist_items(
accession_number: Optional[str] = None,
modality: Optional[str] = None,
scheduled_date: Optional[str] = None,
scheduled_time: Optional[str] = None,
patient_id: Optional[str] = None,
) -> List[WorklistItem]:
"""
Expand All @@ -375,7 +376,8 @@ def find_worklist_items(
Args:
accession_number: Filter by accession number
modality: Filter by modality (e.g., "MG")
scheduled_date: Filter by scheduled date (YYYYMMDD)
scheduled_date: Filter by scheduled date (YYYYMMDD, or range like "20240101-20240131")
scheduled_time: Filter by scheduled time (HHMMSS, or range like "080000-170000")
patient_id: Filter by patient ID

Returns:
Expand All @@ -399,8 +401,14 @@ def find_worklist_items(
params.append(modality)

if scheduled_date:
where_clauses.append("scheduled_date = ?")
params.append(scheduled_date)
where_clause, clause_params = self.scheduled_query_clause("scheduled_date", scheduled_date)
where_clauses.append(where_clause)
params.extend(clause_params)

if scheduled_time:
where_clause, clause_params = self.scheduled_query_clause("scheduled_time", scheduled_time)
where_clauses.append(where_clause)
params.extend(clause_params)

if patient_id:
where_clauses.append("patient_id = ?")
Expand All @@ -416,6 +424,27 @@ def find_worklist_items(

return [WorklistItem(**row) for row in cursor.fetchall()]

def scheduled_query_clause(self, param_name: str, param_value: str) -> tuple[str, List[str]]:
"""
Helper to build SQL clause for scheduled date/time parameters.

Args:
param_name: "scheduled_date" or "scheduled_time"
param_value: Value to filter by (e.g., "20240101", "20240101-20240131", "-20240131", "20240101-")

Returns:
Tuple of (SQL clause string, list of parameters)
"""
if param_value.endswith("-"):
return f"{param_name} >= ?", [param_value[:-1].strip()]
elif param_value.startswith("-"):
return f"{param_name} <= ?", [param_value[1:].strip()]
elif "-" in param_value:
start, end = [s.strip() for s in param_value.split("-", 1)]
return f"{param_name} >= ? AND {param_name} <= ?", [start, end]
else:
return f"{param_name} = ?", [param_value.strip()]

def get_worklist_item(self, accession_number: str) -> Optional[WorklistItem]:
"""
Get a single WorklistItem instance by accession number.
Expand Down
123 changes: 119 additions & 4 deletions tests/integration/test_c_find_returns_worklist_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def with_worklist_items(self, storage):
patient_name="JONES^MARY",
patient_birth_date="19900202",
patient_sex="F",
scheduled_date="20240102",
scheduled_date="20240302",
scheduled_time="094500",
modality="MG",
procedure_code="12345-6",
Expand Down Expand Up @@ -89,15 +89,15 @@ def test_cfind_returns_scheduled_items(self, event, storage):
assert ds.StudyDescription == "MAMMOGRAPHY"
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepDescription == "MAMMOGRAPHY"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240102"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240302"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime == "094500"

status, ds = results[2]
assert status == SUCCESS
assert ds is None

def test_cfind_filters_by_scheduled_date(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20240101"
def test_cfind_filters_by_scheduled_date_range(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20240101-20240201"

results = list(CFind(storage).call(event))

Expand All @@ -118,7 +118,37 @@ def test_cfind_filters_by_scheduled_date(self, event, storage):

def test_cfind_filters_by_accession_number(self, event, storage):
event.identifier.AccessionNumber = "ACC234567"
results = list(CFind(storage).call(event))
assert len(results) == 2
status, ds = results[0]
assert status == PENDING
assert ds.PatientID == "999234567"
assert ds.PatientName == "JONES^MARY"
assert ds.PatientBirthDate == "19900202"
assert ds.AccessionNumber == "ACC234567"

def test_cfind_filters_by_before_scheduled_date(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "-20240101"

results = list(CFind(storage).call(event))

assert len(results) == 2

status, ds = results[0]
assert status == PENDING
assert ds.PatientID == "999123456"
assert ds.PatientName == "SMITH^JANE"
assert ds.PatientBirthDate == "19800101"
assert ds.AccessionNumber == "ACC123456"
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240101"

status, ds = results[1]
assert status == SUCCESS
assert ds is None

def test_cfind_filters_by_after_scheduled_date(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20240201-"
results = list(CFind(storage).call(event))

assert len(results) == 2
Expand All @@ -127,7 +157,92 @@ def test_cfind_filters_by_accession_number(self, event, storage):
assert status == PENDING
assert ds.PatientID == "999234567"
assert ds.PatientName == "JONES^MARY"
assert ds.PatientBirthDate == "19900202"
assert ds.AccessionNumber == "ACC234567"
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240302"

status, ds = results[1]
assert status == SUCCESS
assert ds is None

def test_cfind_filters_by_scheduled_time_range(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime = "090000-093000"

results = list(CFind(storage).call(event))

assert len(results) == 2

status, ds = results[0]
assert status == PENDING
assert ds.PatientID == "999123456"
assert ds.PatientName == "SMITH^JANE"
assert ds.PatientBirthDate == "19800101"
assert ds.AccessionNumber == "ACC123456"
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime == "090000"

status, ds = results[1]
assert status == SUCCESS
assert ds is None

def test_cfind_filters_by_before_scheduled_time(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime = "-093000"

results = list(CFind(storage).call(event))

assert len(results) == 2

status, ds = results[0]
assert status == PENDING
assert ds.PatientID == "999123456"
assert ds.PatientName == "SMITH^JANE"
assert ds.PatientBirthDate == "19800101"
assert ds.AccessionNumber == "ACC123456"
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime == "090000"

status, ds = results[1]
assert status == SUCCESS
assert ds is None

def test_cfind_filters_by_after_scheduled_time(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime = "093000-"

results = list(CFind(storage).call(event))

assert len(results) == 2

status, ds = results[0]
assert status == PENDING
assert ds.PatientID == "999234567"
assert ds.PatientName == "JONES^MARY"
assert ds.PatientBirthDate == "19900202"
assert ds.AccessionNumber == "ACC234567"
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime == "094500"

status, ds = results[1]
assert status == SUCCESS
assert ds is None

def test_cfind_filters_by_date_and_time_range(self, event, storage):
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20240101-20240201"
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime = "090000-093000"

results = list(CFind(storage).call(event))

assert len(results) == 2

status, ds = results[0]
assert status == PENDING
assert ds.PatientID == "999123456"
assert ds.PatientName == "SMITH^JANE"
assert ds.PatientBirthDate == "19800101"
assert ds.AccessionNumber == "ACC123456"
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240101"
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime == "090000"

status, ds = results[1]
assert status == SUCCESS
Expand Down
20 changes: 16 additions & 4 deletions tests/services/mwl/test_c_find.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test_call_with_accession_number_filter(self, handler, mock_storage, mock_eve
list(handler.call(mock_event))

mock_storage.find_worklist_items.assert_called_once_with(
accession_number="ACC12345", modality=None, scheduled_date=None, patient_id=None
accession_number="ACC12345", modality=None, scheduled_date=None, scheduled_time=None, patient_id=None
)

def test_call_with_modality_filter(self, handler, mock_storage, mock_event):
Expand All @@ -127,7 +127,7 @@ def test_call_with_modality_filter(self, handler, mock_storage, mock_event):
list(handler.call(mock_event))

mock_storage.find_worklist_items.assert_called_once_with(
accession_number=None, modality="MG", scheduled_date=None, patient_id=None
accession_number=None, modality="MG", scheduled_date=None, scheduled_time=None, patient_id=None
)

def test_call_with_date_filter(self, handler, mock_storage, mock_event):
Expand All @@ -139,7 +139,19 @@ def test_call_with_date_filter(self, handler, mock_storage, mock_event):
list(handler.call(mock_event))

mock_storage.find_worklist_items.assert_called_once_with(
accession_number=None, modality=None, scheduled_date="20260107", patient_id=None
accession_number=None, modality=None, scheduled_date="20260107", scheduled_time=None, patient_id=None
)

def test_call_with_time_filter(self, handler, mock_storage, mock_event):
sps_item = Dataset()
sps_item.ScheduledProcedureStepStartTime = "100000"
mock_event.identifier.ScheduledProcedureStepSequence = [sps_item]
mock_storage.find_worklist_items.return_value = []

list(handler.call(mock_event))

mock_storage.find_worklist_items.assert_called_once_with(
accession_number=None, modality=None, scheduled_date=None, scheduled_time="100000", patient_id=None
)

def test_call_with_patient_id_filter(self, handler, mock_storage, mock_event):
Expand All @@ -149,7 +161,7 @@ def test_call_with_patient_id_filter(self, handler, mock_storage, mock_event):
list(handler.call(mock_event))

mock_storage.find_worklist_items.assert_called_once_with(
accession_number=None, modality=None, scheduled_date=None, patient_id="9876543210"
accession_number=None, modality=None, scheduled_date=None, scheduled_time=None, patient_id="9876543210"
)

def test_call_handles_storage_exception(self, handler, mock_storage, mock_event):
Expand Down
Loading
Loading