openmrs_data_sanitizer 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45352f6a9ff782926a46e2e93973f3a7873b8316bf482481d09c1543de7b958c
4
- data.tar.gz: ef10ff0800b3895cd22de64c0171255d3870888b15fb302d41f4c0fff5acc89d
3
+ metadata.gz: ea1ff9af55bd7fa8cc3659a91ffd9995cb6f91b7b5c1297b31c99fbb7c264f5d
4
+ data.tar.gz: 5fe2a537ea70364ab0d3dd5da607f12627799154d46f14581527f6a38ac39eea
5
5
  SHA512:
6
- metadata.gz: a931566411fae2f5cf78b5e59757a9ae7c2610c6916d67610623a8906cd1865c94b3c2bca2adda5ca9737e601a4d983e1a36349ad305ce7beb4a186905d22e33
7
- data.tar.gz: 9748ee31837097d5f9d4c1210f79b569f678dc78feb7a841c7cac65b5a9332e03cb12f2805727d9b89c7c273f2f38d464253edc9e6fd3785029f1cc433d41fa4
6
+ metadata.gz: d20b6330c65ec39e01f0602dd540c9c8f77df1670a28efc581bf08918957c6620a83eaf2944065757d6714ae0507d63669adb7f40b2e2746d4f6e9444e43c094
7
+ data.tar.gz: 1382c14116c18556c52c47da591095250dbf44fff7ace6dfbf37f3bad4ad8310bd75dedff4e1c5ab0b578ac69e06913c90751be73944f538317ce5fb09e0a0e9
@@ -681,7 +681,7 @@ module OpenmrsDataSanitizer
681
681
  FROM #{schema}.encounter e
682
682
  INNER JOIN #{schema}.obs ON e.encounter_id = obs.encounter_id AND obs.voided = 0 AND obs.concept_id = 5090 -- Height concept_id
683
683
  WHERE e.voided = 0 and e.encounter_type = 6 and e.program_id = 1
684
- GROUP BY obs.person_id, DATE(obs.obs_datetime);
684
+ GROUP BY e.patient_id, DATE(obs.obs_datetime);
685
685
  SQL
686
686
  end
687
687
 
@@ -694,7 +694,7 @@ module OpenmrsDataSanitizer
694
694
  AND obs.voided = 0
695
695
  AND obs.concept_id = 5089
696
696
  WHERE e.voided = 0 and e.encounter_type = 6 and e.program_id = 1
697
- GROUP BY obs.person_id, DATE(obs.obs_datetime);
697
+ GROUP BY e.patient_id, DATE(obs.obs_datetime);
698
698
  SQL
699
699
  end
700
700
 
@@ -808,37 +808,35 @@ module OpenmrsDataSanitizer
808
808
  AND obs.voided = 0
809
809
  AND obs.concept_id = 5096
810
810
  WHERE e.voided = 0 and e.encounter_type = 7 and e.program_id = 1
811
- GROUP BY obs.person_id, DATE(obs.obs_datetime);
811
+ GROUP BY e.patient_id, DATE(obs.obs_datetime);
812
812
  SQL
813
813
  end
814
814
 
815
815
  def insert_data_sanitizer_arv_medication
816
816
  ActiveRecord::Base.connection.execute <<~SQL
817
817
  INSERT INTO #{schema}.data_sanitizer_arv_medication (patient_id, order_id, visit_date, drug_runout_date, num_unique_arvs, unique_arvs_given, drug_names)
818
- SELECT e.patient_id, o.order_id, DATE(o.start_date) AS visit_date, DATE(MIN(o.auto_expire_date)) AS drug_runout_date,
818
+ SELECT o.patient_id, o.order_id, DATE(o.start_date) AS visit_date, DATE(MIN(o.auto_expire_date)) AS drug_runout_date,
819
819
  COUNT(DISTINCT d.drug_id) AS num_unique_arvs,GROUP_CONCAT(DISTINCT d.drug_id SEPARATOR ', ') AS unique_arvs_given,
820
820
  GROUP_CONCAT(DISTINCT d.name SEPARATOR ', ') AS drug_names
821
821
  FROM #{schema}.orders o
822
822
  INNER JOIN #{schema}.drug_order da ON da.order_id = o.order_id AND o.voided = 0 AND da.quantity > 0
823
823
  INNER JOIN #{schema}.drug d ON d.drug_id = da.drug_inventory_id
824
- INNER JOIN #{schema}.obs ON obs.order_id = o.order_id AND obs.voided = 0
825
- INNER JOIN #{schema}.encounter e ON e.program_id = 1 AND e.encounter_id = obs.encounter_id AND e.encounter_type = 54
824
+ INNER JOIN #{schema}.encounter e ON e.program_id = 1 AND e.encounter_id = o.encounter_id AND e.encounter_type = 54
826
825
  INNER JOIN #{schema}.arv_drug ON arv_drug.drug_id = d.drug_id
827
- GROUP BY obs.person_id, o.order_id, DATE(o.start_date);
826
+ GROUP BY o.patient_id, DATE(o.start_date);
828
827
  SQL
829
828
  end
830
829
 
831
830
  def insert_data_sanitizer_arv_orders
832
831
  ActiveRecord::Base.connection.execute <<~SQL
833
832
  INSERT INTO #{schema}.data_sanitizer_arv_orders(patient_id, order_id, encounter_id, visit_date, drug_id, drug_name, units, equivalent_daily_dose, instructions, start_date, runout_date, quantity)
834
- SELECT m.patient_id, o.order_id, orders.encounter_id , m.visit_date,
835
- d.drug_id, d.name, d.units, o.equivalent_daily_dose, orders.instructions,
836
- orders.start_date, orders.auto_expire_date,SUM(o.quantity)
837
- FROM #{schema}.data_sanitizer_arv_medication m
838
- INNER JOIN #{schema}.drug_order o ON o.order_id = m.order_id
839
- INNER JOIN #{schema}.drug d ON d.drug_id = o.drug_inventory_id
840
- INNER JOIN #{schema}.orders ON orders.order_id = o.order_id
841
- GROUP BY d.drug_id, o.order_id, m.visit_date;
833
+ SELECT e.patient_id, o.order_id, o.encounter_id, DATE(o.start_date) AS visit_date, da.drug_inventory_id AS drug_id, d.name AS drug_name, d.units, da.equivalent_daily_dose, o.instructions, DATE(o.start_date), DATE(o.auto_expire_date), da.quantity
834
+ FROM #{schema}.orders o
835
+ INNER JOIN #{schema}.encounter e ON e.encounter_id = o.encounter_id AND e.program_id = 1 AND e.encounter_type = 54
836
+ INNER JOIN #{schema}.drug_order da ON da.order_id = o.order_id AND o.voided = 0 AND da.quantity > 0
837
+ INNER JOIN #{schema}.drug d ON d.drug_id = da.drug_inventory_id
838
+ INNER JOIN #{schema}.arv_drug ad ON ad.drug_id = d.drug_id
839
+ WHERE o.voided = 0
842
840
  SQL
843
841
  end
844
842
 
@@ -13,13 +13,14 @@ module OpenmrsDataSanitizer
13
13
  # rubocop:disable Metrics/ClassLength
14
14
  # AWS DataSanitizer
15
15
  class DataSanitizer
16
- attr_accessor :regimen_combinations, :concept_names, :faker_names, :sites
16
+ attr_accessor :regimen_combinations, :concept_names, :faker_names, :sites, :skip
17
17
 
18
- def initialize(sites: [])
18
+ def initialize(sites: [], skip: true)
19
19
  @concept_names = Concurrent::Hash.new
20
20
  @faker_names = Concurrent::Hash.new
21
21
  @regimen_combinations = {}
22
22
  @sites = sites
23
+ @skip = skip
23
24
  load_regimen_combinations
24
25
  end
25
26
 
@@ -47,7 +48,7 @@ module OpenmrsDataSanitizer
47
48
  queue = Queue.new
48
49
  sites.each { |loc| queue << loc }
49
50
 
50
- threads = Array.new(10) do
51
+ threads = Array.new(60) do
51
52
  Thread.new do
52
53
  until queue.empty?
53
54
  loc = begin
@@ -57,29 +58,24 @@ module OpenmrsDataSanitizer
57
58
  end
58
59
  next unless loc
59
60
 
60
- thread_variables # Set thread variables before processing
61
61
  process_location(loc) # Process location
62
- write_data_to_files # Write data to files
63
- clear_thread_variables # Clear thread variables after processing
64
62
  end
65
63
  end
66
64
  end
67
65
 
68
66
  threads.each(&:join)
67
+ close_files
69
68
  end
70
69
 
71
- def thread_variables
72
- Thread.current[:fhir_encounters] = Concurrent::Array.new
73
- Thread.current[:fhir_observations] = Concurrent::Array.new
74
- Thread.current[:fhir_medication_dispense] = Concurrent::Array.new
75
- Thread.current[:patients_json] = Concurrent::Array.new
76
- end
77
-
78
- def clear_thread_variables
79
- Thread.current[:fhir_encounters] = nil
80
- Thread.current[:fhir_observations] = nil
81
- Thread.current[:fhir_medication_dispense] = nil
82
- Thread.current[:patients_json] = nil
70
+ def close_files
71
+ dir_path = Rails.root.join('log/openmrs_data_sanitizer')
72
+ file_path = dir_path.join('*.json')
73
+ Dir[file_path].each do |file|
74
+ # Remove trailing comma and append closing bracket
75
+ system("sed -i '$s/,$/]/' #{file}")
76
+ # Log the file closure
77
+ Rails.logger.info "Closed file: #{file}"
78
+ end
83
79
  end
84
80
 
85
81
  def process_location(loc)
@@ -90,7 +86,7 @@ module OpenmrsDataSanitizer
90
86
  site_name = site['facility']
91
87
  schema = site['schema']
92
88
 
93
- OpenmrsDataSanitizer::DataAggregator.new(schema:).aggregate
89
+ OpenmrsDataSanitizer::DataAggregator.new(schema:).aggregate unless skip
94
90
 
95
91
  process_patients(schema, site_name)
96
92
  rescue StandardError => e
@@ -109,13 +105,6 @@ module OpenmrsDataSanitizer
109
105
  process_medication(schema:)
110
106
  end
111
107
 
112
- def write_data_to_files
113
- write_to_file(Thread.current[:patients_json].to_json, 'patients') unless Thread.current[:patients_json].blank?
114
- write_to_file(Thread.current[:fhir_encounters].to_json, 'visits') unless Thread.current[:fhir_encounters].blank?
115
- write_to_file(Thread.current[:fhir_observations].to_json, 'observations') unless Thread.current[:fhir_observations].blank?
116
- write_to_file(Thread.current[:fhir_medication_dispense].to_json, 'medications') unless Thread.current[:fhir_medication_dispense].blank?
117
- end
118
-
119
108
  # ===================================
120
109
  # REGION: REGIMEN COMBINATIONS
121
110
  # ===================================
@@ -156,14 +145,14 @@ module OpenmrsDataSanitizer
156
145
 
157
146
  # rubocop:disable Metrics/AbcSize
158
147
  def build_patient_json(patient, site_name)
159
- patient_id = patient['person_id'].to_i
160
- village_name = get_or_generate_faker_value(patient['village_name'], Faker::Address, :community)
161
- cell_number = get_or_generate_faker_value(patient['phone_number'], Faker::PhoneNumber, :phone_number)
162
- family_name = get_or_generate_faker_value(patient['family_name'], Faker::Name, :last_name)
163
- given_name = get_or_generate_faker_value(patient['given_name'], Faker::Name, :first_name)
164
- middle_name = get_or_generate_faker_value(patient['middle_name'], Faker::Name, :middle_name)
165
-
166
- Thread.current[:patients_json] << FHIR::Patient.new(
148
+ patient_id = patient['patient_id'].to_i
149
+ village_name = get_or_generate_faker_value(patient['village_name']&.titlecase, Faker::Address, :community)
150
+ cell_number = get_or_generate_faker_value(patient['phone_number']&.titlecase, Faker::PhoneNumber, :phone_number)
151
+ family_name = get_or_generate_faker_value(patient['family_name']&.titlecase, Faker::Name, :last_name)
152
+ given_name = get_or_generate_faker_value(patient['given_name']&.titlecase, Faker::Name, :first_name)
153
+ middle_name = get_or_generate_faker_value(patient['middle_name']&.titlecase, Faker::Name, :middle_name)
154
+
155
+ fhir_patient = FHIR::Patient.new(
167
156
  id: patient_id,
168
157
  identifier: [{ system: "#{site_name}_#{patient_id}", value: patient_id }],
169
158
  name: [{ use: 'official', family: family_name, given: [given_name, middle_name] }],
@@ -172,6 +161,7 @@ module OpenmrsDataSanitizer
172
161
  address: [{ use: 'home', village: village_name }],
173
162
  telecom: [{ system: 'phone', value: cell_number, use: 'mobile' }]
174
163
  )
164
+ write_to_file(fhir_patient.to_json, 'patients') unless fhir_patient.blank?
175
165
  end
176
166
 
177
167
  def fetch_gender(gender:)
@@ -213,10 +203,11 @@ module OpenmrsDataSanitizer
213
203
 
214
204
  def aws_fhir_encounter(visit:, regimen:)
215
205
  patient_id = visit['patient_id'].to_i
216
- Thread.current[:fhir_encounters] << create_fhir_encounter(patient_id, visit['visit_date'])
206
+ fhir_encounter = create_fhir_encounter(patient_id, visit['visit_date'])
207
+ write_to_file(fhir_encounter.to_json, 'visits') unless fhir_encounter.blank?
217
208
 
218
209
  observations = process_indicators(visit, regimen)
219
- create_fhir_observations(observations, patient_id, visit['visit_date'])
210
+ create_fhir_observations(observations, patient_id, visit['visit_date'], fhir_encounter.id)
220
211
  end
221
212
 
222
213
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@@ -276,11 +267,11 @@ module OpenmrsDataSanitizer
276
267
  end
277
268
 
278
269
  # rubocop:disable Metrics/PerceivedComplexity
279
- def create_fhir_observations(observations, patient_id, visit_date)
270
+ def create_fhir_observations(observations, patient_id, visit_date, encounter_id)
280
271
  observations.each do |obs|
281
272
  next if obs.blank? || obs[:code].blank? || obs[:value].blank?
282
273
 
283
- Thread.current[:fhir_observations] << FHIR::Observation.new(
274
+ fhir_obs = FHIR::Observation.new(
284
275
  status: 'final',
285
276
  code: {
286
277
  coding: [
@@ -295,20 +286,19 @@ module OpenmrsDataSanitizer
295
286
  reference: "Patient/#{patient_id}"
296
287
  },
297
288
  encounter: {
298
- reference: "Encounter/#{Thread.current[:fhir_encounters].last.id}"
289
+ reference: "Encounter/#{encounter_id}"
299
290
  },
300
291
  effectiveDateTime: visit_date
301
292
  )
302
-
303
293
  if obs[:unit]
304
- Thread.current[:fhir_observations].last.valueQuantity = {
294
+ fhir_obs.valueQuantity = {
305
295
  value: obs[:value],
306
296
  unit: obs[:unit],
307
297
  system: 'EGPAF Malawi EMR',
308
298
  code: obs[:code]
309
299
  }
310
300
  else
311
- Thread.current[:fhir_observations].last.valueCodeableConcept = {
301
+ fhir_obs.valueCodeableConcept = {
312
302
  coding: [
313
303
  {
314
304
  system: 'EGPAF Malawi EMR',
@@ -322,6 +312,7 @@ module OpenmrsDataSanitizer
322
312
  ]
323
313
  }
324
314
  end
315
+ write_to_file(fhir_obs.to_json, 'observations') unless fhir_obs.blank?
325
316
  end
326
317
  end
327
318
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/BlockLength, Metrics/PerceivedComplexity
@@ -343,8 +334,8 @@ module OpenmrsDataSanitizer
343
334
 
344
335
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/BlockLength
345
336
  def create_fhir_medications(orders:)
346
- Thread.current[:fhir_medication_dispense] << (orders || []).map do |order|
347
- FHIR::MedicationDispense.new(
337
+ (orders || []).each do |order|
338
+ fhir_med = FHIR::MedicationDispense.new(
348
339
  identifier: {
349
340
  value: order['order_id'].to_i
350
341
  },
@@ -386,6 +377,7 @@ module OpenmrsDataSanitizer
386
377
  }
387
378
  }
388
379
  )
380
+ write_to_file(fhir_med.to_json, 'medications') unless fhir_med.blank?
389
381
  end
390
382
  end
391
383
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/BlockLength
@@ -420,14 +412,15 @@ module OpenmrsDataSanitizer
420
412
 
421
413
  # Use the mutex to handle concurrent writes
422
414
  FILE_MUTEX.synchronize do
423
- if File.exist?(file_path)
424
- system("sed -i '$s/\([][^{},]\)$/,/g' #{file_path}")
425
- json_file.sub!('[', '')
426
- Rails.logger.info "Removed last bracket from file: #{file_path}"
415
+ if !File.exist?(file_path)
416
+ File.open(file_path, 'w') do |out_file|
417
+ out_file.puts('[')
418
+ Rails.logger.info "Created file: #{file_path}"
419
+ end
427
420
  end
428
421
 
429
422
  File.open(file_path, 'a') do |out_file|
430
- out_file.puts(json_file)
423
+ out_file.puts("#{json_file},")
431
424
  Rails.logger.info "Appended to file: #{file_path}"
432
425
  end
433
426
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenmrsDataSanitizer
4
- VERSION = '1.0.6'
4
+ VERSION = '1.0.7'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openmrs_data_sanitizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mwatha
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-03 00:00:00.000000000 Z
11
+ date: 2024-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -142,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
142
  - !ruby/object:Gem::Version
143
143
  version: '0'
144
144
  requirements: []
145
- rubygems_version: 3.5.17
145
+ rubygems_version: 3.4.1
146
146
  signing_key:
147
147
  specification_version: 4
148
148
  summary: This gem will mask all patient identifyable data before exporting to AWS