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



111
112
113
# File 'app/services/lab/orders_service.rb', line 111

def check_tracking_number(tracking_number)
  accession_number_exists?(tracking_number) || nlims_accession_number_exists?(tracking_number)
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
96
97
# 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

  reason_for_test = params[:reason_for_test] || params[:reason_for_test_id]

  if reason_for_test
    Rails.logger.debug("Updating reason for test on order ##{order.order_id}")
    update_reason_for_test(order, Concept.find(reason_for_test)&.id)
  end

  Lab::LabOrderSerializer.serialize_order(order)
end

.update_order_result(order_params) ⇒ Object



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

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



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

def update_order_status(order_params)
  # find the order
  order = find_order(order_params['tracking_number'])
  concept = ConceptName.find_by_name Lab::Metadata::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



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

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