PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::services::pir::patient_reconciliation_service Class Reference

#include <patient_reconciliation_service.h>

Collaboration diagram for kcenon::pacs::services::pir::patient_reconciliation_service:
Collaboration graph

Public Member Functions

 patient_reconciliation_service ()=default
 
bool add_instance (const core::dicom_dataset &dataset)
 Add a DICOM instance to the managed store.
 
reconciliation_result update_demographics (const demographics_update_request &request)
 Update patient demographics across all matching instances.
 
reconciliation_result merge_patients (const patient_merge_request &request)
 Merge instances from source patient to target patient.
 
std::vector< core::dicom_datasetfind_instances (const std::string &patient_id) const
 Find all instances for a given patient ID.
 
size_t instance_count () const noexcept
 Get the total number of managed instances.
 
std::vector< std::string > get_patient_ids () const
 Get distinct patient IDs in the store.
 
const std::vector< reconciliation_audit_record > & audit_trail () const noexcept
 Get the audit trail of reconciliation operations.
 
std::vector< reconciliation_audit_recordaudit_trail_for_patient (const std::string &patient_id) const
 Get audit records for a specific patient.
 

Private Member Functions

void apply_demographics (core::dicom_dataset &dataset, const patient_demographics &demographics) const
 
std::string generate_record_id () const
 

Private Attributes

std::vector< core::dicom_datasetinstances_
 
std::vector< reconciliation_audit_recordaudit_records_
 

Detailed Description

Definition at line 194 of file patient_reconciliation_service.h.

Constructor & Destructor Documentation

◆ patient_reconciliation_service()

kcenon::pacs::services::pir::patient_reconciliation_service::patient_reconciliation_service ( )
default

Member Function Documentation

◆ add_instance()

bool kcenon::pacs::services::pir::patient_reconciliation_service::add_instance ( const core::dicom_dataset & dataset)

Add a DICOM instance to the managed store.

Parameters
datasetThe DICOM dataset to add
Returns
true if added successfully
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 28 of file patient_reconciliation_service.cpp.

29 {
30
31 auto uid = dataset.get_string(tags::sop_instance_uid);
32 if (uid.empty()) {
33 return false;
34 }
35
36 instances_.push_back(dataset);
37 return true;
38}
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
std::string_view uid

References kcenon::pacs::core::dicom_dataset::get_string(), instances_, kcenon::pacs::core::tags::sop_instance_uid, and uid.

Here is the call graph for this function:

◆ apply_demographics()

void kcenon::pacs::services::pir::patient_reconciliation_service::apply_demographics ( core::dicom_dataset & dataset,
const patient_demographics & demographics ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 212 of file patient_reconciliation_service.cpp.

214 {
215
216 if (demographics.patient_name) {
217 dataset.set_string(tags::patient_name, vr_type::PN,
218 demographics.patient_name.value());
219 }
220 if (demographics.patient_id) {
221 dataset.set_string(tags::patient_id, vr_type::LO,
222 demographics.patient_id.value());
223 }
224 if (demographics.patient_birth_date) {
225 dataset.set_string(tags::patient_birth_date, vr_type::DA,
226 demographics.patient_birth_date.value());
227 }
228 if (demographics.patient_sex) {
229 dataset.set_string(tags::patient_sex, vr_type::CS,
230 demographics.patient_sex.value());
231 }
232 if (demographics.issuer_of_patient_id) {
233 dataset.set_string(tags::issuer_of_patient_id, vr_type::LO,
234 demographics.issuer_of_patient_id.value());
235 }
236}
constexpr dicom_tag issuer_of_patient_id
Issuer of Patient ID.
constexpr dicom_tag patient_id
Patient ID.
constexpr dicom_tag patient_birth_date
Patient's Birth Date.
constexpr dicom_tag patient_sex
Patient's Sex.
constexpr dicom_tag patient_name
Patient's Name.

References kcenon::pacs::core::tags::issuer_of_patient_id, kcenon::pacs::services::pir::patient_demographics::issuer_of_patient_id, kcenon::pacs::core::tags::patient_birth_date, kcenon::pacs::services::pir::patient_demographics::patient_birth_date, kcenon::pacs::core::tags::patient_id, kcenon::pacs::services::pir::patient_demographics::patient_id, kcenon::pacs::core::tags::patient_name, kcenon::pacs::services::pir::patient_demographics::patient_name, kcenon::pacs::core::tags::patient_sex, kcenon::pacs::services::pir::patient_demographics::patient_sex, and kcenon::pacs::core::dicom_dataset::set_string().

Referenced by merge_patients(), and update_demographics().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ audit_trail()

const std::vector< reconciliation_audit_record > & kcenon::pacs::services::pir::patient_reconciliation_service::audit_trail ( ) const
nodiscardnoexcept

Get the audit trail of reconciliation operations.

Returns
List of audit records
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 189 of file patient_reconciliation_service.cpp.

189 {
190 return audit_records_;
191}

References audit_records_.

◆ audit_trail_for_patient()

std::vector< reconciliation_audit_record > kcenon::pacs::services::pir::patient_reconciliation_service::audit_trail_for_patient ( const std::string & patient_id) const
nodiscard

Get audit records for a specific patient.

Parameters
patient_idPatient ID to filter by
Returns
Filtered audit records
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 194 of file patient_reconciliation_service.cpp.

195 {
196
197 std::vector<reconciliation_audit_record> results;
198 for (const auto& record : audit_records_) {
199 if (record.primary_patient_id == patient_id ||
200 (record.secondary_patient_id &&
201 record.secondary_patient_id.value() == patient_id)) {
202 results.push_back(record);
203 }
204 }
205 return results;
206}

References audit_records_.

◆ find_instances()

std::vector< core::dicom_dataset > kcenon::pacs::services::pir::patient_reconciliation_service::find_instances ( const std::string & patient_id) const
nodiscard

Find all instances for a given patient ID.

Parameters
patient_idPatient ID to search for
Returns
List of matching DICOM datasets
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 161 of file patient_reconciliation_service.cpp.

162 {
163
164 std::vector<core::dicom_dataset> results;
165 for (const auto& instance : instances_) {
166 if (instance.get_string(tags::patient_id) == patient_id) {
167 results.push_back(instance);
168 }
169 }
170 return results;
171}

References instances_, and kcenon::pacs::core::tags::patient_id.

◆ generate_record_id()

std::string kcenon::pacs::services::pir::patient_reconciliation_service::generate_record_id ( ) const
private
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 238 of file patient_reconciliation_service.cpp.

238 {
239 static std::mt19937_64 gen{std::random_device{}()};
240 static std::uniform_int_distribution<uint64_t> dist;
241
242 auto now = std::chrono::system_clock::now();
243 auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
244 now.time_since_epoch()).count();
245
246 return "PIR-" + std::to_string(timestamp) + "-" +
247 std::to_string(dist(gen) % 100000);
248}

Referenced by merge_patients(), and update_demographics().

Here is the caller graph for this function:

◆ get_patient_ids()

std::vector< std::string > kcenon::pacs::services::pir::patient_reconciliation_service::get_patient_ids ( ) const
nodiscard

Get distinct patient IDs in the store.

Returns
List of unique patient IDs
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 177 of file patient_reconciliation_service.cpp.

177 {
178 std::set<std::string> ids;
179 for (const auto& instance : instances_) {
180 auto pid = instance.get_string(tags::patient_id);
181 if (!pid.empty()) {
182 ids.insert(pid);
183 }
184 }
185 return {ids.begin(), ids.end()};
186}

References instances_, and kcenon::pacs::core::tags::patient_id.

◆ instance_count()

size_t kcenon::pacs::services::pir::patient_reconciliation_service::instance_count ( ) const
nodiscardnoexcept

Get the total number of managed instances.

Returns
Instance count
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 173 of file patient_reconciliation_service.cpp.

173 {
174 return instances_.size();
175}

References instances_.

◆ merge_patients()

reconciliation_result kcenon::pacs::services::pir::patient_reconciliation_service::merge_patients ( const patient_merge_request & request)
nodiscard

Merge instances from source patient to target patient.

All instances belonging to the source patient are reassigned to the target patient. The source patient effectively ceases to exist after the merge.

Parameters
requestPatient merge request
Returns
Result of the operation
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 91 of file patient_reconciliation_service.cpp.

92 {
93
94 reconciliation_result result;
96
97 if (request.source_patient_id.empty()) {
98 result.error_message = "Source patient ID is required";
99 return result;
100 }
101
102 if (request.target_patient_id.empty()) {
103 result.error_message = "Target patient ID is required";
104 return result;
105 }
106
107 if (request.source_patient_id == request.target_patient_id) {
108 result.error_message = "Source and target patient IDs must be different";
109 return result;
110 }
111
112 size_t updated = 0;
113 std::set<std::string> affected_studies;
114
115 for (auto& instance : instances_) {
116 auto pid = instance.get_string(tags::patient_id);
117 if (pid == request.source_patient_id) {
118 // Reassign to target patient
119 instance.set_string(tags::patient_id, vr_type::LO,
120 request.target_patient_id);
121
122 // Apply target demographics if provided
123 if (request.target_demographics) {
124 apply_demographics(instance, request.target_demographics.value());
125 }
126
127 updated++;
128
129 auto study_uid = instance.get_string(tags::study_instance_uid);
130 if (!study_uid.empty()) {
131 affected_studies.insert(study_uid);
132 }
133 }
134 }
135
136 if (updated == 0) {
137 result.error_message = "No instances found for source patient ID: " +
138 request.source_patient_id;
139 return result;
140 }
141
142 result.success = true;
143 result.instances_updated = updated;
144 result.studies_affected = affected_studies.size();
145
146 // Create audit record
147 reconciliation_audit_record audit;
148 audit.record_id = generate_record_id();
150 audit.primary_patient_id = request.target_patient_id;
151 audit.secondary_patient_id = request.source_patient_id;
152 audit.operator_name = request.operator_name.value_or("SYSTEM");
153 audit.instances_updated = updated;
154 audit.timestamp = std::chrono::system_clock::now();
155 audit.success = true;
156 audit_records_.push_back(std::move(audit));
157
158 return result;
159}
void apply_demographics(core::dicom_dataset &dataset, const patient_demographics &demographics) const
constexpr dicom_tag study_instance_uid
Study Instance UID.
@ patient_merge
ADT^A40: merge two patients.

References apply_demographics(), audit_records_, kcenon::pacs::services::pir::reconciliation_result::error_message, generate_record_id(), instances_, kcenon::pacs::services::pir::reconciliation_audit_record::instances_updated, kcenon::pacs::services::pir::reconciliation_result::instances_updated, kcenon::pacs::services::pir::patient_merge_request::operator_name, kcenon::pacs::services::pir::reconciliation_audit_record::operator_name, kcenon::pacs::core::tags::patient_id, kcenon::pacs::services::pir::patient_merge, kcenon::pacs::services::pir::reconciliation_audit_record::primary_patient_id, kcenon::pacs::services::pir::reconciliation_audit_record::record_id, kcenon::pacs::services::pir::reconciliation_audit_record::secondary_patient_id, kcenon::pacs::services::pir::patient_merge_request::source_patient_id, kcenon::pacs::services::pir::reconciliation_result::studies_affected, kcenon::pacs::core::tags::study_instance_uid, kcenon::pacs::services::pir::reconciliation_audit_record::success, kcenon::pacs::services::pir::reconciliation_result::success, kcenon::pacs::services::pir::patient_merge_request::target_demographics, kcenon::pacs::services::pir::patient_merge_request::target_patient_id, kcenon::pacs::services::pir::reconciliation_audit_record::timestamp, kcenon::pacs::services::pir::reconciliation_audit_record::type, and kcenon::pacs::services::pir::reconciliation_result::type.

Here is the call graph for this function:

◆ update_demographics()

reconciliation_result kcenon::pacs::services::pir::patient_reconciliation_service::update_demographics ( const demographics_update_request & request)
nodiscard

Update patient demographics across all matching instances.

Finds all instances with the specified patient ID and updates the patient-level attributes with the new values.

Parameters
requestDemographics update request
Returns
Result of the operation
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/pir/patient_reconciliation_service.h.

Definition at line 40 of file patient_reconciliation_service.cpp.

41 {
42
43 reconciliation_result result;
45
46 if (request.target_patient_id.empty()) {
47 result.error_message = "Target patient ID is required";
48 return result;
49 }
50
51 size_t updated = 0;
52 std::set<std::string> affected_studies;
53
54 for (auto& instance : instances_) {
55 auto pid = instance.get_string(tags::patient_id);
56 if (pid == request.target_patient_id) {
57 apply_demographics(instance, request.updated_demographics);
58 updated++;
59
60 auto study_uid = instance.get_string(tags::study_instance_uid);
61 if (!study_uid.empty()) {
62 affected_studies.insert(study_uid);
63 }
64 }
65 }
66
67 if (updated == 0) {
68 result.error_message = "No instances found for patient ID: " +
69 request.target_patient_id;
70 return result;
71 }
72
73 result.success = true;
74 result.instances_updated = updated;
75 result.studies_affected = affected_studies.size();
76
77 // Create audit record
78 reconciliation_audit_record audit;
79 audit.record_id = generate_record_id();
81 audit.primary_patient_id = request.target_patient_id;
82 audit.operator_name = request.operator_name.value_or("SYSTEM");
83 audit.instances_updated = updated;
84 audit.timestamp = std::chrono::system_clock::now();
85 audit.success = true;
86 audit_records_.push_back(std::move(audit));
87
88 return result;
89}
@ demographics_update
ADT^A08: update patient demographics.

References apply_demographics(), audit_records_, kcenon::pacs::services::pir::demographics_update, kcenon::pacs::services::pir::reconciliation_result::error_message, generate_record_id(), instances_, kcenon::pacs::services::pir::reconciliation_audit_record::instances_updated, kcenon::pacs::services::pir::reconciliation_result::instances_updated, kcenon::pacs::services::pir::demographics_update_request::operator_name, kcenon::pacs::services::pir::reconciliation_audit_record::operator_name, kcenon::pacs::core::tags::patient_id, kcenon::pacs::services::pir::reconciliation_audit_record::primary_patient_id, kcenon::pacs::services::pir::reconciliation_audit_record::record_id, kcenon::pacs::services::pir::reconciliation_result::studies_affected, kcenon::pacs::core::tags::study_instance_uid, kcenon::pacs::services::pir::reconciliation_audit_record::success, kcenon::pacs::services::pir::reconciliation_result::success, kcenon::pacs::services::pir::demographics_update_request::target_patient_id, kcenon::pacs::services::pir::reconciliation_audit_record::timestamp, kcenon::pacs::services::pir::reconciliation_audit_record::type, kcenon::pacs::services::pir::reconciliation_result::type, and kcenon::pacs::services::pir::demographics_update_request::updated_demographics.

Here is the call graph for this function:

Member Data Documentation

◆ audit_records_

std::vector<reconciliation_audit_record> kcenon::pacs::services::pir::patient_reconciliation_service::audit_records_
private

◆ instances_


The documentation for this class was generated from the following files: