his_emr_api_lab 0.0.3 → 0.0.4

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: 778184a052cac6932ec700f03b99615024440af3944c371d0cfa997f357c525c
4
- data.tar.gz: 045fb73daab53abc457c08152c5148251a6dccb239f0c76e09f3172007e44b6e
3
+ metadata.gz: f53ca7acc69718ba31cf2ae278b6fdbdc4996d3ad6a28db0a08d3945d1463998
4
+ data.tar.gz: 77b2cfdc430706b9864e9ec71b2f4b64c2ec11a5695b45b81984c86a8fefefd4
5
5
  SHA512:
6
- metadata.gz: 95f56b7a5d1b36565074904d49e5ff69b34fb57bed690a7bec5d269749c6813e094b4e02b397517523edd90e0714710376f489338788838fad775f3c724659db
7
- data.tar.gz: 380096a9132eb857a4a321260593640eec0d6a5b08f661e97a1ba2396619eb5984c1aca488e364930dff737ff397b07865597b9ed321c7a93101c151a8d2566f
6
+ metadata.gz: 19f53f3c471dd4552f64bf1200a6bbd8051e7bc7bc7e0670b2079bea4af61621575a9c0e7f5cdc06c43ac7b80c2534e6ca704fd06e43b0deed3475ea66690017
7
+ data.tar.gz: cbe4e02964f635b60e7e7b0c6b53ac3b406ab9bff55da582371a3de38a8d65901bcca1771a7b3cf0d8be83e31ac8bf0a15e9c752f7131bb631f1011df95fa713
@@ -29,16 +29,11 @@ module Lab
29
29
  # given block until the queue is empty or connection is terminated
30
30
  # by calling method +choke+.
31
31
  def consume_orders(from: 0, limit: 30)
32
- last_seq = { value: 0 }
33
-
34
32
  bum.binge_changes(since: from, limit: limit, include_docs: true) do |change|
35
33
  next unless change['doc']['type']&.casecmp?('Order')
36
34
 
37
35
  yield OrderDTO.new(change['doc']), self
38
- last_seq[:value] = self.last_seq
39
36
  end
40
-
41
- last_seq[:value]
42
37
  end
43
38
 
44
39
  def create_order(order)
@@ -29,6 +29,7 @@ require 'lab/lab_test'
29
29
  require 'lab/lims_order_mapping'
30
30
  require 'lab/lims_failed_import'
31
31
 
32
+ require_relative './worker'
32
33
  require_relative '../orders_service'
33
34
  require_relative '../results_service'
34
35
  require_relative '../tests_service'
@@ -47,14 +48,16 @@ module Lab
47
48
 
48
49
  attr_reader :rejections
49
50
 
50
- def consume_orders(from: nil, limit: 50_000)
51
+ def consume_orders(from: nil, **_kwargs)
52
+ limit = 50_000
53
+
51
54
  Parallel.each(read_orders(from, limit),
52
55
  in_processes: MAX_THREADS,
53
56
  finish: order_pmap_post_processor(from)) do |row|
54
57
  next unless row['doc']['type']&.casecmp?('Order')
55
58
 
56
- User.current = Migrator.lab_user
57
- yield OrderDTO.new(row['doc']), OpenStruct.new(last_seq: from)
59
+ User.current = Utils.lab_user
60
+ yield OrderDTO.new(row['doc']), OpenStruct.new(last_seq: (from || 0) + limit, current_seq: from)
58
61
  end
59
62
  end
60
63
 
@@ -70,7 +73,7 @@ module Lab
70
73
  private
71
74
 
72
75
  def last_seq_path
73
- Rails.root.join('log/lims/migration-last-id.dat')
76
+ LIMS_LOG_PATH.join('migration-last-id.dat')
74
77
  end
75
78
 
76
79
  def order_pmap_post_processor(last_seq)
@@ -129,18 +132,6 @@ module Lab
129
132
  def update_last_seq(_last_seq); end
130
133
  end
131
134
 
132
- def self.lab_user
133
- user = User.find_by_username('lab_daemon')
134
- return user if user
135
-
136
- god_user = User.first
137
-
138
- person = Person.create!(creator: god_user.user_id)
139
- PersonName.create!(person: person, given_name: 'Lab', family_name: 'Daemon', creator: god_user.user_id)
140
-
141
- User.create!(username: 'lab_daemon', person: person, creator: god_user.user_id)
142
- end
143
-
144
135
  def self.save_csv(filename, rows:, headers: nil)
145
136
  CSV.open(filename, File::WRONLY | File::CREAT) do |csv|
146
137
  csv << headers if headers
@@ -148,7 +139,7 @@ module Lab
148
139
  end
149
140
  end
150
141
 
151
- MIGRATION_REJECTIONS_CSV_PATH = Rails.root.join('log/lims/migration-rejections.csv')
142
+ MIGRATION_REJECTIONS_CSV_PATH = LIMS_LOG_PATH.join('migration-rejections.csv')
152
143
 
153
144
  def self.export_rejections(rejections)
154
145
  headers = ['Accession number', 'NHID', 'First name', 'Last name', 'Reason']
@@ -165,7 +156,7 @@ module Lab
165
156
  save_csv(MIGRATION_REJECTIONS_CSV_PATH, headers: headers, rows: rows)
166
157
  end
167
158
 
168
- MIGRATION_FAILURES_CSV_PATH = Rails.root.join('log/lims/migration-failures.csv')
159
+ MIGRATION_FAILURES_CSV_PATH = LIMS_LOG_PATH.join('migration-failures.csv')
169
160
 
170
161
  def self.export_failures
171
162
  headers = ['Accession number', 'NHID', 'Reason', 'Difference']
@@ -181,7 +172,7 @@ module Lab
181
172
  save_csv(MIGRATION_FAILURES_CSV_PATH, headers: headers, rows: rows)
182
173
  end
183
174
 
184
- MIGRATION_LOG_PATH = Rails.root.join('log/lims/migration.log')
175
+ MIGRATION_LOG_PATH = LIMS_LOG_PATH.join('migration.log')
185
176
 
186
177
  def self.start_migration
187
178
  log_dir = Rails.root.join('log/lims')
@@ -97,7 +97,9 @@ module Lab
97
97
  end
98
98
 
99
99
  def format_test_results(order)
100
- order.tests.each_with_object({}) do |test, results|
100
+ order.tests&.each_with_object({}) do |test, results|
101
+ next unless test.result
102
+
101
103
  results[test.name] = {
102
104
  results: test.result.each_with_object({}) do |measure, measures|
103
105
  measures[measure.indicator.name] = { result_value: "#{measure.value_modifier}#{measure.value}" }
@@ -39,6 +39,18 @@ module Lab
39
39
  end
40
40
  end
41
41
 
42
+ def self.lab_user
43
+ user = User.find_by_username('lab_daemon')
44
+ return user if user
45
+
46
+ god_user = User.first
47
+
48
+ person = Person.create!(creator: god_user.user_id)
49
+ PersonName.create!(person: person, given_name: 'Lab', family_name: 'Daemon', creator: god_user.user_id)
50
+
51
+ User.create!(username: 'lab_daemon', person: person, creator: god_user.user_id)
52
+ end
53
+
42
54
  def self.parse_date(str_date, fallback_date = nil)
43
55
  if str_date.blank? && fallback_date.blank?
44
56
  raise "Can't parse blank date"
@@ -2,12 +2,16 @@
2
2
 
3
3
  require 'cgi/util'
4
4
 
5
+ require_relative './api'
5
6
  require_relative './exceptions'
6
7
  require_relative './order_serializer'
7
8
  require_relative './utils'
8
9
 
9
10
  module Lab
10
11
  module Lims
12
+ LIMS_LOG_PATH = Rails.root.join('log/lims')
13
+ Dir.mkdir(LIMS_LOG_PATH) unless File.exist?(LIMS_LOG_PATH)
14
+
11
15
  ##
12
16
  # Pull/Push orders from/to the LIMS queue (Oops meant CouchDB).
13
17
  class Worker
@@ -15,6 +19,19 @@ module Lab
15
19
 
16
20
  attr_reader :lims_api
17
21
 
22
+ def self.start
23
+ File.open(LIMS_LOG_PATH.join('worker.lock'), File::WRONLY | File::CREAT, 0o644) do |fout|
24
+ fout.flock(File::LOCK_EX)
25
+
26
+ User.current = Utils.lab_user
27
+
28
+ fout.write("Worker ##{Process.pid} started at #{Time.now}")
29
+ worker = new(Api.new)
30
+ worker.pull_orders
31
+ worker.push_orders
32
+ end
33
+ end
34
+
18
35
  def initialize(lims_api)
19
36
  @lims_api = lims_api
20
37
  end
@@ -52,8 +69,8 @@ module Lab
52
69
  lims_api.update_order(mapping.lims_id, order_dto)
53
70
  mapping.update(pushed_at: Time.now)
54
71
  else
55
- order_dto = lims_api.create_order(order_dto)
56
- LimsOrderMapping.create!(order: order, lims_id: order_dto['_id'], pushed_at: Time.now)
72
+ update = lims_api.create_order(order_dto)
73
+ LimsOrderMapping.create!(order: order, lims_id: update['id'], revision: update['rev'], pushed_at: Time.now)
57
74
  end
58
75
  end
59
76
 
@@ -64,7 +81,8 @@ module Lab
64
81
  # Pulls orders from the LIMS queue and writes them to the local database
65
82
  def pull_orders
66
83
  logger.info("Retrieving LIMS orders starting from #{last_seq}")
67
- lims_api.consume_orders(from: last_seq) do |order_dto, context|
84
+
85
+ lims_api.consume_orders(from: last_seq, limit: 100) do |order_dto, context|
68
86
  logger.debug("Retrieved order ##{order_dto[:tracking_number]}: #{order_dto}")
69
87
 
70
88
  patient = find_patient_by_nhid(order_dto[:patient][:id])
@@ -80,6 +98,8 @@ module Lab
80
98
  save_failed_import(order_dto, 'Demographics not matching', diff)
81
99
  end
82
100
 
101
+ update_last_seq(context.current_seq)
102
+
83
103
  [:accepted, "Patient NPID, '#{order_dto[:patient][:id]}', matched"]
84
104
  rescue DuplicateNHID
85
105
  logger.warn("Failed to import order due to duplicate patient NHID: #{order_dto[:patient][:id]}")
@@ -90,8 +110,6 @@ module Lab
90
110
  rescue LimsException => e
91
111
  logger.warn("Failed to import order due to #{e.class} - #{e.message}")
92
112
  save_failed_import(order_dto, e.message)
93
- ensure
94
- update_last_seq(context.last_seq)
95
113
  end
96
114
  end
97
115
 
@@ -303,7 +321,7 @@ module Lab
303
321
  end
304
322
 
305
323
  def last_seq_path
306
- Rails.root.join('log/lims/last-seq.dat')
324
+ LIMS_LOG_PATH.join('last_seq.dat')
307
325
  end
308
326
  end
309
327
  end
@@ -24,18 +24,21 @@ class CouchBum
24
24
  # within the passed block.
25
25
  def binge_changes(since: 0, limit: nil, include_docs: nil, &block)
26
26
  catch(:choke) do
27
- extra_params = stringify_params(limit: limit, include_docs: include_docs)
27
+ logger.debug("Binging #{limit} changes from '#{since}'")
28
+ params = stringify_params(limit: limit, include_docs: include_docs)
29
+ params = "since=#{since}&#{params}" unless since.blank?
28
30
 
29
- changes = couch_rest(:get, "_changes?since=#{since}&#{extra_params}")
31
+ changes = couch_rest(:get, "_changes?#{params}")
30
32
  context = BingeContext.new(changes)
31
- changes['results'].each { |change| context.instance_exec(change, &block) }
33
+ changes['results'].each do |change|
34
+ context.current_seq = change['seq']
35
+ context.instance_exec(change, &block)
36
+ end
32
37
  end
33
38
  end
34
39
 
35
40
  def couch_rest(method, route, *args, **kwargs)
36
41
  url = expand_route(route)
37
-
38
- logger.debug("CouchBum: Executing #{method} #{url}")
39
42
  CouchRest.send(method, url, *args, **kwargs)
40
43
  rescue CouchRest::Exception => e
41
44
  logger.error("Failed to communicate with CouchDB: Status: #{e.http_code} - #{e.http_body}")
@@ -46,6 +49,8 @@ class CouchBum
46
49
 
47
50
  # Context under which the callback passed to binge_changes is executed.
48
51
  class BingeContext
52
+ attr_accessor :current_seq
53
+
49
54
  def initialize(changes)
50
55
  @changes = changes
51
56
  end
data/lib/lab/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lab
4
- VERSION = '0.0.3'
4
+ VERSION = '0.0.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: his_emr_api_lab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elizabeth Glaser Pediatric Foundation Malawi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-18 00:00:00.000000000 Z
11
+ date: 2021-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: couchrest