Module: Lab::OrdersService

Defined in:
app/services/lab/orders_service.rb

Overview

Manage lab orders.

Lab orders are just ordinary openmrs orders with extra metadata that separates them from other orders. Lab orders have an order type of ‘Lab’ with the order’s test type as the order’s concept. The order’s start date is the day the order is made. Additional information pertaining to the order is stored as observations that point to the order. The specimen types, requesting clinician, target lab, and reason for test are saved as observations to the order. Refer to method #order_test for more information.

Class Method Summary collapse

Class Method Details

.check_tracking_number(tracking_number) ⇒ Object



109
110
111
# File 'app/services/lab/orders_service.rb', line 109

def check_tracking_number(tracking_number)
  accession_number_exists?(tracking_number) || nlims_accession_number_exists?(tracking_number)
end

.lab_orders(start_date, end_date, concept_id = nil, include_data: false) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/services/lab/orders_service.rb', line 139

def lab_orders(start_date, end_date, concept_id = nil, include_data: false)
  tests = Lab::LabTest.where('date_created >= ? AND date_created <= ?', start_date, end_date)
  tests = tests.where(value_coded: concept_id) if concept_id
  orders = Lab::LabOrder.where(order_id: tests.pluck(:order_id))
  data = {
    count: orders.count,
    last_order_date: Lab::LabOrder.last&.start_date&.to_date,
    lab_orders: []
  }
  data[:lab_orders] = orders.map do |order|
    Lab::LabOrderSerializer.serialize_order(
      order, requesting_clinician: order.requesting_clinician,
             reason_for_test: order.reason_for_test,
             target_lab: order.target_lab
    )
  end if include_data
  data
end

.order_test(order_params) ⇒ Object

Create a lab order.

Parameters schema:

{
  encounter_id: {
    type: :integer,
    required: :false,
    description: 'Attach order to this if program_id and patient_id are not provided'
  },
  program_id: { type: :integer, required: false },
  patient_id: { type: :integer, required: false }
  specimen: { type: :object, properties: { concept_id: :integer }, required: i[concept_id] },
  test_type_ids: {
    type: :array,
    items: {
      type: :object,
      properties: { concept_id: :integer },
      required: i[concept_id]
    }
  },
  start_date: { type: :datetime }
  accession_number: { type: :string }
  target_lab: { type: :string },
  reason_for_test_id: { type: :integer },
  requesting_clinician: { type: :string }
}

encounter_id: is an ID of the encounter the lab order is to be created under test_type_id: is a concept_id of the name of test being ordered specimen_type_id: is a list of IDs for the specimens to be tested (can be ommited) target_lab: is the name of the lab where test will be carried out reason_for_test_id: is a concept_id for a (standard) reason of why the test is being carried out requesting_clinician: Name of the clinician requesting the test (defaults to current user)



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/services/lab/orders_service.rb', line 52

def order_test(order_params)
  Order.transaction do
    encounter = find_encounter(order_params)
    if order_params[:accession_number].present? && check_tracking_number(order_params[:accession_number])
      raise 'Accession number already exists'
    end

    order = create_order(encounter, order_params)

    Lab::TestsService.create_tests(order, order_params[:date], order_params[:tests])

    Lab::LabOrderSerializer.serialize_order(
      order, requesting_clinician: add_requesting_clinician(order, order_params),
             reason_for_test: add_reason_for_test(order, order_params),
             target_lab: add_target_lab(order, order_params)
    )
  end
end

.update_order(order_id, params) ⇒ Object

Raises:

  • (::InvalidParameterError)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'app/services/lab/orders_service.rb', line 71

def update_order(order_id, params)
  specimen_id = params.dig(:specimen, :concept_id)
  raise ::InvalidParameterError, 'Specimen concept_id is required' unless specimen_id

  order = Lab::LabOrder.find(order_id)
  if order.concept_id != unknown_concept_id && !params[:force_update]&.casecmp?('true')
    raise ::UnprocessableEntityError, "Can't change order specimen once set"
  end

  if specimen_id.to_i != order.concept_id
    Rails.logger.debug("Updating order ##{order.order_id}")
    order.update!(concept_id: specimen_id,
                  discontinued: true,
                  discontinued_by: User.current.user_id,
                  discontinued_date: params[:date]&.to_date || Time.now,
                  discontinued_reason_non_coded: 'Sample drawn/updated')
  end

  if params[:reason_for_test_id]
    Rails.logger.debug("Updating reason for test on order ##{order.order_id}")
    update_reason_for_test(order, params[:reason_for_test_id])
  end

  Lab::LabOrderSerializer.serialize_order(order)
end

.update_order_result(order_params) ⇒ Object



132
133
134
135
136
137
# File 'app/services/lab/orders_service.rb', line 132

def update_order_result(order_params)
  order = find_order(order_params['tracking_number'])
  order_dto = Lab::Lims::OrderSerializer.serialize_order(order)
  patch_order_dto_with_lims_results!(order_dto, order_params['results'])
  Lab::Lims::PullWorker.new(nil).process_order(order_dto)
end

.update_order_status(order_params) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'app/services/lab/orders_service.rb', line 113

def update_order_status(order_params)
  # find the order
  order = find_order(order_params['tracking_number'])
  concept = ConceptName.find_by_name Lab::::LAB_ORDER_STATUS_CONCEPT_NAME
  ActiveRecord::Base.transaction do
    void_order_status(order, concept)
    Observation.create!(
      person_id: order.patient_id,
      encounter_id: order.encounter_id,
      concept_id: concept.concept_id,
      order_id: order.id,
      obs_datetime: order_params['status_time'] || Time.now,
      value_text: order_params['status'],
      creator: User.current.id
    )
  end
  create_rejection_notification(order_params) if order_params['status'] == 'test-rejected'
end

.void_order(order_id, reason) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
# File 'app/services/lab/orders_service.rb', line 97

def void_order(order_id, reason)
  order = Lab::LabOrder.includes(i[requesting_clinician reason_for_test target_lab], tests: [:result])
                       .find(order_id)

  order.requesting_clinician&.void(reason)
  order.reason_for_test&.void(reason)
  order.target_lab&.void(reason)

  order.tests.each { |test| test.void(reason) }
  order.void(reason)
end