his_emr_api_lab 2.1.9.pre.alpha → 2.1.9.pre.beta

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: cfef9418fc9d94d233f24d04883623d67e0c59c2aacea66bc15d3cca61192f78
4
- data.tar.gz: 2d6324bf11f30c87398819042e3a0835275596961bfd838d088a63ae7a4f93c2
3
+ metadata.gz: c6c20f1ba07edd60ba5795eaaef1ca3f34395060b1f9ed0160a5513777d657d0
4
+ data.tar.gz: d16b695b3592233474fa9bbc2f90c85db7d04161a02f8107c56f92fd4e82a9fb
5
5
  SHA512:
6
- metadata.gz: c7eaa989ae6027aaba3bcd29e90136d1f93eda66854f7ee5bf84453420e0c66a40a928e460e00ee48bdee3fac8e2de05b7c030a7c71c8d4a6bf9457704dc7c6f
7
- data.tar.gz: 16048c52a25d2876d79d6b3526b13625c67de47c44717de48910f905a75bb02dbd1cd48d7ce22e8b58947e61a1cb603340ea3bbdb1cce7536bb1774f41a72d65
6
+ metadata.gz: 035cf4578ee6f60ba3406a66f88ea33cc54ea7d85ab38524b7e6ae54c9b4b80e03fe2938fc34d047e72df9423b71b8eba1f40004a8fd688555b56c3aebb81605
7
+ data.tar.gz: feda70dff8797923f46078a42429b274d7562eb5105a5d43c1d746f744436c6c516847aa2ef68d7b235f1d1a216981e10d4c707bc6f4fb45372d6b867c412a2a
data/README.md CHANGED
@@ -22,25 +22,25 @@ For details on how to perform these operations please see the
22
22
  Add this line to your application's Gemfile:
23
23
 
24
24
  ```ruby
25
- gem 'his_emr_api_lab', git: 'https://github.com/EGPAFMalawiHIS/HIS-EMR-API-Lab', branch: 'development'
25
+ gem 'lab', git: 'https://github.com/EGPAFMalawiHIS/HIS-EMR-API-Lab', branch: 'development'
26
26
  ```
27
27
 
28
28
  And then execute:
29
29
 
30
30
  ```bash
31
- $ bundle install
31
+ $ bundle install lab
32
32
  ```
33
33
 
34
34
  Or install it yourself as:
35
35
 
36
36
  ```bash
37
- $ gem install his_emr_api_lab
37
+ $ gem install lab
38
38
  ```
39
39
 
40
40
  Finally run:
41
41
 
42
42
  ```bash
43
- $ bundle exec rails his_emr_api_lab:install
43
+ $ bundle exec rails lab:install
44
44
  ```
45
45
 
46
46
  ## Configuration
@@ -66,19 +66,6 @@ but too much a departure from it is frowned upon. For example, you will be forgi
66
66
  for writing a method with 15 to 20 lines if you clearly justify why you couldn't
67
67
  break that method into multiple smaller methods.
68
68
 
69
- ## Publishing
70
-
71
- To publish a new version of the gem, first update the version number in
72
- `lib/lab/version.rb` and then run the following command:
73
-
74
- ```bash
75
- $ gem build his_emr_api_lab.gemspec
76
- $ gem push his_emr_api_lab-<version>.gem
77
- ```
78
- Make sure to replace `<version>` with the version number you set in `lib/lab/version.rb`.
79
-
80
- NB: You need to have an account on [rubygems.org](https://rubygems.org/) and permission to publish gems.
81
-
82
69
  ## License
83
70
 
84
71
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -52,8 +52,7 @@ module Lab
52
52
  end
53
53
 
54
54
  def order_status
55
- order_params = params.permit(:tracking_number, :status, :status_time, :comments, :status_id,
56
- updated_by: [:first_name, :last_name, :id, :phone_number])
55
+ order_params = params.permit(:tracking_number, :status, :status_time, :comments)
57
56
  OrdersService.update_order_status(order_params)
58
57
  render json: { message: "Status for order #{order_params['tracking_number']} successfully updated" }, status: :ok
59
58
  end
@@ -7,8 +7,11 @@ module Lab
7
7
  queue_as :default
8
8
  def perform(results_obs_id, serializer, result_enter_by)
9
9
  Rails.logger.info("Lab::ProcessLabResultJob: Processing result completion for #{serializer}")
10
+ # set location context for the job based on the order's encounter to ensure proper context for any operations performed in the job
10
11
  results_obs = Lab::LabResult.unscoped.find(results_obs_id)
12
+ encounter = Encounter.unscoped.find_by(encounter_id: results_obs.encounter_id)
13
+ Location.current = Location.find(encounter.location_id) if encounter&.location_id
11
14
  Lab::ResultsService.process_result_completion(results_obs, serializer, result_enter_by)
12
15
  end
13
16
  end
14
- end
17
+ end
@@ -10,7 +10,8 @@ module Lab
10
10
  Rails.logger.info('Initialising LIMS REST API...')
11
11
 
12
12
  User.current = Lab::Lims::Utils.lab_user
13
- Location.current = Location.find_by_name('ART clinic')
13
+ # Set location from patient's most recent encounter to ensure proper context
14
+ set_location_from_patient_encounter(patient_id)
14
15
 
15
16
  lockfile = Rails.root.join('tmp', "update-patient-orders-#{patient_id}.lock")
16
17
 
@@ -28,5 +29,53 @@ module Lab
28
29
 
29
30
  File.unlink(lockfile) if done
30
31
  end
32
+
33
+ private
34
+
35
+ def set_location_from_patient_encounter(patient_id)
36
+ Rails.logger.info("Setting location context for patient #{patient_id}")
37
+
38
+ # Strategy 1: Find location from patient's most recent order (ANY order type)
39
+ recent_order = Order.unscoped
40
+ .where(patient_id: patient_id)
41
+ .order(start_date: :desc)
42
+ .first
43
+
44
+ if recent_order
45
+ encounter = Encounter.unscoped.find_by(encounter_id: recent_order.encounter_id)
46
+ if encounter&.location_id
47
+ Location.current = Location.find(encounter.location_id)
48
+ Rails.logger.info("Location set from patient's recent order: #{Location.current.name} (ID: #{Location.current.location_id})")
49
+ return
50
+ end
51
+ end
52
+
53
+ # Strategy 2: Find location from patient's most recent encounter
54
+ recent_encounter = Encounter.unscoped
55
+ .where(patient_id: patient_id)
56
+ .order(encounter_datetime: :desc)
57
+ .first
58
+
59
+ if recent_encounter&.location_id
60
+ Location.current = Location.find(recent_encounter.location_id)
61
+ Rails.logger.info("Location set from patient's recent encounter: #{Location.current.name} (ID: #{Location.current.location_id})")
62
+ return
63
+ end
64
+
65
+ # Fallback chain: Try multiple options to ensure location is ALWAYS set
66
+ Location.current ||= begin
67
+ Location.current_health_center
68
+ rescue StandardError
69
+ nil
70
+ end
71
+ Location.current ||= Location.first
72
+
73
+ if Location.current
74
+ Rails.logger.info("Location set to fallback: #{Location.current.name} (ID: #{Location.current.location_id})")
75
+ else
76
+ Rails.logger.error('CRITICAL: Could not set Location.current - no locations found in database!')
77
+ raise 'No locations available in database'
78
+ end
79
+ end
31
80
  end
32
81
  end
@@ -8,10 +8,14 @@ module Lab
8
8
  Rails.logger.info("Voiding order ##{order_id} in LIMS")
9
9
 
10
10
  User.current = Lab::Lims::Utils.lab_user
11
- Location.current = Location.find_by_name('ART clinic')
11
+ # Set location from order's encounter to ensure proper context
12
+ order = Lab::LabOrder.unscoped.find(order_id)
13
+ encounter = Encounter.unscoped.find_by(encounter_id: order.encounter_id)
14
+ Location.current = Location.find(encounter.location_id) if encounter&.location_id
15
+ Location.current ||= Location.find_by_name('ART clinic')
12
16
 
13
17
  worker = Lab::Lims::PushWorker.new(Lab::Lims::ApiFactory.create_api)
14
- worker.push_order(Lab::LabOrder.unscoped.find(order_id))
18
+ worker.push_order(order)
15
19
  end
16
20
  end
17
21
  end
@@ -8,11 +8,6 @@ module Lab
8
8
 
9
9
  -> { where(concept:) }
10
10
  end
11
-
12
- # Cache the concept ID to avoid lookups in association scopes
13
- def order_status_concept_id
14
- @order_status_concept_id ||= ConceptName.find_by(name: 'Lab Order Status')&.concept_id
15
- end
16
11
  end
17
12
 
18
13
  has_many :tests,
@@ -49,20 +44,12 @@ module Lab
49
44
  class_name: '::Lab::LimsOrderMapping',
50
45
  foreign_key: :order_id
51
46
 
52
- # Status trails are stored as observations with concept 'Lab Order Status'
53
- has_many :status_trail_observations,
54
- lambda {
55
- unscoped.where(voided: 0, concept_id: Lab::LabOrder.order_status_concept_id).order(obs_datetime: :asc)
56
- },
57
- class_name: 'Observation',
58
- foreign_key: :order_id
59
-
60
47
  default_scope do
61
48
  joins(:order_type)
62
49
  .merge(OrderType.where(name: [
63
- Lab::Metadata::ORDER_TYPE_NAME,
64
- Lab::Metadata::HTS_ORDER_TYPE_NAME
65
- ]))
50
+ Lab::Metadata::ORDER_TYPE_NAME,
51
+ Lab::Metadata::HTS_ORDER_TYPE_NAME
52
+ ]))
66
53
  .where.not(concept_id: ConceptName.where(name: 'Tests ordered').select(:concept_id))
67
54
  end
68
55
 
@@ -70,13 +57,11 @@ module Lab
70
57
  scope :not_drawn, -> { where(concept_id: ConceptName.where(name: 'Unknown').select(:concept_id)) }
71
58
 
72
59
  def self.prefetch_relationships
73
- # NOTE: status_trail_observations and test results are not preloaded due to
74
- # Rails limitations with eager loading unscoped associations. They load on-demand instead.
75
- preload(:reason_for_test,
76
- :requesting_clinician,
77
- :target_lab,
78
- :comment_to_fulfiller,
79
- :tests)
60
+ includes(:reason_for_test,
61
+ :requesting_clinician,
62
+ :target_lab,
63
+ :comment_to_fulfiller,
64
+ tests: [:result])
80
65
  end
81
66
  end
82
67
  end
@@ -3,9 +3,9 @@
3
3
  module Lab
4
4
  class LabResult < Observation
5
5
  def children
6
- Observation.unscoped.where(obs_group_id: obs_id, voided: 0)
6
+ Observation.where(obs_group_id: obs_id, voided: 0)
7
7
  end
8
-
8
+
9
9
  alias measures children
10
10
 
11
11
  default_scope do
@@ -6,33 +6,14 @@ module Lab
6
6
  where(concept: ConceptName.where(name: Lab::Metadata::TEST_TYPE_CONCEPT_NAME))
7
7
  end
8
8
 
9
- # Cache the concept IDs as class methods to avoid lookups in association scopes
10
- def self.test_status_concept_id
11
- @test_status_concept_id ||= ConceptName.find_by(name: 'Lab Test Status')&.concept_id
12
- end
13
-
14
- def self.test_result_concept_id
15
- @test_result_concept_id ||= ConceptName.find_by(name: Lab::Metadata::TEST_RESULT_CONCEPT_NAME)&.concept_id
16
- end
17
-
18
9
  has_one :result,
19
- -> { unscoped.where(voided: 0, concept_id: Lab::LabTest.test_result_concept_id) },
10
+ -> { where(concept: ConceptName.where(name: Lab::Metadata::TEST_RESULT_CONCEPT_NAME)) },
20
11
  class_name: 'Lab::LabResult',
21
12
  foreign_key: :obs_group_id
22
13
 
23
- # Status trails are stored as observations with concept 'Lab Test Status'
24
- # They are linked via obs_group_id (this test obs is the parent)
25
- has_many :status_trail_observations,
26
- lambda {
27
- unscoped.where(voided: 0, concept_id: Lab::LabTest.test_status_concept_id).order(obs_datetime: :asc)
28
- },
29
- class_name: 'Observation',
30
- foreign_key: :obs_group_id,
31
- primary_key: :obs_id
32
-
33
14
  def void(reason)
34
15
  result&.void(reason)
35
- super
16
+ super(reason)
36
17
  end
37
18
  end
38
19
  end
@@ -9,7 +9,8 @@ module Lab
9
9
  reason_for_test ||= order.reason_for_test
10
10
  target_lab = target_lab&.value_text || order.target_lab&.value_text || Location.current_health_center&.name
11
11
 
12
- encounter = Encounter.find_by_encounter_id(order.encounter_id)
12
+ # Use unscoped to find encounter across all locations
13
+ encounter = Encounter.unscoped.find_by_encounter_id(order.encounter_id)
13
14
  program = Program.find_by_program_id(encounter.program_id)
14
15
 
15
16
  ActiveSupport::HashWithIndifferentAccess.new(
@@ -36,10 +37,8 @@ module Lab
36
37
  name: concept_name(reason_for_test&.value_coded)
37
38
  },
38
39
  delivery_mode: order&.lims_acknowledgement_status&.acknowledgement_type,
39
- order_status: latest_order_status(order),
40
- order_status_trail: serialize_order_status_trail(order),
41
40
  tests: tests.map do |test|
42
- result_obs = test.result
41
+ result_obs = test.children.first
43
42
 
44
43
  {
45
44
  id: test.obs_id,
@@ -47,9 +46,7 @@ module Lab
47
46
  uuid: test.uuid,
48
47
  name: concept_name(test.value_coded),
49
48
  test_method: test_method(order, test.value_coded),
50
- result: result_obs && ResultSerializer.serialize(result_obs),
51
- test_status: latest_test_status(test),
52
- test_status_trail: serialize_test_status_trail(test)
49
+ result: result_obs && ResultSerializer.serialize(result_obs)
53
50
  }
54
51
  end
55
52
  }
@@ -78,72 +75,5 @@ module Lab
78
75
  .select(:concept_id)
79
76
  LabTest.unscoped.where(concept:, order:, voided: true)
80
77
  end
81
-
82
- def self.latest_order_status(order)
83
- # Query obs table for latest order status
84
- latest_obs = order.status_trail_observations.last
85
- return nil unless latest_obs
86
-
87
- updated_by = parse_comments_json(latest_obs.comments)
88
-
89
- {
90
- status_id: 0, # status_id not used with text values
91
- status: latest_obs.value_text,
92
- timestamp: latest_obs.obs_datetime,
93
- updated_by: updated_by
94
- }
95
- end
96
-
97
- def self.serialize_order_status_trail(order)
98
- # Query obs table for order status trail
99
- order.status_trail_observations.map do |obs|
100
- updated_by = parse_comments_json(obs.comments)
101
-
102
- {
103
- status_id: 0, # status_id not used with text values
104
- status: obs.value_text,
105
- timestamp: obs.obs_datetime,
106
- updated_by: updated_by
107
- }
108
- end
109
- end
110
-
111
- def self.latest_test_status(test)
112
- # Query obs table for latest test status
113
- latest_obs = test.status_trail_observations.last
114
- return nil unless latest_obs
115
-
116
- updated_by = parse_comments_json(latest_obs.comments)
117
-
118
- {
119
- status_id: 0, # status_id not used with text values
120
- status: latest_obs.value_text,
121
- timestamp: latest_obs.obs_datetime,
122
- updated_by: updated_by
123
- }
124
- end
125
-
126
- def self.serialize_test_status_trail(test)
127
- # Query obs table for test status trail
128
- test.status_trail_observations.map do |obs|
129
- updated_by = parse_comments_json(obs.comments)
130
-
131
- {
132
- status_id: 0, # status_id not used with text values
133
- status: obs.value_text,
134
- timestamp: obs.obs_datetime,
135
- updated_by: updated_by
136
- }
137
- end
138
- end
139
-
140
- # Helper to parse updated_by from obs comments field
141
- def self.parse_comments_json(comments)
142
- return {} if comments.blank?
143
-
144
- JSON.parse(comments)
145
- rescue JSON::ParserError
146
- {}
147
- end
148
78
  end
149
79
  end
@@ -77,82 +77,15 @@ module Lab
77
77
  def consume_orders(*_args, patient_id: nil, **_kwargs)
78
78
  orders_pending_updates(patient_id).each do |order|
79
79
  order_dto = Lab::Lims::OrderSerializer.serialize_order(order)
80
-
81
- # Always fetch the full order from NLIMS to get status trails
82
- begin
83
- lims_order = find_lims_order(order.accession_number)
84
- patch_order_dto_with_lims_order!(order_dto, lims_order)
85
-
86
- Rails.logger.debug("NLIMS order structure for #{order.accession_number}:")
87
- Rails.logger.debug(" Has 'order' key: #{lims_order.key?('order')}")
88
- Rails.logger.debug(" Has 'data' key: #{lims_order.key?('data')}")
89
- Rails.logger.debug(" Top level keys: #{lims_order.keys.inspect}")
90
-
91
- # Also extract status trails from the NLIMS order
92
- # Note: NLIMS might return order data under 'order' or 'data.order'
93
- order_data = lims_order['order'] || lims_order.dig('data', 'order') || lims_order
94
-
95
- if order_data && order_data['status_trail']
96
- Rails.logger.info("Found #{order_data['status_trail'].size} order status trail entries from NLIMS")
97
- order_dto[:sample_statuses] ||= []
98
- # Convert NLIMS status trail to the format expected by PullWorker
99
- # Note: sample_statuses must be an array of single-key hashes
100
- order_data['status_trail'].each do |trail|
101
- # Convert ISO 8601 timestamp to YYYYMMDDHHmmss format
102
- timestamp_key = convert_timestamp_to_key(trail['timestamp'])
103
- order_dto[:sample_statuses] << {
104
- timestamp_key => {
105
- 'status_id' => trail['status_id'],
106
- 'status' => trail['status'],
107
- 'updated_by' => trail['updated_by']
108
- }
109
- }
110
- Rails.logger.debug(" Added order status: #{trail['status']} at #{timestamp_key}")
111
- end
112
- Rails.logger.debug("Final sample_statuses: #{order_dto[:sample_statuses].inspect}")
113
- else
114
- Rails.logger.warn("No order status_trail found in NLIMS response for #{order.accession_number}")
115
- Rails.logger.debug("Order data keys: #{order_data&.keys&.inspect}")
116
- end
117
-
118
- # Extract test status trails from NLIMS tests
119
- tests_data = lims_order['tests'] || lims_order.dig('data', 'tests') || []
120
- if tests_data.is_a?(Array)
121
- Rails.logger.debug("Processing #{tests_data.size} tests from NLIMS")
122
- order_dto['test_statuses'] ||= {}
123
- tests_data.each do |test|
124
- next unless test['status_trail'].is_a?(Array)
125
-
126
- test_name = test.dig('test_type', 'name')
127
- next unless test_name
128
-
129
- Rails.logger.debug(" Found #{test['status_trail'].size} status trail entries for test #{test_name}")
130
- order_dto['test_statuses'][test_name] ||= {}
131
- test['status_trail'].each do |trail|
132
- # Convert ISO 8601 timestamp to YYYYMMDDHHmmss format
133
- timestamp_key = convert_timestamp_to_key(trail['timestamp'])
134
- order_dto['test_statuses'][test_name][timestamp_key] = {
135
- 'status_id' => trail['status_id'],
136
- 'status' => trail['status'],
137
- 'updated_by' => trail['updated_by']
138
- }
139
- end
140
- end
141
- end
142
- rescue RestClient::NotFound
143
- Rails.logger.warn("Order ##{order.accession_number} not found in NLIMS, using local data only")
80
+ if order_dto['priority'].nil? || order_dto['sample_type'].casecmp?('not_specified')
81
+ patch_order_dto_with_lims_order!(order_dto, find_lims_order(order.accession_number))
144
82
  end
145
-
146
- # Try to fetch results if available
147
83
  if order_dto['test_results'].empty?
148
84
  begin
149
85
  patch_order_dto_with_lims_results!(order_dto, find_lims_results(order.accession_number))
150
- rescue InvalidParameters => e
151
- Rails.logger.info("No results available for ##{order.accession_number}: #{e.message}")
152
- # Don't skip - continue processing to save status trails
153
- rescue RestClient::NotFound
154
- Rails.logger.info("No results found for ##{order.accession_number}")
155
- # Don't skip - continue processing to save status trails
86
+ rescue InvalidParameters => e # LIMS responds with a 401 when a result is not found :(
87
+ Rails.logger.error("Failed to fetch results for ##{order.accession_number}: #{e.message}")
88
+ next
156
89
  end
157
90
  end
158
91
 
@@ -294,7 +227,7 @@ module Lab
294
227
  {
295
228
  order: {
296
229
  tracking_number: order_dto.fetch(:tracking_number),
297
- district: current_district,
230
+ district: order_dto.fetch(:districy),
298
231
  health_facility_name: order_dto.fetch(:sending_facility),
299
232
  sending_facility: order_dto.fetch(:sending_facility),
300
233
  arv_number: order_dto.fetch(:patient).fetch(:arv_number),
@@ -348,24 +281,17 @@ module Lab
348
281
  status: 'specimen_collected',
349
282
  time_updated: date_updated,
350
283
  sample_type: order_dto.fetch(:sample_type_map),
351
- updated_by: status.fetch(:updated_by)
284
+ updated_by: status.fetch(:updated_by),
285
+ status_trail: [
286
+ updated_by: {
287
+ first_name: status.fetch(:updated_by).fetch(:first_name),
288
+ last_name: status.fetch(:updated_by).fetch(:last_name),
289
+ id_number: status.fetch(:updated_by).fetch(:id)
290
+ }
291
+ ]
352
292
  }
353
293
  end
354
294
 
355
- def current_district
356
- health_centre = Location.current_health_center
357
- raise 'Current health centre not set' unless health_centre
358
-
359
- district = health_centre.district || Lab::Lims::Config.application['district']
360
-
361
- unless district
362
- health_centre_name = "##{health_centre.id} - #{health_centre.name}"
363
- raise "Current health centre district not set: #{health_centre_name}"
364
- end
365
-
366
- district
367
- end
368
-
369
295
  ##
370
296
  # Extracts sample drawn status from an OrderDto
371
297
  def sample_drawn_status(order_dto)
@@ -511,23 +437,25 @@ module Lab
511
437
  order_dto['test_results'].each do |test_name, results|
512
438
  Rails.logger.info("Pushing result for order ##{order_dto['tracking_number']}")
513
439
  in_authenticated_session do |headers|
514
- params = make_update_test_params(order_dto['tracking_number'], test_name, results)
440
+ params = make_update_test_params(order_dto, test_name, results)
515
441
 
516
- RestClient.post(expand_uri("tests/#{order_dto['tracking_number']}", api_version: 'v2'), params, headers)
442
+ RestClient.put(expand_uri("tests/#{order_dto['tracking_number']}", api_version: 'v2'), params, headers)
517
443
  end
518
444
  end
519
445
  end
520
446
 
521
- def make_update_test_params(_tracking_number, test, results, test_status = 'Drawn')
447
+ def make_update_test_params(order_dto, test, results, test_status = 'Drawn')
448
+ # Find the concept from the test name (which is a string)
449
+ concept = ::ConceptName.find_by(name: test)&.concept
522
450
  {
523
451
  test_status:,
524
452
  time_updated: results['result_date'],
525
453
  test_type: {
526
- name: ::Concept.find(test.concept_id).test_catalogue_name,
527
- nlims_code: ::Concept.find(test.concept_id).nlims_code
454
+ name: concept&.test_catalogue_name,
455
+ nlims_code: concept&.nlims_code
528
456
  },
529
- test_results: results['results'].map do |measure, _value|
530
- measure_name, measure_value = measure
457
+ test_results: results['results'].map do |measure_name, value|
458
+ measure_value = value['result_value']
531
459
  {
532
460
  measure: {
533
461
  name: measure_name,
@@ -539,6 +467,18 @@ module Lab
539
467
  result_date: results['result_date']
540
468
  }
541
469
  }
470
+ end,
471
+ status_trail: order_dto['sample_statuses'].map do |trail_entry|
472
+ date, status = trail_entry.each_pair.first
473
+ {
474
+ status: status['status'],
475
+ timestamp: date,
476
+ updated_by: {
477
+ first_name: status.fetch('updated_by').fetch('first_name'),
478
+ last_name: status.fetch('updated_by').fetch('last_name'),
479
+ id_number: status.fetch('updated_by').fetch('id')
480
+ }
481
+ }
542
482
  end
543
483
  }
544
484
  end
@@ -617,20 +557,6 @@ module Lab
617
557
 
618
558
  orders
619
559
  end
620
-
621
- # Converts ISO 8601 timestamp to YYYYMMDDHHmmss format
622
- def convert_timestamp_to_key(timestamp)
623
- return timestamp if timestamp.nil? || timestamp.empty?
624
-
625
- begin
626
- # Parse ISO 8601 timestamp and format as YYYYMMDDHHmmss
627
- Time.parse(timestamp).strftime('%Y%m%d%H%M%S')
628
- rescue StandardError => e
629
- Rails.logger.warn("Failed to parse timestamp '#{timestamp}': #{e.message}")
630
- # Fallback: remove all non-digits
631
- timestamp.to_s.gsub(/\D/, '')
632
- end
633
- end
634
560
  end
635
561
  end
636
562
  end
@@ -759,7 +685,7 @@ module Lab
759
685
  def make_create_params(order_dto)
760
686
  {
761
687
  tracking_number: order_dto.fetch(:tracking_number),
762
- district: current_district,
688
+ district: order_dto.fetch(:districy),
763
689
  health_facility_name: order_dto.fetch(:sending_facility),
764
690
  first_name: order_dto.fetch(:patient).fetch(:first_name),
765
691
  last_name: order_dto.fetch(:patient).fetch(:last_name),
@@ -797,20 +723,6 @@ module Lab
797
723
  }
798
724
  end
799
725
 
800
- def current_district
801
- health_centre = Location.current_health_center
802
- raise 'Current health centre not set' unless health_centre
803
-
804
- district = health_centre.district || Lab::Lims::Config.application['district']
805
-
806
- unless district
807
- health_centre_name = "##{health_centre.id} - #{health_centre.name}"
808
- raise "Current health centre district not set: #{health_centre_name}"
809
- end
810
-
811
- district
812
- end
813
-
814
726
  ##
815
727
  # Extracts sample drawn status from an OrderDto
816
728
  def sample_drawn_status(order_dto)