Skip to content

Commit 0e3bd76

Browse files
committed
Add the return key attributes as specified in the conformance doc
The documentation says non-requested keys will be ignored, so we are safe to always return the full set for each item.
1 parent 73b643c commit 0e3bd76

3 files changed

Lines changed: 99 additions & 26 deletions

File tree

src/services/mwl/c_find.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,49 @@ def _build_worklist_response(self, item: WorklistItem) -> Dataset:
8686
ds.PatientID = item.patient_id
8787
ds.PatientName = item.patient_name
8888
ds.PatientBirthDate = item.patient_birth_date
89-
if item.patient_sex:
90-
ds.PatientSex = item.patient_sex
89+
ds.PatientSex = item.patient_sex
90+
ds.PatientAge = item.patient_age
91+
ds.PatientWeight = item.patient_weight
92+
ds.PatientAddress = item.patient_address
93+
ds.PatientComments = item.patient_comments
9194

9295
# Study information
9396
ds.AccessionNumber = item.accession_number
94-
if item.study_instance_uid:
95-
ds.StudyInstanceUID = item.study_instance_uid
97+
ds.StudyInstanceUID = item.study_instance_uid
9698

97-
if item.study_description:
98-
ds.StudyDescription = item.study_description
99-
sps_item.ScheduledProcedureStepDescription = ds.StudyDescription
99+
ds.StudyDescription = item.study_description
100+
sps_item.ScheduledProcedureStepDescription = ds.StudyDescription
100101

101-
if item.procedure_code:
102-
ds.RequestedProcedureID = item.procedure_code
103-
sps_item.ScheduledProcedureStepID = ds.RequestedProcedureID
102+
ds.RequestedProcedureID = item.procedure_code
103+
104+
ds.RequestedProcedureCodeSequence = [Dataset()]
105+
ds.RequestedProcedureCodeSequence[0].CodeValue = item.procedure_code
106+
ds.RequestedProcedureCodeSequence[0].CodingSchemeDesignator = item.procedure_coding_scheme_designator
107+
ds.RequestedProcedureCodeSequence[0].CodeMeaning = item.procedure_code_meaning
108+
109+
ds.ReasonForRequestedProcedureCodeSequence = [Dataset()]
110+
ds.ReasonForRequestedProcedureCodeSequence[0].CodeValue = item.reason_code_value
111+
ds.ReasonForRequestedProcedureCodeSequence[0].CodingSchemeDesignator = item.reason_coding_scheme_designator
112+
ds.ReasonForRequestedProcedureCodeSequence[0].CodeMeaning = item.reason_code_meaning
113+
114+
sps_item.ScheduledProcedureStepID = ds.RequestedProcedureID
104115

105116
# Scheduled Procedure Step Sequence
106117
sps_item.ScheduledProcedureStepStartDate = item.scheduled_date
107118
sps_item.ScheduledProcedureStepStartTime = item.scheduled_time
108119
sps_item.Modality = item.modality
120+
sps_item.ScheduledStationAETitle = item.scheduled_station_aet
121+
sps_item.ScheduledPerformingPhysicianName = item.scheduled_performing_physician_name
122+
sps_item.ScheduledStationName = item.scheduled_station_name
123+
sps_item.ScheduledProcedureStepLocation = item.scheduled_procedure_step_location
124+
sps_item.ScheduledProtocolCodeSequence = [Dataset()]
125+
sps_item.ScheduledProtocolCodeSequence[0].CodeValue = item.scheduled_protocol_code_value
126+
sps_item.ScheduledProtocolCodeSequence[0].CodingSchemeDesignator = item.scheduled_protocol_coding_scheme_designator
127+
sps_item.ScheduledProtocolCodeSequence[0].CodeMeaning = item.scheduled_protocol_code_meaning
109128

110129
ds.ScheduledProcedureStepSequence = [sps_item]
111130

131+
112132
logger.debug("Built worklist response for accession %s", item.accession_number)
113133

114134
return ds

src/services/storage.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ class WorklistItem:
291291
scheduled_date: str = field(doc="Date the procedure is scheduled for.")
292292
scheduled_time: str = field(doc="Time the procedure is scheduled for.")
293293
status: str = field(doc="Status of the worklist item", default=MWLStatus.SCHEDULED.value)
294+
294295
source_message_id: Optional[str] = field(
295296
default=None, doc="Message ID from system which created this worklist item", hash=True
296297
)
@@ -302,6 +303,36 @@ class WorklistItem:
302303
default=None, doc="Modality Performed Procedure Step (MPPS) instance UID if available."
303304
)
304305

306+
patient_age: Optional[str] = field(default=None, doc="Age of the patient at the time of scheduling.")
307+
patient_weight: Optional[str] = field(default=None, doc="Weight of the patient at the time of scheduling.")
308+
patient_address: Optional[str] = field(default=None, doc="Address of the patient.")
309+
patient_comments: Optional[str] = field(default=None, doc="Additional comments about the patient.")
310+
311+
procedure_coding_scheme_designator: Optional[str] = field(
312+
default=None, doc="Coding scheme designator for the procedure code."
313+
)
314+
procedure_code_meaning: Optional[str] = field(default=None, doc="Code meaning for the procedure code.")
315+
316+
reason_code_value: Optional[str] = field(default=None, doc="Code value for the reason for requested procedure.")
317+
reason_coding_scheme_designator: Optional[str] = field(
318+
default=None, doc="Coding scheme designator for the reason for requested procedure."
319+
)
320+
reason_code_meaning: Optional[str] = field(default=None, doc="Code meaning for the reason for requested procedure.")
321+
322+
scheduled_performing_physician_name: Optional[str] = field(
323+
default=None, doc="Name of the scheduled performing physician."
324+
)
325+
scheduled_procedure_step_location: Optional[str] = field(default=None, doc="Location of the scheduled procedure step.")
326+
scheduled_station_aet: Optional[str] = field(default=None, doc="AE Title of the scheduled station.")
327+
scheduled_station_name: Optional[str] = field(default=None, doc="Name of the scheduled station.")
328+
scheduled_protocol_code_value: Optional[str] = field(default=None, doc="Code value for the scheduled protocol.")
329+
scheduled_protocol_coding_scheme_designator: Optional[str] = field(
330+
default=None, doc="Coding scheme designator for the scheduled protocol."
331+
)
332+
scheduled_protocol_code_meaning: Optional[str] = field(
333+
default=None, doc="Code meaning for the scheduled protocol."
334+
)
335+
305336

306337
class WorklistItemNotFoundError(Exception):
307338
"""Raised when a worklist item is not found in storage."""

tests/services/mwl/test_c_find.py

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -214,23 +214,45 @@ def test_call_handles_storage_exception(self, handler, mock_storage, mock_event)
214214
assert status == FAILURE
215215
assert ds is None
216216

217-
def test_build_worklist_response_missing_optional_fields(self, handler):
218-
minimal_item = WorklistItem(
219-
accession_number="ACC001",
220-
patient_id="9876543210",
221-
patient_name="TEST^PATIENT",
222-
patient_birth_date="19800101",
223-
scheduled_date="20260107",
224-
scheduled_time="100000",
225-
modality="MG",
226-
)
217+
def test_call_return_key_attributes_present(self, handler, mock_storage, mock_event, sample_worklist_item):
218+
worklist_item = WorklistItem(**sample_worklist_item)
219+
mock_storage.find_worklist_items.return_value = [worklist_item]
227220

228-
ds = handler._build_worklist_response(minimal_item)
221+
results = list(handler.call(mock_event))
229222

230-
# Required fields present
223+
assert len(results) == 2
224+
status, ds = results[0]
225+
assert status == PENDING
231226
assert ds.PatientID == "9876543210"
232227
assert ds.AccessionNumber == "ACC001"
233-
# Optional fields absent
234-
assert not hasattr(ds, "PatientSex")
235-
assert not hasattr(ds, "StudyInstanceUID")
236-
assert not hasattr(ds, "StudyDescription")
228+
assert ds.PatientName == "TEST^PATIENT"
229+
assert ds.PatientBirthDate == "19800101"
230+
231+
assert ds.PatientAddress is None
232+
assert ds.PatientComments is None
233+
assert ds.PatientWeight is None
234+
assert ds.PatientAge is None
235+
assert ds.PatientSex == "F"
236+
237+
assert ds.StudyDescription == "Bilateral Screening Mammogram"
238+
assert ds.StudyInstanceUID == "1.2.3.4.5" # gitleaks:allow
239+
240+
scheduled_procedure_step = ds.ScheduledProcedureStepSequence[0]
241+
242+
assert scheduled_procedure_step.Modality == "MG"
243+
assert scheduled_procedure_step.ScheduledProcedureStepStartDate == "20260107"
244+
assert scheduled_procedure_step.ScheduledProcedureStepStartTime == "100000"
245+
assert scheduled_procedure_step.ScheduledProcedureStepID == "PROC001"
246+
assert scheduled_procedure_step.ScheduledStationAETitle is None
247+
assert scheduled_procedure_step.ScheduledStationName is None
248+
assert scheduled_procedure_step.ScheduledProtocolCodeSequence[0].CodeValue is None
249+
assert scheduled_procedure_step.ScheduledProtocolCodeSequence[0].CodingSchemeDesignator is None
250+
assert scheduled_procedure_step.ScheduledProtocolCodeSequence[0].CodeMeaning is None
251+
252+
assert ds.ReasonForRequestedProcedureCodeSequence[0].CodeValue is None
253+
assert ds.ReasonForRequestedProcedureCodeSequence[0].CodingSchemeDesignator is None
254+
assert ds.ReasonForRequestedProcedureCodeSequence[0].CodeMeaning is None
255+
256+
assert ds.RequestedProcedureCodeSequence[0].CodeValue == "PROC001"
257+
assert ds.RequestedProcedureCodeSequence[0].CodingSchemeDesignator is None
258+
assert ds.RequestedProcedureCodeSequence[0].CodeMeaning is None

0 commit comments

Comments
 (0)